|
在此贴上以前做过的平衡小车资料,一来供众网友学习交流,二来申请stm32f429探索套件。。。/ V: t7 F1 a% l5 } 先上图
原材料清单:% y9 m d7 C {! ~6 U. c, [" e9 U ——————————————————————————————————————————. y- v- r; f) T* I 主控:stm32f103rct6 传感器:mpu6050(带陀螺仪和加速度) 电机驱动芯片:l298n+ k. `' ]5 R" T/ R3 Z( q2 ~ 电机:冯哈伯2224 编码器:电机自带16线! p9 D0 J. |8 f1 P9 `3 k 电池:两节18650 轮子架子:淘宝店购买,减速比1:5 —————————————————————————————————————————— 处理过程: —————————————————————————————————————————— 其实程序过程很简单,先是采集传感器MPU6050的数据,并进行加工,获得当前小车倾斜角,然后根据此角度做PID调节,得到小车两个电机的PWM脉宽,调整轮子速度,使之回到倾角为0的状态,即保持平衡。然后就不停地重复采集->处理->调节->处理这一过程。3 X; W! m( [: o l$ _) Z' u( M* y 在此基础上,附加两电机的PWM值,即可实现前进,倒退,左转,右转动作 —————————————————————————————————————————— 难点分析: —————————————————————————————————————————— 有两个难点" x. W# f2 n, u3 M 1.传感器的数据处理是小车的最大难点。一是传感器受震动影响很大,很容易超量程;二是传感器数据漂移比较厉害。而关键的小车倾角就来源于此传感器数据。为此,参考网上数据滤波处理方式,采用卡尔曼滤波算法,融合陀螺仪和加速度传感器数据得出小车倾角。 2.PID,比例系数的调节不用多讲,需要耐心的测试和调节。我要说的是,单纯靠倾角做PID不能使小车平衡,因为当小车倾角接近0度时,改变的PWM值无法使小车越过平衡点,造成小车朝一边加速前进,所以要将速度也添加至PID调节中,做积分 ——————————————————————————————————————————- 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)
|
微信公众号
手机版
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
问题:1,我快速改变板子倾角时Angle的变化正常吗?
2,Angle正常变化的时候是应该与Angle_ax的值相近吗?7 d/ F2 N2 B/ J, O6 p$ v O+ y
现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现中间的角度增大+ a5 C: ?4 R3 F0 e# o! E
*************读取数据********************
//定义MPU6050内部地址
#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
#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
#define ACCEL_YOUT_H 0x3D" P/ i* B+ X2 J
#define ACCEL_YOUT_L 0x3E
#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
#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
#define GYRO_YOUT_L 0x46$ m( _" u+ {( K) @- K4 b; h- h: b
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
//读取寄存器原生数据
MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);
MPU6050_Raw_Data.Accel_Y = (buf[2]<<8 | buf[3]);
MPU6050_Raw_Data.Accel_Z = (buf[4]<<8 | buf[5]);
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]);, }5 D6 f8 ?% D( m3 A
MPU6050_Raw_Data.Gyro_Z = (buf[12]<<8 | buf[13]);
//将原生数据转换为实际值,计算公式跟寄存器的配置有关
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; 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;
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
" L, v3 z. e' m6 e3 A! ^/ X
//******卡尔曼参数************+ @# z" S# Y3 u2 W
const float Q_angle=0.001;
const float Q_gyro=0.003;
const 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;
float Q_bias, Angle_err;
float PCt_0, PCt_1, E;
float K_0, K_1, t_0, t_1;
float Pdot[4] ={0,0,0,0};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };
) } w; J1 o8 k; p( ?
/*****************卡尔曼滤波**************************************************/4 u+ O" s' G) R+ z0 C
void Kalman_Filter(float Accel,float Gyro) " r! `/ T" `# `; M& f9 ?
{
Angle+=(Gyro - Q_bias) * dt; //先验估计
) 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
PP[0][0] += Pdot[0] * dt; // Pk-先验估计误差协方差微分的积分
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. \
Angle_err = Accel - Angle; //zk-先验估计
PCt_0 = C_0 * PP[0][0];- n2 O& p5 {. g) B
PCt_1 = C_0 * PP[1][0];
E = R_angle + C_0 * PCt_0;' V h, u+ S4 x0 P' P/ o* e! p
K_0 = PCt_0 / E;) c1 T! F* W+ n, t
K_1 = PCt_1 / E;
t_0 = PCt_0;+ V1 d4 D! r7 K% F( L4 V) O: ?
t_1 = C_0 * PP[0][1];
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;
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; //输出值(后验估计)的微分=角速度
- W# x+ p2 b! V% c" }
}
******************倾角计算*****************2 c5 ^+ i. X3 b/ N
void Angle_Calculate(void)
{
6 d* N, ?, k! H* z4 J" z0 K
/****************************加速度****************************************/: A6 r) k8 ]3 I1 ?9 m0 x' x
Accel_x = MPU6050_Real_Data.Accel_X; //读取X轴加速度8 B9 x- V5 [& S* x$ }
Angle_ax = Accel_x*1.2*180/3.14; //弧度转换为度
/****************************角速度****************************************/: b6 g7 {" }' v$ p# A
0 n% h8 y5 j4 {& }( P& g
Gyro_y = MPU6050_Real_Data.Gyro_Y;
时间dt,所以此处不用积分
/***************************卡尔曼融合*************************************/, 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
回复:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
收了 感谢楼主
- n: d- R1 r( p: J: H$ v( n, ^
客气。。。
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
回复:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作
RE:【MCU实战经验】+基于stm32两轮平衡车制作