这是代码的效果,没有达到最好的状态,可以自己再改一下参数,下面我介绍一下我代码的思路和如何改进改程序。大一小白第一次发文章,说的不好的地方请多见谅。
代码整体思路就是利用三路输出模拟量红外循迹模块进行循迹,模拟量处理算法是用的魔石的方法,大家可以去bilbil学习一下。模拟量信号的采集就是用的ADC采集和DMA传输,这样效率会高一些,速度控制用的是速度闭增量式PI,方向控制用的是位置式PD。为什么速度用PI,方向用PD呢,我的个人理解是增量式PID速度控制中(注意增量式PID中的的参数和位置式中PID参数的计算公式是不同的),增量式中的I(参数I*误差)是用来提高响应速度(比如设定速度是10,刚刚开机的速度是0,I越大,速度从0增加到10所用的时间也就越短,也就是加速度越大),增量式PID的每一次的控制量是在上一次控制量的基础上进行改变,所以你想,I越大,每一次你在原来基础上改变的这个量也就越大,就能越早的达到目标,但是这个时候也会带来一个问题就是过冲,这个时候就需要P(参数P*这一次误差-上一次误差)来消减过冲。
方向PID控制中用的是位置式PID,也就是每一次输出的都是直接控制量,这个量是通过循迹传感器处理后的数据和设定值(0)做差得到误差值,通过PID得到控制舵机的输出量,这里的位置式中的P(参数P*误差)主要是提高响应数度,D(参数D*(这一次误差-上一次误差))主要是当黑线突然变化时,也就是弯道,输出比较大的控制量。
下面我就分享一下我调试过程。我的最终调试目标是可以在小车速度尽量快的情况下稳定的完成循迹,所以一开始调试的时候我就把速度设定的比较大,但是速度大了之后会有很多问题,比如跑直线的时候抖动会非常厉害,在曲率小的弯道会超调(就是小弯道舵机就拐很大的弯),在曲率大的弯道也会反应不过来,效果非常差。
我是一个一个问题解决的,首先是先解决如何快速跑直线,减小抖动的。抖动的根本原因还是PID参数问题,因为对循迹模块输出的数据处理以后,数据的大概范围是-9000-9000,数据为0表示在黑线中间,速度很快以后,因为方向位置式PD参数中的P比较大,所以有一点误差就会输出比较大的控制量,这个问题很好解决,减小P就可以啦,这样跑直线的时候就不会抖动了,但是这样在遇到曲率比较大的弯道的时候就反应不过来了,起初我想的是调大D,来提高转弯时候的输出量,但是没调好,如果仔细调P和D直接的关系应该可以调好。所以我就多写了几组PD参数,当检测到弯道的时候用另外一套PD参数,如何检测弯道呢,我用的方法是abs(bias-bias_lest) > 1000 || abs(bias)>6500,也就是检测误差的变化率和误差的大小,这样就能很好的检测到弯道了,这里的1000和6500可以根据自己赛道和小车的情况自己调整。
第二个问题就是遇到曲率大弯道会拐不过来,也就是转弯半径过大,这个问题如果只用舵机进行控制的话明显就不行了,因为我试过,当检测到弯道时舵机输出量最大转弯半径还是太大了,已经达到舵机的极限了,所以只能利用后轮的差速来实现漂移的效果,这样就可以了,于是我又写了一组差速PID控制函数,把这个函数算出来的输出量加到数度PI控制函数里,这样就能相互作用达到差速的效果,我代码中会有。
void TraceMove(int TraceDate,float TarSpeed)
{
int turnpwm=0,turn_speed=0;
int ServorAngle=0;
turnpwm=ChangeTraceTurn(TraceDate);
turn_speed=ChangeTraceTurn_speed(TraceDate);
Get_Motor_Speed(&Encoder_Left,&Encoder_Right);
Motor_A=turn_speed+Incremental_PI_A(-Encoder_Left,TarSpeed); //===速度闭环控制计算电机A最终PWM
Motor_B=-turn_speed+Incremental_PI_B(Encoder_Right,TarSpeed); //===速度闭环控制计算电机B最终PWM
Xianfu_Pwm(); //===PWM限幅
Set_Pwm_Motor1(Motor_A);
Set_Pwm_Motor2(Motor_B);
ServorAngle=turnpwm+Servo_MID;
Set_Servor_Angle(ServorAngle); //设置舵机角度
}
其中turn_speed是算出来的差速输出量,把误差参数传递进去进行计算。
代码中有一些负号不用管,是因为我左右轮的编码器极性差异。
第三个问题就因为我想提高速度,所以跑直线的时候速度比较快,当突然遇到弯道的时候容易冲出去,所以我就写了一个控制设定速度的函数,这个函数是根据之前说的检测弯道的方法来进行控制,当遇到弯道时,减小设定速度就可以了。
int textspeed(int TraceDate)
{
int speed=10;
static int bias,bias_lest;
bias=TraceDate;
if(abs(bias-bias_lest) > 500 || abs(bias)>4500 )
speed=3;
if(abs(bias-bias_lest) > 1000 || abs(bias)>6500)
speed=1;
else
speed=10;
bias_lest=bias;
return speed;
}
最后我说一下可以改进的地方,大家通过视频可以看出来在拐弯的地方速度是慢下来了,其实也没必要在整个拐弯的过程都这么慢,可以把过曲线分为三段,第一阶段是检测到弯道,这个时候要减速,但是肯定还是会冲出去一些的;然后是中间阶段,中间阶段是冲出黑线后的阶段,这个时候就不需要再这么慢了,可以适当提高速度;第三个阶段是回归到黑线,这个阶段应该再稍微减小数度,因为如过快还是会冲出去,如好等车驶入正轨以后就可以回归到正常循迹模式了,也就是快速跑直线模式。
好啦,第一次分享就到这里吧,谢谢大家,等代码审核过了会在评论区发给大家的!
版权声明:本文为CSDN博主「include“小白”」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_54841340/article/details/117548201
暂无评论