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

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

[复制链接]
思考的大兵 发布时间:2014-4-12 20:54
在此贴上以前做过的平衡小车资料,一来供众网友学习交流,二来申请stm32f429探索套件。。。
7 r# B7 u' [5 @3 h+ R# L1 B+ C) {6 i先上图3 g' D1 ~( e( M9 `" P& j+ k# p
wifi0s0-806875369IMG_20140412_203839.jpg
6 H  `2 i7 b8 Z3 g/ X原材料清单:
; W8 z% ?3 x) _, q* ?, y——————————————————————————————————————————$ A# @* u4 [1 U
主控:stm32f103rct6; O3 [+ U  W7 u. h! j( J( _
传感器:mpu6050(带陀螺仪和加速度)" \+ @. k9 C0 ^6 A
电机驱动芯片:l298n) f8 b5 q$ g% O3 \
电机:冯哈伯2224
, |/ c+ ?, [: ~编码器:电机自带16线1 V1 b) o6 X! i9 U
电池:两节18650
$ F1 q# T# R3 \& Z- r+ E- H! \9 H轮子架子:淘宝店购买,减速比1:5
" f6 F9 l4 p2 X  ]——————————————————————————————————————————2 {' K# N# A! E0 b! y
处理过程:
7 C! _- e: t0 y( U$ Y; }& E: P——————————————————————————————————————————
3 d# O: P3 F/ z3 \  F! ^# i其实程序过程很简单,先是采集传感器MPU6050的数据,并进行加工,获得当前小车倾斜角,然后根据此角度做PID调节,得到小车两个电机的PWM脉宽,调整轮子速度,使之回到倾角为0的状态,即保持平衡。然后就不停地重复采集->处理->调节->处理这一过程。& a2 p6 A* Q  X0 I+ T) [) H
在此基础上,附加两电机的PWM值,即可实现前进,倒退,左转,右转动作
. [: x) N/ i# D7 q" G——————————————————————————————————————————
3 c5 F( O+ E$ O* S& W" w- b难点分析:$ q) `: i3 n0 N  \
——————————————————————————————————————————
3 v# l+ C5 f( K6 t2 `6 ^有两个难点. C4 C; u8 J' W+ g
1.传感器的数据处理是小车的最大难点。一是传感器受震动影响很大,很容易超量程;二是传感器数据漂移比较厉害。而关键的小车倾角就来源于此传感器数据。为此,参考网上数据滤波处理方式,采用卡尔曼滤波算法,融合陀螺仪和加速度传感器数据得出小车倾角。
  Y" u8 w- x- y# p' d* q& ~2.PID,比例系数的调节不用多讲,需要耐心的测试和调节。我要说的是,单纯靠倾角做PID不能使小车平衡,因为当小车倾角接近0度时,改变的PWM值无法使小车越过平衡点,造成小车朝一边加速前进,所以要将速度也添加至PID调节中,做积分) r  ^; P7 _+ L$ a9 Y0 b
——————————————————————————————————————————
5 t& p$ G; Q, D+ i! s, L( A9 m/ v1 e制作心得:
; J5 h7 S1 x% K8 A3 w——————————————————————————————————————————
' K# I; E- s; i! x/ ^, b9 w8 I关于平衡小车,大多数网友应该都曾做过或者想过要做。于是百度搜资料,其中最多的应该是飞思卡尔直立车的资料,当初我也看下下,平衡车的原理都懂了,但那时还没搞过PID调节和数据滤波,所以具体怎么写程序并不知道。至于平衡车的程序资料也非常少。后来在网上参考相关数据滤波,PID调节后,才渐渐掌握。在此我也就贴上我的程序代码,供大家学习交流,少走弯路。有什么问题,欢迎回帖。当然也希望大家多支持此贴,祝我申请F429套件成功!哈哈/ p! o: P% i8 j3 i; l" l
——————————————————————————————————————————- K+ c$ r" N: N% U' {2 ?
卡尔曼滤波.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的值/ |9 i( m+ I! K7 i
问题:1,我快速改变板子倾角时Angle的变化正常吗?
# S9 v, a% F$ g0 }5 P      2,Angle正常变化的时候是应该与Angle_ax的值相近吗?$ M* B3 \9 Q3 G) _6 K6 p* `: w; N- ~

0 e8 j1 @/ W2 `现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现中间的角度增大
/ l) o) S3 F& K2 S/ a' d. b& _; @" ^+ r: {& `1 z2 u2 H! z
6 |* k, @$ ~0 j
*************读取数据********************
0 j" F4 U+ E1 i  s//定义MPU6050内部地址
- ]# B, {# Q- l6 F2 t#define        SMPLRT_DIV                0x19        //陀螺仪采样率 典型值 0X07 125Hz
- c& |/ K+ t: v. `( v#define        CONFIG                          0x1A        //低通滤波频率 典型值 0x00
  J$ k" U% G  {( O9 E# h% y( |#define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围                 典型值 0x18 不自检 2000deg/s
" F: @, b3 ^. V: A' v& |" M#define        ACCEL_CONFIG        0x1C        //加速度计自检及测量范围及高通滤波频率 典型值 0x01 不自检 2G 5Hz
) u$ y" V2 T: m! O% {) Q7 I: M#define INT_PIN_CFG     0x37% Q% v, y" g% Q. Z9 z$ a, K
#define INT_ENABLE      0x38
4 s0 d3 p0 L: |% e3 y+ C#define INT_STATUS      0x3A    //只读
. s/ ?( M  w0 @. _  @#define        ACCEL_XOUT_H        0x3B& \: n4 j' I. _% q8 O
#define        ACCEL_XOUT_L        0x3C
3 o% f/ q5 @+ e0 q0 k0 w8 e#define        ACCEL_YOUT_H        0x3D
# p& m9 o9 O  j# x7 q: T#define        ACCEL_YOUT_L        0x3E; ]8 e& X5 ?. r) ?3 y8 z
#define        ACCEL_ZOUT_H        0x3F4 \  C6 O) b; ^6 A5 ]/ M) k
#define        ACCEL_ZOUT_L        0x40
/ E1 u8 F- v5 ]6 e2 z' g* ]#define        TEMP_OUT_H                0x413 z; T% G9 {1 x8 }1 z& w
#define        TEMP_OUT_L                0x42
, V- l6 Y1 c- j3 g+ l1 c#define        GYRO_XOUT_H    0x43
* C" Q; ^& M5 s% H" O#define        GYRO_XOUT_L                0x44       
, A& q7 F! y) K0 R#define        GYRO_YOUT_H        0x45
5 |$ Y0 B  P, T! Z#define        GYRO_YOUT_L                0x46
; i3 b& ?" o4 @#define        GYRO_ZOUT_H        0x47
4 ^1 q! _3 ^- \( K- w: ?) \7 t, k#define        GYRO_ZOUT_L                0x48
- w' v. @1 H  F8 Z0 V/ C0 W# t  A! k  c6 k0 T; B
//读取寄存器原生数据1 [+ T  ?4 r1 i% K8 ]! G6 c/ }( t
           9 {3 x  T* j5 H; ?3 R2 E
        MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);% d  W0 y9 q# ?6 v( E. D
        MPU6050_Raw_Data.Accel_Y = (buf[2]<<8 | buf[3]);
. I3 Y; B6 X" d' [$ a# S6 C* z. K        MPU6050_Raw_Data.Accel_Z = (buf[4]<<8 | buf[5]);
3 L' i( y' m0 ?# o        MPU6050_Raw_Data.Temp =    (buf[6]<<8 | buf[7]);  , S1 T$ e9 ^* g1 c& \
        MPU6050_Raw_Data.Gyro_X = (buf[8]<<8 | buf[9]);9 z/ z8 B5 O- Z
        MPU6050_Raw_Data.Gyro_Y = (buf[10]<<8 | buf[11]);' |% ?. y+ S1 D0 M! ?0 O2 H
        MPU6050_Raw_Data.Gyro_Z = (buf[12]<<8 | buf[13]);
$ A# Q. q# B- x: \3 P      
) ?: v7 p$ [0 j+ ^0 U1 Q  a       2 Y4 w& z1 n- Z* W" i, o
        //将原生数据转换为实际值,计算公式跟寄存器的配置有关1 G7 F( D1 O1 i1 Z
        MPU6050_Real_Data.Accel_X = -(float)(MPU6050_Raw_Data.Accel_X)/8192.0; ! x2 u' z( w; p+ V; F1 @% `' ~" u
        MPU6050_Real_Data.Accel_Y = -(float)(MPU6050_Raw_Data.Accel_Y)/8192.0;
% [* V. i& ]2 T5 n0 V        MPU6050_Real_Data.Accel_Z = (float)(MPU6050_Raw_Data.Accel_Z)/8192.0; ! Y! g$ C& [, S  U7 O; ~
              MPU6050_Real_Data.Gyro_X=-(float)(MPU6050_Raw_Data.Gyro_X - gyroADC_X_offset)/65.5;   
7 D- w3 F- |7 L        MPU6050_Real_Data.Gyro_Y=-(float)(MPU6050_Raw_Data.Gyro_Y - gyroADC_Y_offset)/65.5;   ( I% ^' _7 L6 }( S3 `
        MPU6050_Real_Data.Gyro_Z=(float)(MPU6050_Raw_Data.Gyro_Z - gyroADC_Z_offset)/65.5;   
! P  J: \! l. {4 @1 v    } 5 W% }; s2 k) N9 m: s, I
   
6 z+ f9 S4 S  e- `% ?$ s2 K. j, _5 o. U1 j) h
* @, u' r4 D* v. E* I, h
//******卡尔曼参数************
/ }9 ~9 u) ]6 j* x+ z, H1 U                ; ?4 p7 J4 w. k1 }  R" a* J' b) O
const float Q_angle=0.001;  
1 @- K, o; p8 Y4 |/ ?6 ]8 kconst float Q_gyro=0.003;
5 l2 b. ^6 p% S1 [const float R_angle=0.5;
- X, I0 y% {3 @+ S, pconst float dt=0.01;                          //dt为kalman滤波器采样时间;
5 f+ T% g, B1 B3 Iconst char  C_0 = 1;
5 L! h. q" e2 [* B; x5 g! E% A: ?float Q_bias, Angle_err;
: c/ b1 t" f/ ^" b1 Afloat PCt_0, PCt_1, E;
) T0 ~9 q, t5 S9 Yfloat K_0, K_1, t_0, t_1;
6 F6 L; u6 d4 z* y7 D5 P* d7 h+ @- ?float Pdot[4] ={0,0,0,0};
0 v" k3 x- a2 z4 Q2 D/ ?float PP[2][2] = { { 1, 0 },{ 0, 1 } };% b- X0 S2 Y5 A+ u
: i# a7 \5 R1 J3 Q# M( y! e7 {
/*****************卡尔曼滤波**************************************************/
* r. H7 q+ N7 I# qvoid Kalman_Filter(float Accel,float Gyro)                5 J3 O0 `( g( y( e9 |
{
9 t. \& Q; ~7 Y* V; C: f9 K" W        Angle+=(Gyro - Q_bias) * dt; //先验估计
4 @3 A9 ^, D( t. I4 c- Z! W* Y8 N       
$ `7 ~6 c/ f' H% \# X- g* N        Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分& V" p) r* O* ~

4 p+ @; ?% a4 L        Pdot[1]= -PP[1][1];% @- Q! |0 `9 `* D4 C
        Pdot[2]= -PP[1][1];8 ^% _3 h; e0 M' d1 \0 y
        Pdot[3]=Q_gyro;
7 V7 J, W9 B  a  m4 B       
* j% y0 @/ M/ e" M, |. L3 O' q) z        PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
) q% c; y. y9 c# ?/ Y8 E& S' g        PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差& i" S6 i7 {! h; a5 |! ]8 f
        PP[1][0] += Pdot[2] * dt;. z) T' D' X# w; Q% l) B  J
        PP[1][1] += Pdot[3] * dt;
9 W  {" ~+ y5 @1 K3 r* F& M7 ]& q                : S; F. j7 T; f' C
        Angle_err = Accel - Angle;        //zk-先验估计
0 k$ m7 C" O; B1 f8 `       
. e+ E# d5 c, r* }6 w* u        PCt_0 = C_0 * PP[0][0];
2 x8 F9 L* x, k        PCt_1 = C_0 * PP[1][0];
- |8 U- S- M- l/ \" H# x# Q        6 {  _$ ?1 u  a' [8 I1 ^. m
        E = R_angle + C_0 * PCt_0;6 J! t2 q, O% L6 T" n" q9 L0 V
       
1 J, E9 k% q1 g+ r        K_0 = PCt_0 / E;5 y0 ?, |  E3 U# d& v; D( U* g  c* _
        K_1 = PCt_1 / E;6 Q$ g: ^8 y4 J% V* w
       
2 v2 ?: G- Y8 e9 H        t_0 = PCt_0;# n1 {! ~# D9 r' e7 H
        t_1 = C_0 * PP[0][1];
' S* I: o+ {+ @0 \( l/ y0 ^7 r4 |4 |% N) O1 k6 p9 ?6 t4 X8 O
        PP[0][0] -= K_0 * t_0;                 //后验估计误差协方差
1 x& L3 a2 F: g* k, H        PP[0][1] -= K_0 * t_1;
4 f' r' @  H; o5 J1 s        PP[1][0] -= K_1 * t_0;" z/ v$ H! T' t
        PP[1][1] -= K_1 * t_1;
$ V% M7 f1 t& I0 o1 F               
# l" J( R  O- u0 ~        Angle        += K_0 * Angle_err;         //后验估计& B3 q$ F1 b9 ^# b( Q
        Q_bias        += K_1 * Angle_err;         //后验估计/ b) s! V) A: J( M4 t# Y- r
        Gyro_y   = Gyro - Q_bias;         //输出值(后验估计)的微分=角速度
3 G3 z% V- y! ?, B+ p
( r" e0 r! ~0 f/ q}; Y1 i, {5 O# {( p% N8 w
8 c  e2 s8 f' ^( J# Q
******************倾角计算*****************7 y2 Z% l: x% w2 _
void Angle_Calculate(void); d( B4 B2 @8 [
{9 d, U# h) ], m/ J( t

# h  z$ L. S% x1 t" B  z! E/****************************加速度****************************************/6 z8 }' @1 m! `5 P% G! @2 r. Q- ^
       
6 C% ]8 D1 z6 ?$ n! j& ^) f        Accel_x  =  MPU6050_Real_Data.Accel_X;          //读取X轴加速度' d! _3 d" E5 n3 e  d$ a* e/ I
        Angle_ax = Accel_x*1.2*180/3.14;     //弧度转换为度2 X5 H  }% [+ X5 U& [7 E* r/ O
  N3 U8 c* k" z; g, m
/****************************角速度****************************************/
1 c( ?0 B% U6 A9 ?+ v, G( b, ?       
2 ~8 G0 Z9 \2 T7 y+ J9 j' Q         Gyro_y = MPU6050_Real_Data.Gyro_Y;             - d' u* C* Y- a1 x$ p$ R+ U' D0 Z9 Z
时间dt,所以此处不用积分
  R9 L  ^7 a- {$ W3 u. `/***************************卡尔曼融合*************************************/  G% \  v) g9 G+ {' y1 p5 }5 _
        Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角
1 x) N5 [2 a7 Z7 j4 A       
! w" V9 \. W1 A& j1 ^0 r  m; s( B0 O: U) f
大米周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发表:& Z# t9 i. S0 R: s5 S
收了  感谢楼主 . u0 l9 `! Z7 ]

* g8 B3 ?& c+ t2 E/ r+ R客气。。。
疯子咬手指 回答时间: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 手机版