STM32-pid平衡车详细教学 #
本文是基于stm32f103c8t6单片机开发的平衡小车项目。这个项目常用于广大学子的pid算法的入门项目,我认为pid应用并非很难,重要的是调参。所以调参的过程很重要。而且平衡车也相对简单,也以选择它作为学完32后的第一个项目(本人就是)。本人的小车添加了直立环,速度环和转向环。最后有源码和调好的视频。
一.下面介绍平衡车的硬件: #
- 1.一个开发板或者用面包板也可以,开发板可以自己嘉立创打板,也可以选择淘宝的亚博智能科技的开发板。
- 2.两个编码电机(520,370都可以,只要有编码器就行),或者买直流电机再买编码器,也是可以的。
- Ps:如果买亚博智能科技的板子,需要买他家的电机,因为别的商家的电机接口不一样!
- 3.tb6612电机驱动不多说,买个10多块的,不要图便宜买几块的,到时候小车抽搐就难受了。
- 4.hc-06蓝牙通信模块,用于手机控制小车,也可用上位机调参。
- 5.Mpu605陀螺仪模块,这个模块用于测量小车的三维的各种参数。
- 6.12v可充电的锂电池,开发板应有降压模块。
- 7.Oled0.96屏幕,可有可无。
- 8.车模(轮胎等等)。
- 9.St-link下载器(也有可用J-link等下载器)。
- 10.如果要加避障功能,可以购买超声波避障模块。
- 11.适当的杜邦线,螺丝刀,电池充电器等等基础器件。
ps:可能说的不全,如果有遗漏根据自己的需求自行购买。 贴一张组装好的照片
二.介绍用到的单片机软件资源: #
- 1.3个通用定时器分别是:TIM2,TIM3,TIM3.
- 2.1个usart3串口
- 3.Oled和Mpu6050的软件模拟IIC通信
PS:如果添加避障模块,应该还要一个定时器用来计时超声波模块。其他功能如果需要 自行分配单片机资源。
三.介绍主要硬件模块的使用方式: #
- 1.tb6612: 下面是tb6612的引脚图
PwmA和PwmB是要从单片机输入的两个pwm波接收口,Ain1,Ain2为PwmA的io控制,对应的为右边的A01,A02,通过控制两个io口的高低电平来控制电机的正反转。同理PwmB也是如此。至于Vcc和Gnd是用来上电的(要共地)。STBY接5V/3.3V,VM接12V即可.
- 2.电机编码器: 这个图片已经介绍的很清楚了,有的电机接口不一样,要注意。
- 3.mpu6050:这个模块涉及太多,简单应用可以去看b站江科大的mpu6050, https://blog.csdn.net/weixin_41640116/article/details/104878646 这是更加详细的介绍,有需要可以去看看。
四.下面是各个软件资源的分配: #
- 1.TIM2:输出两路pwm波,开启定时中断,再次中断中存放着最主要的电机控制程序,周期应该最好不要超过10us。
- 2.TIM3和TIM4为读取两个电机的编码值。
- 3.Usart3用于与手机相连接。
五.接着介绍最主要的pid部分: #
六.Pid代码: #
(Ps:直立环需P,D,速度环需P,I,转向环需P,D)
1.三环变量声明: #
extern float Kp,Ki,Kd; //直立环参数
float err; //此次误差
float last_err; //上次误差
float err_sum=0; //误差累加
float err_difference; //误差的差值
extern float VKp,VKi; //速度环参数
float err2; //此次误差
float filt_velocity; //滤波后的速度
float last_filt_velocity;//上一次的滤波后的速度
//float velocity_err_sum=0; //速度的累加
float velocity_sum;
extern float tkp,tkd;//转向环
float yaw_err,yaw_err_differnence,last_yaw_err;
2.直立环: #
//直立环:
int vertical_PID_value(float measure,float calcu)
{
err = measure - calcu; //误差
err_sum+=err; //误差的累加
err_difference = err - last_err; //误差的差值
last_err = err; //此次误差记录为“上次误差”
return Kp*err + Ki*err_sum + Kd*err_difference;
}
3.速度环: #
//速度环:
int velocity_PID_value(int velocity_measure,int velocity_calcu)
{
float a=0.3; //滤波系数(反映滤波程度)
err2=velocity_measure-velocity_calcu;
filt_velocity = a*err2 + (1-a)*last_filt_velocity; //一阶速度滤波
velocity_sum+= filt_velocity; //速度的累加
I_xianfu(&velocity_sum,3000); //累加限幅,调参时可以去掉
last_filt_velocity = filt_velocity; //此次速度记录为“上次速度”
return VKp*filt_velocity + VKi*velocity_sum;
}
//I限幅:
void I_xianfu(float *velocity_sum,int max)
{
if(*velocity_sum>max) *velocity_sum=max;
if(*velocity_sum<-max) *velocity_sum=-max;
}
4.转向环: #
//转向环
int yaw_pid_value(float yaw_measure,float yaw_calcu){
yaw_err=yaw_measure-yaw_calcu;
//防止临界突然转动,改变系统稳定
if(yaw_err>=180){yaw_err-=360;}
if(yaw_err<-180){yaw_err+=360;}
yaw_err_differnence=yaw_err-last_yaw_err;
last_yaw_err=yaw_err;
return tkp*yaw_err+tkd*yaw_err_differnence;
}
七.Pid调参: #
PS:极性就是参数符号的正负。 (所有调参时初始参数为0,一点一点加,调极性时所有环的pid参数初始为0)
1.直立环: #
- 确立极性;给P一定的值,如果发现小车有缓慢摔倒而不是促进摔倒的话,证明极性正确。
- P值;P值不断加大直到出现低频抖动。
- D值:D值增加后发现有一定的平衡性,加到小车可以平稳的直立,但注意此时是假平衡,他只可以站立一会,所以速度环弥补,为了引用速度环还要增加D值,知道出现低频的快速抖动,注意要及时关闭电机,防止电机电流过大损坏电机或其他器件。
2.速度环(正反馈): #
- 确定极性:给一定P值,用手转动轮子,轮子很快的转动起来,证明极性正确,否则你会发现有一股力阻止你转动轮子。
- 工程经验:多年来总结的经验,加入速度环之前应将直立环的参数调成原来的0.6倍。
- 增大PI值:速度环P=200*I,根据此关系可以一起调两个值,逐渐增大,直到出现平稳状态,如果出现一些抖动,可适当增大直立环的D值来抑制系统。
3.转向环: #
- 还是要确定极性:和速度环差不多。
- 调参:首先转向环可以有三种组合方式: 纯p控制,p+d控制,p+d+i控制。如果只有p,调法很简单,极性确认完之后,p从0往上加,直到你满意的效果为止。如果p大了,就会出现过冲现象,即给小车一个角度理论值后(或者用手拨弄一下小车)车头会左右摆动几下才稳定,此时就可以加入d来抑制过冲,也是从0开始往上加,观察到过冲越来越小,直到你满意为止,如果d太大了,小车会抽搐(高频率小幅度震荡),要避免这种现象发生,这就是最常用的p+d控制。如果你想追求更高的精度,消除稳态误差,那么加一点点i就可以了,即p+d+i控制,不过这个稳态误差一般可以忽略不计,如果你稳态误差很大,考虑是不是p太小了。
PS:调参视频:可观看
点我<-或者
更加详细八.控制代码部分 #
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
if(MPU6050_DMP_Get_Data(&pitch,&roll,&yaw)==0)
{
measure = roll; //roll测量值
calcu = zhongzhi; //roll理论值
measure_yaw=yaw;
velocity = ( read_encoder2() + read_encoder1() )/2; //速度测量值
//PID计算:直立环+速度环
PWM = vertical_PID_value(measure, calcu) + 1.88555*velocity_PID_value(velocity,ad_v);
//1.88555这个系数可以有也可没有,用pid参数可以弥补,1.88555就是我大概试出来的一个范围然后瞎打的
PWM_yaw=yaw_pid_value(measure_yaw,calcu_yaw);
//转向环计算
pwm_left=PWM-PWM_yaw;
pwm_right=PWM+PWM_yaw;
PWM_Xianfu(5000,&PWM); //PWM限幅,速度环调参时可以先去掉
SETPWM_left(pwm_left);SETPWM_right(pwm_right);
if(motor_flag) {SETPWM_left(pwm_left);SETPWM_right(pwm_right);} //给电机PWM
else {SETPWM_left(0);SETPWM_right(0);} //关闭电机
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
(直立环和速度环为串级pid,要保证定时中断周期不超过10us)
9.成功视频 #
视频中的蓝牙调试助手随便一找就有,作者在这里就不贴链接了(因为作者也找不着了)
点此获取源码:
源码有问题主页联系作者或者邮箱:1039214848@qq.com