今天接着之前的智能车硬件部分,记录智能车控制部分的个人理解,本文采用自动控制原理来分析智能车的方向控制。
为了更好地理解“控制”,我们复习一下自动控制原理的相关理论知识。
首先,通过分析一辆真正在道路上行驶的汽车来开始今天的话题;汽车能够在道路上正常行驶是依托人的控制,从自动控制原理的角度来看人和车组成了一个人工控制系统;其中车的行驶姿态作为系统的被控量,车保持在道路中间行驶作为给定量,人眼对车的行驶姿态进行采集并将信息(反馈量)传输给大脑,大脑分析并比较车的行驶姿态与期望姿态是否有偏差,若偏离,则经过思考按照操作规则(控制量)指挥双手调节方向盘,从而把车辆的行驶姿态恢复到期望值(给定量)上。
到这里捋清了汽车的姿态控制,很明显,人在车的正常行驶中起到了主导作用,可以说没有人参与汽车就无法运行。参赛的小车必然是不可能有人去驾驶操作的,而是需要小车能够自动完成所有的赛道元素;要让小车在赛道上自动的正常行驶,就需要寻找可以替代人的设备来完成人的操作,组成一个自动控制系统。这里补充一个知识点——何为自动控制?
自动控制:是指在没有人直接参与的情况下,利用外加的设备或装置(控制装置或控制器),使机器、设备或者生产过程(被控对象)的某个工作态或参数(被控量)自动的按照规律(给定量)运行。
对照前面提到的自动控制定义,可以得到小车的方向控制的各个环节。
典型环节 | 对应装置 |
---|---|
比较器 | 单片机 |
控制器 | 单片机 |
执行结构 | 舵机 / 电机驱动 |
被控对象 | 前轮打角角度 / 驱动左右轮 |
反馈环节 | 摄像头 / 电磁 |
由于车模结构的不同,小车方向控制的各环节会有所区别,例如L车、B车的执行结构只有舵机;F车、E车的执行机构只有驱动轮;而C车的执行机构既有舵机又有驱动轮。这里以C车为例,各自动控制系统环节与小车实际对应关系如下图所示:
给定环节可以理解为电磁模块和摄像头模块,给定量可以理解为小车位于直道行驶是的舵机控制占空比值或者摄像头的理论中线值。
比较环节在智能车系统中可以理解为单片机的偏差计算函数,偏差量就是该函数计算出的误差值。下面是电磁偏差计算代码片
。
// 此代码一般放在定时其中断,保证偏差计算的时序稳定
//电感采集获取赛道信息,三电感 \\ 000 000 000 //
L=adc_once(ADC_P00, ADC_10BIT);//左电感值
M=adc_once(ADC_P01, ADC_10BIT);//中间电感值
R=adc_once(ADC_P05, ADC_10BIT);//右电感值
My_Direction.NowError=50*(R-L)/(L+M+R);//差比和计算偏差
//My_Direction.NowError就是偏差量
而摄像头的偏差量主要是通过计算前瞻的数值与理想中值的差值获取,这个部分打算后面专门出一篇描述摄像头的文章,在此不做详细描述。
整个系统的控制器就是偏差处理函数,方向环多为离散的PD控制器(PD控制器会在后面PID的文章中做介绍),而控制量就是偏差处理函数计算出的结果,还是以电磁为例;下面是电磁偏差处理代码片
。
/*******************************************************************************
* 函数名 :Direction_out
* 描述 :方向环
* 参数 :void
* 返回 :void
* 编写者 : 小向是个Der
* 编写日期 : 2021-12-19
*******************************************************************************/
void Direction_Out(void)
{
My_Direction.KP=10.0;
My_Direction.KD=2.5;
//转向PD控制//电感差比和算出的偏差做位置式PD计算
My_Direction.SumError=My_Direction.KP*My_Direction.NowError+\
My_Direction.KD*(My_Direction.NowError-My_Direction.PrevError);
My_Direction.PrevError=My_Direction.NowError;
//中心偏差滤波、加权滑动平均滤波
My_Direction.Pre1_Error[3]= My_Direction.Pre1_Error[2];
My_Direction.Pre1_Error[2]= My_Direction.Pre1_Error[1];
My_Direction.Pre1_Error[1]= My_Direction.Pre1_Error[0];
My_Direction.Pre1_Error[0]=My_Direction.SumError;
My_Direction.Direct_Parameter=My_Direction.Pre1_Error[0]*0.8+My_Direction.Pre1_Error[1]*0.1+\
My_Direction.Pre1_Error[2]*0.06+My_Direction.Pre1_Error[3]*0.04 ;
//此处Price_PWM就是控制量
Price_PWM=(int16)(My_Direction.Direct_Parameter);
}
执行机构在此系统中主要是电机驱动和舵机,其中电机驱动已经在硬件篇介绍过,也有大佬们的文章作为参考,原理就是利用控制器输出的控制量这里就是上述代码中的Price_PWM,分别加减到两个电机的PWM占空比上,实现内外轮速度差,进而使小车转向差速代码片
如下,这里对于电机驱动不在做过多赘述,重点介绍一下舵机。
//差速处理
dutyL=200+Price_PWM/5+2*error;
dutyR=200-Price_PWM/5-2*error;
//电机动作 单极控制
pwm_duty(PWMA_CH2P_P62, 0);
pwm_duty(PWMA_CH1P_P60, dutyL*12);
pwm_duty(PWMA_CH4P_P66, 0);
pwm_duty(PWMA_CH3P_P64, dutyR*12);
舵机是一种位置(角度)伺服的驱动器,我们可以通过给信号脚不同的占空比来让舵机进行打角进而控制小车方向。例如C车的S3010舵机,它需要使用周期20ms(50Hz)的PWM驱动,高电平时间和舵机打角的对应关系如下:
这里补充一下PWM技术,我们常说的PWM可以理解为一组方波,其周期就是两个相邻的上升沿或者两个相邻下降沿的时间,上述舵机使用的就是一个周期为20毫秒的PWM驱动;而占空比就是在一个周期内高电平的时间。
PWM技术简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在测量、通信、工控等方面。
PWM的频率:
是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位Hz。
PWM的周期:
T=1/f,T是周期,f是频率。
如果频率为50Hz ,也就是说一个周期是20ms,那么一秒钟就有 50次PWM周期
占空比
是一个脉冲周期内,高电平的时间与整个周期时间的比例,单位是% (0%-100%)
由上图可知S3010舵机位于理论中值时一个周期的高电平时间应该为1.5ms由此可得占空比为7.5%,由此可以推算出单片机的对应占空比值:
Duty= 7.5%×周期为20ms时的总计数值 (假设一个周期需要计数18000次)
则舵机理论中值Duty_mid=1350;
注意一定是让舵机到达理论中值后再安装转向机构,还需要借助按键找出舵机的左右极限值,并且在程序内部要写限幅,保护舵机避免被烧。
电磁偏差处理代码片`。
/*******************************************************************************
* 函数名 :Steering_Init
* 描述 :舵机初始化
* 参数 :
freq PWM频率(10Hz-3MHz)
angl 舵机角度(正:右转 负:左转 -150 <= angl <= 150)
* 返回 :void
* 编写者 :
* 编写日期 :2021-12-19
*******************************************************************************/
void Steering_Init(uint32 freq, int16 angl)
{
uint16 PWM1_Duty;
if(angl > 140)angl = 140; //限幅
if(angl < -110)angl = -110;
PWM1_Duty = 1350 - angl; //duty占空比为1350时,舵机居中
pwm_init(PWMB_CH1_P74,freq,PWM1_Duty); //PWMA初始化
}
/*******************************************************************************
* 函数名 :steering_angl
* 描述 :舵机角度设置
* 参数 :
angl 舵机角度(正:右转 负:左转 -150 <= angl <= 150)
* 返回 :void
* 编写者 :
* 编写日期 :2021-12-19
*******************************************************************************/
void Steering_Angl(int16 angl)
{
uint16 PWM1_duty;
if(angl > 140)angl = 140; //限幅
if(angl < -110)angl = -110;
PWM1_duty = 1350 - angl; //duty占空比为680时,舵机居中
pwm_duty(PWMB_CH1_P74,PWM1_duty); //PWMA设置占空比
}
根据控制器计算的控制量,附加到舵机的PWM,实现舵机的打角 代码
。
//转向限制幅度
if(Price_PWM>=500) Price_PWM=500;
if(Price_PWM<=-500) Price_PWM=-500;
Steering_Angl(Price_PWM/2);//输出到舵机打角
整个方向控制系统的被控对象是小车的转向机构,也就是舵机和左右驱动轮,而被控量就是小车的前进角度。
在方向控制系统中,反馈对象是摄像头和电磁模块,而对应的反馈量是电感值和前瞻中心值。
关于方向控制就介绍到这,笔者水平有限,若发现问题欢迎各位私信指出。