【开源实战】智能竞赛小车零基础制作指南|省赛一等奖(全地形机器人)
前言
大二时,我羡慕学长们在比赛中拿奖,于是跟着学点知识,报名参加吉林省人工智能创新大赛全地形赛道,想锻炼自己并加学分。无论结果如何,我都想总结这次经历分享给学弟学妹,让他们少走弯路。
另外,我也是个新手小白,要是有啥说错的地方,大家尽管提,我虚心接受!

介绍
本项目小车的核心是用的Arduino Uno R3控制板,然后用L298N作为驱动模块。它主要是靠激光寻迹模块来感知地形的。激光寻迹模块会传回不同的信号,小车根据这些信号判断出不同的地形,然后做出相应的决策。
主要是完成如下赛道:
在比赛时候,大部分人都用的是履带小车,我做的是四轮小车。我的小车没有上中间的高台,不过最后还是拿到了省一等奖,还挺惊喜的!😁
一、硬件结构
1.整体结构展示





2.材料选型
- 主控:Arduino UNO R3 一个

- 激光寻迹模块 五个

- 分线端子 两个

- 减速直流电机 四个

- 2P 一个(多买点)

- 洞洞板 一个(多买点)

- 降压模块 一个(多买点)

- L298N驱动模块 一个(多买点)

- 导向轮 两个

- 12V锂电池 一个

- 小车底板 一个

- 排母若干

- 排针若干

- 铜线若干

- 轮胎和联轴器

- 开关

除了主要部件,还用了铜柱、热缩管、标签贴纸、杜邦线、尼龙扎带、螺丝螺母等辅助材料。
3.洞洞板拖锡
为什么要用洞洞板拖锡?
因为作者不太熟练用嘉立创EDA😢,再加上时间特别紧张,等不及电路板寄到学校,所以只能选择拖锡了。好在之前买了好多洞洞板,刚好派上用场。
可以提前准备好下载好程序的备用主控板。这样在赛场上,如果哪个模块或者主板烧毁或者故障了,就不用再根据代码一点点重新连线了。直接用排针排母拔插的方式,快速替换掉有问题的模块就行。这样一来,引脚之间的连接会更稳定,不会出现接触不良的情况。而且在小车比赛行进或者被搬运的时候,也能减少因为飞线不稳导致的故障。
- 在纸上把主控板和各个功能模块的引脚分配规划好
| 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,安装后连接开发板,选择对应的开发板和端口,编写代码并上传

4.资源下载
资料包内容如下:

三、经验教训
小车的结构一定要稳定,速度再快也得稳!重要的事情说三遍:稳定、稳定、稳定!轮子最好换成窄一点的,这样通过U型管道和方形隧道会更方便。比赛情况千变万化,可能会有大灯干扰,地形也可能和在学校模拟的时候不一样,所以一定要做好十足的准备!
总结
如果需要资料,可以通过上面的视频链接找到我的主页私信我,也可以直接私信我哦!
最后祝大家比赛顺利,小车一路畅通无阻!😁
视频主页
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)