K60的简介,我们本次使用了以下模块。
1. FTM模块:K60中集成3个FTM模块,而今年我们选用两个B车进行追踪循迹。B车模使用单电机、单舵机,另外需要一个编码器。所以对3个FTM模块进行如下配置:FTM0用以产生300Hz PWM信号控制舵机,FMT1用以产生18.5KHz PWM信号控制电机,FTM2用以采集编码器数据。
2. 定时器模块:K60中有多个定时器模块,我们使用了其中2个。其一用以产生5ms中断,处理相关控制程序。另一个用以超声波模块的计时。
3. SPI模块:我们使用了K60的一个SPI模块,用以和无线射频模块NRF24L01P通信。 4.外部中断:我们使用了三个外部中断。第一个是PORTA的下降沿中断,用以响应干簧管检测到磁铁。第二个是PORTD的跳变沿中断,用以响应超声波模块的输出信号。最后一个是PORTE的下降沿中断,用以响应NRF24L01P模块的相关操作。
数据采集算法
传感器是智能车的眼睛,它们给智能车循迹和追踪提供了必不可少的信息。因此,在智能车软件设计中必须保证数据采集算法的稳定性,同时兼顾其快速性。本车比赛,我们的智能车主要采集以下传感器的数据:电感传感器电路板、编码器、超声波、干簧管。下面主要详述超声波模块、电感传感器电路板的数据采集。
1 .超声波模块数据采集
我们使用的超声波模块的DO引脚输出50Hz的矩形波信号,通过高电平的时间向单片机传递数据。本超声波传感器的高电平时间为声波单程传输的时间,通过这个时间可计算出两车之间的距离。 我们使用外部中断和计时器结合的方式测量高电平时间。首先配置PORTD11为跳变沿中断。中断被触发时,如果PORTD11为高电平则开始计时,如果PORTD11为低电平则停止计时并记录时间间隔。 2. 电感传感器电路板的数据采集
电感传感器电路板通过输出电压的大小反应响应位置和方向的磁场强度。本次比赛中,我们使用了10个电感分布在6个不同位置,因此每个周期都要采集10路ADC数据,每路ADC数据采集32次进行平均滤波。K60芯片中有两路ADC模块,为了最大程度的减少采集数据的时间,我们采用两个ADC模块并行采集的方法。 首先,将10路ADC分为两组,第一组6个使用ADC0模块采集,第二组4个使用ADC1模块采集,两个ADC模块同时采集数据。以第一组为例,依次采集6路ADC数据,循环32次。当两个ADC模块都完成任务时,ADC转换结束。最后进行平均滤波。
控制算法 1. 定位算法
A.两个电感定位算法 在电磁组算法设计中,“差比和”(即用连个电感数据的差除以它们的和)是一个简单易用的定位算法,但是我们测量发现“差比和”算法得出的偏差距离用着较大非线性。如下图所示,其横轴为实际偏差(单位mm),其纵轴为“差比和”得出的偏差。可以发现,在实际偏差较小时,“差比和”算出的偏差变化较快,实际偏差较大时“差比和”算出的偏差变化较缓。
“差比和”定位与实际偏差比较图
为了使定位具有更好的线性度,我们拟合出一个函数将差比和的值近似转换为离中心线的实际偏差。如下图所示,其横轴为实际偏差(单位mm),其纵轴为“差比和”得出的偏差,红线表示实测的曲线,蓝线表示用以非线性矫正的一个近似的曲线。
非线性矫正曲线
B. 多个电感的定位算法
使用上述的两个电感定位算法,可以使两个在同一直线上不同位置的电感两两算出一个距离偏差。由于两个电感的测距有效范围有限,我们采用三个横向电感取其中较准确的两个电感计算距离。
记三个横向的电感对应的数值从左到右分别为Left、Mid、Right。
当Left最大时,使用Left和Mid两个电感值计算偏差; 当Right最大时,使用Left和Mid两个电感值计算偏差; 当Mid最大时,根据Left和Right计算出的偏差来计算Left-Right、Left-Mid、
Mid-Right三组偏差E0,E1和E2的比重K0,K1和K2。最后通过
(E0*K0+E1*K1+E2*K2)/(K0+K1+k2)
计算出近似的实际偏差,使得三组数据计算值之间平滑过渡。
2 .基于增量式PID的速度控制
A. 电机特性的研究与建模 本次比赛我们使用了B车模,相比于直立车模,B车模对电机的PID调节要求不是很高。但为了更好的理解PID控制算法和电机特性,我们通过电机的特性曲线近似求出电机的传递函数。
首先记录车在给电机20%恒定占空比时的速度和时间曲线,以此作为电机传递函数的阶跃响应,如下图所示。然后利用MATLAB得出曲线的近似表达式:
e = 91.1457 - 64.6742*e^(-t/3.4654) - 13.6656*e^(-t/3.4654*2) - 12.6844*e^(-t/3.4654*3);
最后以此函数作为电机传递函数的阶跃响应,求得其传递函数: -0.733 s^3 + 60.96 s^2 + 119.7 s + 45.48 ---------------------------------------- s^3 + 2.276 s^2 + 1.583 s + 0.3276
电机传递函数的阶跃响应
利用此传递函数和MATLAB的PID调节器,我们很快的得出了快速稳定地控制车速的PI参数,并未使用D参数。这个建模的过程并非必要的环节,通过不断的调试与修改完全可以达到这个要求甚至比建模调的更好,但是在这个过程中我们对PID的理解得以加深。
B. 增量式PID
增量式PID是指数字控制器的输出只是控制量的增量Δu(k)。采用增量式算法时,计算机输出的控制量Δu(k)对应的是本次执行机构位置的增量,而不是对应执行机构的实际位置,因此要求执行机构必须具有对控制量增量的累积功能,才能完成对被控对象的控制操作。执行机构的累积功能可以采用硬件的方法实现;也可以采用软件来实现,如利用算式 u(k)=u(k-1)+Δu(k)程序化来完成。
式中Δe(k)=e(k)-e(k-1)
2. 基于位置式PID的舵机控制
A. 位置式PID 基本PID控制
器的理想算式为
u(t)——控制器(也称调节器)的输出;
e(t)——控制器的输入(常常是设定值与被控量之差,即e(t)=r(t)-c(t)); Kp——控制器的比例放大系数; Ti ——控制器的积分时间; Td——控制器的微分时间。
设u(k)为第k次采样时刻控制器的输出值,可得离散的PID算式
式中 在本次比赛中我们采用了位置式PD控制算法,即积分系数Ki为0。
B. PID参数的计算算法
在调试过程中,我们发现当定位算法做的较好的时候,定值的PD参数也可以让小车快速稳定的循迹。为了进一步提高小车的速度和稳定性,我们加入了动态调整PD参数的算法,我们称之为“二维表PD模糊整定”。
“二维表PD模糊整定”参数表
如上图所示,横向由左到右分别表示偏差变化率为{-35,-25,-15,0,15,25,30},纵轴没两行为一组工6组,每组2行分别表示Kp,Kd参数,6组由上至下分别表示偏差{30,60,90,120,150,200}。
通过这种方法得出一个2输入2输出的“PD模糊整定”算法,其输入为偏差和偏差变化率,输出为Kp和Kd参数。每一组偏差E和偏差变化率Ec对应的输出都可以通过以上二维表来定义,当E、Ec不能准确对应表中某个位置时,算法通过其相邻的参数计算出所要的Kp、Kd参数。
调试程序
1. 无线接收上位机参数的程序
在调试过程中需要不断的修改参数,尤其是我们使用了二维表后参数的修改幅度急剧增大。按键调节方案已经不能高效的胜任这么大数量的参数修改了,为此我们编写了无线发送参数的上位机和小车上对应的接收处理程序。
为了让数据准确的无线传输,我们定义了帧格式。我们采用的无线通信模块是NRF24L01P,我们定义一帧数据为32字节。帧格式为:
起始标志 功能码 数据 校验码 剩余字节 0x7f 0x7f 2字节 2-16字节 2字节 若干0x00 起始标志:由于NRF24L01P一帧被定义为确定的32字节,起始标志作用并不大。加入起始标志可使得上位机适应蓝牙模块发送。
功能码:功能码用以标志后面数据是什么数据,接收端程序根据功能码处理后面的数据部分。例如功能码为0x00 0x10时,程序数据部分的前2字节作为无符号整形数据保存到temp变量,temp/100的值赋值给Kp。这样就实现了对Kp变量的重新赋值。
数据:接收端程序根据功能码处理此部分。
校验码:采用CRC16校验方式,用以确保数据传输的正确无误。
上位机截图
2. 无线发送小车状态量的程序
在调试过程中有时靠人眼观察无法准确的知晓小车的运行状态,尤其是程序计算的一些中间状态量。当我们将这些状态量在电脑上通过曲线显示出来时,就更容易把握小车的运行状态了,这些曲线为整定参数提供了有效的依据。
在这部分我们采用了是NRF24L01P模块发送数据。需要发送的数据主要有:电机速度、舵机占空比信号、距中心线偏差等数据。此部分的帧格式由虚拟示波器给出,我们编写响应的发送代码。
voidmsg_datascope(float data0,float data1,float data2,float
data3,float data4,float data5,float data6)
{
msg_buff_tx[0]=30;// USB-NRF24L01模块要用的格式 msg_buff_tx[1]=0x24;// 上位机要用的格式
*(float*)((uint32)msg_buff_tx+2)= data0; *(float*)((uint32)msg_buff_tx+6)= data1; *(float*)((uint32)msg_buff_tx+10)= data2; *(float*)((uint32)msg_buff_tx+14)= data3; *(float*)((uint32)msg_buff_tx+18)= data4; *(float*)((uint32)msg_buff_tx+22)= data5; *(float*)((uint32)msg_buff_tx+26)= data6; msg_buff_tx[30]=29;
if(nrf_tx(msg_buff_tx,DATA_PACKET)==1) while(nrf_tx_state()== NRF_TXING); }
因篇幅问题不能全部显示,请点此查看更多更全内容