概述
今天是2020年2月9日,因为新冠肺炎的原因,学校依然没有要开学的意思。大学即将结束,在这个空闲的日子。老学长决定写一些大学四年的竞赛经验分享。
先评价一下这个比赛吧,我们那一年参赛是在青岛理工大学的黄岛校区(具体是哪一个我也记不大清楚了)。当时去比赛的时候感觉他们学校对比赛还是非常重视的。这个比赛在山东省的规模也比较大,获奖比较容易,所以说这个比赛获奖的含金量跟电子设计大赛那种A类竞赛也差得远。
如果认真去准备这个比赛的话 ,你就会发现竞赛的题目还是比较有意思的。我们只做过智能避障小车,所以我只讨论小车的题。最后有心情会分享一些其他题目的见闻。
竞赛题目
(一)比赛任务
小车从出发区出发后,沿车道行驶一圈,并返回到结束区。
(二)比赛场地
比赛前一天现场调试的图,请忽略这些大长腿。
竞赛要求是小车跑完全程,时间越短分数越高。当然基本上全程跑下来就是一等奖。
图中可以看到赛道2/4~3/4处有六个点,其中三个点放有木柱。
实际比赛的时候只有三根柱子留在赛道,按照往年的经验(仅供参考,出问题别打我,以前两三年都这样),留下的都是外侧的柱子(②③⑤),车子可以直接在内侧无障碍通过。
详细设计过程
由于这个比赛含金量没那么高,我们参加这个比赛的重点放在了乐趣和锻炼上面。所以从赛道跑法比较特别和激进,但是程序和板子设计比较规范。
车体设计
我们用的是三轮车,前面两个轮子驱动,一个万向轮拖着跑。我们采用最小规格,也就是14厘米的车子。所有传感器都是光电开关,下图黄色的那种。
我们一共用了五个这样的传感器。加下来我先说电路设计,在具体说传感器怎么用。同时会讲到准备中碰到的问题。
智能车的电路肯定很简单,我们用的是TI MSP430F5529官方的那个Launchpad板子。供电采用三节18650的锂电池,电压在11~12V之间。然后整两块LM2596的稳压板,一个稳压5V给Launchpad供电,另一个稳压10V给传感器和电机驱动供电。
这个地方我们当时遇到一个问题,本来传感器和电机驱动都没加稳压,直接用电池供电。跑着跑着传感器就傻了。后来发现电池电压下降了,这个传感器感应的距离和供电的电压好像有关系,不稳压的话传感器发挥不大稳定。
这是设计的第一版PCB,左边是驱动部分,用的L298N电机驱动,右边是传感器部分,留了好多接口。用的时候两部分用排针插起来,上下结构。
竞赛要求在覆铜层有队伍名称。电路就这个样子很简单。
比赛 具体的要求规则书里都有,认真阅读。貌似人家都用的51的单片机,我们实验室就缺51,TI的单片机一大堆。
现在开车
先说跑直线,就是从起点到第一个拐点这一段。
void XJ ()//循迹
{
if(GD1L)//右偏左调
{
set_left_speed(75);
set_right_speed(85);
}
else if(GD2H)//左偏右调
{
set_left_speed(85);
set_right_speed(75);
}
else//正向直行
{
set_left_speed(85);
set_right_speed(85);
}
}
我们用的是让车贴着左边跑,光电管GD1朝向地面,GD2朝向跑道。当车左偏时GD2信号拉高,降低右轮速度。右偏时降低左轮速度。看程序一目了然。
两个管子的灵敏度靠调节管子的角度来调节。准备比赛的时候看人家的视频都慢悠悠的跑,我们打算采用高速跑法,所以用了全速的85%速度。至于速度多少合适,自己去调节。
两个管子角度差不多就是这个样子,迁就着看吧。咱也不会画。
这时候前面过第一个弯,注意骚操作来了。
我们需要再添加一个管子GD3,这个管子负责转弯用,但是它的角度要更加偏左,保证跑直线的时候它不会感应到跑道。当车跑到的红的①点时,能先于GD1看到红色④圆圈的位置。所以它的朝向应该时GD1的左前方。
正常过弯肯定时左转转弯,我们最初也是这么干的,当GD3感应到跑道的时候执行转弯程序,左轮减速,右轮加速,左转。车的转弯半径肯定会增大,还要去考虑⑦号障碍物。因为我们的车是前驱的,你去考虑倒车入库的原理。如果我们采用倒车的方式拐弯。。。。。嘿嘿嘿嘿。
看我们是怎么做的,当车跑到红色①位置时GD3感应到跑道(我们交流的时候就说它看到跑道)这时候车继续往前跑,当小车跑到红色②位置时GD1看到跑道。
我们开始执行转弯程序。让左轮迅速转为倒车,右轮速度变为0 。由于惯性,小车会先冲到红色③的位置,然后左轮倒车。直到GD1看不到跑道的时候,转弯程序改为循迹直行。
void ZW()//转弯
{
if(GD3L&&GD1L) //这时候车在2位置
{
//由于惯性车会跑到3位置
Motor_BCK(); //电机反转
while(GD1L) //向左后方倒车直到GD1看到跑道边缘
{
set_left_speed(75);
set_right_speed(0);
}MOTOR_FWD(); //电机正转开始跑直线
}else XJ ();
}
过⑧号障碍物
按照我们的跑法,全程只过这一个障碍物,这个障碍物我们新增了三个传感器。
正前方一个GD5。正左边一个GD6,位置在车辆中部。右前方一个GD4,放下超斜下方,为了检测右边跑道边缘。
void BZ()//壁障
{
if(GD5L)
{
/***************************************
刹车并后退一点,留出转弯空间,直到正前方的
传感器看不到障碍物。
******************************************/
while(GD5L)
{
Motor_BCK();
set_left_speed(70);
set_right_speed(70);
}
/***************************************
右转,直到右前方GD4传感器看到跑道边缘,这时候车头
朝向右前方45°方向。
******************************************/
MOTOR_FWD();
while(GD4H)
{
set_left_speed(75);
set_right_speed(0);
}
/***************************************
左转并前进,直到左侧传感器看到8号障碍物这时候
车体应该在障碍物的右前方
******************************************/
while(GD6L)
{
set_left_speed(65);
set_right_speed(85);
}
}
/***************************************
这时候执行转弯程序,车子以原地转圈,直到
左前方GD3扫过跑道边缘,自动进直行程序。
******************************************/
else ZW();
}`
说起来比较复杂,跑起来比较骚。咋跑的看上面程序。
如何跑完全程
这时候我们的车已经到了第二个拐弯处。
执行过弯程序,然后直行。
过第三个弯。
注意这时候我们的车已经执行了四次转弯程序。
接下来要过前面的弯道。我们采取的策略是让车直接冲过去。
沿着这个地方直接冲过去。
我们要在程序中屏蔽所有传感器,让车保持直行,冲过去之后要让车恢复循迹和转弯功能。
看程序
void ZW()//转弯
{
if(GD3L&&GD1L)
{
if(p==4)
while(GD1L)
{
set_left_speed(90);
set_right_speed(90);
}
Motor_BCK();
while(GD1L)
{
set_left_speed(75);
set_right_speed(0);
}
MOTOR_FWD();
p++;
}else XJ ();
}
把转弯程序进行修改,添加一个计数P,当过弯程序执行4次之后,
while(GD1L)
{
set_left_speed(90);
set_right_speed(90);
}
保持直行,直到GD1看不到跑道,这时候GD1看向地面。
接下来循迹转弯,全程跑完。
更新
说一下程序优先级问题
我是把避障程序设置优先级最高,转弯程序次之,最后是直行。
下面是完整的程序。
/*
* MOTO_Control.c
*
* Created on: 2018年8月31日
* Author: qjwdream
*/
#include "motor_control.h"
char p=0;
void MOTOR_INIT()
{
P6DIR |= BIT0;
P6DIR |= BIT1;
P8DIR |= BIT2;
P3DIR |= BIT7;
}
void GD_init()
{
P2DIR &= ~BIT6;
P2DIR &= ~BIT3;
P2DIR &= ~BIT2;
P2DIR &= ~BIT7;
P2DIR &= ~BIT0;
P1DIR &= ~BIT6;
P1DIR &= ~BIT2;
P1DIR &= ~BIT4;
P1DIR &= ~BIT5;
P1DIR &= ~BIT3;
}
void MOTOR_FWD()
{
P8OUT &= ~BIT2;
P3OUT |= BIT7;
P6OUT &= ~BIT0;
P6OUT |= BIT1;
}
void MOTOR_STP()
{
P8OUT |= BIT2;
P3OUT |= BIT7;
P6OUT |= BIT0;
P6OUT |= BIT1;
}
void Motor_BCK()
{
P8OUT |= BIT2;
P3OUT &= ~BIT7;
P6OUT |= BIT0;
P6OUT &= ~BIT1;
}
void system_start()
{
MOTOR_INIT();
GD_init();
TIMER_INIT ();
HB_PWM_20k(50);
MOTOR_FWD();
}
void set_left_speed(char speed)
{
Timer_A_setCompareValue(TIMER_A2_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_2,
speed
);
}
void set_right_speed(char speed)
{
Timer_A_setCompareValue(TIMER_A2_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_1,
speed
);
}
void XJ ()
{
if(GD1L)//右偏左调
{
set_left_speed(75);
set_right_speed(85);
}
else if(GD2H)//左偏右调
{
set_left_speed(85);
set_right_speed(75);
}
else//正向直行
{
set_left_speed(85);
set_right_speed(85);
}
}
void GQ()//转弯
{
while(1)
{
set_left_speed(100);
set_right_speed(100);
}
}
void ZW()//转弯
{
if(GD3L&&GD1L)
{
if(p==4)
while(GD1L)
{
set_left_speed(90);
set_right_speed(90);
}
Motor_BCK();
while(GD1L)
{
set_left_speed(75);
set_right_speed(0);
}
MOTOR_FWD();
p++;
}else XJ ();
}
void BZ()//壁障
{
if(GD5L)
{
/***************************************
刹车并后退一点,留出转弯空间,直到正前方的
传感器看不到障碍物。
******************************************/
while(GD5L)
{
Motor_BCK();
set_left_speed(70);
set_right_speed(70);
}
/***************************************
右转,直到右前方GD4传感器看到跑道边缘,这时候车头
朝向右前方45°方向。
******************************************/
MOTOR_FWD();
while(GD4H)
{
set_left_speed(75);
set_right_speed(0);
}
/***************************************
左转并前进,直到左侧传感器看到8号障碍物这时候
车体应该在障碍物的右前方
******************************************/
while(GD6L)
{
set_left_speed(65);
set_right_speed(85);
}
}
/***************************************
这时候执行转弯程序,车子以原地转圈,直到
左前方GD3扫过跑道边缘,自动进直行程序。
******************************************/
else ZW();
}