STM32 PID 平衡车制作教程

基于 STM32F103C8T6 的 PID 平衡车项目,含直立环、速度环、转向环的详细调参与代码实现。

STM32 PID 平衡车详细教学

本文是基于 STM32F103C8T6 单片机开发的平衡小车项目。这个项目常用于广大学子的 PID 算法的入门项目,我认为 PID 应用并非很难,重要的是调参。所以调参的过程很重要。而且平衡车也相对简单,也以选择它作为学完 32 后的第一个项目(本人就是)。本人的小车添加了直立环,速度环和转向环。最后有源码和调好的视频。


一、下面介绍平衡车的硬件

  1. 一个开发板或者用面包板也可以,开发板可以自己嘉立创打板,也可以选择淘宝的亚博智能科技的开发板。
  2. 两个编码电机(520、370 都可以,只要有编码器就行),或者买直流电机再买编码器,也是可以的。

    PS:如果买亚博智能科技的板子,需要买他家的电机,因为别的商家的电机接口不一样!

  3. TB6612 电机驱动不多说,买个 10 多块的,不要图便宜买几块的,到时候小车抽搐就难受了。
  4. HC-06 蓝牙通信模块,用于手机控制小车,也可用上位机调参。
  5. MPU6050 陀螺仪模块,这个模块用于测量小车的三维的各种参数。
  6. 12V 可充电的锂电池,开发板应有降压模块。
  7. OLED 0.96 屏幕,可有可无。
  8. 车模(轮胎等等)。
  9. ST-Link 下载器(也有可用 J-Link 等下载器)。
  10. 如果要加避障功能,可以购买超声波避障模块。
  11. 适当的杜邦线,螺丝刀,电池充电器等等基础器件。

PS:可能说的不全,如果有遗漏根据自己的需求自行购买。

贴一张组装好的照片:

组装照片

二、介绍用到的单片机软件资源

  1. 3 个通用定时器分别是:TIM2、TIM3、TIM4。
  2. 1 个 USART3 串口。
  3. OLED 和 MPU6050 的软件模拟 IIC 通信。

PS: 如果添加避障模块,应该还要一个定时器用来计时超声波模块。其他功能如果需要,自行分配单片机资源。

三、介绍主要硬件模块的使用方式

  1. TB6612: 下面是 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 教程,这是更加详细的介绍: MPU6050 详细教程 ,有需要可以去看看。

四、下面是各个软件资源的分配

  1. TIM2: 输出两路 PWM 波,开启定时中断,在中断中存放着最主要的电机控制程序,周期应该最好不要超过 10μs。
  2. TIM3 和 TIM4: 为读取两个电机的编码值。
  3. USART3: 用于与手机相连接。

五、接着介绍最主要的 PID 部分

六、PID 代码

(PS:直立环需 P、D,速度环需 P、I,转向环需 P、D)


1. 三环变量声明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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_sum;

extern float tkp,tkd;//转向环
float yaw_err,yaw_err_differnence,last_yaw_err;

2. 直立环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//直立环:
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. 速度环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//速度环:
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. 转向环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//转向环
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:调参视频可观看: 平衡车调参教程 更加详细的调参教程

八、控制代码部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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,要保证定时中断周期不超过 10μs)

九、成功视频

演示视频: STM32 平衡车演示

视频中的蓝牙调试助手随便一找就有,作者在这里就不贴链接了(因为作者也找不着了)。

点此获取源码: 源码下载

有问题主页联系作者或者邮箱: 1039214848@qq.com