打印
[应用相关]

STM32入门平衡车

[复制链接]
104|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本文主要介绍作者自己制作STM32平衡车的过程,因为作者本人主要为了学习PID算法,故没有加很多功能。

硬件部分:

不想自己画时间去设计主控板,故使用网上开源的底板,很好用,如果也有相同需求的小伙伴,也可以照抄。

主控使用STM32F103C8T6,降压模块是某宝上的成品模块,大家如果自己制作,也很简单,例如7805等LDO芯片都可以使用,外围电路少。电机驱动是一个集成的半桥模块,原理就是开关MOS管,如果大家有兴趣,也可以去制作,这个过程还是很有意思的。陀螺仪使用的MPU6050,虽然零飘很严重,但我们对精度并没有很大的要求,直接使用就行了。(后面的四轴飞行器制作,使用的另一款六轴传感器)





硬件部分就是这样。

软件部分:

平衡车的核心部分首先是这个MPU6050,可以说它是平衡车的心脏,我使用的是软件I2C和DMP库的姿态解算,比较简单,还可以使用四元数解算配合卡尔曼滤波等滤波算法一起使用(大多用于自制飞行器),我这里并没有很高的精度需求,故不需要使用。所以使用的是DMP库。(文末会附上源码)

得到解算的欧拉角后,我们就可以调直立环了,这就不得不提到大名鼎鼎的PID。

PID:即为对偏差进行比例、积分和微分控制。由三个元素构成,分别是比例(P),积分(I),微分(D)。工程中P必然存在,在P的基础上又有如PI控制(比例积分),PD控制(比例微分),PID控制(比例积分微分)。

比例项:提高响应速度,减小静差。
积分项:消除稳态误差。
微分项:减小震荡以及超调。

而PID又分为位置式PID和增量式PID。

位置式PID: PWM_out=Kp×e(k)+Ki× Σe(k) +Kd×[e(k)-e(k-1)]

e(k):本次偏差
e(k-1):上一次偏差
Σe(k):e(k)以及以前的偏差的累积和,其中k为1,2,…
PWM_out:输出
int Position_PID(int Encoder, int Target)
{
        static float Bias, PWM_out, Integral_bias, Last_bias;
        Bias = Encoder-Target;                // 计算偏差
        Integral_bias += Bias;                // 计算偏差的积分
        // 位置式PID控制器公式
        PWM_out = Position_Kp*Bias+Position_Ki* Integral_bias+ Position_KD*(Bias- Last_bias)
        Last_bias = Bias;                        // 保存上一次偏差
        return PWM_out;                                // 输出
}
增量式PID: PWM_out=Kp×e(k)+Ki× e(k-1) +Kd×e(k-2)

e(k):本次偏差
e(k-1):上一次偏差
e(k-2):上上次偏差
PWM_out:输出
float IncPIDCal(PID *pid, int32_t NowValue, int32_t AimValue)     
{
        int32_t iError;                          //当前误差值
        float Output;                           //控制输出增量值
       
        iError = AimValue - NowValue;            //目标值与当前值之差

        Output = (pid->P * iError)               //E[k]项
                        -(pid->I * pid->LastError)       //E[k-1]项
                        +(pid->D * pid->PrevError);      //E[k-2]项

        pid->PrevError = pid->LastError;         //存储误差,用于下次计算
        pid->LastError = iError;
       
        return(Output);                         //返回增量值
}

大家可根据合适的选择。

位置式PID:

1、对单片机算力要求更高,因为它的积分项是过去所有时刻的总和,工作量大。(这点作者本人并没有很好的体会,因为现在的单片机算力都比较强,并且工程量不大)

2、因为最新的单片机主频普遍比较高,积分项的累计会很快,如果不对积分项进行及时有效地限幅,肯能会发生重大事故。

3、并且积分项由于累加缘故,会表现出一定的滞后性,所以一般位置式PID只使用PD。

增量式PID:

1、只使用前后三次测量值的偏差,因此没有误差累加,且计算量小。

2、积分截断效应大,有稳态误差;溢出的影响大。有的被控对象用增量式则不太好。

但不论是哪一种PID,在使用时,要对输出和积分项进行适当的限幅,以防发生重失误,可在后来慢慢加大限幅。

直立环:

这里使用的是PD,需要各位慢慢调,只有直立环并不能很好的站住,后续需要加入速度环才能站稳。输入的真实角度和真实角速度是由MPU6050的安装方向所决定,并不是一尘不变,各位读者需要注意一下。

Kp,Kd的方向:这也是一个易错点,平衡车向哪边倒,轮就向哪边滚,不知道大家能否理解,如下图所示,所以大家调节之前一定要确认好极性,不然做很多无用功。



调节方法:将Kd=0,慢慢加Kp,一点点加,当小车在稳态附近时产生较高频率大幅度晃动时,立马断电,以防烧毁电机,然后再慢慢的降低Kp,降低到不晃动或小幅度晃动即可,切记不能着急,慢慢来。确定了Kp后,将Kp乘以0.6~0.8,(我也不知道原因,工程经验)然后确定好Kp方向慢慢加大Kp值,当小车出现高频小幅度震荡时,慢慢降低Kp,前后尝试,这是小车能在稳态停住几秒,但并不能抵抗外力,很容易倒,需加入速度环。

/*********************
直立环PD控制器:Kp*Ek+Kd*Ek_D

入口:期望角度、真实角度、真实角速度
出口:直立环输出
*********************/
int Vertical(float Med,float Angle,float gyro_Y)
{
        int PWM_out;
       
        PWM_out=Vertical_Kp*(Angle-Med)+Vertical_Kd*(gyro_Y-0);
        return PWM_out;
}
速度环:

速度环需要先对编码器进行采样,切记不可以放在主函数循环中,放在中断里进行采样,将采样的值传入速度环函数,进行低通滤波,(这里的低通滤波非必要,可不进行)低通滤波中的权重a需视情况而定,(推荐大家一个上位机软件Vofa+,可以将滤波前后的波形打出来进行对比),这里使用的时PI,并进行有效限幅,调节方法和直立环一样。

/*********************
速度环PI:Kp*Ek+Ki*Ek_S
*********************/
int Velocity(int Target,int encoder_left,int encoder_right)
{
        static int Encoder_S,EnC_Err_Lowout_last,PWM_out,Encoder_Err,EnC_Err_Lowout;
        float a=0.7;
       
        //1.计算速度偏差
        Encoder_Err=((encoder_left+encoder_right)-Target);//舍去误差--我的理解:能够让速度为"0"的角度,就是机械中值。
        //2.对速度偏差进行低通滤波
        //low_out=(1-a)*Ek+a*low_out_last;
        EnC_Err_Lowout=(1-a)*Encoder_Err+a*EnC_Err_Lowout_last;//使得波形更加平滑,滤除高频干扰,防止速度突变。
        EnC_Err_Lowout_last=EnC_Err_Lowout;//防止速度过大的影响直立环的正常工作。
        //3.对速度偏差积分,积分出位移
        Encoder_S+=EnC_Err_Lowout;
        //4.积分限幅
        Encoder_S=Encoder_S>20000?20000:(Encoder_S<(-20000)?(-20000):Encoder_S);
       
        if(stop==1)Encoder_S=0,stop=0;//清零积分量
       
        //5.速度环控制输出计算
        PWM_out=Velocity_Kp*EnC_Err_Lowout+Velocity_Ki*Encoder_S;
        return PWM_out;
}

转向环:

/*********************
转向环:系数*Z轴角速度+系数*遥控数据
*********************/
int Turn(int gyro_Z,int RC)
{
        int PWM_out;
        //这不是一个严格的PD控制器,Kd针对的是转向的约束,但Kp针对的是遥控的转向。
        PWM_out=Turn_Kd*gyro_Z + Turn_Kp*RC;
        return PWM_out;
}
三环代码大概如此,在本工程中,我将三环进行并联,直接相加就可以,但切记速度不可过快,以防影响直立环。(在后面的文章中,会在四轴四轴飞行器专题详细介绍串联PID,更加稳定的调节。)

作者这篇文章主要给大家介绍PID算法,水平有限,讲得不好和不对的地方,希望大家指出,如有疑问也欢迎大家评论区讨论,作者尽量给出答复。

工程源码:链接:https://pan.baidu.com/s/1miTIfhVCHh2fi99lE24NiA
提取码:s9qj
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/paulgeorge__13/article/details/145180592

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

50

帖子

0

粉丝