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

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

[复制链接]
思考的大兵 发布时间:2014-4-12 20:54
在此贴上以前做过的平衡小车资料,一来供众网友学习交流,二来申请stm32f429探索套件。。。/ J( R) ?$ |; o# a1 t& C" w7 U% J* L
先上图3 e- o& ?$ E1 ~* Y; i
wifi0s0-806875369IMG_20140412_203839.jpg
% J% t; O( @/ E" s5 |+ ^原材料清单:/ S/ a" |% w8 o1 q3 V# K+ n
——————————————————————————————————————————& E( ?* r1 |/ U5 `
主控:stm32f103rct6$ M2 P5 p/ e) L
传感器:mpu6050(带陀螺仪和加速度): ~9 }/ q1 t% V0 L! R* U
电机驱动芯片:l298n9 t- H3 R* j$ E# l" n% N
电机:冯哈伯22246 U  Q! J0 j8 g( R5 R, e. p/ S5 i, x
编码器:电机自带16线
' d) x! D" P! d, D电池:两节186502 \& }1 x9 b1 q* d+ c
轮子架子:淘宝店购买,减速比1:5
$ Z. _* [, H1 {+ y& G——————————————————————————————————————————
, H( h* J' J  ^" p% ?处理过程:8 U* z- f& s% }* R' t9 D9 C
——————————————————————————————————————————: ]# W+ n) L( s' S- |$ c, F* Q
其实程序过程很简单,先是采集传感器MPU6050的数据,并进行加工,获得当前小车倾斜角,然后根据此角度做PID调节,得到小车两个电机的PWM脉宽,调整轮子速度,使之回到倾角为0的状态,即保持平衡。然后就不停地重复采集->处理->调节->处理这一过程。
+ [. ?* j/ D7 @3 V$ _% F# R2 @/ T在此基础上,附加两电机的PWM值,即可实现前进,倒退,左转,右转动作
# h: l1 C0 H% o' g5 M: j0 |8 E  ?5 X——————————————————————————————————————————
3 P, }9 I9 _4 Y: D( `# j; d难点分析:
2 P6 Y  F  Q$ d1 x——————————————————————————————————————————3 L+ \0 d  L4 _3 ]( ^0 N. D9 X
有两个难点
& Z! G' {1 k2 X0 X1.传感器的数据处理是小车的最大难点。一是传感器受震动影响很大,很容易超量程;二是传感器数据漂移比较厉害。而关键的小车倾角就来源于此传感器数据。为此,参考网上数据滤波处理方式,采用卡尔曼滤波算法,融合陀螺仪和加速度传感器数据得出小车倾角。
7 `* y" O( ]3 R6 S" j2.PID,比例系数的调节不用多讲,需要耐心的测试和调节。我要说的是,单纯靠倾角做PID不能使小车平衡,因为当小车倾角接近0度时,改变的PWM值无法使小车越过平衡点,造成小车朝一边加速前进,所以要将速度也添加至PID调节中,做积分
& c. B+ C3 T* E* }# R' i——————————————————————————————————————————
; V2 I9 J; `& W7 v& g制作心得:8 O' v2 D$ |' f4 k9 v
——————————————————————————————————————————
/ \, ?( f9 T0 E! ^  w关于平衡小车,大多数网友应该都曾做过或者想过要做。于是百度搜资料,其中最多的应该是飞思卡尔直立车的资料,当初我也看下下,平衡车的原理都懂了,但那时还没搞过PID调节和数据滤波,所以具体怎么写程序并不知道。至于平衡车的程序资料也非常少。后来在网上参考相关数据滤波,PID调节后,才渐渐掌握。在此我也就贴上我的程序代码,供大家学习交流,少走弯路。有什么问题,欢迎回帖。当然也希望大家多支持此贴,祝我申请F429套件成功!哈哈
$ h4 R6 ]. k7 G1 u3 Z; o——————————————————————————————————————————
' q" W% n/ `9 _ 卡尔曼滤波.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的值. R# ?! L+ C6 E
问题:1,我快速改变板子倾角时Angle的变化正常吗?
6 y4 l2 ]% \1 V6 B      2,Angle正常变化的时候是应该与Angle_ax的值相近吗?( F0 `) y! `" |4 Z' M& R

8 x* ]5 \( e( v* d现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现中间的角度增大6 g! r8 j* p- c  y  Y+ \
1 j, U5 `  P  s( u6 x
& |+ l: F6 }$ C
*************读取数据********************- t( j' ]) B" s" X- W* i9 K$ P, h
//定义MPU6050内部地址; q. n1 t) K0 S. T! }& V
#define        SMPLRT_DIV                0x19        //陀螺仪采样率 典型值 0X07 125Hz
* G: S, p& C4 O" g#define        CONFIG                          0x1A        //低通滤波频率 典型值 0x00 5 V: A( ]+ J+ h2 {
#define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围                 典型值 0x18 不自检 2000deg/s7 G4 X  K0 w2 u, N& O
#define        ACCEL_CONFIG        0x1C        //加速度计自检及测量范围及高通滤波频率 典型值 0x01 不自检 2G 5Hz) f( X7 s8 s8 J2 A/ m5 j; r
#define INT_PIN_CFG     0x37# a" b7 |! d6 X" y: n0 @
#define INT_ENABLE      0x385 j; P! V, P/ u& t+ b) W
#define INT_STATUS      0x3A    //只读* c0 I0 T$ t% e) c: I* v
#define        ACCEL_XOUT_H        0x3B
5 a( Z% \, h* R1 p* U! g#define        ACCEL_XOUT_L        0x3C
, R7 M& s% ]/ f$ Z7 g#define        ACCEL_YOUT_H        0x3D
7 V7 C4 V, H2 u# b% E#define        ACCEL_YOUT_L        0x3E  i0 Y5 x7 m1 O4 {9 n/ r9 f
#define        ACCEL_ZOUT_H        0x3F5 V/ @4 Y. W' p# M+ d  k% i% t) D; D
#define        ACCEL_ZOUT_L        0x407 S: B/ r9 u( r  i5 V
#define        TEMP_OUT_H                0x41
# w2 T6 `  A( P; _#define        TEMP_OUT_L                0x42
: P) J( k( H8 L7 ~# K8 e) e#define        GYRO_XOUT_H    0x43& r# u0 ?2 N4 W  N% O; b3 @- Z
#define        GYRO_XOUT_L                0x44       
+ g1 ?2 K" U. E#define        GYRO_YOUT_H        0x45- P  u* S4 ]7 a
#define        GYRO_YOUT_L                0x46
. T# d1 k' Z( k/ r) h#define        GYRO_ZOUT_H        0x47
) q$ q, v( X# `6 A/ a! G! e, j#define        GYRO_ZOUT_L                0x48
. C  a: ?! k3 x+ _$ x. r. F: T0 ~2 D! w  X$ i* h- l5 ~
//读取寄存器原生数据
) z& @& A  }5 x% n/ e           ! m0 N5 @/ Y, a' T$ g& c
        MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);
4 `& u! P" }" n5 b2 ]0 [        MPU6050_Raw_Data.Accel_Y = (buf[2]<<8 | buf[3]);+ T3 i- D! _) u! i9 b/ r" K
        MPU6050_Raw_Data.Accel_Z = (buf[4]<<8 | buf[5]); 6 ?* d+ V) a* L  i" A
        MPU6050_Raw_Data.Temp =    (buf[6]<<8 | buf[7]);  
7 y! E4 _. x' H; ?) z        MPU6050_Raw_Data.Gyro_X = (buf[8]<<8 | buf[9]);
; C' I; f  k# @0 G3 n4 n        MPU6050_Raw_Data.Gyro_Y = (buf[10]<<8 | buf[11]);; H- r1 _" }9 n' Z4 Q) M
        MPU6050_Raw_Data.Gyro_Z = (buf[12]<<8 | buf[13]);
% L. l8 ]0 |; }$ N- p5 ^       ! g! n) U, m! a1 w# v! {
       0 _0 {! C3 q/ w3 H' W
        //将原生数据转换为实际值,计算公式跟寄存器的配置有关4 W$ K0 w  L- |( ~3 g8 |, x
        MPU6050_Real_Data.Accel_X = -(float)(MPU6050_Raw_Data.Accel_X)/8192.0;
5 F- Y8 w, X. k" e: n) r6 j: V        MPU6050_Real_Data.Accel_Y = -(float)(MPU6050_Raw_Data.Accel_Y)/8192.0; : a0 Z8 R5 G& D* G% H# R! ?# b
        MPU6050_Real_Data.Accel_Z = (float)(MPU6050_Raw_Data.Accel_Z)/8192.0; 5 K- v3 M3 ?5 P3 H: t
              MPU6050_Real_Data.Gyro_X=-(float)(MPU6050_Raw_Data.Gyro_X - gyroADC_X_offset)/65.5;   
4 ~! s2 f8 J& h! J        MPU6050_Real_Data.Gyro_Y=-(float)(MPU6050_Raw_Data.Gyro_Y - gyroADC_Y_offset)/65.5;   
. |2 ^9 r% O0 k! T7 @$ I        MPU6050_Real_Data.Gyro_Z=(float)(MPU6050_Raw_Data.Gyro_Z - gyroADC_Z_offset)/65.5;   
5 f; o6 x8 V& N, h/ `    } & Y, [/ ?6 i% u% |( H
   
  m! _* a# z: [9 P; |0 }4 g/ a1 }0 L3 b( v, p

8 W$ q4 _7 |! Z9 C: j4 F//******卡尔曼参数************2 ?. v2 d, C( V! m# S7 y
                ; S, A2 y+ o0 Q, D* s
const float Q_angle=0.001;  + S  m. K) x1 N: M& Y4 _, Z
const float Q_gyro=0.003;7 T6 e! w) g7 G4 ~: }7 v, t) U
const float R_angle=0.5;
; j, d5 K( D7 ]% mconst float dt=0.01;                          //dt为kalman滤波器采样时间;
4 E1 ~/ v- U' ~+ i% y0 Econst char  C_0 = 1;2 L! I4 [% c9 f  o+ z
float Q_bias, Angle_err;5 u2 ], R8 t# s- ]9 g* l
float PCt_0, PCt_1, E;. _9 j8 K5 N, G* x( c: i4 Q
float K_0, K_1, t_0, t_1;6 T6 c8 Z; k. u0 ^9 D" f
float Pdot[4] ={0,0,0,0};
- M) m9 A5 X0 ~5 m0 a2 U0 ^float PP[2][2] = { { 1, 0 },{ 0, 1 } };
! K0 v' q# H* K  ~( |) n
" U& J4 U' }) o5 t6 u/*****************卡尔曼滤波**************************************************/
8 l: P3 R2 S& v- ~3 i$ @void Kalman_Filter(float Accel,float Gyro)                0 |" P2 P3 Z. o( [0 u6 @
{  H! |4 N) t7 S( M0 R- [
        Angle+=(Gyro - Q_bias) * dt; //先验估计
( `: ?6 m: B7 v0 U  {       
- l$ v2 f. `# o* ^        Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分; R- ~( R/ a3 s7 M, Y/ R* q" F4 I

+ I& j, g$ P- d, J8 j5 O        Pdot[1]= -PP[1][1];
( q8 i+ U0 k; G        Pdot[2]= -PP[1][1];
; v% z$ m- G' G# d# {9 x        Pdot[3]=Q_gyro;1 O+ d7 o% X. Y/ _$ N
        2 g) E& x% y/ e& ~" g3 D6 |( H
        PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
1 @* A- [: b+ m        PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差1 C/ N5 u7 U  ^/ u7 i. d9 d. `. I
        PP[1][0] += Pdot[2] * dt;" N( r) F- P; O# ~5 W- D
        PP[1][1] += Pdot[3] * dt;
1 _) J/ }5 r; E0 Z, L# g/ L9 H                / `9 P4 u- h8 ^$ g" Y/ w
        Angle_err = Accel - Angle;        //zk-先验估计
% e6 d8 c! e* k; s        ) c  o6 g! F& i9 @2 d: N, [! Q. K
        PCt_0 = C_0 * PP[0][0];/ @- l! S7 u8 ], q/ B8 R
        PCt_1 = C_0 * PP[1][0];
# x" l4 f  j, P: H$ W6 e        ) }3 c! y6 f. O- K# ]
        E = R_angle + C_0 * PCt_0;2 E8 |5 |7 t8 d; M' G
        9 G8 o. d9 }( W# i
        K_0 = PCt_0 / E;; g1 r2 H: y3 f# _0 W, {
        K_1 = PCt_1 / E;2 u; K  U& W1 \
        ' F6 O2 E/ d- S* C0 U, s' M
        t_0 = PCt_0;
3 i+ K# U' Y5 f. f+ g        t_1 = C_0 * PP[0][1];/ B8 e- S5 x' _& S8 D. c

9 O4 |1 k  n6 ?' i5 y& j4 t0 Y        PP[0][0] -= K_0 * t_0;                 //后验估计误差协方差
  d" ]6 F/ b# Y$ R        PP[0][1] -= K_0 * t_1;
9 b7 p* G2 i! h% c2 G        PP[1][0] -= K_1 * t_0;. h5 X0 y3 I  O6 z. Q; i
        PP[1][1] -= K_1 * t_1;
& c# p1 S2 O/ A; [- @$ y! T                5 K. }) Y; ~9 f
        Angle        += K_0 * Angle_err;         //后验估计
7 C1 x- Z, m: S2 ~. n. [        Q_bias        += K_1 * Angle_err;         //后验估计
5 d0 M7 t2 |' r3 N1 N4 F, |% r        Gyro_y   = Gyro - Q_bias;         //输出值(后验估计)的微分=角速度
& M' r% E$ M1 T( y, C
; q  d5 z  J6 H+ q, `}7 d- }3 J7 h$ F7 R' W  G

6 n' w( h" f! ]  Z8 F# H******************倾角计算*****************. @/ \  g2 o4 _1 K" Q
void Angle_Calculate(void)/ ^! v# E* `; ^+ k+ B9 w
{
; Q2 t" q/ f, L2 V1 s8 n0 B4 a
/****************************加速度****************************************/
5 R& C, O! a' ~. {1 ]        ; U7 Q  z3 n0 U; ?: G! Y6 E3 X3 _4 c
        Accel_x  =  MPU6050_Real_Data.Accel_X;          //读取X轴加速度
2 d/ E( y  Q. L/ R" T+ A        Angle_ax = Accel_x*1.2*180/3.14;     //弧度转换为度
* i( A4 U/ x6 B$ U) F' `
0 I$ H* b" V+ Y' R! T/****************************角速度****************************************// i1 ~* A( v, c- \4 s/ N
        * W- [8 i1 s7 ?9 X0 p
         Gyro_y = MPU6050_Real_Data.Gyro_Y;             # d& I: T0 p3 L( v; u& X
时间dt,所以此处不用积分. b8 ^/ F. W. N+ Y- `( M8 p% j. j* ?, i
/***************************卡尔曼融合*************************************/
1 T. A$ t: x; R5 S; [- N" B        Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角
; w/ I$ `# ~0 E7 i- X( a+ w7 M: i& J        # N1 L8 O5 H9 J4 O

3 Z; S! N" _3 y6 S& q
大米周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发表:9 q% L2 p- O2 V) u1 i6 V
收了  感谢楼主 4 f3 I* }! U4 D5 _
5 H$ R6 g7 f* u5 ]9 K! s4 I
客气。。。
疯子咬手指 回答时间: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 手机版