查看: 3342|回复: 2

diy平衡车

[复制链接]
  • TA的每日心情

    2016-11-17 13:26
  • 签到天数: 410 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-8-9 11:22:17 | 显示全部楼层 |阅读模式
    分享到:
    赛格威”(英语:Segway)是一种电力驱动、具有自我平衡能力的个人用运输载具,是都市用交通工具的一种。由美国发明家狄恩·卡门与他的DEKA研发公司(DEKA Research and Development Corp.)团队发明设计,并创立思维车责任有限公司(Segway LLC.),自2001年12月起将思维车商业化量产销售。(资料来源:维基百科中文)
    “赛格威”是一种让人留下深刻印象的代步工具,它占地不足一平方米,乘车人像使用滑板一样站立其上,双手解放,但却可以仅通过身体移动改变重心位置,就进行前进后退,转弯刹车等操作。传统的交通工具都无法做到随心而动,必须把大部分精力放在控制方向和速度上,而“赛格威”并不需要专门的操控装置,一切由车身自主完成,也由此获得了“平衡车”的别名。
    “赛格威”平衡车看来神奇,但你有没有发现它的原理其实很简单呢?拜最新科技所赐,关键零件都可以在淘宝上直接买到,而控制程序也可以查阅原理自行编写。拥有自己的平衡车,其实非常简单。
    倒立摆和机器人
    “赛格威”的平衡问题,实际上是一个多级倒立摆问题。当一个人用手托住一根竹竿的底部使它在空中竖直不倒下,这就是一个一级倒立摆系统的模型。如果第一根竹竿上面用铰链连着其他竹竿,或者竹竿本身具有一定的弹性(可比拟“赛格威”上的有骨骼和关节的大活人),就成了多级倒立摆。
    用手撑竹竿的游戏很多人都玩过,印象最深的应当是它是一个静不稳定系统。在桌面上的水杯能自己站稳,当重心投影落于杯底内时,即使有细小扰动也不会倒下。但是手心里的竹竿大部分时间重心投影不在接触点上,让竹竿保持相对不动靠的是动态调整——竹竿往哪边倒,手就赶紧往哪边凑,让重心回到接触点周围。这就是依靠人眼,大脑和人手完成的动态平衡过程。
    人类的大脑在处理这类问题上有先天优势,因为人的走路过程本质上来说是不断前跌的过程,必须依靠实时伸出支撑脚转移重心来保证直立行进的动态平衡。而让机器人做到这一点就很困难,需要综合解决动态控制过程中的线性问题、鲁棒性问题、镇定问题、随动问题以及跟踪问题等诸多细节——所以至今见到的人形机器人里,能僵硬走路的很多,但能和真人一样上蹿下跳的绝无仅有。
    两名民警驾驶“赛格威”单人警用巡逻车巡逻。图片来源:新华网
    “赛格威”的动态平衡原理和倒立摆相同,将最上方的乘客作为摆臂,然后控制车轮维持系统重心使乘客直立。当驾驶人改变自己身体的角度往前或往后倾时,“赛格威”就会根据倾斜的方向前进或后退,而速度则与驾驶人身体倾斜的程度呈正比以保持平衡。这里的一个巧妙设计是将乘客传感和控制二合一了——“赛格威”前进或后退维持平衡的同时,也达成了按乘客意图前进或后退的目的。最终,熟练的驾驶人可以和自己行走一样,仅凭直觉就能完成前后左右各方向的运动,同时解放双手和大脑思维,这一特点使“赛格威”特别适合游览和警用巡逻。
    DIY自己的“赛格威”
    和人类行走一样,“赛格威”的控制也需要传感器和致动器。它依靠MEMS技术制造的精密固态陀螺仪和加速度计感应车体的旋转,速度和倾斜,高速微处理器计算传感器数据,并驱动轮毂电机完成前进/后退/差速转弯的动作。而在电路之外,为了让它从实验室中的倒立摆变成实用的代步车,还需要准备一些必需的结构零件和附件。
    机械部分
    此次设计的机械机构包括一个简单的独立悬挂。缓冲部分直接采用自行车的避震器(需要更换弹簧),机体做得不很紧凑,主要为了能够拆卸折叠,便于收放和运输。(需要说明的是,结构已提交专利申请,请勿用于商业用途。)
    整机材料很简单,两个独立驱动的轮子+电机驱动板+车身角度传感器+转弯传感器+电池+一个装下这些东西的盒子  。两个轮子、电机、避震器都是来自淘宝的成品。钣金和机加件为单独加工。
    这里贴一些制作图片,详细的零件工程图列在最后。
    整机外形
    结构细节
    电机安装部分
    电机为优耐特电机,250W,24v/质量不好,不作推荐。
    电机法兰部分剖视
    转向机部分:
    整机背面
    装配过程
    锂电池仓
    原设计为铅酸电池,后一朋友为我无偿提供了锂电池,在此再次表示感谢。
    车铣加工
    电机法兰安装
    整体安装
    电路部分
    主控采用AVR的ATMEGA_32,电机驱动为H桥驱动方式,元件选用的IR2184和IRF1405。传感器选用IDG300和ADXL335,电流传感器为ACS755。另外还有一些外围的小功能,可有可无,不详述了。
    控制驱动PCB图
    传感器PCB图
    PCB空板
    焊接需要注意的就是——别太马虎就行。先焊低矮的元器件,再焊大个的!
    焊接基本完成
    连接电机测试
    散热器:
    遥控和语音模块
    控制程序部分
    果壳网友们的素质都很高,这里就提一些关键部分。一些个人认为有用的代码附在最后。
    流程图
    车身角度获取
    选用的传感器为模拟量输出,因此只需要用单片机的AD采集数据后计算出角度值即可,需要注意的是,采集后的数据直接使用效果会很糟糕。需要再次进行滤波计算,得到一个准确、及时、抗扰动的真实角度数据。调速过程中可以用串口将数据输出,辅助调试。
    计算车轮速度
    这里就是简单的PID控制车轮转速,如果不记得就百度看看。调试参数会花点时间,刚开始参数别调过大,否则抖动起来有危险!另外需要设置角度过大停机的功能。
    获取转向数据
    转向数据为采集转向电位器而来,采集后的数据进行滤波处理后再用。转向中间设置一个无效的死区,也是防止误动作。
    遥控
    (图片来自网络)
    遥控为最普通的4键遥控器,淘宝成品。
    语音
    语音选用成品语音模块,厂家提供完整说明文档。
    温度
    硬件原先选用18b20,很是遗憾这部分程序没调通,可能原因1:系统必须有多处中断,并且中断服务程序比较多,因而打乱了18b20的时序,加上没有示波器,因而没调通。可能原因2:智商问题。
    尝试调试了近2小时无果后改用模拟量温度芯片LM35D,电压直接由电阻分压而来。
    其余部分可自由发挥。
    视频演示
    无视频无真相,怕熊上门所以拍了一小段视频。
    客厅实在太小,还放了些杂物,能够行走的地方就只有中间一小块了,跑不开。
    友情提示:此车有一定危险性,不排除摔倒、失控等问题,在空地上玩玩就好,打算用来代步上班的,请给自己买好保险!
    附件1:零件工程图
    点击下载完整工程图(文件大小:6.15M)(本设计已提交专利申请,请勿用于商业用途。)
    附件2:重点代码2.1车身角度滤波代码/************滤波************/float P[2][2] = {{ 1, 0 },{ 0, 1 }};float Pdot[4] ={0,0,0,0};const char C_0 = 1;float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;float Q_angle=0.001, Q_gyro=0.003, R_angle=0.5, dt=0.01;void Kalman_Filter(float angle_m,float gyro_m)  {    angle+=(gyro_m-q_bias) * dt;                   Pdot[0]=Q_angle - P[0][1] - P[1][0];          Pdot[1]=- P[1][1];    Pdot[2]=- P[1][1];    Pdot[3]=Q_gyro;        P[0][0] += Pdot[0] * dt;                 P[0][1] += Pdot[1] * dt;    P[1][0] += Pdot[2] * dt;    P[1][1] += Pdot[3] * dt;    angle_err = angle_m - angle;                  PCt_0 = C_0 * P[0][0];    PCt_1 = C_0 * P[1][0];    E = R_angle + C_0 * PCt_0;        K_0 = PCt_0 / E;    K_1 = PCt_1 / E;        t_0 = PCt_0;    t_1 = C_0 * P[0][1];    P[0][0] -= K_0 * t_0;                  P[0][1] -= K_0 * t_1;    P[1][0] -= K_1 * t_0;    P[1][1] -= K_1 * t_1;    angle   += K_0 * angle_err;            q_bias  += K_1 * angle_err;           angle_dot = gyro_m-q_bias;        }//**************滤波*****************//static float C_angle,C_angle_dot; static float bias_cf;void Complement_filter(float angle_m_cf,float gyro_m_cf){    bias_cf=0.998*bias_cf+0.002*gyro_m_cf;     C_angle_dot=gyro_m_cf-bias_cf;    C_angle=0.98*(C_angle+C_angle_dot*0.02)+0.02*angle_m_cf;}//***************************** 滤波结束*********************************/
    2.2 转向数据处理代码
    /************转向************/void Steering_handle(void) {                   Buf=  0.9 *Buf + 0.1 * AD_Turn;                               Turning= Buf -Turn_Zero;    //                              if(Turning <- Turn_Dead)                       //死区                     Turning+=Turn_Dead;                                          else if(Turning> Turn_Dead)                     Turning-=Turn_Dead;                                       else    Turning= 0;                             if (mode==0)               {                Drive_A=0;                Drive_B=0;                if (!(angle>0.1||angle<-0.1))                {                    mode=1;                }            }             else            {                if(lab==0)                    {                        Turning=0;                    }                else if (Turning>55||Turning<-55)//                    {                        Turning=0;                        lab=3;// turn error                    }                else           //按车速整定转向数据                    {                                        //buf2=Drivespeed;                    //if (buf2<0)buf2*=-1;                    //buf2/=3;                    //Turning/=buf2;                    Turning/=1;                    }                              Drive_A=Drivespeed-Turning;                 Drive_B=Drivespeed+Turning;                    }        } //***************************** 转向结束*********************************/2.3遥控部分状态机/***********按键********/#define BOOL int#define FALSE 0#define TRUE  1#define INT8U unsigned int/**********硬件接口***********/    #define     KEYPIN1               (PINC&(1<<3))    #define     KEYPIN2               (~PINB&(1<<0))    #define     KEYPIN3               (~PINB&(1<<1))    #define     KEYPIN4               (~PINB&(1<<3))    #define     KEYPIN5               (~PINB&(1<<4))        /**********按恪键属性**********/    #define KEY_JT 0x0e    #define KEY_A  0x0d    #define KEY_B  0x0b    #define KEY_C  0x07    #define KEY_D  0x08        #define KEY_NULL    0x0f//#define KEY_LONG_PERIOD      250#define KEY_CONTINUE_PERIOD  25//#define KEY_DOWN       0x80#define KEY_LONG       0x40#define KEY_CONTINUE   0x20#define KEY_UP         0x10//#define KEY_STATE_INIT     0#define KEY_STATE_WOBBLE   1#define KEY_STATE_PRESS    2#define KEY_STATE_LONG     3#define KEY_STATE_CONTINUE 4#define KEY_STATE_RELEASE  5 uchar KeyScan(void)  {    if(KEYPIN2==0) return KEY_A;    if(KEYPIN3==0) return KEY_B;    if(KEYPIN4==0) return KEY_C;    if(KEYPIN5==0) return KEY_D;    if(KEYPIN1==0) return KEY_JT;    return KEY_NULL;}void GetKey(uchar *pKeyValue){     static char KeyState = KEY_STATE_INIT;     static char KeyTimeCount = 0;     static char LastKey = KEY_NULL;      char KeyTemp = KEY_NULL;     KeyTemp = KeyScan();        switch(KeyState)     {         case KEY_STATE_INIT:              {                  if(KEY_NULL!=(KeyTemp))                  {                     KeyState = KEY_STATE_WOBBLE;                  }              }          break;          case KEY_STATE_WOBBLE:                   {                     KeyState = KEY_STATE_PRESS;                }              break;          case KEY_STATE_PRESS:               {                    if(KEY_NULL!=(KeyTemp))                      {                        LastKey = KeyTemp;                            KeyTemp|=KEY_DOWN;                            KeyState = KEY_STATE_LONG ;                    }                    else                    {                        KeyState = KEY_STATE_INIT;                    }                }          break;          case KEY_STATE_LONG:               {                 if(KEY_NULL !=(KeyTemp))                 {                  if(++KeyTimeCount > KEY_LONG_PERIOD)                  {                       KeyTimeCount = 0;                       KeyTemp|=KEY_LONG;                           KeyState = KEY_STATE_CONTINUE;                   }                  }                  else                   {                       KeyState = KEY_STATE_RELEASE;                  }                }        break;        case KEY_STATE_CONTINUE:               {                  if(KEY_NULL !=(KeyTemp))                  {                      if(++KeyTimeCount > KEY_CONTINUE_PERIOD)                       {                           KeyTimeCount = 0;                           KeyTemp |= KEY_CONTINUE;                        }                  }                  else                   {                       KeyState = KEY_STATE_RELEASE;                   }               }               break;               case KEY_STATE_RELEASE:               {                    LastKey |=KEY_UP;                    KeyTemp = LastKey;                    KeyState = KEY_STATE_INIT;               }               break;               default:break;        }        *pKeyValue = KeyTemp;  }   
    2.4电池电压void Get_Batt_Volt(void) {      int buf3=0,b=0;     buf3=0.9*buf3+0.1*AD_Batt;     if (b>10)         {            Voltage=buf3*3000.0/1024/65;            b=10;         }    else        {            b++;        }     }




    本文版权属于果壳网(guokr.com),转载请注明出处。商业使用请联系果壳

    评分

    参与人数 3与非币 +15 收起 理由
    张红一 + 5
    loveeeboard + 5 三周年铜板双倍!
    杨辛庄 + 5 好文 代码有点乱啊

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2016-8-15 09:30
  • 签到天数: 162 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2015-8-10 09:31:37 | 显示全部楼层
    好文 代码有点乱啊
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-7-25 22:49
  • 签到天数: 385 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-8-13 13:12:00 | 显示全部楼层
    好文 代码有点乱啊
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-12-25 09:35 , Processed in 0.164476 second(s), 23 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.