Arduino UNO智能小车全套例程:引脚映射与避障循迹调试指南
2026/9/14 20:29:00 网站建设 项目流程

简介:面向毕业设计与课程设计的Arduino UNO三轮智能小车例程包,覆盖蓝牙遥控、红外遥控、WiFi遥控、自动循迹、超声波避障、测速等常见实验,适合自动化、电子信息、计算机等专业学生完成课设、毕设或大作业,也方便初学者按例程进阶。资源共35个文件,包括19个ino主程序、12个h头文件、1份智能小车Arduino平台IO分布图xlsx和1个使用说明txt,压缩包整体仅59KB;目录按实验场景拆分,如超声波+舵机自动避障、超声波+红外自动跟踪、光电管避障、蓝牙遥控+速度调节、自动循迹等,便于对照运行与二次修改。代码均经过测试成功运行,答辩评审平均分达到96分,可放心作为项目原型;已有194人学习/下载,具备一定参考热度。项目还内置测速、舵机控制、红外接收等多类例程,解压后可快速复现,也能自行扩展传感器或功能。

1. 一套 Arduino UNO 智能小车例程,能节省你两周的调试时间

拿到一款新的智能小车平台,最耗时间的往往不是写代码,而是搞清楚每个传感器该接哪个引脚、PWM 通道够不够用、舵机和电机驱动会不会互相抢占定时器。这套基于 Arduino UNO 的三轮小车例程,把本科毕设里最常见的功能都做成了可直接烧录的实验工程:红外遥控、蓝牙遥控、WiFi 遥控、超声波避障、光电管避障、黑线循迹、霍尔测速,以及超声波加舵机的组合避障。每一份代码都带开关宏定义,同一块板子通过#define切换功能,不用每换一个实验就重新接线。

资源包里的智能小车 arduino 平台 IO 分布图是第一个要看的文件,它回答了"引脚怎么分配"这个最基础也最关键的问题。对做课设的在校生来说,这套代码可以直接作为答辩演示基础;对工程师来说,它的模块划分思路——把传感器采集、运动控制、通信协议分层写——完全可以迁移到 STM32 或 ESP32 平台。下面从硬件映射开始,逐个拆解这些例程的实现逻辑和参数配置。

2. 硬件准备与引脚映射:先看懂 IO 分布图再动手

2.1 三轮小车的底盘结构选型

常见的三轮智能小车有两种布局:一种是两个驱动轮加一个万向轮,另一种是两个驱动轮加一个舵机转向轮。这套例程用的是前者,即两路直流减速电机分别驱动左右轮,通过差速实现转向,后部或前部有一个随动万向轮。

这种结构的优势在于控制模型简单——左轮正转右轮反转就是原地旋转,左轮慢右轮快就是弧线转弯。配合 L298N 或 TB6612 这类 H 桥驱动模块,UNO 只需要输出两路 PWM 控制转速,两路数字 IO 控制方向。比舵机转向的方案少一个闭环环节,调试门槛低不少。

2.2 引脚分配表与 Arduino UNO 的资源约束

打开智能小车 arduino 平台 IO 分布图,典型的分配方案如下表所示:

功能模块Arduino UNO 引脚说明
左电机 PWMD5与右电机共用 Timer0
左电机方向D4HIGH/LOW 切换正反转
右电机 PWMD6与右电机共用 Timer0
右电机方向D7HIGH/LOW 切换正反转
超声波 Trig/EchoD2 / D3舵机安装于 D9
舵机信号D9使用 Servo 库,占用 Timer1
光电对管左/右A0 / A1数字量读取,阈值由电位器调节
循迹传感器模块A2 / A3沿黑线输出高电平
蓝牙模块 RX/TXD10 / D11SoftwareSerial 软串口
霍尔测速中断D2 或 D3外部中断,测速例程专用

这里有一个关键点:UNO 只有 Timer0、Timer1、Timer2 三个定时器。Timer0 被millis()占用,Timer2 通常被 tone() 占用,Servo 库只能用 Timer1。所以舵机和电机 PWM 不能同时依赖同一个定时器,上面的分配方案中舵机接 D9、PWM 走 D5/D6,恰好避开冲突。

提示:如果发现舵机抖动或电机转速异常,先检查是不是某个库偷偷占用了 Timer1。Servo.hIRremote.h在部分版本中存在冲突,IRremote 库建议使用支持 Timer2 的版本或改用 D9 之外的引脚。

2.3 从模板工程复制项目时的快速检查清单

打开 AICar_sys 目录,能看到每个实验都有独立的 .ino 文件。复制一份新工程时,建议按以下顺序检查:

  • 确认开发板型号是 "Arduino/Genuino UNO",处理器选 ATmega328P;
  • 打开工具 -> 端口,确认串口号与设备管理器一致;
  • 在代码头部查找#define开关,比如#define USE_BLUETOOTH#define USE_IR,一次只打开一个功能;
  • 检查 IRread 例程的接收引脚是否与IRrecvDemoRECV_PIN定义一致。

资源包内的 test 目录集中放了 servo、IRread、ultsound、bluetooth 等单项测试代码,先用它们逐个验证硬件,再跑组合实验,能省掉大量排查时间。

3. 传感器例程逐个拆解:红外、超声波、光电对管

3.1 红外遥控实验:从 IRrecvDemo 到指令映射

红外遥控是最容易出成果的实验,因为只需要一个红外接收头和一个遥控器。IRrecvDemo例程的核心代码通常如下:

#include <IRremote.h> const int RECV_PIN = 11; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { Serial.begin(9600); irrecv.enableIRIn(); // 启动红外解码 } void loop() { if (irrecv.decode(&results)) { Serial.println(results.value, HEX); irrecv.resume(); // 收到下一个编码 } }

results.value是 NEC 协议解码后的 32 位数据,常见的遥控器按键值形如FF00FFFF30CF。不同遥控器编码不同,所以 smartcar 例程里专门留了 IRread 目录,先烧录它,打开串口监视器按一遍遥控器按键,把真实键值抄下来替换到宏定义里。

逻辑说明:irrecv.decode()返回 true 说明收到一帧完整数据,results.value是编码值;resume()必须调用,否则接收器停在"已解码"状态无法继续接收。RECV_PIN定义为 11 而非 D2/D3,是因为红外接收对时序要求高,软串口和中断引脚都留给其他模块更稳妥。

3.2 超声波 + 舵机避障:测距转向一体化

超声波避障例程把 HC-SR04 固定在舵机云台上,舵机扫过 0 度到 180 度,小车判断哪个方向距离最远就往哪个方向转弯。核心测距代码:

#define TRIG_PIN 2 #define ECHO_PIN 3 float getDistance() { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); long duration = pulseIn(ECHO_PIN, HIGH); return duration * 0.034 / 2; // 声速340m/s,往返距离减半 }

参数说明:TRIG 高电平持续 10 微秒触发测距,pulseIn等待 ECHO 引脚变为 HIGH 并测量持续时间,返回的是微秒数。距离(厘米)等于声速(34000 cm/s)乘以时间再除以 2。实际使用中,20 到 400 厘米范围内精度可接受,超过这个范围要加滤波,比如连续取五次去掉最大最小值再平均。

舵机扫描策略上,常见的做法是分三步:先朝前方测一次,再朝左 90 度测一次,最后朝右 90 度测一次,比较三组距离决定转向方向和角度。资源包里的超声波+舵机+光电对管自动避障实验在此基础上叠加了光电对管,用于检测桌面边缘或台阶,防止小车从高处跌落,相当于"防坠崖"保护。

3.3 光电对管避障与红外跟踪

光电对管实验用的是 TCRT5000 模块,它内部集成了红外发射管和接收管,近距离检测反射红外线的强度。检测到障碍物时输出电平翻转。接线很简单,VCC、GND、OUT 三根线,OUT 接 A0 或 A1。

int leftSensor = analogRead(A0); int rightSensor = analogRead(A1); if (leftSensor > threshold && rightSensor > threshold) { // 两侧都有障碍,后退 } else if (leftSensor > threshold) { // 只有左侧有障碍,右转 }

threshold是判定阈值,一般在 200 到 600 之间,具体数值取决于环境光强度和障碍物表面反射率。模块上自带的电位器可以调节灵敏度,调到指示灯刚熄灭的位置即可。

光电对管组的参数用analogRead而非digitalRead,是为了保留灵敏度调节的余量——环境光变化时模拟量读数会漂移,纯数字量容易误触发。把读数直接打印到串口,观察不同距离下的数值变化,再设定阈值,这样最可靠。

4. 运动控制与测速:从 PWM 调速到霍尔编码器闭环

4.1 测速实验原理与中断计数

测速实验用的是霍尔传感器配合磁钢。电机轴上贴一块小磁铁,霍尔模块检测到磁场变化就输出一个脉冲。根据三轮车常用的减速电机参数——通常减速比 1:30 左右,电机每转一圈霍尔输出一个脉冲,轮子转一圈需要 30 个脉冲。测速代码:

volatile unsigned long pulseCount = 0; void countPulse() { pulseCount++; } void setup() { attachInterrupt(digitalPinToInterrupt(2), countPulse, RISING); Serial.begin(9600); } void loop() { pulseCount = 0; delay(1000); float rps = pulseCount / 30.0; // 每秒转数 float speed = rps * 3.14159 * wheelDiameter; // cm/s Serial.print("Speed: "); Serial.print(speed); Serial.println(" cm/s"); }

这里有两个细节值得注意:volatile关键字必须加,因为countPulse在中断上下文执行,pulseCount被主循环读取,不加 volatile 会被编译器优化掉更新;RISING表示只在信号上升沿触发中断,如果磁铁极性安装反了或霍尔模块输出是低电平有效,要改成FALLING

4.2 测速数值与 PWM 占空比的关系

实际测试时,PWM 值从 0 到 255 线性增加,但轮子转速并不完全线性。以普通 N20 减速电机为例,PWM=100 时转速约 60 转/分,PWM=200 时转速约 130 转/分,曲线接近直线但有小幅下凹。原因是电机内部的摩擦阻力和反电动势非线性。

如果需要做速度闭环,光测脉冲不够,还要加 PID。资源包里的"蓝牙遥控+速度调节"例程在测速基础上增加了简单的比例控制:目标速度和当前速度的差值乘以 Kp,叠加到 PWM 上。Kp 一般从 2 到 5 开始试,观察速度响应曲线再微调。

4.3 循迹实验:传感器布局与转向策略

自动循迹实验是课设出现率最高的功能。典型的循迹模块包含 2 到 5 路红外对管,沿黑线排列。两路版本的逻辑最简单:

  • 左传感器在线上、右传感器压到白底:说明车头偏右,需要左转;
  • 右传感器在线上、左传感器压到白底:说明车头偏左,需要右转;
  • 两个传感器都在线上:直行;
  • 两个传感器都在白底:可能冲出赛道,按上一次方向继续前进或原地旋转寻找黑线。
int leftTrack = digitalRead(A2); int rightTrack = digitalRead(A3); if (leftTrack == LOW && rightTrack == HIGH) { // 左转,左轮减速 analogWrite(PWM_LEFT, BASE_SPEED - 60); analogWrite(PWM_RIGHT, BASE_SPEED + 60); } else if (leftTrack == HIGH && rightTrack == LOW) { // 右转,右轮减速 analogWrite(PWM_LEFT, BASE_SPEED + 60); analogWrite(PWM_RIGHT, BASE_SPEED - 60); }

BASE_SPEED建议设 120 到 150 之间,差速 60 左右。速度太快会导致小车冲出弯道,因为两路传感器只有两种组合,检测不到线的曲率变化;速度太慢则转向到位后回正不及时,走 S 形。

值得留意的是,循迹例程普遍存在一个坑:黑线在传感器正下方时输出 LOW,在白底输出 HIGH,这个电平逻辑因模块而异。接线之前先把模块悬空对着黑线实测一次,确认逻辑再写判断条件。

5. 无线控制链路:蓝牙遥控、WiFi 遥控与 smartlink 配置

5.1 蓝牙遥控:SoftwareSerial 软串口收发

蓝牙遥控例程用的是 HC-05 或 HC-06 模块,通过 D10/D11 软串口与 UNO 通信。HC-05 默认波特率 9600,8N1 格式。代码结构:

#include <SoftwareSerial.h> SoftwareSerial btSerial(10, 11); // RX, TX char cmd; void setup() { Serial.begin(9600); btSerial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); } void loop() { if (btSerial.available()) { cmd = btSerial.read(); switch (cmd) { case 'F': moveForward(); break; case 'B': moveBackward(); break; case 'L': turnLeft(); break; case 'R': turnRight(); break; case 'S': stopCar(); break; } } }

协议约定是单字符命令,F/B/L/R/S分别是前进、后退、左转、右转、停止。手机端用一个串口蓝牙调试助手,发送字符即可控制。参数说明:btSerial.available()返回接收缓冲区字节数,每次只读一个字节,所以发送 'F' 就直接触发前进。

软串口的局限要注意:D10/D11 上不能用SoftwareSerial收发同时跑高速数据,9600 波特率是稳定上限。如果想要手机实时回传传感器数据,最好换硬件串口 D0/D1,把调试串口改到软串口。

5.2 WiFi 遥控与 smartlink 的两种接法

WiFi 遥控例程通常是 UNO 外接 ESP8266 或 ESP-01 模块。ESP8266 跑 AT 固件,UNO 通过串口发 AT 指令配置 WiFi 连接。smartlink 目录里放了手机 App 配网相关的代码,核心逻辑是利用 ESP8266 的 SmartConfig 功能,手机 App 广播 SSID 和密码,模块自动抓取并连接。

AT 指令序列一般是:

btSerial.println("AT+CWMODE=1"); // Station 模式 delay(500); btSerial.println("AT+CWJAP=\"SSID\",\"password\""); // 连接路由器 delay(3000); btSerial.println("AT+CIPMUX=1"); // 开启多连接 delay(500); btSerial.println("AT+CIPSERVER=1,8080"); // 启动 TCP Server

每一条 AT 指令都要等待模块返回OKERROR再执行下一条,否则 ESP8266 没就绪时下发指令会被丢弃。AT+CIPSERVER=1,8080启动端口 8080 的 TCP 服务端,手机 App 连上同一个路由器后,向模块 IP 的 8080 端口发送 TCP 报文,UNO 从串口读到数据后解析出控制指令。

WiFi 方案比蓝牙的优势是距离远、可以穿透一堵墙,缺点是延迟稍高且依赖路由器。做毕设演示时,如果现场网络环境不可控,建议准备一条退路——用蓝牙方案保底。

5.3 蓝牙遥控 + 速度调节的组合模式

"蓝牙遥控+速度调节"例程在遥控指令基础上增加了 PWM 占空比调节命令,协议扩展为两位字符:第一位是命令类型,第二位是数值。比如V180表示设置速度为 180,A100表示加速度到 100。解析用strtok或直接字符串比较:

String input = btSerial.readStringUntil('\n'); if (input.startsWith("V")) { int targetSpeed = input.substring(1).toInt(); currentSpeed = targetSpeed; analogWrite(PWM_LEFT, currentSpeed); analogWrite(PWM_RIGHT, currentSpeed); }

这样遥控器上可以做两个滑动条,一个管速度,一个管方向。手机 App 端发送频率建议限制在每秒 10 帧以内,UNO 的串口缓冲区只有 64 字节,发太频繁会丢命令。

6. 进阶调试技巧:IO 分布图之外的实战经验

6.1 用 Wokwi 模拟器做代码先行验证

接线前先验证逻辑,用 Wokwi 仿真平台可以省大量时间。Wokwi 支持 Arduino UNO 的电路仿真,在浏览器里添加 UNO、HC-SR04、舵机和电机驱动模块,烧录同一份代码即可跑通逻辑。注意模拟环境里 HC-SR04 的返回时间和真实硬件有差异,只能验证程序流程,不能验证时序精度。

6.2 电机 PWM 共地的坑

L298N 或 TB6612 驱动模块和 UNO 必须共地,否则控制信号没有参考电平,电机要么不转要么乱转。很多同学第一次上电发现电机不动,第一反应是代码问题,实际上只是少了根 GND 线。检查顺序:先看电源指示灯,再看信号线是否共地,最后才怀疑代码。

6.3 串口打印与波形观测结合定位问题

如果测速数值异常,先打印原始脉冲计数而不算速度,确认中断是否触发。如果循迹反应迟钝,把传感器模拟值直接打到串口,放到黑线上看读数变化。遇到舵机抖动,用示波器看 PWM 波形频率,Servo 库默认 50Hz,低于标准会抖动。

// 调试用:直接打印原始值 Serial.print("L:"); Serial.print(analogRead(A2)); Serial.print(" R:"); Serial.println(analogRead(A3)); delay(100);

这套例程包拿到的第一件事是烧录 test 目录下的单项测试,每一项通过后再组合跑完整流程。把红外键值表、传感器阈值、PWM 基础速度记录在代码注释里,后面做参数调优会省很多事。答辩演示前至少连续跑 30 分钟,确认电池电量稳定下电机不会过热降速。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询