前言
本文总结了一次参加吉林省人工智能创新大赛全地形赛道的经历,旨在分享制作经验,帮助初学者少走弯路。
介绍
本项目小车的核心是 Arduino Uno R3 控制板,使用 L298N 作为驱动模块。它主要依靠激光寻迹模块来感知地形。激光寻迹模块会传回不同的信号,小车根据这些信号判断出不同的地形,然后做出相应的决策。
赛道主要包括如下部分:
在比赛时,大部分人都用的是履带小车,本方案采用的是四轮小车。虽然未上中间的高台,但最终获得了省一等奖。
一、硬件结构
1.整体结构展示
2.材料选型
- 分线端子:两个
- 激光寻迹模块:五个
- 主控:Arduino UNO R3:一个
- 减速直流电机:四个
- 2P 接线端子:一个(多买点)
- 洞洞板:一个(多买点)
- 降压模块:一个(多买点)
- L298N 驱动模块:一个(多买点)
- 导向轮:两个
- 12V 锂电池:一个
- 小车底板:一个
- 排母若干
- 排针若干
- 铜线若干
- 轮胎和联轴器
- 开关
除了主要部件,还用了铜柱、热缩管、标签贴纸、杜邦线、尼龙扎带、螺丝螺母等辅助材料。
3.洞洞板拖锡
为什么要用洞洞板拖锡? 因为时间紧张,无法等待定制电路板,所以选择手工焊接。提前准备好下载好程序的备用主控板,以便在赛场上快速替换故障模块。引脚之间采用排针排母连接,保证稳定性。
- 在纸上把主控板和各个功能模块的引脚分配规划好
| L298N 引脚 | Arduino Uno R3 引脚 |
|---|---|
| ENA | 11 |
| IN1 | 12 |
| IN2 | 13 |
| IN3 | 8 |
| IN4 | 9 |
| ENB | 10 |
Arduino Uno R3 中带波浪线标注的引脚才具有 PWM 输出功能
| 激光寻迹模块 引脚 | Arduino Uno R3 引脚 |
|---|---|
| L1 | 2 |
| L2 | 3 |
| ME | 4 |
| R2 | 5 |
| R1 | 6 |
- 把每个模块的电源供电安排好
| 模块种类 | 电压 |
|---|---|
| Arduino Uno R3 | 5V(Vin) |
| L298N | 12V |
| 激光寻迹模块 | 5V |
锂电池的 12V 直接接给 L298N。尽量别用 L298N 输出的 5V 给主控芯片供电,因为那个电压不太稳。可以把锂电池的 12V 接到降压模块上,让降压模块输出 5V,专门给单片机和 5 个激光寻迹模块供电。激光寻迹模块单独供电的同时,要和 Arduino Uno R3 的信号口连接,并且所有模块要共地。L298N 也得和 Arduino Uno R3 共地。
4.3D打印零件
五路激光寻迹模块支架
因为激光寻迹模块得倾斜摆放,才能发挥出最好的效果。不过,激光的具体倾斜角度要根据不同的小车模型来调整。
导向轮支架
轻松过弯道,就算有时候激光寻迹模块识别不到亚克力板下面的黑线,它也能通过物理接触通过。
二、软件思路
1.控制思路
根据寻迹模块检测到黑线的次数,调用对应的障碍子函数,每种障碍都有自己的处理逻辑。
首先确定小车的行走路线,然后根据路线里障碍的顺序来写代码。 思路是先写好小车前进、后退、左转、右转这些基本动作的子函数。在速度控制方面,设计了低速、中速、高速三种前进模式,还有小速度和大速度下的左右转。此外,还写了后退、停止的子函数,以及针对特定地形的速度函数,比如上台阶和通过 U 型管道的速度肯定是不一样的。
速度子函数代码示例:
void W() //正常速度模式
{
digitalWrite(IN1, 1);
digitalWrite(IN2, 0);
analogWrite(ENA, 140); //PWM 值根据不同转速而定
digitalWrite(IN3, 1);
digitalWrite(IN4, 0);
analogWrite(ENB, 140);
}
设置变量 n 来进行不同状态之间的转换。 像是通过小台阶,将方法写成两个部分分别是小台阶上和小台阶下两个子函数,之后再小台阶上下的子函数里面,进行速度的配置,其他障碍依次类推,越复杂的障碍对应的子函数越多配置速度更加详细。 使用多个变量(如 n、j、t、Q 等)作为计时器或状态转换的条件,用于控制模式的切换和特定动作的执行。
Serial.println("在调试过程中,最好加上输出语句或者设置断点,这样能清楚地了解代码的执行情况")
U 型管模块代码示例:
void U()
{
int L1_V = digitalRead(L1);
int L2_V = digitalRead(L2);
int ME_V = digitalRead(ME);
int R2_V = digitalRead(R2);
int R1_V = digitalRead(R1);
if (L1_V == 1 && L2_V == 1 && ME_V == 1 && R2_V == 1 && R1_V == 1) //1 1 1 1 1
{
LW();
n = 6;
}
else if (L1_V == 0 && L2_V == 0 && ME_V == 1 && R2_V == 0 && R1_V == 0) //0 0 1 0 0
{
LW();
}
else if (L1_V == 0 && L2_V == 1 && ME_V == 0 && R2_V == 0 && R1_V == 0) //0 1 0 0 0
{
XZ();
}
else if (L1_V == 0 && L2_V == 0 && ME_V == 0 && R2_V == 1 && R1_V == 0) //0 0 0 1 0
{
XY();
}
else if (L1_V == 0 && L2_V == 0 && ME_V == 0 && R2_V == 0 && R1_V == 0) //0 0 0 0 0
{
LW();
}
}
状态机代码示例:
switch(n)
{
case 0:
{
while(1)
{
jiansudai();
Serial.println("减速带");
if (n >= 4)
{
n = 3;
Serial.println("改变的 n");
Serial.println(n);
break;
}
}
break;
}
case 3:
{
while(1)
{
caodi();
Serial.println("草地");
Serial.println(n);
if (n >= 7)
{
Serial.println(">=8");
Serial.println(n);
n = 4;
break;
}
}
break;
}
default:
Serial.println("未知状态");
break;
}
2.代码烧录
下载 Arduino IDE,安装后连接开发板,选择对应的开发板和端口,编写代码并上传。
3.资源下载
资料包内容如下:
三、经验教训
小车的结构一定要稳定,速度再快也得稳!轮子最好换成窄一点的,这样通过 U 型管道和方形隧道会更方便。比赛情况千变万化,可能会有大灯干扰,地形也可能和在学校模拟的时候不一样,所以一定要做好十足的准备!
总结
祝大家比赛顺利,小车一路畅通无阻!


