第六届CUIT校级智能车电磁组竞赛
Posted 薛薛无敌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第六届CUIT校级智能车电磁组竞赛相关的知识,希望对你有一定的参考价值。
第六届CUIT校级智能车竞赛
作为一名大一新生,小白报名参加了电磁循迹的四轮组竞赛。小白在写这篇博客的时候呢,马上就要进行比赛了,前前后后花了差不多一月的时间准备这次比赛,在这里对整个调试的过程进行一次总结。
硬件
舵机(MG996R),电机(2,3元的电机(小黄)),电机驱动(A4950),电池(两节18650电池),LM2986降压模块,XL6019升压模块, HC-06蓝牙模块,干簧管。
软件
电磁检测
小白的智能车设置了5个电感检测赛道(实则只使用了4个),从左到右依次是水平电感,竖直电感,水平电感,竖直电感,水平电感,电磁杆安装完成之后,要将小车摆放在磁感线的中间位置,使得左右四个电感成对称分布,然后调节每个电感的滑动变阻器,使得左右电感的数据大致相同,这样的话,就可以在检测弯道的时候,由于对称的两个电感的数值差值不同(或正或负,或大或小),就可以给舵机输出对应的占空比控制舵机转向。
以上是小白的智能车电磁杆配置,但是在之后的调试过程中发现,似乎将两个竖直电感改成内八字电感就可以更加方便的检测环岛的入环(由于时间有限,该方法小白未进行验证)。至于为什么要设置两个竖直电感进行检测,这也是为了方便进行跑环岛,小白的程序再跑环岛的时候只用了两个竖直电感进行检测,跑除环岛之外的赛道的时候用的是最边上的两个水平电感进行检测,(小白参考的是Z小璇的博客:环岛检测)这也就解释了上文说到的,小白只用了四个电感检测赛道(多出的那个ADC通道口,小白在后期为了使用干簧管,刚好使用到,也算是小白运气比较好吧,不然还真的无法使用干簧管)。
ADC模块
小白采用的是STM32F103C8T6板载的12位ADC,将电磁杆采回的电压值使用DMA传输到芯片的内存中(程序里面的数组),小白建议可以使用DMA的地方,都使用DMA,因为它确实很牛逼。(小白初期呢,还加了一个SPI的OLED模块,用于观察赛道的数据,但其实它比较占用芯片的运算资源,后来发现,其实一个蓝牙模块就足够,HC-06加上一个电脑端上位机VOFA+,小白极力推荐这个上位机,另外将在文末给出VOFA+的下载地址和基本使用方法)
电感数值滤波
小白直接就使用了差比和进行滤波,小白呢,先给出他的C语言代码,再逐个分析。(小白的宏定义的LIMIT是读者自行调整的)
#define LIMIT1 69
#define LIMIT2 67
float store[10][5], all[5];
float Re;
extern uint32_t g_value[5];//DMA传回的电感值,共有5个ADC通道,(采用g_作为前缀是参考的华为C语言编程规范)
void Store_Value(void)//对DMA传回的电感值,进行最简单的一个平均数滤波
{
uint32_t i, j;
for ( i = 0; i < 10; i++)
{
for (j = 0; j < 5; j++)
{
store[i][j] = g_value[j];
}
}
for (i = 0; i < 5; i++)
{
for (j = 0; j < 10; j++)
{
all[i] += store[j][i];
}
all[i] = all[i] / 10;
}
}
float Filter_Hor_Output(void)//水平电感的滤波输出
{
Store_Value();
Re = (all[4] - all[0]) / (all[4] + all[0]);//差比和滤波
Re = Re * LIMIT1;//对滤波之后的数值进行一定的放大,使其数值可以直接传入PID进行舵机PWM占空比的输出
return Re;
}
float Filter_Ver_Output(void)//竖直电感的滤波输出
{
Store_Value();
Re = (all[3] - all[1]) / (all[3] + all[1]);//差比和滤波
Re = Re * LIMIT2;//对滤波之后的数值进行一定的放大,使其数值可以直接传入PID进行舵机PWM占空比的输出
return Re;
}
参见华为C语言编程规范
对于一个刚进入实验室的小白,学长推荐使用归一化,差比和,但是小白似乎并未想到归一化的正确编程方式,有大佬会的话,能否教教小白。至于小白使用的差比和,我觉得他的作用,就是在小车偏离中央磁感线的时候能给输出一个常量,它可以是一个正数,可以是一个负数,因此这就对应了两种不同的拐弯方向,至于拐弯的大小,则由这个常量的大小决定。这是小白对差比和的最浅显的理解,要是读者想更深层次的去了解该内容,可以去自行搜索。
PID算法
小白先给出自己的代码。(小白只使用了Kp 和Kd,这两个参数需要读者自行去调整)
struct _PID
{
float P;
float D;
}pid_p;
struct Error
{
float Last_Error ;
}ERROR_ERROR;
ERROR_ERROR.Last_Error = 0;//该语句是对上一次偏差的初始化,只需要执行一次,因此可以放到while循环语句之前
static float PID_Realize(int NowPlace, float Point)
{
float iError, Realize;
iError = Point - NowPlace;
Realize = pid_p.P * iError + pid_p.D *(iError - ERROR_ERROR.Last_Error);
ERROR_ERROR.Last_Error = iError;
return Realize;
}
float PID_Initial(int NowPlace, float Point)
{
float Return;
pid_p.P = 0.79;
pid_p.D = 0.1;
Return = PID_Realize(NowPlace, Point);
if(Return < -24)//对PID返回的数值进行限幅,否则可能导致舵机偏转角度过大,损坏车模
{
return -24;
}
if ( Return > 22)
{
return 18;
}
return Return;
}
小白的代码经过PID的输出可以直接传给舵机PWM占空比的输出,如果Kp和Kd的参数调整的好的话,小车跑起来就很丝滑。
环岛检测
环岛的检测的话,是整个智能车竞赛的难点,如何入环,如何出环,如何区分开环岛和十字路口,是三座大山。代码的话,小白就不给了,如果需要拿去参考的话,可以私信小白。小白主要讲一下自己的思路。
环道与直道有两个交叉点,在这两个交叉点的附近,竖直电感的值会发生突变,于是我检测这两个DMA传回的值是否大于2300(假设是0~4095之间的2300),如果大于,那么就给一个标志位;当在第二个交叉路口的时候,这两个值又将会突变,于是在满足之前的标志位的情况下,检测两个DMA传回的数值是否大于2000(假设是2000),如果是,则将水平电感检测方案转换到竖直电感检测方案(前文小白提到自己用的是两种方案进行电磁检测),这时候小车就会自动拐进去环岛。同理在出环岛的时候也是一样的方法。若是读者在实际操作过程中,发现小车在出环岛的时候会直接走出弯道,在确保代码没有错误的情况下,也可以手动设置PWM占空比让小车拐弯(当然这是一个非常笨的方法,不建议采用,因为这将会导致对赛道的兼容性变差)。
小白在成功跑完环岛之后,莫名其妙的发现十字路口的电感数据和环岛的电感数据类似,使得小车将十字路口误认为是环岛。因此小白还在检测环岛的代码上再加上任意一个水平电感的阈值(因为在检测环岛标志的水平电感的数值一定会大于十字路口的水平电感的数值,因为环岛哪里有两根磁感线的重合),这样就不会检测错误。
文末
(小白的VOFA+程序不知道为什么在打开的时候,会卡住,显示VOFA+未响应,要是有读者会解决的话,希望不吝赐教)。
VOFA+简易使用方法:
在自己的程序里面只需要添加如下代码,即可使用VOFA+;
printf("%d, %d, %d, %d, %d\\n", g_value[4], g_value[3], g_value[2], g_value[1], g_value[0]);
在自己的程序里面只需要添加如下代码,即可使用VOFA+;
printf("%d, %d, %d, %d, %d\\n", g_value[4], g_value[3], g_value[2], g_value[1], g_value[0]);
注意末尾一定要加上\\n,逗号是否必须添加,读者可以自行探索。
以上是关于第六届CUIT校级智能车电磁组竞赛的主要内容,如果未能解决你的问题,请参考以下文章
全国大学生智能车竞赛(创意组)陕西理工大学校级选拔赛顺利举行