这次我们来看一个基于 Arduino 的智能小车项目它集成了红外遥控、红外避障和红外循迹三种核心模式并能根据环境自动或手动切换。这个项目非常适合作为单片机、嵌入式或电子设计课程的期末实践也适合创客和硬件爱好者入门。它不依赖复杂的云服务或AI模型核心在于硬件搭建、传感器融合与逻辑控制门槛低但功能完整。项目的核心是“三模智能切换”小车能通过红外遥控器接收指令也能通过红外传感器自主避障或循线行驶。这种设计让你在一套硬件上体验三种经典的控制逻辑从手动遥控到半自动再到全自动覆盖了智能小车开发的大部分基础知识点。对于想快速上手Arduino、理解传感器应用和状态机编程的开发者来说这是一个非常高效的练手项目。本文将带你从零开始完成这个红外三模智能小车的硬件搭建、软件编程和功能验证。我们会重点拆解“三模”是如何实现的如何编写代码让小车在不同模式间平滑切换以及如何调试红外传感器以确保其稳定工作。无论你是学生准备课程设计还是爱好者想做一个有趣的玩具都能从这篇文章中找到清晰的步骤和可复用的代码。1. 核心能力速览能力项说明项目类型Arduino开源硬件项目智能小车核心功能红外遥控手动、红外避障自动、红外循迹自动三种模式智能切换控制核心Arduino UNO R3 或兼容开发板如CH340版本主要传感器红外接收头、红外避障模块、红外循迹模块执行机构L298N电机驱动模块、直流减速电机、万向轮供电方案7.4V锂电池组通过L298N为电机供电通过降压模块或开发板为控制部分供电通信方式红外信号遥控、传感器数字/模拟信号编程环境Arduino IDE代码特点状态机设计、多传感器数据融合、模式切换逻辑适合场景单片机教学、课程设计、电子竞赛基础训练、创客入门项目2. 适用场景与使用边界这个智能小车项目主要适用于以下几类人群和场景高校学生用于《单片机原理与应用》、《嵌入式系统设计》等课程的期末大作业或课程设计能完整展示传感器应用、电机控制和多任务调度能力。电子爱好者与创客作为一个综合性的入门项目可以快速学习如何将Arduino、传感器、电机驱动等模块组合成一个可交互的智能体。中小学科技教师作为STEAM教育或机器人社团的实践案例直观展示自动化控制的概念。它能解决什么问题实践闭环学习将抽象的编程逻辑if-else, 状态机与具体的物理运动前进、后退、转弯结合起来。理解传感器融合学习如何处理来自红外遥控、避障探头和循迹探头等不同源的数据并做出综合决策。掌握经典控制模式一次性实践手动遥控、环境感知避障和路径跟踪循迹这三种机器人基础控制范式。它的局限性是什么环境依赖性强红外传感器对环境光敏感强光直射可能导致误判循迹需要高对比度的黑白线路。功能相对基础属于入门级项目不具备SLAM、视觉导航、复杂路径规划等高级功能。通信距离短红外遥控受限于指向性和距离通常有效范围在几米内且不能有遮挡。承载与扩展有限基于Arduino UNO和L298N的架构负载能力和计算资源有限不适合添加过多重型传感器或复杂算法。安全与合规提醒小车电机具有一定动力请在空旷、平坦的场地测试远离台阶、水域避免对人或宠物造成冲撞。使用锂电池时注意充放电安全避免短路、过充或撞击电池。本项目为学习演示用途请勿用于可能危害公共安全或侵犯他人隐私的场合。3. 环境准备与前置条件在开始动手之前请确保你已准备好以下硬件和软件环境。硬件清单主控板Arduino UNO R3 一块或兼容板如采用CH340串口芯片的版本。小车底盘四轮或两轮驱动底盘一套包含直流减速电机、轮子、万向轮、亚克力板或金属支架。电机驱动L298N电机驱动模块 一块。电源7.4V 2S锂电池组带XT60或T插头一个用于驱动电机。5V/3.3V降压模块可选如果使用独立电源为Arduino供电。或一套18650电池盒输出7.4V。红外相关模块红外接收头如VS1838B一个用于接收遥控器信号。红外避障传感器模块数字输出常见为3引脚至少3个建议左、中、右。红外循迹传感器模块数字或模拟输出至少2个用于检测黑白线。遥控器一个通用的红外遥控器如NEC编码格式。连接件杜邦线公对公、公对母若干用于连接各模块。工具螺丝刀、扎带、电烙铁可选用于焊接排针、万用表可选用于调试。软件清单Arduino IDE从Arduino官网下载并安装最新版本。确保已安装对应主控板的驱动如CH340驱动。必要的库IRremote库用于解码红外遥控信号。可以通过Arduino IDE的库管理器搜索安装。开发电脑Windows, macOS 或 Linux 系统均可。环境检查清单[ ] Arduino IDE 能正确识别并选择开发板工具 - 开发板 - Arduino Uno。[ ] 能选择正确的端口工具 - 端口。[ ] 能用Blink示例程序成功点亮板载LED验证开发环境和烧录流程正常。[ ] 准备好所有硬件并初步了解各模块的引脚定义VCC, GND, Signal/OUT。4. 硬件搭建与电路连接硬件连接是项目成功的基础。请遵循“电源分区、信号独立”的原则避免电机干扰控制电路。电源系统连接电机电源将7.4V锂电池的正负极连接到L298N驱动模块的电源输入端子12V, GND。控制逻辑电源方案A推荐将L298N上的5V输出端子与Arduino UNO的5V引脚相连同时将两者的GND相连。此方案利用L298N内置的5V稳压芯片为Arduino供电。注意此时务必拔掉Arduino上通过USB或DC口接入的其他电源避免冲突。方案B使用独立的5V降压模块从锂电池取电降压后接入Arduino的Vin或5V引脚具体看模块输出和Arduino输入规格。同时确保Arduino、L298N、所有传感器的GND共地。使能跳线确保L298N模块上使能电机A和电机B的跳线帽已插上如果使用PWM调速则需通过Arduino引脚控制使能跳线帽拔掉。信号线连接请根据下表进行连接。务必在断电状态下操作Arduino UNO 引脚连接模块模块引脚功能说明D2红外接收头OUT接收红外遥控信号D3L298NIN1控制电机A方向左轮D5L298NIN2控制电机A方向左轮D6L298NIN3控制电机B方向右轮D9L298NIN4控制电机B方向右轮D10L298NENA (可选)左轮PWM调速若跳线帽拔掉D11L298NENB (可选)右轮PWM调速若跳线帽拔掉A0左侧红外避障OUT检测左侧障碍A1中间红外避障OUT检测前方障碍A2右侧红外避障OUT检测右侧障碍A3左侧红外循迹OUT检测左侧黑线A4右侧红外循迹OUT检测右侧黑线5V所有传感器、L298N逻辑VCC提供5V电源GND所有模块GND共地连接连接要点电机与车轮对应确保接线后令左轮电机接在L298N的OUT1和OUT2右轮电机接在OUT3和OUT4。可以通过后续程序测试正反转是否正确。传感器方向安装红外避障和循迹传感器时注意其探测方向朝向小车前方及地面。循迹传感器调试大多数红外循迹模块上有可调电位器用于调节灵敏度。在目标场地如白纸黑线上通过模块上的指示灯或串口输出调试到能稳定区分黑白状态。5. 软件编程与核心逻辑代码是项目的大脑。我们将采用状态机State Machine的设计模式来管理“遥控”、“避障”、“循迹”三种模式。5.1 基础驱动与宏定义首先定义引脚、引入库并编写基础的电机控制函数。#include IRremote.h // 引入红外遥控库 // 电机控制引脚定义 #define MOTOR_LEFT_IN1 3 #define MOTOR_LEFT_IN2 5 #define MOTOR_RIGHT_IN3 6 #define MOTOR_RIGHT_IN4 9 #define MOTOR_LEFT_PWM 10 // 如果使用PWM调速 #define MOTOR_RIGHT_PWM 11 // 如果使用PWM调速 // 红外传感器引脚定义 #define IR_RECEIVER_PIN 2 #define OBSTACLE_LEFT A0 #define OBSTACLE_CENTER A1 #define OBSTACLE_RIGHT A2 #define TRACKER_LEFT A3 #define TRACKER_RIGHT A4 // 工作模式枚举 enum OperationMode { MODE_MANUAL, // 手动遥控模式 MODE_AVOID, // 自动避障模式 MODE_TRACK // 自动循迹模式 }; OperationMode currentMode MODE_MANUAL; // 初始模式为手动 IRrecv irrecv(IR_RECEIVER_PIN); decode_results results; // 初始化函数 void setup() { Serial.begin(9600); irrecv.enableIRIn(); // 启动红外接收 // 设置电机控制引脚为输出 pinMode(MOTOR_LEFT_IN1, OUTPUT); pinMode(MOTOR_LEFT_IN2, OUTPUT); pinMode(MOTOR_RIGHT_IN3, OUTPUT); pinMode(MOTOR_RIGHT_IN4, OUTPUT); pinMode(MOTOR_LEFT_PWM, OUTPUT); pinMode(MOTOR_RIGHT_PWM, OUTPUT); // 设置传感器引脚为输入 pinMode(OBSTACLE_LEFT, INPUT); pinMode(OBSTACLE_CENTER, INPUT); pinMode(OBSTACLE_RIGHT, INPUT); pinMode(TRACKER_LEFT, INPUT); pinMode(TRACKER_RIGHT, INPUT); // 初始停止电机 stopMotors(); } // 基础电机动作函数 void motorForward() { digitalWrite(MOTOR_LEFT_IN1, HIGH); digitalWrite(MOTOR_LEFT_IN2, LOW); digitalWrite(MOTOR_RIGHT_IN3, HIGH); digitalWrite(MOTOR_RIGHT_IN4, LOW); analogWrite(MOTOR_LEFT_PWM, 200); // 设置PWM速度 analogWrite(MOTOR_RIGHT_PWM, 200); } void motorBackward() { digitalWrite(MOTOR_LEFT_IN1, LOW); digitalWrite(MOTOR_LEFT_IN2, HIGH); digitalWrite(MOTOR_RIGHT_IN3, LOW); digitalWrite(MOTOR_RIGHT_IN4, HIGH); analogWrite(MOTOR_LEFT_PWM, 200); analogWrite(MOTOR_RIGHT_PWM, 200); } void turnLeft() { digitalWrite(MOTOR_LEFT_IN1, LOW); digitalWrite(MOTOR_LEFT_IN2, HIGH); digitalWrite(MOTOR_RIGHT_IN3, HIGH); digitalWrite(MOTOR_RIGHT_IN4, LOW); analogWrite(MOTOR_LEFT_PWM, 150); analogWrite(MOTOR_RIGHT_PWM, 150); } void turnRight() { digitalWrite(MOTOR_LEFT_IN1, HIGH); digitalWrite(MOTOR_LEFT_IN2, LOW); digitalWrite(MOTOR_RIGHT_IN3, LOW); digitalWrite(MOTOR_RIGHT_IN4, HIGH); analogWrite(MOTOR_LEFT_PWM, 150); analogWrite(MOTOR_RIGHT_PWM, 150); } void stopMotors() { digitalWrite(MOTOR_LEFT_IN1, LOW); digitalWrite(MOTOR_LEFT_IN2, LOW); digitalWrite(MOTOR_RIGHT_IN3, LOW); digitalWrite(MOTOR_RIGHT_IN4, LOW); analogWrite(MOTOR_LEFT_PWM, 0); analogWrite(MOTOR_RIGHT_PWM, 0); }5.2 模式切换与红外遥控解码在loop()函数中我们持续监听红外遥控信号并根据按键切换模式。void loop() { // 1. 检查并处理红外遥控信号 if (irrecv.decode(results)) { unsigned long irValue results.value; Serial.print(“红外解码: 0x”); Serial.println(irValue, HEX); // 打印键值用于学习遥控器 switch (irValue) { case 0xFFA25D: // 假设‘CH-’键对应手动模式 currentMode MODE_MANUAL; Serial.println(“切换到[手动遥控]模式”); break; case 0xFF629D: // 假设‘CH’键对应避障模式 currentMode MODE_AVOID; Serial.println(“切换到[自动避障]模式”); break; case 0xFFE21D: // 假设‘CH’键对应循迹模式 currentMode MODE_TRACK; Serial.println(“切换到[自动循迹]模式”); break; // 手动模式下的方向控制 case 0xFF18E7: // ‘2’ 前进 if (currentMode MODE_MANUAL) motorForward(); break; case 0xFF4AB5: // ‘8’ 后退 if (currentMode MODE_MANUAL) motorBackward(); break; case 0xFF10EF: // ‘4’ 左转 if (currentMode MODE_MANUAL) turnLeft(); break; case 0xFF5AA5: // ‘6’ 右转 if (currentMode MODE_MANUAL) turnRight(); break; case 0xFF38C7: // ‘5’ 停止 if (currentMode MODE_MANUAL) stopMotors(); break; } irrecv.resume(); // 接收下一个红外信号 } // 2. 根据当前模式执行相应任务 switch (currentMode) { case MODE_MANUAL: // 手动模式下动作已由红外按键直接触发此处可空或加状态指示 break; case MODE_AVOID: autonomousAvoid(); break; case MODE_TRACK: autonomousTrack(); break; } delay(50); // 主循环延迟避免过于频繁的传感器读取 }关键点你需要先用一个简单的程序读取你手中遥控器每个按键的十六进制码替换上面case后的值。可以使用IRremote库的示例代码IRrecvDumpV2来获取。5.3 自动避障逻辑实现自动避障模式的核心是读取三个方向的避障传感器根据障碍物位置决策运动方向。void autonomousAvoid() { int leftSensor digitalRead(OBSTACLE_LEFT); int centerSensor digitalRead(OBSTACLE_CENTER); int rightSensor digitalRead(OBSTACLE_RIGHT); // 传感器逻辑通常检测到障碍物时输出 LOW (0)未检测到输出 HIGH (1) // 请根据你的模块实际输出调整逻辑 bool leftObstacle (leftSensor LOW); bool centerObstacle (centerSensor LOW); bool rightObstacle (rightSensor LOW); // 决策逻辑 if (!centerObstacle) { // 前方无障碍直行 motorForward(); } else if (!leftObstacle centerObstacle) { // 前方有障碍左侧空闲左转 turnLeft(); delay(300); // 左转一段时间 } else if (!rightObstacle centerObstacle) { // 前方有障碍右侧空闲右转 turnRight(); delay(300); } else if (leftObstacle centerObstacle rightObstacle) { // 三面都有障碍后退然后随机转向 motorBackward(); delay(500); stopMotors(); // 随机选择一个方向转弯 if (random(2) 0) { turnLeft(); } else { turnRight(); } delay(400); } else { // 其他情况停止 stopMotors(); } }5.4 自动循迹逻辑实现自动循迹模式通过两个地面红外传感器检测黑白线使小车沿黑线行驶。void autonomousTrack() { int leftTrack digitalRead(TRACKER_LEFT); int rightTrack digitalRead(TRACKER_RIGHT); // 传感器逻辑通常检测到黑线低反射时输出 HIGH (1)检测到白色高反射输出 LOW (0) // 请根据你的模块和场地实际调试 bool leftOnLine (leftTrack HIGH); bool rightOnLine (rightTrack HIGH); // 经典的双传感器PID比例控制逻辑简化版 if (leftOnLine !rightOnLine) { // 左传感器压线车体偏右需要左转校正 turnLeft(); } else if (!leftOnLine rightOnLine) { // 右传感器压线车体偏左需要右转校正 turnRight(); } else if (!leftOnLine !rightOnLine) { // 两个传感器都在白区说明可能丢失线路可以小幅度前进或原地旋转寻找 motorForward(); delay(100); } else if (leftOnLine rightOnLine) { // 两个传感器都检测到黑线可能遇到十字路口或停止线这里处理为停止 // 实际可扩展为路口识别逻辑 stopMotors(); } }6. 功能测试与效果验证代码编写完成后不要急于组装完整小车应分模块、分模式进行测试。6.1 模块独立测试电机与驱动测试将电机接上L298N但先不与Arduino连接。用杜邦线手动给L298N的IN1/IN2/IN3/IN4高低电平观察电机是否按预期正反转。确认无误后编写一个简单的测试程序让两个电机依次正转、反转、停止检查接线是否正确。红外遥控测试仅连接红外接收头到Arduino。上传IRrecvDumpV2示例程序。打开串口监视器按下遥控器按键记录下常用按键方向键、模式切换键对应的十六进制码并更新到主程序的switch-case中。避障传感器测试连接一个避障传感器到Arduino。上传一个读取数字引脚并打印到串口的程序。用手或物体在传感器前移动观察串口输出的变化0或1确认检测距离和逻辑是否符合预期。循迹传感器测试连接一个循迹传感器到Arduino。准备一张白纸和黑色电工胶带。上传读取程序将传感器分别对准白纸和黑线记录输出值并调节模块上的电位器使黑白区分明显。6.2 集成与模式切换测试将所有模块连接好上传完整代码。上电与初始化打开电源观察Arduino板载LED是否正常各传感器模块指示灯是否正常。打开串口监视器查看是否有初始化信息以及当前模式提示。手动遥控模式测试按下映射为“手动模式”的遥控键串口应显示“切换到[手动遥控]模式”。分别按下前进、后退、左转、右转、停止键观察小车运动是否与指令一致。常见问题电机转向反了。解决方案交换电机接线如OUT1和OUT2对调或修改程序中对应引脚的HIGH/LOW逻辑。自动避障模式测试按下“避障模式”键将小车放在空旷处它应开始前进。用手或书本在小车前方、左前方、右前方制造障碍观察其避障行为左转、右转或后退。常见问题传感器误触发。解决方案调整传感器安装高度和角度在代码中增加去抖动逻辑如连续多次检测才确认或为传感器加装遮光罩。自动循迹模式测试按下“循迹模式”键将小车放在准备好的黑白循迹赛道上如“8”字或环形。观察小车是否能稳定沿黑线行驶在弯道处是否平滑过渡。常见问题冲出赛道或抖动严重。解决方案精细调节循迹传感器的灵敏度电位器优化转弯的PWM速度和延时考虑增加更多传感器如3个或5个以实现更精确的控制。6.3 性能与稳定性观察电源监控长时间运行后触摸电池和L298N模块检查是否有异常发热。电机堵转时电流很大易导致发热。信号稳定性在多种光照条件下测试红外传感器观察是否因环境光过强而导致失效。模式切换响应快速连续切换模式观察小车行为是否出现混乱或延迟检查代码中状态切换逻辑是否严谨。7. 资源占用与扩展性分析微控制器资源占用数字I/O引脚本项目使用了约10个数字引脚包括PWM对于Arduino UNO的14个数字I/O来说仍有扩展空间。模拟输入引脚使用了5个模拟引脚实际用作数字输入UNO的6个模拟输入几乎占满。程序存储空间上述核心代码编译后约占用6-8KB远小于UNO的32KB Flash留有大量空间增加功能。内存全局变量和库占用部分RAM但状态机逻辑简单内存充足。扩展性建议增加功能可添加蓝牙模块HC-05/06实现手机APP控制与红外遥控形成互补。增加传感器可增加超声波模块进行更精确的测距避障或增加编码器实现精确里程计算。优化电源增加电压检测模块当电池电压过低时报警或自动返回充电。改进算法在循迹模式中实现简单的PID控制算法使转弯更平滑在避障模式中实现更复杂的搜索策略如沿墙走。结构优化设计并3D打印定制车壳优化传感器布局和重心。8. 常见问题与排查方法问题现象可能原因排查方式解决方案上电后无任何反应1. 电源未接通或电压不足2. Arduino未正确供电3. 电源线虚焊或松动1. 用万用表测量电池输出电压2. 检查Arduino板载电源指示灯是否亮3. 摇晃检查各电源连接点1. 充电或更换电池2. 检查L298N 5V输出或独立5V模块连接3. 重新焊接或插紧连接线电机不转或单向转动1. L298N使能跳线帽未插或PWM引脚未设置2. 电机线接触不良3. 程序引脚定义错误4. 电机损坏1. 检查L298N使能跳线2. 直接给电机端子供电测试3. 用简单测试程序逐一测试电机4. 交换电机测试1. 插上跳线帽或正确配置PWM引脚2. 重新连接电机线3. 核对代码与接线图4. 更换电机红外遥控失灵1. 红外接收头引脚接反2. 遥控器电池没电3. 环境强光干扰4. 库冲突或解码错误1. 检查VCC, GND, OUT接线2. 更换遥控器电池3. 避开阳光直射或日光灯4. 运行IRrecvDumpV2示例确认能否解码1. 纠正接线2. 换电池3. 改变测试环境4. 确保使用正确的IRremote库版本核对键值避障传感器一直触发或不触发1. 传感器灵敏度未调节2. 检测距离设置不当3. 外界物体干扰4. 传感器损坏1. 调节传感器上的电位器2. 参考手册调整安装距离3. 清除传感器前方杂物4. 更换传感器测试1. 顺时针/逆时针调节电位器2. 安装高度通常距地2-10cm3. 保持检测区域干净4. 使用万用表测量信号输出循迹小车跑偏或冲出赛道1. 传感器离地高度不一致2. 黑白线对比度不够3. 电机转速差异4. 程序逻辑阈值不合理1. 调整传感器使其距地高度一致2. 使用更黑的黑线和更白的底板3. 校准电机PWM值4. 在赛道上实际调试传感器输出值调整判断逻辑1. 机械固定确保平整2. 改善赛道条件3. 微调左右电机的PWM基准值4. 根据实测数据优化autonomousTrack()中的条件判断模式切换混乱1. 红外键值冲突或误触发2. 状态变量currentMode被意外修改3. 循环执行过快传感器干扰1. 打印所有红外键值确认唯一性2. 检查代码中所有修改currentMode的地方3. 在主循环loop()中增加适当延时1. 为模式切换键选择间隔较远的键值2. 将currentMode的修改严格限制在红外解码部分3. 增加delay(50)或使用非阻塞定时小车运动时抽搐或抖动1. 电源功率不足带载后电压下降2. 程序控制频率过高电机响应不及3. 机械结构松动1. 测量电机启动时电池电压2. 减少主循环频率或电机控制频率3. 检查轮子、联轴器是否紧固1. 使用容量更大的电池或电容缓冲2. 增加控制指令间的延时3. 紧固所有螺丝和连接件9. 最佳实践与项目优化建议完成基础功能后可以通过以下实践让项目更完善、更稳定代码模块化将电机控制、传感器读取、红外解码、模式逻辑分别封装成独立的函数或类提高代码可读性和可维护性。参数可配置化将电机速度、转弯延时、传感器阈值等经常需要调整的参数定义为全局常量或通过串口指令修改避免反复修改和烧录代码。增加状态反馈为小车添加LED指示灯或蜂鸣器用不同颜色或声音表示当前工作模式、低电量报警、错误状态等。实现软启动/软停止在电机控制函数中使用for循环渐变PWM值而不是突然全速可以保护电机和驱动电路运动也更平滑。引入非阻塞编程使用millis()函数替代delay()让小车在执行动作如转弯300ms的同时仍然能响应红外信号或检测传感器提高系统响应性。做好绝缘与固定使用热熔胶或尼龙扎带固定所有导线和模块避免行驶中因振动导致脱落或短路。在金属底盘上为所有裸露的焊点或引脚套上热缩管。建立测试日志在开发过程中充分利用串口打印功能输出关键变量如传感器值、当前模式、电机指令这是调试最有效的手段。10. 总结这个Arduino红外三模智能切换小车项目成功地将遥控、避障、循迹三种经典机器人应用集成于一体。它的价值不在于功能的复杂性而在于提供了一个完整的、可触摸的嵌入式系统学习框架。从硬件选型、电路连接到传感器数据采集、状态机编程再到多模式调度与调试你完整地走完了一个典型电子产品的开发流程。最值得尝试的点在于“模式切换”的逻辑设计它让你思考如何优雅地管理一个系统的不同行为状态。最先应该验证的是电机的双向控制和红外遥控的解码这是整个项目运动的基础。最容易踩的坑是电源干扰和传感器调试务必遵循“分模块测试、再集成”的原则。下一步你可以以此为基底进行扩展加入超声波模块实现更精准的避障增加OLED屏幕显示状态信息通过蓝牙接入手机实现遥控与自动模式的融合控制甚至尝试用ESP32替换Arduino为其增加Wi-Fi图传功能。这个小车底盘就是一个等待你赋予更多智慧的运动平台。