你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【MCU实战经验】+基于stm32两轮平衡车制作  

[复制链接]
思考的大兵 发布时间:2014-4-12 20:54
在此贴上以前做过的平衡小车资料,一来供众网友学习交流,二来申请stm32f429探索套件。。。/ V: t7 F1 a% l5 }
先上图
3 V, ?( @8 m+ C& P# T2 h! h  }7 P# `1 ~ wifi0s0-806875369IMG_20140412_203839.jpg
, w0 }3 l5 W' k% _" l4 U+ k: ^原材料清单:% y9 m  d7 C  {! ~6 U. c, [" e9 U
——————————————————————————————————————————. y- v- r; f) T* I
主控:stm32f103rct6
5 z5 T+ `! N: x  T" G+ E9 v传感器:mpu6050(带陀螺仪和加速度)
! I& F; E8 A3 g7 `% \7 r4 T电机驱动芯片:l298n+ k. `' ]5 R" T/ R3 Z( q2 ~
电机:冯哈伯2224
7 R$ `! U) p/ Q5 u/ A  U8 g( g编码器:电机自带16线! p9 D0 J. |8 f1 P9 `3 k
电池:两节18650
1 }9 i1 D. X, A0 E7 _. W% e轮子架子:淘宝店购买,减速比1:5
0 N( o1 z0 k, \* ]  Q, A. P$ S——————————————————————————————————————————
, n. Y7 I& O5 A' V) n: q处理过程:
; a9 i! `! _# V* q' M6 s——————————————————————————————————————————
: T  z; d9 K! Z; J$ m& L其实程序过程很简单,先是采集传感器MPU6050的数据,并进行加工,获得当前小车倾斜角,然后根据此角度做PID调节,得到小车两个电机的PWM脉宽,调整轮子速度,使之回到倾角为0的状态,即保持平衡。然后就不停地重复采集->处理->调节->处理这一过程。3 X; W! m( [: o  l$ _) Z' u( M* y
在此基础上,附加两电机的PWM值,即可实现前进,倒退,左转,右转动作
# R8 [; n" d/ e: x6 ^) {; [——————————————————————————————————————————
. u- x# v' v0 z$ p6 i3 d+ }难点分析:
! O* y0 J4 H3 d& [0 o" N1 C——————————————————————————————————————————
% B; b* G% F; L8 h9 d& A6 a3 A$ o有两个难点" x. W# f2 n, u3 M
1.传感器的数据处理是小车的最大难点。一是传感器受震动影响很大,很容易超量程;二是传感器数据漂移比较厉害。而关键的小车倾角就来源于此传感器数据。为此,参考网上数据滤波处理方式,采用卡尔曼滤波算法,融合陀螺仪和加速度传感器数据得出小车倾角。
4 C; M5 r( [8 b) h0 _& h/ N2.PID,比例系数的调节不用多讲,需要耐心的测试和调节。我要说的是,单纯靠倾角做PID不能使小车平衡,因为当小车倾角接近0度时,改变的PWM值无法使小车越过平衡点,造成小车朝一边加速前进,所以要将速度也添加至PID调节中,做积分
& ?0 b. O- P3 @0 t0 k$ i: J, Y* o——————————————————————————————————————————- I' r" ^  X/ k/ N9 H9 N; c. I/ R
制作心得:  ?& B0 [  }3 @  V, A/ a
——————————————————————————————————————————" F, W; r  G; j9 \, w: ~
关于平衡小车,大多数网友应该都曾做过或者想过要做。于是百度搜资料,其中最多的应该是飞思卡尔直立车的资料,当初我也看下下,平衡车的原理都懂了,但那时还没搞过PID调节和数据滤波,所以具体怎么写程序并不知道。至于平衡车的程序资料也非常少。后来在网上参考相关数据滤波,PID调节后,才渐渐掌握。在此我也就贴上我的程序代码,供大家学习交流,少走弯路。有什么问题,欢迎回帖。当然也希望大家多支持此贴,祝我申请F429套件成功!哈哈) o( {# C5 M4 n+ w0 M
——————————————————————————————————————————' M- A/ _9 q4 A" }( a% m, P
卡尔曼滤波.rar (2.76 MB, 下载次数: 12100)
wifi0s0-270124067IMG_20140412_203825.jpg
wifi0s0-1287192638IMG_20140412_203903.jpg
wifi0s0-1379330287IMG_20140412_204252.jpg
wifi0s0690935772IMG_20140412_204349.jpg

平衡小车.rar

下载

3.02 MB, 下载次数: 54095

评分

参与人数 1 ST金币 +5 收起 理由
努力的人 + 5 感谢分享

查看全部评分

赞 3 收藏 24 评论180 发布时间:2014-4-12 20:54

举报

180个回答
青春不再荡漾 回答时间:2014-9-16 11:32:17

回复:【MCU实战经验】+基于stm32两轮平衡车制作

楼主有几个问题请教下,您用的编码器是16线的,是不是接线就三根呢,一根电源,一根接地,还有一根信号线,可是我从你的程序中看不出来信号线是接几号引脚啊?其二,楼主的PID看上去没有用增量式或者位置式的,PWM是直接根据KP*角度+KD*速度计算出来的,这样的话这个PWM是不是不准,不知楼主最后的效果咋样?求回复哈
heheqian 回答时间:2014-8-26 14:07:09

回复:【MCU实战经验】+基于stm32两轮平衡车制作

  又强又好,顶!
孤独的文艺青年 回答时间:2016-8-9 18:34:51
我用printf("%0.2f    %0.2f    %0.2f\r\n",Angle,Angle_ax,Gyro_y);函数分别读取的加速度,角速度和倾角,我发现当我快速的改变板子的倾角的时候,比如快速变化10度,Angle(卡尔曼滤波后的倾角)瞬时变化非常快,可能会瞬间变化几十度然后回到正常角度,而当我缓慢变化10度的时候,Angle变化是正常线性变化到10度,在这两种变化中,Angle_ax(从MPU6050读取的值经过处理后的陀螺仪的Y轴数据)的变化一直都是线性正常的,并且Angle的值特别接近Angle_ax的值
1 l/ g3 s/ m) K1 h% l问题:1,我快速改变板子倾角时Angle的变化正常吗?
, ^8 y' l& J" j      2,Angle正常变化的时候是应该与Angle_ax的值相近吗?7 d/ F2 N2 B/ J, O6 p$ v  O+ y

  w, h/ g5 }! Y, y' @6 F! _现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现中间的角度增大+ a5 C: ?4 R3 F0 e# o! E

) D+ y* X  I5 X+ {# P3 b& o
2 t4 |+ ^# }! w* r5 n. n3 j*************读取数据********************
# s0 B% p8 G: H: p2 K: ]' p//定义MPU6050内部地址
( \/ p% r' `, I; q1 \; R#define        SMPLRT_DIV                0x19        //陀螺仪采样率 典型值 0X07 125Hz6 p. J7 A) K6 t% J8 N
#define        CONFIG                          0x1A        //低通滤波频率 典型值 0x00 * X; Q: |5 C; J( B& u
#define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围                 典型值 0x18 不自检 2000deg/s2 j: p* W  F& j9 ]$ H- d
#define        ACCEL_CONFIG        0x1C        //加速度计自检及测量范围及高通滤波频率 典型值 0x01 不自检 2G 5Hz
$ F3 [8 C, a9 ^6 Q" p: n#define INT_PIN_CFG     0x37% l8 U$ {/ [9 _0 _0 j
#define INT_ENABLE      0x385 Y6 E1 u) }1 M; @* j6 Q
#define INT_STATUS      0x3A    //只读8 ]- b8 C, F' |+ Z) V0 {1 l
#define        ACCEL_XOUT_H        0x3B: c4 `0 b% s0 f+ I1 H/ w
#define        ACCEL_XOUT_L        0x3C
1 c/ |5 m) S7 d" u% t' c, x/ n" p#define        ACCEL_YOUT_H        0x3D" P/ i* B+ X2 J
#define        ACCEL_YOUT_L        0x3E
* H7 ~# |, C! f3 I#define        ACCEL_ZOUT_H        0x3F: u% {0 ^5 l2 `0 Z0 u
#define        ACCEL_ZOUT_L        0x40, A, x) }8 l) X# e4 N" a
#define        TEMP_OUT_H                0x41; {0 c: H5 Y4 w2 x7 s4 ~* F# f
#define        TEMP_OUT_L                0x42
6 m: O7 z+ W6 i#define        GYRO_XOUT_H    0x43. x" v* H0 b* n& v2 [/ |, t& n
#define        GYRO_XOUT_L                0x44        2 m, X, m  Q3 O) C9 |* w
#define        GYRO_YOUT_H        0x45
5 h' a4 B7 o& g& x/ Q#define        GYRO_YOUT_L                0x46$ m( _" u+ {( K) @- K4 b; h- h: b
#define        GYRO_ZOUT_H        0x47
4 s+ \+ |# v4 S) X#define        GYRO_ZOUT_L                0x48
! l6 q3 O+ v8 M. v& w% w
* J# O0 D& r: E/ F//读取寄存器原生数据
8 y1 N6 I0 |/ V$ B           
/ `7 o/ m& |3 o4 P+ e, K0 x        MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);
4 t- V" F) o+ w2 b' s, ~        MPU6050_Raw_Data.Accel_Y = (buf[2]<<8 | buf[3]);
& z1 W4 R; |3 w5 u6 E        MPU6050_Raw_Data.Accel_Z = (buf[4]<<8 | buf[5]);
' `& F/ R6 D% }8 a* J/ G        MPU6050_Raw_Data.Temp =    (buf[6]<<8 | buf[7]);  
5 \- H8 q3 [, q. l& j7 {        MPU6050_Raw_Data.Gyro_X = (buf[8]<<8 | buf[9]);
5 ~) e* \) X& I( h5 L0 r. y5 G2 F! D  t        MPU6050_Raw_Data.Gyro_Y = (buf[10]<<8 | buf[11]);, }5 D6 f8 ?% D( m3 A
        MPU6050_Raw_Data.Gyro_Z = (buf[12]<<8 | buf[13]);
  H) n- z# ], {0 x      
0 S0 P  Y5 C+ c1 T- ~      
3 m4 o. U( n. [* g        //将原生数据转换为实际值,计算公式跟寄存器的配置有关
. w8 K8 j6 R& U. M* j! W6 e        MPU6050_Real_Data.Accel_X = -(float)(MPU6050_Raw_Data.Accel_X)/8192.0;
+ ?- x+ x: O6 K        MPU6050_Real_Data.Accel_Y = -(float)(MPU6050_Raw_Data.Accel_Y)/8192.0; 5 O7 ^9 ~" O# ?- w3 o( c: ?
        MPU6050_Real_Data.Accel_Z = (float)(MPU6050_Raw_Data.Accel_Z)/8192.0; ) l9 N) g: {! k' g) j4 U
              MPU6050_Real_Data.Gyro_X=-(float)(MPU6050_Raw_Data.Gyro_X - gyroADC_X_offset)/65.5;   
0 O; ~8 }% G6 v7 e. C        MPU6050_Real_Data.Gyro_Y=-(float)(MPU6050_Raw_Data.Gyro_Y - gyroADC_Y_offset)/65.5;   ) }. I! z8 w; e) B& @2 e9 \
        MPU6050_Real_Data.Gyro_Z=(float)(MPU6050_Raw_Data.Gyro_Z - gyroADC_Z_offset)/65.5;   : v7 S$ j% N, X" A; ~) K8 I0 V/ @
    } , V. @3 Z2 P+ A$ p9 G0 U
   
4 r* d( w  c- [3 E+ m" L, v3 z. e' m6 e3 A! ^/ X

, R8 F% V; G6 m- I% e2 P* E0 S+ F//******卡尔曼参数************+ @# z" S# Y3 u2 W
               
8 m. Z) M' `4 x1 [" kconst float Q_angle=0.001;  
* V" S) J& w! _+ R+ U! Fconst float Q_gyro=0.003;
+ v5 S9 ~) S6 q: i/ I" }8 qconst float R_angle=0.5;7 y. w7 F. t2 V/ b- |' I1 t0 a
const float dt=0.01;                          //dt为kalman滤波器采样时间;6 Q+ n; Q% Q" y9 l: k3 n  L; w
const char  C_0 = 1;
' r, l7 Y7 t: J& ^' V8 `" ]float Q_bias, Angle_err;
; q5 h, m1 r  ~: _float PCt_0, PCt_1, E;
+ }  L" ?$ [; q; j2 wfloat K_0, K_1, t_0, t_1;
9 _  p% ~6 V6 o8 M6 ]* `float Pdot[4] ={0,0,0,0};
% m# ]3 X9 |1 r2 U& Z+ |1 v7 B: |float PP[2][2] = { { 1, 0 },{ 0, 1 } };
( e  b9 I/ k: l0 o7 }% x' m) }  w; J1 o8 k; p( ?
/*****************卡尔曼滤波**************************************************/4 u+ O" s' G) R+ z0 C
void Kalman_Filter(float Accel,float Gyro)                " r! `/ T" `# `; M& f9 ?
{
( M% U3 M- w$ M+ f        Angle+=(Gyro - Q_bias) * dt; //先验估计
# |: \, ?5 W6 n' x, M        ) J" c1 Z  H1 m! E) n2 u& A9 \
        Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分5 a7 M5 f) g0 a/ k9 `6 m9 s- E% i
& W/ \( }% X4 v2 F% }
        Pdot[1]= -PP[1][1];) ]8 s- P: |$ Z
        Pdot[2]= -PP[1][1];8 g. ]" u+ S# ~3 [/ T0 D/ B
        Pdot[3]=Q_gyro;& X! W8 Z2 ~) ^5 V- M
       
& w! r( Y( ?- _% n* z        PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
6 u( d+ r+ u9 {3 A# P+ n' N. b        PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差8 r9 `. v, W2 S" m8 q
        PP[1][0] += Pdot[2] * dt;1 s" s2 U8 v9 L& Q# t" o7 W
        PP[1][1] += Pdot[3] * dt;! U; {' u' E% c2 {# q. \
               
/ ~5 s  |2 C- C        Angle_err = Accel - Angle;        //zk-先验估计
/ ^3 j9 A+ T& H5 J- P       
  X- j1 x" e: e2 Q        PCt_0 = C_0 * PP[0][0];- n2 O& p5 {. g) B
        PCt_1 = C_0 * PP[1][0];
9 i) j& @2 L1 L       
# `% H# J2 q( Q1 J+ r( U8 e0 c0 [        E = R_angle + C_0 * PCt_0;' V  h, u+ S4 x0 P' P/ o* e! p
       
, I4 z" s) q! S* N2 M        K_0 = PCt_0 / E;) c1 T! F* W+ n, t
        K_1 = PCt_1 / E;
8 r( _" C- G! B9 n. ?       
! C0 q" Q2 e6 z  R4 ]$ i$ W        t_0 = PCt_0;+ V1 d4 D! r7 K% F( L4 V) O: ?
        t_1 = C_0 * PP[0][1];
% c0 Q4 O" o3 ]6 G4 I; ?6 _$ H: k0 j1 {! U" b8 |; w
        PP[0][0] -= K_0 * t_0;                 //后验估计误差协方差7 B$ S5 f' }' P- F# Z
        PP[0][1] -= K_0 * t_1;+ a4 I7 m& N! s* Y* c% H
        PP[1][0] -= K_1 * t_0;' r$ y# w6 q5 E3 a
        PP[1][1] -= K_1 * t_1;
- K* @& P' Q9 t4 l                8 ]: O6 Y: g) u
        Angle        += K_0 * Angle_err;         //后验估计7 f8 U- ?$ X" Y, w7 j
        Q_bias        += K_1 * Angle_err;         //后验估计8 B7 e5 l8 G& z3 E5 l4 ]1 C
        Gyro_y   = Gyro - Q_bias;         //输出值(后验估计)的微分=角速度
$ Y$ C- M/ S, X" k/ C$ D- W# x+ p2 b! V% c" }
}
1 P/ f- V* E# p9 Z6 C& h6 i
6 h) L: E/ F+ ^******************倾角计算*****************2 c5 ^+ i. X3 b/ N
void Angle_Calculate(void)
& f) H, e& Z2 I, b+ k- m1 e{
& r# f# C6 {7 ?6 U; E9 Z6 d* N, ?, k! H* z4 J" z0 K
/****************************加速度****************************************/: A6 r) k8 ]3 I1 ?9 m0 x' x
       
, m  a6 i5 w( v3 J: W        Accel_x  =  MPU6050_Real_Data.Accel_X;          //读取X轴加速度8 B9 x- V5 [& S* x$ }
        Angle_ax = Accel_x*1.2*180/3.14;     //弧度转换为度
: q' P( f. E, [/ D
: s; S* l3 n" _7 s/****************************角速度****************************************/: b6 g7 {" }' v$ p# A
        0 n% h8 y5 j4 {& }( P& g
         Gyro_y = MPU6050_Real_Data.Gyro_Y;             
! X. g! _; W; b0 d& @! J时间dt,所以此处不用积分
: W) F+ U" K  m* Y2 C$ t/***************************卡尔曼融合*************************************/, L* z1 R1 @* g, n' y: m- l- F( F
        Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角: _0 V1 D8 X- m* I$ Q% k
        5 n" C) y0 _. o$ N

0 ?( [1 }2 D9 Q* Q8 b/ f! K3 n
大米周822 回答时间:2014-4-12 21:39:32

回复:【MCU实战经验】+基于stm32两轮平衡车制作

顶下,楼主好人。。。
疯子咬手指 回答时间:2014-4-12 22:19:27

RE:【MCU实战经验】+基于stm32两轮平衡车制作

收了  感谢楼主
思考的大兵 回答时间:2014-4-13 08:48:38

回复:【MCU实战经验】+基于stm32两轮平衡车制作

回复第 3 楼 于2014-04-12 22:19:27发表:7 w1 X; T6 d# K  M% D8 o
收了  感谢楼主 
( T4 {' ^1 v+ P) Q- n: d- R1 r( p: J: H$ v( n, ^
客气。。。
疯子咬手指 回答时间:2014-4-21 19:00:34

RE:【MCU实战经验】+基于stm32两轮平衡车制作

阔出去了  定起
robot0612 回答时间:2014-5-6 21:19:47

RE:【MCU实战经验】+基于stm32两轮平衡车制作

还不错
123de7 回答时间:2014-7-1 21:02:47

回复:【MCU实战经验】+基于stm32两轮平衡车制作

正需要呢,顶一个!!!
刘源爱电子 回答时间:2014-7-17 17:52:20

回复:【MCU实战经验】+基于stm32两轮平衡车制作

感谢
zhangkongziwo 回答时间:2014-8-3 16:39:17

回复:【MCU实战经验】+基于stm32两轮平衡车制作

 
chunyangjs 回答时间:2014-8-8 12:15:39

RE:【MCU实战经验】+基于stm32两轮平衡车制作

顶下,楼主好人。。。
熊二在深圳 回答时间:2014-8-8 14:53:43

RE:【MCU实战经验】+基于stm32两轮平衡车制作

这个是高大上的项目。赞一个
hengchu 回答时间:2014-8-10 01:15:37

RE:【MCU实战经验】+基于stm32两轮平衡车制作

做了好久,就是滤波不懂,楼主好人,愿好人一生平安
wqlovt 回答时间:2014-9-16 13:24:48

RE:【MCU实战经验】+基于stm32两轮平衡车制作

感谢分享!!!!!!!!!!!!!

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版