1. 项目缘起为什么选择Seeeduino XIAO来做避障小车如果你玩过Arduino大概率是从经典的Uno或者Nano开始的。它们功能齐全社区资源丰富是入门的不二之选。但当你真的想做一个能跑起来、能感知环境、结构紧凑的移动机器人时Uno那硕大的板子和有限的引脚资源往往会让你在设计底盘、布线、供电时感到掣肘。这就是我这次选择Seeeduino XIAO作为核心控制器来打造超声波避障机器人的根本原因。这个小家伙尺寸只有23.5mm x 17.5mm比大拇指指甲盖大不了多少但它搭载了一颗ARM Cortex-M0内核的微控制器性能远超传统的8位AVR芯片。更重要的是它保留了Arduino IDE开发的便利性你可以用熟悉的setup()和loop()来写代码同时享受32位MCU带来的更高主频和更丰富的外设。对于避障小车这个项目XIAO的几个特性简直是量身定做首先是极小的体积可以轻松塞进各种迷你底盘让整车设计更灵活其次是足够的GPIO驱动两个直流电机、一个超声波模块、几个状态指示灯绰绰有余再者是低功耗特性对于电池供电的移动平台至关重要。而“超声波避障”本身是机器人自主导航中最经典、最直观的入门课题。它不涉及复杂的图像识别或SLAM算法核心逻辑就是“测量-判断-执行”用超声波传感器测量前方障碍物的距离根据设定的阈值决定小车的行动策略前进、转向或后退。这个过程完美涵盖了嵌入式开发的几个核心环节传感器数据采集、控制逻辑实现以及执行器电机驱动。通过这个项目你不仅能收获一个活蹦乱跳的机器人更能透彻理解一个自动控制系统是如何闭环工作的。2. 硬件选型与核心部件拆解一个完整的避障机器人硬件上可以看作由四大模块构成大脑主控、眼睛传感器、腿脚驱动与执行和躯干电源与结构。下面我们来逐一拆解并解释为什么我这样选型。2.1 主控板Seeeduino XIAO的潜力与局限Seeeduino XIAO的核心是SAMD21G18A微控制器这是一颗ARM Cortex-M0芯片运行频率48MHz拥有256KB Flash和32KB SRAM。对比Arduino Uno的ATmega328P16MHz 32KB Flash 2KB SRAM性能是碾压级的。更大的内存意味着你可以编写更复杂的逻辑或者使用更多的库函数而不用担心空间不足。它的引脚虽然只有14个但复用功能强大。对于本项目我们主要用到以下几组数字I/O与PWM驱动电机需要PWM信号进行调速XIAO的多路PWM输出完全满足要求。模拟输入虽然超声波是数字传感器但预留的模拟输入口可以方便后续扩展比如增加光线传感器或模拟量的红外测距。串口用于调试信息输出在开发阶段至关重要。I2C接口这是一个关键优势。如果未来你想升级传感器比如使用精度更高、功能更多的ToF测距传感器如VL53L0X或者添加一个OLED显示屏来实时显示距离信息都可以通过I2C总线轻松挂载而不会占用额外的GPIO。需要注意的局限XIAO的工作电压是3.3V而很多电机驱动模块和传感器是5V逻辑的。直接连接可能存在电平不匹配的风险严重时会损坏XIAO。因此在选配其他模块时务必确认其兼容3.3V逻辑或者准备电平转换电路。2.2 感知之眼HC-SR04超声波模块详解HC-SR04大概是电子制作领域最知名的超声波测距模块了成本低廉、使用简单。其工作原理是典型的“声纳”机制控制端发送一个至少10微秒的高电平脉冲到Trig引脚模块会自动发射8个40kHz的超声波脉冲并检测回波。当接收到回波时Echo引脚会输出一个高电平脉冲脉冲的宽度与声波往返的时间成正比。计算距离的公式为距离 (高电平时间 × 声速) / 2。在空气中声速受温度影响较大常温下20°C约为343米/秒。在代码中我们通常用一个简化公式距离厘米 高电平时间微秒 / 58。实操中的关键点供电电压HC-SR04虽然常见5V版本但也有3.3V兼容的型号。为保险起见建议购买时明确选择支持3.3V逻辑的型号或者通过简单的电阻分压电路对Echo引脚信号进行降压后再接入XIAO。测量周期两次测量之间需要至少60ms的间隔以防止上一次发射的声波干扰下一次测量。测量盲区与角度HC-SR04的测量盲区大约在2-3厘米太近的物体无法检测。其探测角度约为15度这意味着它探测到的不是一个点而是一个锥形区域。在判断障碍物时需要考虑这个因素。2.3 动力总成电机、驱动与电源方案小车的移动能力由电机、驱动板和电源共同决定。电机选择我推荐使用N20微型减速电机搭配65mm左右的塑料轮子。这种电机体积小、扭矩大经过齿轮箱减速增扭、价格便宜非常适合小型机器人平台。注意要选择带编码器版本的型号虽然本项目避障用不上编码器但它为后续实现精确的里程计或PID速度控制留下了升级空间。驱动电路绝对不能直接用XIAO的GPIO口驱动电机GPIO口的驱动电流通常20mA以内远不足以驱动电机需要几百mA。我们必须使用电机驱动模块。对于这种双轮差分驱动的小车最经典的选择是L298N或TB6612FNG驱动板。L298N老牌芯片皮实耐用但发热较大效率相对低。TB6612FNG我更推荐这个。它是MOSFET桥驱动效率高、发热小支持更大的电流1.2A连续3.2A峰值而且有待机模式更省电。其逻辑电压可以低至2.7V完美兼容XIAO的3.3V。电源管理这是项目稳定的基石。整个系统需要两路电源逻辑电源为XIAO、传感器、驱动板逻辑部分供电。推荐使用一块3.7V的锂电池如常见的10440或14500电池其电压范围3.0V-4.2V正好适合XIAO和3.3V系统。可以通过一个低压差稳压器LDO获得更稳定的3.3V。电机电源电机启动和堵转时电流很大最好与逻辑电源分开避免电压骤降导致主控板复位。可以使用另一块相同的锂电池或者使用一块容量更大的电池如7.4V 2S锂电池通过驱动板给电机供电同时用降压模块为逻辑部分提供5V或3.3V。务必在电机电源两端并联一个大电容如470uF-1000uF的电解电容以吸收电机产生的瞬间电流冲击和电火花干扰。2.4 车身与结构从散件到整车你可以购买现成的两轮差分底盘套件通常包含底盘板、两个电机、两个轮子、一个万向轮或牛眼轮以及螺丝包。这是最快捷的方式。如果想更个性化也可以用亚克力板或3D打印自己设计底盘。设计时需要考虑电池、主板、驱动板的安装位置以及超声波传感器的安装高度和朝向通常水平向前。3. 电路连接与接线图解析正确的硬件连接是成功的一半。下面以Seeeduino XIAO TB6612FNG HC-SR04 (3.3V兼容版) 双N20电机的组合为例详细说明接线方法。请务必在断电状态下操作。电源部分准备两节3.7V锂电池BAT1和BAT2。BAT1正负极接入TB6612FNG的VM电机电源和GND引脚。BAT2正负极接入一个降压模块如AMS1117-3.3输出稳定的3.3V。这个3.3V输出同时连接到Seeeduino XIAO的3V3和GND。TB6612FNG的VCC逻辑电源和GND。HC-SR04的VCC和GND。注意所有模块的“地”GND必须连接在一起共地是电路正常工作的基础。信号连接部分TB6612FNG驱动板AIN1- XIAOD0(控制电机A方向)AIN2- XIAOD1(控制电机A方向)PWMA- XIAOD2(电机A调速PWM)BIN1- XIAOD3(控制电机B方向)BIN2- XIAOD4(控制电机B方向)PWMB- XIAOD5(电机B调速PWM)STBY- 接3.3V高电平使能驱动板HC-SR04超声波模块Trig- XIAOD6Echo- XIAOD7电机输出将左侧电机两根线接在TB6612的A01和A02右侧电机接在B01和B02。如果电机转向与预期相反交换接线即可。提示在实际焊接或使用杜邦线连接前最好先在面包板上搭建整个电路进行测试确认所有功能正常后再转移到最终底盘上。4. 核心代码逻辑与避障算法实现硬件搭建好后我们开始编写机器人的“大脑”。代码的核心任务是循环执行测量距离 - 根据距离决策 - 控制电机动作。4.1 基础驱动函数封装首先我们将电机控制抽象成几个简单的函数让主逻辑更清晰。// 引脚定义 const int AIN1 0; const int AIN2 1; const int PWMA 2; const int BIN1 3; const int BIN2 4; const int PWMB 5; const int TRIG_PIN 6; const int ECHO_PIN 7; // 电机控制函数 void setMotor(int motor, int speed, int direction) { // speed: 0-255, direction: 0刹车/停止, 1正转, -1反转 int in1, in2, pwm; if (motor 0) { // 左电机 in1 AIN1; in2 AIN2; pwm PWMA; } else { // 右电机 in1 BIN1; in2 BIN2; pwm PWMB; } speed constrain(speed, 0, 255); // 限制速度范围 if (direction 1) { // 正转 digitalWrite(in1, HIGH); digitalWrite(in2, LOW); analogWrite(pwm, speed); } else if (direction -1) { // 反转 digitalWrite(in1, LOW); digitalWrite(in2, HIGH); analogWrite(pwm, speed); } else { // 停止/刹车 digitalWrite(in1, LOW); digitalWrite(in2, LOW); analogWrite(pwm, 0); } } void moveForward(int speed) { setMotor(0, speed, 1); setMotor(1, speed, 1); } void moveBackward(int speed) { setMotor(0, speed, -1); setMotor(1, speed, -1); } void turnLeft(int speed) { // 左轮后退右轮前进实现原地左转 setMotor(0, speed, -1); setMotor(1, speed, 1); } void turnRight(int speed) { // 左轮前进右轮后退实现原地右转 setMotor(0, speed, 1); setMotor(1, speed, -1); } void stopMotors() { setMotor(0, 0, 0); setMotor(1, 0, 0); }4.2 超声波测距函数与滤波接下来实现一个稳定可靠的测距函数。原始超声波读数可能会有跳变加入简单的软件滤波能提升稳定性。float getDistance() { // 发送触发信号 digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); // 读取回波高电平持续时间 long duration pulseIn(ECHO_PIN, HIGH, 30000); // 超时30ms对应约5米距离 // 计算距离厘米 float distance duration * 0.034 / 2; // 声速按340m/s计算 // 简单的滤波如果读数异常如超时返回0或极大值则返回上一次的有效值 static float lastValidDistance 50.0; // 初始化为一个安全距离 if (distance 0.5 distance 400) { // 有效范围假设为0.5cm到4米 lastValidDistance distance; } else { distance lastValidDistance; // 返回上一次有效值 } return distance; } // 更高级的滤波连续采样N次取中值或平均值 float getFilteredDistance(int samples) { float distances[samples]; for (int i 0; i samples; i) { distances[i] getDistance(); delay(30); // 每次测量间隔至少60ms这里取30ms是考虑到函数本身执行时间 } // 简单排序取中值这里简化处理取平均值 float sum 0; for (int i 0; i samples; i) { sum distances[i]; } return sum / samples; }4.3 避障决策状态机最简单的避障逻辑是“if-else”阈值判断但我们可以设计一个更健壮、行为更自然的状态机。机器人可以有几个状态前进、避障转向、后退、随机探索。enum RobotState { STATE_FORWARD, STATE_OBSTACLE_AVOID, STATE_BACK_UP, STATE_RANDOM_TURN }; RobotState currentState STATE_FORWARD; unsigned long stateStartTime 0; const int AVOID_THRESHOLD 20; // 避障阈值单位厘米 const int BACKUP_DISTANCE 10; // 后退时要求达到的距离 const int BACKUP_TIME 800; // 后退持续时间毫秒 const int TURN_TIME 500; // 转向持续时间毫秒 void robotStateMachine() { float dist getFilteredDistance(3); // 取3次采样平均值 switch (currentState) { case STATE_FORWARD: moveForward(150); // 以中等速度前进 if (dist AVOID_THRESHOLD) { // 发现障碍物进入避障状态 currentState STATE_OBSTACLE_AVOID; stateStartTime millis(); stopMotors(); delay(100); // 停顿一下更拟人 } break; case STATE_OBSTACLE_AVOID: // 先短暂后退一点获得转向空间 moveBackward(100); delay(300); stopMotors(); delay(200); // 随机决定向左还是向右转避免陷入死循环 if (random(2) 0) { // 50%概率 turnLeft(150); Serial.println(Turning Left); } else { turnRight(150); Serial.println(Turning Right); } delay(TURN_TIME); // 转向一段时间 stopMotors(); delay(200); // 转向后再次测距如果前方仍然有障碍可能进入死胡同需要更复杂的策略 dist getFilteredDistance(3); if (dist AVOID_THRESHOLD 5) { // 仍然很近进入后退状态 currentState STATE_BACK_UP; stateStartTime millis(); } else { // 前方畅通回到前进状态 currentState STATE_FORWARD; } break; case STATE_BACK_UP: moveBackward(120); if (millis() - stateStartTime BACKUP_TIME) { stopMotors(); // 后退结束后来一个大角度的随机转向尝试脱离困境 currentState STATE_RANDOM_TURN; stateStartTime millis(); } break; case STATE_RANDOM_TURN: // 执行一个较长时间的随机转向 if (random(2) 0) { turnLeft(150); } else { turnRight(150); } if (millis() - stateStartTime TURN_TIME * 2) { // 转向时间加倍 stopMotors(); currentState STATE_FORWARD; // 转向结束继续前进探索 } break; } } void setup() { // 初始化所有引脚 pinMode(AIN1, OUTPUT); pinMode(AIN2, OUTPUT); pinMode(BIN1, OUTPUT); pinMode(BIN2, OUTPUT); pinMode(PWMA, OUTPUT); pinMode(PWMB, OUTPUT); pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT); Serial.begin(115200); // 初始化串口用于调试 randomSeed(analogRead(A0)); // 用悬空模拟引脚噪声作为随机种子 stopMotors(); // 确保电机初始为停止状态 } void loop() { robotStateMachine(); // 运行状态机 // 可以在这里添加一些调试信息输出但不要延迟太久 // static unsigned long lastPrint 0; // if (millis() - lastPrint 500) { // Serial.print(State: ); Serial.print(currentState); // Serial.print(, Dist: ); Serial.println(getDistance()); // lastPrint millis(); // } }这个状态机实现了一个基本的“前进-遇障转向-后退脱困”的循环并且引入了随机性使得小车的行为不那么刻板更能应对复杂环境。5. 系统调试与性能优化实战代码烧录进去小车可能不会立刻如你所愿地工作。调试是项目中最关键的一环。5.1 分模块调试法不要一次性把所有代码都写全。采用分步调试电机测试先写一个简单的测试程序让两个电机分别正转、反转、调速确认接线正确电机转向符合预期。传感器测试单独测试超声波模块在loop里不断打印测得的距离值。用手在传感器前移动观察数值变化是否平滑、准确。这一步能排除硬件连接和基本函数逻辑的问题。逻辑测试将电机控制和传感器读数结合起来写一个最简单的逻辑距离大于30厘米前进小于30厘米停止。观察小车能否在障碍物前停下。状态机集成最后将完整的避障状态机代码集成进去。5.2 常见问题与排查小车不动或抽搐检查电源用万用表测量电机驱动板VM和逻辑VCC的电压。电机启动时电压是否骤降如果低于驱动板或XIAO的最低工作电压就会复位。这就是为什么强调电机电源要并联大电容以及逻辑与动力电源最好分离的原因。检查PWM信号用示波器或者一个简单的LED串联一个电阻接在PWM引脚上观察在调速时LED的亮度是否有变化确认PWM信号正常输出。检查STBY引脚TB6612的STBY引脚必须接高电平3.3V才能使能接低电平则所有输出关闭。超声波读数不稳定或总是超大值电平兼容确认Echo引脚信号电压不超过3.3V。如果是5V模块必须分压。电源噪声电机的火花会产生强烈的电磁干扰。确保超声波模块的电源线远离电机和驱动板的大电流线路。可以在超声波模块的VCC和GND之间就近并联一个0.1uF的瓷片电容和一个10uF的电解电容来滤波。软件超时pulseIn函数默认超时时间可能太短导致未收到回波时返回0。我们代码中已设置为30000微秒30ms基本够用。避障行为“智障”阈值调整AVOID_THRESHOLD避障阈值需要根据小车的速度、刹车距离以及传感器安装高度来调整。速度越快这个值应该越大。传感器安装位置传感器朝下或朝上安装了吗确保它水平向前。安装位置太高可能会错过矮的障碍物如桌腿太低则可能将地面起伏误判为障碍。环境干扰超声波可能被柔软的表面如窗帘、布艺沙发吸收导致测距不准。也可能被其他同频率的声源干扰。5.3 进阶优化思路当基础功能实现后可以考虑以下优化让小车更智能多传感器融合在车身左前和右前各增加一个超声波或红外传感器。这样不仅可以探测正前方还能探测左右侧的障碍物实现更智能的绕行决策比如选择障碍物较少的一侧转向。速度闭环控制如果电机带编码器可以引入PID控制器让小车在不同地面地毯、木地板上都能保持恒定的设定速度这样避障距离的判断会更精确。增加“记忆”功能利用XIAO的EEPROM或者Flash让小车记住导致它“被困住”的转向序列下次遇到类似情况时尝试不同的策略实现简单的学习行为。无线遥控与调试为XIAO增加一个蓝牙如HC-05/06或Wi-Fi如ESP-01S模块。这样你可以用手机或电脑实时接收小车的传感器数据、状态信息甚至远程更新它的行为逻辑调试会方便得多。6. 从项目到作品外观整合与功能扩展硬件和代码都稳定后最后一步是把它变成一个完整的“作品”。结构整合使用尼龙柱、螺丝将XIAO、驱动板、电池盒等牢固地固定在底盘上。用扎带整理线束避免松散的电线卷入车轮。为超声波传感器设计一个简单的支架使其稳固且朝向正确。电源开关在电池和主板之间串联一个拨动开关方便随时断电。状态指示可以增加一个双色LED。例如正常前进时亮绿灯检测到障碍物时亮红灯并闪烁这样即使不看串口输出也能直观了解小车状态。扩展功能声光互动增加一个蜂鸣器在转向或后退时发出不同的提示音。增加几个LED灯条做成呼吸灯或转向指示灯效果。上位机可视化通过串口或无线模块将实时距离数据、电机速度、机器人状态发送到电脑用Processing或Python的Matplotlib库绘制出简单的运行曲线和虚拟环境实现数据可视化监控。巡线功能叠加在底盘增加几个红外反射式传感器就可以实现“超声波避障”“红外巡线”的双模式机器人通过一个拨码开关切换模式。完成这个Seeeduino XIAO超声波避障机器人你收获的远不止一个会跑的小车。你实践了从需求分析、硬件选型、电路设计、代码架构到调试优化的完整嵌入式开发流程。你理解了传感器如何与真实世界交互学会了如何让代码去应对不确定的环境。更重要的是你掌握了如何将一个复杂的系统拆解成一个个可管理、可测试的模块这种系统化思维的能力会伴随你在任何一个软硬件项目中走得更远。