第12课 循线智能车#
12.1 项目介绍:#
在前面的课程中,我们学习了如何制作“画地为牢”智能车。今天,我们将结合之前的知识,挑战一个更有趣的项目——循迹智能车。
想象一下,如果地面上有一条黑色的轨道,小车能不能像火车一样,自动沿着轨道行驶而不偏离呢?这就是我们要实现的目标!
12.2 工作原理:#
智能车底部安装了三个“眼睛”(循迹传感器),分别位于左侧、中间和右侧。
黑线会吸收光线,传感器接收到的反射光很少,输出高电平(1)。
白色地面会反射光线,传感器接收到的反射光很多,输出低电平(0)。
Arduino 主控板会根据这三个传感器的状态,判断小车相对于黑线的位置,并指挥左右两组电机做出相应的动作(前进、左转、右转或停止),从而让小车稳稳地走在黑线上。
12.3 逻辑分析#
为了让小车走直线,我们需要根据传感器的反馈制定一套“交通规则”。以下是具体的判断逻辑:
中间传感器 |
左边传感器 |
右边传感器 |
小车状态分析 |
执行动作 |
|---|---|---|---|---|
检测到黑线 (1) |
白线 (0) |
白线 (0) |
小车正对黑线中心 |
前进 |
检测到黑线 (1) |
黑线 (1) |
白线 (0) |
小车偏右,需要向左修正 |
左转 |
检测到黑线 (1) |
白线 (0) |
黑线 (1) |
小车偏左,需要向右修正 |
右转 |
检测到黑线 (1) |
黑线 (1) |
黑线 (1) |
遇到十字路口或T型路口 |
前进 |
未检测到黑线 (0) |
黑线 (1) |
白线 (0) |
严重偏离,车身在右侧 |
左转找回路线 |
未检测到黑线 (0) |
白线 (0) |
黑线 (1) |
严重偏离,车身在左侧 |
右转找回路线 |
未检测到黑线 (0) |
白线 (0) |
白线 (0) |
完全脱离轨道 |
停止 |
未检测到黑线 (0) |
黑线 (1) |
黑线 (1) |
到达终点或特殊标记 |
停止 |
注意: 不同品牌的循迹模块对黑/白的电平定义可能相反。本教程基于检测到黑线输出高电平(1),检测到白线输出低电平(0)的模块进行编写。如果你的模块相反,请调整代码中的判断条件。
12.4 项目组件:#
组装好的智能车(未插上蓝牙模块) *1 |
USB线 *1 |
5号(1.5V)电池 *6(电池自备) |
|---|---|---|
|
|
|
12.5 接线图:#
⚠️ 特别注意:4WD智能车已经组装好了,这里不需要把三路循迹模块和4个电机拆下来又重新组装和接线,这里再次提供接线图,是为了方便您编写代码!
三路循迹模块 |
电机驱动扩展板 |
|---|---|
S1右侧® |
D8 |
S2中间(M) |
D7 |
S3左侧(L) |
D11 |
V |
5V |
G |
G |
电机 |
电机驱动扩展板 |
|---|---|
左侧电机(M1) |
B2 |
左侧电机(M2) |
B1 |
右侧电机(M3) |
A1 |
右侧电机(M4) |
A2 |

⚠️ 特别注意:
接线时请确保电源断开(拔掉Arduino主控板上的USB线或将电机驱动扩展板上的拨码开关拨到 “OFF” 端),避免短路。
电源连接:电池盒电源接到电机驱动扩展板的 BAT 接口(注意正负极不要接反),端口正反面,请勿反插,否则会损坏端口。
电池正负极切勿接反,否则可能烧毁电机驱动扩展板。
12.6 示例代码:#
⚠️ 重要提示:
上传示例代码前,请务必拔掉蓝牙模块! 因为蓝牙模块也占用Arduino的串口通信(TX/RX),如果不拔掉,示例代码上传会失败。
/*
keyes 4WD 多功能智能车
课程 12
线路跟踪机器人
http://www.keyes-robot.com
*/
const int L_PIN = 11; // 左边传感器引脚
const int M_PIN = 7; // 中间传感器引脚
const int R_PIN = 8; // 右边传感器引脚
const int MA = 2; // 电机A方向控制引脚
const int PWMA = 6; // 电机A速度控制引脚
const int MB = 4; // 电机B方向控制引脚
const int PWMB = 5; // 电机B速度控制引脚
int lVal, mVal, rVal;
/* 功能:小车前进 */
void advance() {
digitalWrite(MA, HIGH); // 电机A正转
analogWrite(PWMA, 150); // 电机A速度为150
digitalWrite(MB, HIGH); // 电机B正转
analogWrite(PWMB, 150); // 电机B速度为150
}
/* 功能:小车后退 */
void back() {
digitalWrite(MA, LOW); // 电机A反转
analogWrite(PWMA, 150); // 电机A速度为150
digitalWrite(MB, LOW); // 电机B反转
analogWrite(PWMB, 150); // 电机B速度为150
}
/* 功能:小车左转 */
void turnLeft() {
digitalWrite(MA, HIGH); // 电机A正转
analogWrite(PWMA, 150); // 电机A速度为150
digitalWrite(MB, LOW); // 电机B反转
analogWrite(PWMB, 150); // 电机B速度为150
}
/* 功能:小车右转 */
void turnRight() {
digitalWrite(MA, LOW); // 电机A反转
analogWrite(PWMA, 150); // 电机A速度为150
digitalWrite(MB, HIGH); // 电机B正转
analogWrite(PWMB, 150); // 电机B速度为150
}
/* 功能:小车停止 */
void stopCar() {
analogWrite(PWMA, 0); // 电机A速度为0
analogWrite(PWMB, 0); // 电机B速度为0
}
void setup() {
Serial.begin(9600); // 设置波特率为9600
pinMode(L_PIN, INPUT); // 左边传感器引脚配置为输入模式
pinMode(M_PIN, INPUT); // 中间传感器引脚配置为输入模式
pinMode(R_PIN, INPUT); // 右边传感器引脚配置为输入模式
pinMode(MA, OUTPUT); // 电机A方向引脚配置为输出模式
pinMode(PWMA, OUTPUT); // 电机A速度引脚配置为输出模式
pinMode(MB, OUTPUT); // 电机B方向引脚配置为输出模式
pinMode(PWMB, OUTPUT); // 电机B速度引脚配置为输出模式
}
void loop() {
lVal = digitalRead(L_PIN); // 读取左边传感器的值
mVal = digitalRead(M_PIN); // 读取中间传感器的值
rVal = digitalRead(R_PIN); // 读取右边传感器的值
if (mVal == 1) { // 中间检测到黑线
if (lVal == 1 && rVal == 0) { // 左边检测到黑线,右边没有,左转
turnLeft();
}
else if (lVal == 0 && rVal == 1) { // 右边检测到黑线,左边没有,右转
turnRight();
}
else { // 其他情况前进
advance();
}
}
else { // 中间未检测到黑线
if (lVal == 1 && rVal == 0) { // 左边检测到黑线,右边没有,左转
turnLeft();
}
else if (lVal == 0 && rVal == 1) { // 右边检测到黑线,左边没有,右转
turnRight();
}
else { // 其他情况停止
stopCar();
}
}
}
12.7 项目结果:#
⚠️ 重要提示:
上传示例代码前,请务必拔掉蓝牙模块! 因为蓝牙模块也占用Arduino的串口通信(TX/RX),如果不拔掉,示例代码上传会失败。
外接电源,将电机驱动扩展板上的拨码开关拨到 “OFF” 端。选择好正确的开发板板型(Arduino Uno)和 适当的串口端口(COMxx),然后单击
按钮上传示例代码至Arduino控制板。
1. 铺设轨道:使用黑色电工胶带在白地板或白纸上贴出一条平滑的黑色轨道。建议先贴直线,再尝试贴弯道。
2. 放置小车:将4WD智能车放在起跑线上,确保三路循迹传感器模块上的中间传感器正对着黑线。
3. 上电运行:将电机驱动扩展板上的拨码开关拨到 “ON” 端。上电后,观察4WD智能车是否沿着黑线平稳行驶。

12.8 常见问题排查:#
4WD智能车不走:检查电池是否有电,驱动板开关是否打开,电机接线是否牢固。
4WD智能车反向跑:检查电机接线是否接反,或者代码中
HIGH/LOW的逻辑是否与你的电机驱动板匹配。总是冲出轨道:
可能是速度太快,尝试将代码中的
150改小(如100)。可能是传感器灵敏度问题,调节循迹模块上的蓝色电位器,直到指示灯在黑线上亮、白线上灭。
左右颠倒:如果4WD智能车该左转时却右转,交换代码中
turnLeft和turnRight函数里的电机控制逻辑,或者交换左右电机的接线。
12.9 代码解释:#
1\ 引脚定义:我们使用了 const int 来定义引脚号,这样如果以后接线变了,只需要修改顶部的定义,不用去代码里到处找数字。
2. 函数封装:我们将4WD智能车的动作(前进advance、后退back、左转turnLeft、右转turnRight、停止stopCar)写成了独立的函数。这样做可以让主程序 loop() 看起来非常清晰,就像在读故事一样:“如果左边偏了,就调用左转函数”。


