|
在此贴上以前做过的平衡小车资料,一来供众网友学习交流,二来申请stm32f429探索套件。。。/ J( R) ?$ |; o# a1 t& C" w7 U% J* L 先上图3 e- o& ?$ E1 ~* Y; i
原材料清单:/ 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线 电池:两节186502 \& }1 x9 b1 q* d+ c 轮子架子:淘宝店购买,减速比1:5 —————————————————————————————————————————— 处理过程:8 U* z- f& s% }* R' t9 D9 C ——————————————————————————————————————————: ]# W+ n) L( s' S- |$ c, F* Q 其实程序过程很简单,先是采集传感器MPU6050的数据,并进行加工,获得当前小车倾斜角,然后根据此角度做PID调节,得到小车两个电机的PWM脉宽,调整轮子速度,使之回到倾角为0的状态,即保持平衡。然后就不停地重复采集->处理->调节->处理这一过程。 在此基础上,附加两电机的PWM值,即可实现前进,倒退,左转,右转动作 —————————————————————————————————————————— 难点分析: ——————————————————————————————————————————3 L+ \0 d L4 _3 ]( ^0 N. D9 X 有两个难点 1.传感器的数据处理是小车的最大难点。一是传感器受震动影响很大,很容易超量程;二是传感器数据漂移比较厉害。而关键的小车倾角就来源于此传感器数据。为此,参考网上数据滤波处理方式,采用卡尔曼滤波算法,融合陀螺仪和加速度传感器数据得出小车倾角。 2.PID,比例系数的调节不用多讲,需要耐心的测试和调节。我要说的是,单纯靠倾角做PID不能使小车平衡,因为当小车倾角接近0度时,改变的PWM值无法使小车越过平衡点,造成小车朝一边加速前进,所以要将速度也添加至PID调节中,做积分 —————————————————————————————————————————— 制作心得:8 O' v2 D$ |' f4 k9 v —————————————————————————————————————————— 关于平衡小车,大多数网友应该都曾做过或者想过要做。于是百度搜资料,其中最多的应该是飞思卡尔直立车的资料,当初我也看下下,平衡车的原理都懂了,但那时还没搞过PID调节和数据滤波,所以具体怎么写程序并不知道。至于平衡车的程序资料也非常少。后来在网上参考相关数据滤波,PID调节后,才渐渐掌握。在此我也就贴上我的程序代码,供大家学习交流,少走弯路。有什么问题,欢迎回帖。当然也希望大家多支持此贴,祝我申请F429套件成功!哈哈 ![]() ——————————————————————————————————————————
å¡å°æ¼æ»¤æ³¢.rar
(2.76 MB, 下载次数: 12100)
|
微信公众号
手机版
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
问题:1,我快速改变板子倾角时Angle的变化正常吗?
2,Angle正常变化的时候是应该与Angle_ax的值相近吗?( F0 `) y! `" |4 Z' M& R
现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现中间的角度增大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
#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
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#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
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43& r# u0 ?2 N4 W N% O; b3 @- Z
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45- P u* S4 ]7 a
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
0 ~2 D! w X$ i* h- l5 ~
//读取寄存器原生数据
! m0 N5 @/ Y, a' T$ g& c
MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);
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]);
MPU6050_Raw_Data.Gyro_X = (buf[8]<<8 | buf[9]);
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]);
! 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;
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;
MPU6050_Real_Data.Gyro_Y=-(float)(MPU6050_Raw_Data.Gyro_Y - gyroADC_Y_offset)/65.5;
MPU6050_Real_Data.Gyro_Z=(float)(MPU6050_Raw_Data.Gyro_Z - gyroADC_Z_offset)/65.5;
} & Y, [/ ?6 i% u% |( H
4 g/ a1 }0 L3 b( v, p
//******卡尔曼参数************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;
const float dt=0.01; //dt为kalman滤波器采样时间;
const 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};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };
/*****************卡尔曼滤波**************************************************/
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; //先验估计
Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分; R- ~( R/ a3 s7 M, Y/ R* q" F4 I
Pdot[1]= -PP[1][1];
Pdot[2]= -PP[1][1];
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-先验估计误差协方差微分的积分
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;
/ `9 P4 u- h8 ^$ g" Y/ w
Angle_err = Accel - Angle; //zk-先验估计
) 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];
) }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;
t_1 = C_0 * PP[0][1];/ B8 e- S5 x' _& S8 D. c
PP[0][0] -= K_0 * t_0; //后验估计误差协方差
PP[0][1] -= K_0 * t_1;
PP[1][0] -= K_1 * t_0;. h5 X0 y3 I O6 z. Q; i
PP[1][1] -= K_1 * t_1;
5 K. }) Y; ~9 f
Angle += K_0 * Angle_err; //后验估计
Q_bias += K_1 * Angle_err; //后验估计
Gyro_y = Gyro - Q_bias; //输出值(后验估计)的微分=角速度
}7 d- }3 J7 h$ F7 R' W G
******************倾角计算*****************. @/ \ g2 o4 _1 K" Q
void Angle_Calculate(void)/ ^! v# E* `; ^+ k+ B9 w
{
2 V1 s8 n0 B4 a
/****************************加速度****************************************/
; U7 Q z3 n0 U; ?: G! Y6 E3 X3 _4 c
Accel_x = MPU6050_Real_Data.Accel_X; //读取X轴加速度
Angle_ax = Accel_x*1.2*180/3.14; //弧度转换为度
/****************************角速度****************************************// 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
/***************************卡尔曼融合*************************************/
Kalman_Filter(Angle_ax,Gyro_y); //卡尔曼滤波计算倾角
# N1 L8 O5 H9 J4 O
回复:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
收了 感谢楼主 4 f3 I* }! U4 D5 _
5 H$ R6 g7 f* u5 ]9 K! s4 I
客气。。。
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作