资讯动态

用ESP32和Arduino从零实现自动清扫机器人:硬件选型、控制逻辑与调试指南

发布时间:2026/9/8 5:43:30 来源:尧图企业网站定制
一台功能完整的清扫机从来不是把电机、轮子和刷子接上电就能跑起来的。真正决定它能不能在桌腿、墙角、门槛之间正常工作的是传感器数据怎么读、运动状态怎么切换、电机指令怎么输出以及发现走不动时该怎么定位问题。网上流传的“这个清扫机教程太详细了吧”这类评价之所以会出现往往不是因为零件清单长而是因为教程把硬件选型、装配顺序、控制逻辑、调试方法和排错路径串成了同一条主线。这篇文章就按照这条主线从零拆解一台自动清扫机器人的设计与实现。文中所有代码以 ESP32 和 Arduino 开发框架为例适合刚接触嵌入式开发、又想独立完成一个完整小项目的读者。学完之后你既能写出一套可运行的清扫控制程序也能在硬件出问题时按照链路一步步排查。1. 清扫机项目的整体拆解从“会转的刷子”到“能避障的机器人”1.1 清扫机的核心任务不是把灰扫开而是自主覆盖区域很多人理解清扫机第一反应是“有个刷子把垃圾扫到集尘盒里”。但这只回答了清扫机构怎么工作没有回答清扫机怎么移动。真正让清扫机有价值的是它在没有人操作的情况下能够在房间内持续移动并覆盖尽可能大的区域。覆盖能力、避障能力和持续工作是三个核心指标。覆盖能力指清扫机在一个时间段内实际扫过的面积占可清扫面积的比例。随机碰撞式清扫机在实际室内测试中覆盖效率通常不会很高但随着运行时间增加大部分区域都会被覆盖到。这也是低端清扫机器人能用“跑得久一点”来弥补算法不足的原因。明白这一点就知道为什么清扫机的主程序不能只写“前进”和“后退”而是要设计一套状态切换机制。1.2 两种主流导航策略随机覆盖和路径规划清扫机常见的导航策略可以分成两类。第一类是随机碰撞式清扫机直线前进撞到障碍物后旋转一个随机角度再继续前进。这种策略实现成本很低只需要碰撞开关、超声波或者红外测距就能完成。缺点是没有记忆同一个区域可能反复清扫而某些角落长时间进不去。第二类是路径规划式清扫机先构建房间地图再规划“弓”字形或分区清扫路径。这种策略通常需要里程计、陀螺仪、激光雷达或者视觉传感器配合 SLAM 算法实现。成本和算法复杂度明显更高但清扫效率和覆盖率也更高。对于入门项目建议先实现随机碰撞加上沿墙清扫。沿墙清扫能明显提升边缘区域的覆盖率是低成本方案里收益最高的一项改进。1.3 项目分层设计硬件、驱动、算法、应用把清扫机当成一个嵌入式系统来设计代码才不会越写越乱。可以按四层划分层次职责典型内容应用层决定“下一步去干什么”状态机、清扫策略、电量管理算法层把传感器数据变成决策输入避障判断、距离滤波、沿墙逻辑驱动层控制具体硬件电机 PWM、传感器读取、IO 读写硬件层物理设备与电路ESP32、电机驱动板、传感器、电池调试时严格按层检查先确认硬件层接线正常再验证驱动层能控制电机然后看算法层判断是否合理最后才看应用层决策是否符合预期。很多人直接改应用层代码结果问题出在驱动层引脚接反浪费大量时间。2. 硬件物料与装配准备先把零件和工具对齐2.1 核心硬件清单与选型说明以下是一套适合学习的最小硬件组合。这里给出的型号是为了说明选型思路实际购买时以自己手里模块的规格为准。部件建议型号/规格作用备注主控板ESP32 DevKitC运行控制程序引脚多支持 WiFi/蓝牙电机驱动TB6612FNG驱动左右两个直流电机比 L298N 压降小适合电池供电直流减速电机带轮子的 TT 电机或 N20 电机提供行走动力选带编码器的版本可以后续做里程计万向轮小号牛眼轮形成三点支撑让车体稳定转向超声波模块HC-SR04检测前方障碍物测距范围约 2cm 到 400cm红外避障模块红外对射式3 路检测侧向和角落障碍物受环境光影响需要调阈值碰撞开关微动开关 2 到 3 个检测接触碰撞作为超声波盲区的补充跌落传感器反射式红外3 到 4 路检测台阶和悬空边缘防止从桌面或楼梯掉下清扫电机3V 到 6V 直流小电机带动滚刷或边刷转动需要单独的驱动管或 MOS 管电池7.4V 2S 锂电池或两节 18650整机供电容量影响续航降压模块5V/3.3V 降压模块给主控和传感器供电需要满足电流需求选型时注意一点主控板的 GPIO 输出电流很小不能直接驱动电机必须经过电机驱动板。驱动板的逻辑电源可以和主控共用一个 5V但电机电源要单独从电池取电以免电机启动瞬间拉低主控电压导致重启。2.2 供电与驱动方案电池、降压和电流匹配供电设计是清扫机最容易出问题的地方。电机启动瞬间电流可以达到额定电流的数倍如果电池内阻大、降压模块输出能力弱主控就会复位。可以按以下顺序计算供电需求确定电机额定电压和额定电流。两个行走电机加一个清扫电机的峰值电流是整机电流上限。选择放电能力足够的电池。使用 7.4V 锂电池时要看持续放电电流是否大于整机峰值电流。主控和传感器使用独立降压。推荐使用输出能力在 500mA 以上的 5V 和 3.3V 降压模块。所有模块必须共地。电源负端要全部接到同一个 GND否则传感器信号会不稳定。常见错误是只给主控供电不给驱动板逻辑电源供电结果电机完全不动。TB6612FNG 的 VM 接电池正极VCC 接 5VGND 接电池负极两个输入引脚接 ESP32 的 GPIO两个 PWM 引脚接带 PWM 功能的 GPIO。2.3 引脚规划先画表再接线接线前先把引脚规划写下来避免写完代码发现引脚冲突。下面是一个可参考的分配表功能ESP32 引脚说明左电机 PWMGPIO 25需要 PWM 输出左电机 IN1GPIO 26方向控制左电机 IN2GPIO 27方向控制右电机 PWMGPIO 14需要 PWM 输出右电机 IN1GPIO 12方向控制右电机 IN2GPIO 13方向控制清扫电机控制GPIO 15高电平启动清扫电机超声波 TrigGPIO 5发送触发信号超声波 EchoGPIO 18接收回波红外避障左GPIO 34输入模式红外避障右GPIO 35输入模式碰撞开关左GPIO 32输入模式上拉碰撞开关右GPIO 33输入模式上拉跌落传感器GPIO 36, 39输入模式注意 ESP32 的 34、35、36、39 引脚只能作为输入使用不能接电机驱动输出。接线完成后用万用表的通断档逐条核对再用代码逐个引脚读取状态确认每个传感器都能被主控读到。2.4 装配顺序与接线规范推荐装配顺序先固定两个行走电机和万向轮确认车体能自由推动。再安装电机驱动板、主控板、降压模块用铜柱分层固定。安装超声波、红外、碰撞、跌落传感器注意传感器朝前的方向和安装高度。接好电源线、信号线线材用扎带整理避免被轮子卷入。最后安装清扫电机、滚刷和集尘盒确认滚刷转动方向能把垃圾扫向集尘盒。接线规范方面建议所有信号线使用不同颜色区分电源正极统一使用红色负极统一使用黑色。不要把杜邦线直接插在电机驱动板的螺丝端子上而不拧紧震动会导致接触不良。3. 控制逻辑与核心代码让清扫机从静止到自主行动3.1 状态机设计清扫机程序的主骨架清扫机的主程序不应该是“从头到尾一个循环”而应该拆成有限个状态。每种状态下清扫机执行一种固定行为当传感器条件满足时切换到另一个状态。常见状态定义如下状态含义进入条件行为IDLE待机上电、电量低停止所有电机FORWARD直线前进前方无障碍双电机同速前进OBSTACLE_TURN避障旋转前方有障碍原地旋转指定角度EDGE_FOLLOW沿墙清扫侧向检测到墙前进并保持离墙距离CONTACT_BACK碰撞后退碰撞开关触发后退一小段LOW_POWER低电量返回电压低于阈值返回充电座或停机用枚举定义状态enum RobotState { STATE_IDLE, STATE_FORWARD, STATE_OBSTACLE_TURN, STATE_EDGE_FOLLOW, STATE_CONTACT_BACK, STATE_LOW_POWER }; RobotState currentState STATE_IDLE;主循环每轮只做三件事更新传感器数据判断是否需要切换状态根据当前状态控制电机。void loop() { updateSensors(); // 1. 读取所有传感器 updateState(); // 2. 状态切换判断 executeState(); // 3. 执行当前状态 delay(10); // 避免循环过快造成传感器抖动 }这种写法的好处是每个状态的行为边界清晰新增一种行为时只需要增加一个枚举值和对应执行函数不会把主循环改成几百行的 if 嵌套。3.2 电机驱动与 PWM 调速实现ESP32 使用ledc通道输出 PWM。初始化时先配置两个 PWM 通道频率设置在 1000Hz 左右即可。TB6612FNG 的方向引脚接 HIGH 或 LOW 决定电机正反转PWM 引脚决定速度。const int MOTOR_LEFT_IN1 26; const int MOTOR_LEFT_IN2 27; const int MOTOR_LEFT_PWM 25; const int MOTOR_RIGHT_IN1 12; const int MOTOR_RIGHT_IN2 13; const int MOTOR_RIGHT_PWM 14; void setupMotors() { pinMode(MOTOR_LEFT_IN1, OUTPUT); pinMode(MOTOR_LEFT_IN2, OUTPUT); pinMode(MOTOR_RIGHT_IN1, OUTPUT); pinMode(MOTOR_RIGHT_IN2, OUTPUT); ledcSetup(0, 1000, 8); ledcSetup(1, 1000, 8); ledcAttachPin(MOTOR_LEFT_PWM, 0); ledcAttachPin(MOTOR_RIGHT_PWM, 1); } void setMotor(int pwmChannel, int in1, int in2, int speedValue) { if (speedValue 0) { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); } else { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); speedValue -speedValue; } ledcWrite(pwmChannel, constrain(speedValue, 0, 255)); } void setRobotMotion(int leftSpeed, int rightSpeed) { setMotor(0, MOTOR_LEFT_IN1, MOTOR_LEFT_IN2, leftSpeed); setMotor(1, MOTOR_RIGHT_IN1, MOTOR_RIGHT_IN2, rightSpeed); }setRobotMotion(120, 120)表示直行setRobotMotion(-120, 120)表示原地左转。速度值低于 50 时电机可能转不动因为直流电机存在启动死区这个现象会在后面调优时再处理。3.3 超声波避障与随机转向超声波模块需要读取距离。HC-SR04 的读取时序是Trig 引脚输出 10 微秒以上的高电平然后读取 Echo 引脚的高电平持续时间根据声速换算距离。const int ULTRASONIC_TRIG 5; const int ULTRASONIC_ECHO 18; float readFrontDistance() { digitalWrite(ULTRASONIC_TRIG, LOW); delayMicroseconds(2); digitalWrite(ULTRASONIC_TRIG, HIGH); delayMicroseconds(10); digitalWrite(ULTRASONIC_TRIG, LOW); long duration pulseIn(ULTRASONIC_ECHO, HIGH, 30000); if (duration 0) { return 999.0f; // 超时认为前方无障碍 } return duration * 0.034 / 2.0; }避障逻辑在主循环中表现为状态切换条件。当前方距离小于阈值时从 FORWARD 切换到 OBSTACLE_TURN原地旋转一段时间后恢复前进。为了让清扫覆盖更均匀转向方向可以随机选择const float OBSTACLE_THRESHOLD 25.0f; // 单位 cm void updateState() { switch (currentState) { case STATE_FORWARD: if (frontDistance OBSTACLE_THRESHOLD) { turnDirection random(0, 2) 0 ? -1 : 1; currentState STATE_OBSTACLE_TURN; stateStartTime millis(); } break; case STATE_OBSTACLE_TURN: if (millis() - stateStartTime 500) { currentState STATE_FORWARD; } break; default: break; } }转向时长 500ms 只是一个起步值。实际需要的时长取决于电机转速和车体结构要通过实验测量转 90 度需要的时间再写入代码。3.4 碰撞开关与防跌落逻辑超声波在近距范围内有盲区而且对细小的桌腿、玻璃等物体可能检测不到。碰撞开关的作用就是在已经撞到障碍物时给主控一个明确信号。碰撞开关接上拉输入模式触发时读到 LOW。const int COLLISION_LEFT 32; const int COLLISION_RIGHT 33; void setup() { pinMode(COLLISION_LEFT, INPUT_PULLUP); pinMode(COLLISION_RIGHT, INPUT_PULLUP); } bool isCollisionLeft() { return digitalRead(COLLISION_LEFT) LOW; }跌落传感器使用反射式红外模块安装在车体前部、左前、右前三个位置。当模块下方是悬空状态时红外反射量发生变化输出电平翻转。处理逻辑是任意一个跌落传感器触发立即停车并后退转向。void updateState() { if (dropLeft || dropRight || dropFront) { currentState STATE_CONTACT_BACK; stateStartTime millis(); return; } // 其他状态切换判断 }这里要注意跌落传感器检测的是反射率变化而不是真实高度。黑色地面、透明玻璃、反光地板都可能造成误判安装后需要在实际地面上逐路测试。3.5 清扫电机控制与回充预留清扫电机不需要调速时可以用一个 GPIO 配合 MOS 管或驱动板通道控制启停。在 FORWARD 和其他清扫状态下保持清扫电机开启在避障旋转和待机时可以继续保持开启也可以暂时关闭以省电。代码上只需要一个布尔变量const int BRUSH_MOTOR_PIN 15; void setBrushMotor(bool on) { digitalWrite(BRUSH_MOTOR_PIN, on ? HIGH : LOW); }如果后续要支持自动回充可以在状态机里预留 STATE_RETURN_TO_DOCK在电池电压检测模块接入 ADC 引脚之后用电压阈值触发回充状态。原型阶段可以先只做低电量停机提示避免电压低于保护板阈值导致电池过放。4. 运行验证与参数调优从能跑到跑得聪明4.1 启动前的安全检查清单第一次上电前不要直接放地上跑。先按以下清单检查电池电压是否在额定范围内正负极是否接反。电机驱动板信号线是否按引脚表接对方向引脚不能悬空。所有模块是否共地信号地线是否接到同一 GND。主控板是否独立供电电机启动时主控不能复位。轮子、滚刷、线材是否干涉转动时不会被卡住。清扫机放在桌面上时跌落传感器是否会误触发周围是否有台阶。检查通过后先用一个低速值测试电机不安装滚刷只让车体空跑。4.2 传感器数据实时观察方法调试最有用的手段是串口输出。把每个传感器的原始值通过 Serial 打印出来确认读到的是有效数据。void updateSensors() { frontDistance readFrontDistance(); collisionLeft isCollisionLeft(); collisionRight isCollisionRight(); dropLeft digitalRead(DROP_LEFT_PIN); dropRight digitalRead(DROP_RIGHT_PIN); } void printDebugInfo() { Serial.printf(dist%.1fcm leftCol%d rightCol%d drop%d%d\n, frontDistance, collisionLeft, collisionRight, dropLeft, dropRight); }在避障阈值调优时用手在超声波前方慢慢移动观察串口距离值是否连续变化。如果距离值跳动很大先检查供电是否稳定、超声波安装方向是否正确、是否与其他传感器信号线靠得太近。4.3 关键参数的调优方向清扫机运行效果不好多数不是代码逻辑错了而是参数不合适。常见参数见表参数起步值调小的影响调大的影响推荐思路避障阈值25cm清扫机靠近障碍物才转向碰撞概率增加提前转向覆盖率下降根据房间家具密度调整转向时长500ms转不到所需角度反复撞墙转向过度覆盖重叠多实测转 90 度所需时长前进速度120覆盖速度慢更稳定电机响应变差碰撞概率增加优先保证稳定碰撞后退时长300ms后退不足再次碰撞后退过多浪费覆盖时间让车体离开障碍即可调参时要一次只改一个参数。改完后记录现象再改下一个。不要同时改避障阈值和转向时长否则无法判断效果变化来自哪个参数。4.4 预期现象与异常现象对照运行验证阶段可以对照下表判断清扫机是否正常场景预期现象明显异常放在开阔地面直线前进速度为设定值明显跑偏、抖动、原地转圈前方用手遮挡停车并旋转方向随机不反应、反复前后抖动推到墙边碰撞开关触发后退转向继续顶墙电机嗡嗡响放在桌面边缘任意跌落传感器触发后停车直接冲出桌面连续运行 5 分钟可稳定绕障电量显示正常中途重启、速度变慢5. 常见问题与排查链路不动、乱转、卡死怎么处理5.1 电机不转的排查链路现象是清扫机上电后行走电机或者扫刷电机完全不动也没有声音。按顺序检查电池电压是否正常开关是否打开电源指示灯是否亮。驱动板 VCC 是否有 5VVM 是否有电池电压。驱动板方向引脚是否都有确定电平不能悬空。主控是否在运行串口是否能打印调试信息。PWM 引脚是否选择了 ESP32 的可用输出引脚是否被其他外设占用。电机线是否接牢是否有断线。常见原因是接线时把 IN1 和 IN2 接到了错误的引脚或者忘记给驱动板 VCC 供电。排查时先用万用表量电压再读串口确认主控代码最后检查电机本身不要一上来就怀疑电机坏了。5.2 避障失灵的原因分析避障失灵分两种表现对障碍物没有任何反应或者距离很远就乱转。对障碍物没有反应先看超声波读取值。HC-SR04 安装角度如果朝下或者被结构件遮挡回波路径异常距离值就会一直很大。再看避障阈值如果地面杂物多阈值太小车已经贴近障碍物才触发会频繁碰撞。距离很远就乱转常见原因是红外避障模块阈值调得太灵敏把地面、阴影、反光都当成障碍物。红外模块上一般有电位器可以旋转调整检测距离。调试时用一个固定障碍物反复测试找到既不误报又能检测到障碍的阈值点。5.3 原地打转或反复后退现象是清扫机不前进一直在原地旋转或者刚前进一点就后退。按优先级检查左右电机转向定义是否一致。一个电机 IN1 高电平为正转另一个可能相反导致差速逻辑错乱。两个电机速度是否明显不同。可以用同一 PWM 值分别测试左右轮测量 10 秒实际移动距离差距大时在代码里分别校准。碰撞开关是否一直处于触发状态。如果碰撞开关安装位置不对车体震动会持续触发程序会不断进入后退逻辑。跌落传感器是否误报。浅色地板或反光地面会让反射式红外持续输出触发电平。排查这类问题最快的办法是把各个传感器触发状态用串口打印出来观察是哪个输入在反复变化。5.4 续航不足与供电不稳定续航短常见原因有三个。第一是电机堵转。滚刷缠上毛发、轮轴卡入线材电机电流剧增电池电量快速消耗。此时车体往往伴随明显异响。第二是 PWM 占空比过高。电机长期满速运行电流大续航自然短。可以在不影响清扫效果的前提下降低前进速度。第三是电池容量本身不够。入门项目常用 18650 电池容量在 2000mAh 到 3000mAh 之间实际可用容量还要乘上放电效率。如果需要长时间清扫可以换成容量更大的电池或者选择低功耗主控方案。供电不稳定表现为清扫机在碰撞瞬间重启。这通常是电机启动瞬间把电池电压拉低导致主控供电低于工作电压。解决方法是让主控和传感器从降压模块供电降压模块输入端并联一个 470uF 以上的电解电容吸收瞬间压降。6. 从原型走向工程化生产环境中的改进方向6.1 硬件层面的可靠性提升原型跑通之后如果想把清扫机做成长期使用的设备需要考虑以下改进把杜邦线换成焊接连接或 PCB 端子降低震动松脱概率。给电机加电流检测电阻程序里做堵转保护发现电流异常立即停止清扫电机。增加独立电源开关和保险丝防止短路损坏电池和主控。使用带编码器的电机为里程计和定位算法提供数据。电池加装保护板避免过放、过充和短路。原型阶段可以接受飞线和胶带生产或长期使用阶段必须考虑可靠性和可维护性。6.2 软件层面的生产化改进软件方面有几个优先级较高的改进。第一是数据滤波。超声波传感器偶尔会读到突变的距离值可以在代码里取连续 3 次读数的中位数过滤掉异常点。中位数滤波在嵌入式场景中实现简单计算量也小。第二是看门狗和异常恢复。如果清扫机被卡住比如卡在桌腿之间长时间无法脱困程序需要检测“电机在转但位置没有变化”的情况执行脱困策略。没有编码器时可以依据碰撞触发频率和超声波距离变化来判断是否卡死。第三是参数外置化。把避障阈值、转向时长、速度值放在一个配置结构体里或者放在 EEPROM 中调参时不用反复改代码重新烧录。第四是电量管理。通过 ADC 采样电池电压结合放电曲线估算剩余电量在低电量时先减速再执行关停或回充流程。建议生产环境下至少要做到“异常可观测、故障可恢复、数据可回放”。串口日志、状态记录和运行时间统计三样都要有。6.3 从随机避障到 SLAM清扫机的进阶路径如果随机避障方案已经不能满足需求下一步可以按以下顺序升级加编码器实现里程计估算车体位置。加陀螺仪 IMU校正转向角度和方向漂移。使用激光雷达或深度相机构建房间栅格地图。引入 SLAM 算法在地图上定位清扫机位置。生成弓字形清扫路径实现分区覆盖和回充规划。这个升级顺序对应着从“反应式控制”到“状态估计”再到“规划控制”的学习路径。每一步都会引入新的数学基础和工程问题价值在于每个问题都能在手边的清扫机上直接验证。6.4 学习过程中的弯路提醒最后提醒三个常见的学习弯路。第一个弯路是过度堆硬件。看到别人用激光雷达就马上买但基础避障还没调稳。建议先把随机避障做到“在标准测试房间里不困住、不跌落、不长时间重复”再考虑升级。第二个弯路是只跑代码不调参数。同一个程序在不同电机、电池、地面条件下表现完全不同要养成测量和记录的习惯把“感觉还行”变成“转向时长 600ms、避障阈值 25cm、速度 120”这类可复现的描述。第三个弯路是忽略安全。电机有力量锂电有风险清扫机有跌落可能。每次修改结构或程序后都先在桌面和空旷区域低速测试再放到真实环境运行。嵌入式项目的正确顺序永远是接线检查、静态检查、低速空跑、功能验证、全速运行。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价