DIY

DIY一辆自己的 “赛格威”平衡车!

自制赛格威segway自平衡车

上善若水42 发表于  2013-11-28 17:58

首先向大家表示歉意,去年发帖展示初代平衡车时就已经承诺编辑出一份制作说明,但一直未能完成,很是抱歉!

原因有四:
1、    太过粗糙,发出来确实有碍观瞻;
2、    上次做车没留下几张照片,无图无真相;
3、    一直工作比较繁忙,实在没能抽出时间;
4、    (接原因2)本意尽快再做一个,留下照片。但女皇迟迟不给批款,所以才延误至今!

此次为了完成自己的承诺,可是耗费了2月的零花钱。并且有视频有真相,希望您能喜欢。

原理简介

“赛格威”平衡车

图片来自 electrictourcompany.com

“赛格威”(英语: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++;
        }     
}

热门评论

  • 2013-11-28 22:02 天净半缘

    “赛格威”(英语:Segway)的老板开自家的山地型“赛格威”上山。。然后摔死了。。。真是让人忍不住的吐槽啊。

    [61] 评论
  • 2013-11-28 18:57 老冯的红围脖

    楼主强大啊!儿子一直想有个赛格威,可惜买不起!不过看了楼主的制作,真是羡慕。机械部分制作都可以完成,不过电路部分本人一点基础也没有,电路板怎么做?没有现成的吗?看来靠我自己实现不了这个梦了!谢谢楼主

    [22] 评论
  • 2013-11-28 18:24 飞鱼BH1JSS 飞行爱好者,航模控

    楼主太土豪,光看加工设备就让人口水一地啊~

    [18] 评论

显示所有评论

全部评论(326)
  • 1楼
    2013-11-28 18:20 忧伤的尼姑

    问题是自己做这种机械运动要求很高的东西行吗,工艺不达标 会不会容易坏

    来自NOKIA Lumia 620
    [0] 评论
  • 2楼
    2013-11-28 18:24 飞鱼BH1JSS 飞行爱好者,航模控

    楼主太土豪,光看加工设备就让人口水一地啊~

    [18] 评论
  • 3楼
    2013-11-28 18:51 子隐于斯

    Shut up and take my money!

    [4] 评论
  • 4楼
    2013-11-28 18:57 老冯的红围脖

    楼主强大啊!儿子一直想有个赛格威,可惜买不起!不过看了楼主的制作,真是羡慕。机械部分制作都可以完成,不过电路部分本人一点基础也没有,电路板怎么做?没有现成的吗?看来靠我自己实现不了这个梦了!谢谢楼主

    [22] 评论
  • 5楼
    2013-11-28 19:33 广西老文

    最后算下成本用了多少?

    [0] 评论
  • 6楼
    2013-11-28 19:41 EVA747

    太强大了…

    来自山寨果壳.wp
    [0] 评论
  • 7楼
    2013-11-28 19:45 卩s灬Zero

    辛苦了

    来自果壳精选

    [0] 评论
  • 8楼
    2013-11-28 19:53 大技霸

    材料成本好象可以控制在2000以内

    [1] 评论
  • 9楼
    2013-11-28 21:04 五湖78910海

    楼主V5

    [0] 评论
  • 10楼
    2013-11-28 21:34 oh_no_wa

    楼主威武,结构牛。能不能把电机pid处理部分分享一下啊~~或者主要考虑了哪些方面的东西,有没用到分段pid处理

    [1] 评论
  • 11楼
    2013-11-28 22:02 天净半缘

    “赛格威”(英语:Segway)的老板开自家的山地型“赛格威”上山。。然后摔死了。。。真是让人忍不住的吐槽啊。

    [61] 评论
  • 12楼
    2013-11-28 22:14 bluesky365

    看着就很牛x的样子。。我也知道这家伙的老板挂了。。

    [0] 评论
  • 13楼
    2013-11-28 23:20 dalarang

    老兄终于出教程了,仔细看了下,机械部分没办法处理,要专门找人做。

    语音、遥控、温度这几个是做什么用,额外增加的功能?

    是不是能提供机械部分的成品购买。没有加工设备和相应技术,就算买了电机、轮子和框架也组合不上,电路部分可以自己做。

    [0] 评论
  • 14楼
    2013-11-28 23:46 dalarang

    想了想,主要的困难还是在电机和轮子上,只要能买到连着轮子的电机,将其固定在金属框架上,问题就解决了一大半。
    转向杆可以焊死在车体上,在手柄位置安个电位器,用手指头拨动电位器转向即可,不需要转动整个转向杆,这样机械部分应该可以自己做了。

    [0] 评论
  • 15楼
    2013-11-29 06:24 在月球旅游的_罗槑槑 DIY爱好者,万有青年养成计划入围选手

    真好啊手上的电机一直觉得建模太麻烦这下直接拿楼主的就好啦!应该是一样的电机_(:з」∠)_

    [0] 评论
  • 16楼
    2013-11-29 08:47 上善若水42
    引用@dalarang 的话:兄终于出教程了,仔细看了下,机械部分没办法处理,要专门找人做。语音、遥控、温度这几个是做什么用,额外增加的功能?是不是能提供机械部分的成品购买。没有加工设备和相应技术,就算买了电机、轮子和。。。。

    直接拿给加工商制作,全部机械部分1000左右即可完成,省时省心

    [0] 评论
  • 17楼
    2013-11-29 08:48 上善若水42
    引用@在月球旅游的_罗槑槑 的话:真好啊手上的电机一直觉得建模太麻烦这下直接拿楼主的就好啦!应该是一样的电机_(:з」∠)_


    请自行核定数据

    [0] 评论
  • 18楼
    2013-11-29 08:49 上善若水42
    引用@oh_no_wa 的话:楼主威武,结构牛。能不能把电机pid处理部分分享一下啊~~或者主要考虑了哪些方面的东西,有没用到分段pid处理


    主要也就超速的处理 ,基本方法就是超速后就给一个大的驱动力,用以将车身给纠正过来

    [0] 评论
  • 19楼
    2013-11-29 08:50 上善若水42
    引用@飞鱼BH1JSS 的话:楼主太土豪,光看加工设备就让人口水一地啊~


    加工设备借用的公司的,大部分零件为外发加工

    [0] 评论
  • 20楼
    2013-11-29 09:44 Jeffrey_Li

    楼主的pcb是用什么软件做的?能发个pcb的设计源文件吗?

    [0] 评论
  • 21楼
    2013-11-29 11:05 dalarang
    引用@上善若水42 的话:直接拿给加工商制作,全部机械部分1000左右即可完成,省时省心

    兄台这个是业余时间做的吗,闲时能做出这么工整的东西来确实很强,连机械图纸都画出来了。
    机械部分1000应该没包括轮子和电机吧,淘宝看了下这两个也要800左右,电池预估要600,电子元器件+PCB打样200,加杂七杂八费用大概3000应该够吧。
    没做过电机的控制电路,可否放出电机驱动电路部分的原理图,记得电机运行瞬间反向或截止的时候会有比较大的反向电压,会损坏MOS管吗。另外电机调速是不是用PWM方式?

    [0] 评论
  • 22楼
    2013-11-29 11:40 上善若水42
    引用@dalarang 的话:兄台这个是业余时间做的吗,闲时能做出这么工整的东西来确实很强,连机械图纸都画出来了。机械部分1000应该没包括轮子和电机吧,淘宝看了下这两个也要800左右,电池预估要600,电子元器件+PCB打样...


    机械部分部含标准件,1k仅为加工费。总体3k差不多。电机的h桥驱动电路很多,我这个也不一定完全合理,还请自行查找。只要电路设计合理,不用担心mos。

    直流有刷电机调速PWM ,貌似业内都这个方法

    [0] 评论
  • 23楼
    2013-11-29 11:56 Mizuho

    马克刘明

    有种黑科技的感觉啊……

    [1] 评论
  • 24楼
    2013-11-29 12:06 dalarang
    引用@上善若水42 的话:机械部分部含标准件,1k仅为加工费。总体3k差不多。电机的h桥驱动电路很多,我这个也不一定完全合理,还请自行查找。只要电路设计合理,不用担心mos。直流有刷电机调速PWM ,貌似业内都这个方法

    在论坛找到兄台以前发的H桥驱动问询帖,感觉很不错,特别是几个或非门来控制IR2184的方式很妙,从硬件上避免了H桥单侧导通短路的问题,还具有H桥使能功能,收藏了留着以后参考。

    [0] 评论
  • 25楼
    2013-11-29 13:12 Greeny 果壳视频编辑,实验党
    引用@上善若水42 的话:机械部分部含标准件,1k仅为加工费。总体3k差不多。电机的h桥驱动电路很多,我这个也不一定完全合理,还请自行查找。只要电路设计合理,不用担心mos。直流有刷电机调速PWM ,貌似业内都这个方法

    3K是总成本吗?

    [0] 评论
  • 26楼
    2013-11-29 13:16 屌如阳元石

    技术改变生活

    [0] 评论
  • 27楼
    2013-11-29 13:16 上善若水42
    引用@Greeny 的话:3K是总成本吗?

    是的,3k左右

    [0] 评论
  • 28楼
    2013-11-29 13:39 Cast 机械专业,DIY爱好者

    哈哈哈哈~我大机械威武~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·

    专利多久申请下来的?走熟人了么?

    [0] 评论
  • 29楼
    2013-11-29 13:41 黄自由

    大神,电路板是自己搞的还是别人帮的?

    [0] 评论
  • 30楼
    2013-11-29 14:07 猪了个去 智能科学专业

    楼主好辛苦~~~

    [0] 评论

显示所有评论

你的评论

登录 发表评论

更多科研事,扫码早知道

关于我们 加入果壳 媒体报道 帮助中心 果壳活动 免责声明 联系我们 移动版 移动应用

©2017果壳网    京ICP证100430号    京网文[2015] 0609-239号    新出发京零字东150005号     京公网安备11010502007133号

违法和不良信息举报邮箱:jubao@guokr.com    举报电话:13691127034