ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于树莓派CM4的救援机器人搭建实战:从GPIO规划到运动控制

基于树莓派CM4的救援机器人搭建实战:从GPIO规划到运动控制 在准备这台Raspberry Pi Rescue Robot之前我其实已经被树莓派的GPIO折腾过好几轮。真正让我下定决心用Compute Module 4做核心的是一次废墟搜救演练中的意外——完整版的树莓派4B在剧烈颠簸中SD卡系统崩了而旁边那块固定在载板上的CM4核心板一点事没有。这篇博文就来聊聊一台以树莓派为核心、能进废墟的救援机器人到底应该怎么搭。内容从主控选型、GPIO引脚规划、运动控制架构到传感器组装和野外踩坑都是我自己实测过的方案适合准备用树莓派做移动机器人、或者想了解CM4 GPIO引脚图怎么落到实际项目里的朋友。1. 为什么救援机器人选择树莓派CM4当主控1.1 普通树莓派4B和CM4的取舍装在移动平台上才知道的差别很多人做机器人原型第一反应都是拿一块完整版树莓派4B插上SD卡就开始写代码。这个方案做桌面Demo没问题但一旦把板子装到履带底盘上跑在水泥碎块和砖头瓦砾之间问题就暴露出来了。第一是SD卡。树莓派4B的系统放在microSD卡里机器人过障时整台车都在震动SD卡和卡座的接触本身并不可靠。救援现场不仅有震动还可能有灰尘和潮气SD卡一旦接触不良轻则文件系统只读、进程崩溃重则系统直接起不来。我那次演练就是这么挂掉的。第二是物理固定。完整版树莓派4B四周有USB、网口、HDMI这些立式接口在机器人内部需要额外做一堆支架去固定而且线缆受力后容易把接口怼坏。CM4是核心板形态没有那些外设接口全靠一块载板把信号引出来金属屏蔽罩朝下固定在铜柱或者载板螺丝孔上抗震动性能好很多。第三是eMMC存储。CM4有两种型号带eMMC和不带eMMC的救援机器人我强烈建议选带eMMC的版本。eMMC是焊在板子上的存储芯片没有活动触点读写稳定性和寿命都远好于TF卡。树莓派系统跑起来之后日志、临时文件、数据库这些写操作其实挺频繁TF卡在持续写入下容易积累坏块eMMC就没这个焦虑。还有一个细节值得单独说CM4核心板本身没有网口和USB座它通过SODIMM连接器插到载板上。所以你去搜“raspberry pi compute module 4 gpio引脚图”的时候搜出来的往往是一张200pin的引脚定义图不是普通树莓派那种40pin排针。CM4真正往外接的是载板上的40pin排针而这两者的BCM编号基本和树莓派4B保持一致。这意味着你在树莓派4B上写的GPIO代码迁移到CM4载板上几乎不用改但接线前还是得对着载板说明书核一遍千万别只凭丝印判断。1.2 那为什么不用Arduino、ESP32或者Jetson Nano救援机器人这个场景主控需要同时干好几件事跑Linux系统、处理摄像头画面、提供网页控制界面、跟下位机通信、定时采集传感器数据。Arduino和ESP32虽然实时性好但算力太弱做不了视频流和OpenCV这类重活。Jetson Nano算力强但功耗高一截而且这板子的价格在预算敏感的项目里确实肉疼。树莓派CM4的定位正好卡在中间功耗能控制在5V/1.5A左右性能足够跑Python应用和轻量视觉软件生态又成熟。但我也要提醒一句不要把树莓派当成实时控制器。Linux不是实时操作系统进程调度、Wi-Fi中断、USB热插拔都会让一个GPIO口翻转的时间产生几十毫秒的抖动。这对LED闪烁无所谓对电机PWM和编码器计数就是灾难。所以我的方案是树莓派只做决策和感知电机控制交给下位机。这个架构后面会详细讲。1.3 底盘、电机和供电总价不是这么算的救援机器人的基础是底盘。我用的是一台常规履带式底盘两侧各一个12V直流减速电机自带霍尔编码器。履带的好处是越障能力强能过一些碎石和小台阶在废墟环境里比轮式从容得多。两个独立电机分别驱动左右履带通过差速实现转向这对后续运动控制也很直观。电机驱动板我用的是自带TB6612FNG芯片的模块可以同时驱动两路电机峰值电流单路能到1.2A左右对我们的电机够用。如果电机功率更大就得换成BTS7960或者更大电流的驱动模块选型时注意电机堵转电流最好留出1.5倍以上余量。供电是整个系统里最容易出错的地方。我一开始偷懒用一块12V锂电池同时给电机和树莓派供电12V经过一个降压模块变5V给CM4载板。实测下来电机一启动5V电压就出现明显跌落树莓派频繁重启。后来改成双路供电12V动力电直接给电机驱动另用一个独立的5V/5A降压模块专供树莓派和外设电机侧和逻辑侧的地在电池输出端单点共地。这个改动之后系统稳定非常多。便宜板子的降压模块动态响应不行如果预算允许直接上好的BEC或者DCDC模块能少很多事。2. 40Pin GPIO在救援机器人里的完整规划2.1 先把机器人需要的I/O盘了一遍GPIO规划是树莓派救援机器人项目里最容易被低估的环节。很多人一上来就急着接线结果做到一半发现引脚冲突、复用不对、上电时序捣乱到处飞线。我建议先坐下来把机器人的I/O需求清单列出来再对着引脚图分配。这台救援机器人最终需要的接口大概有这些I2C总线挂SHT30温湿度、BMP388气压、ADS1115模数转换、MLX90640热成像一共四个I2C设备。UART串口GPS模块一路下位机电机控制走USB转串口这里不占GPIO的UART。普通GPIO输入左右碰撞开关各一路急停按钮状态一路。普通GPIO输出继电器控制一个红色警示灯蜂鸣器一路状态LED两路。PWM输出云台舵机一路用来控制摄像头俯仰角。SPI或CSI摄像头用CSI接口不占GPIO。如果使用SPI屏幕或SPI传感器再另外规划。2.2 我实际的GPIO分配表确定完需求后我对着CM4载板的40Pin定义做了这样一张分配表。注意BCM编号才是代码里用的编号物理引脚号是接线时看的。物理引脚BCM编号功能用途13V3电源给I2C传感器供3.3V25V电源给舵机和继电器供5V3GPIO2I2C1 SDA温湿度/气压/ADC/热成像5GPIO3I2C1 SCL同上7GPIO4普通GPIO蜂鸣器控制8GPIO14UART0 TXDGPS模块TX10GPIO15UART0 RXDGPS模块RX11GPIO17普通GPIO急停继电器状态读取13GPIO27普通GPIO状态LED115GPIO22普通GPIO输入左碰撞开关16GPIO23普通GPIO输入右碰撞开关18GPIO24普通GPIO警示灯继电器控制29GPIO5普通GPIO状态LED231GPIO6普通GPIO备用输入32GPIO12PWM0云台舵机控制36GPIO16普通GPIO备用输出37GPIO26普通GPIO急停按钮状态这张表有几个原则I2C和UART先固定因为它们有明确的硬件复用关系不能随便换碰撞开关、急停这些安全相关输入放在单独的GPIO上不和PWM、I2C混用所有中断输入都选在支持BCM2835中断的引脚上避免后面写代码时发现某个GPIO不支持边沿中断。2.3 上电时序、串口启用和I2C总线的坑40Pin GPIO光看分配还不够实际调通至少还会踩这几个坑。第一个是上电瞬间的引脚电平。树莓派CM4在启动过程中部分GPIO会短暂处于高阻甚至被拉高状态。如果GPIO直接驱动继电器或者蜂鸣器上电时可能抽风一下。我的继电器模块是低电平触发所以我把控制脚接了一个10k电阻到3.3V做默认高电平等程序初始化后再拉低触发这样上电瞬间不会误动作。碰撞开关和急停按钮这类输入默认接上拉电阻让它在常态下为高电平触发时接地为低电平。第二个是UART的默认分配。树莓派系统默认把GPIO14/15分配给了蓝牙串口直接拿来接GPS会收不到数据。需要在/boot/config.txt里加一行dtoverlaydisable-bt把蓝牙关了UART0才能给GPIO用。同理I2C需要手动启用在raspi-config里打开或者写dtparami2con。第三个是I2C地址冲突。一条I2C总线上挂多个设备每个设备的地址必须唯一。我用的SHT30地址是0x44BMP388地址通常是0x77ADS1115是0x48MLX90640是0x33这几个互不冲突。如果你用别的型号先用i2cdetect -y 1扫一遍地址再接线免得焊好了才发现冲突。第四个是PWM复用。GPIO12、GPIO13、GPIO18、GPIO19这几个脚共享一个PWM控制器同时用两路PWM的时候要小心配置。我这里只用GPIO12驱动一个舵机问题不大。如果你想把四路电机PWM全接到树莓派上那硬件资源马上就不够用这也是我坚持走串口下位机的原因之一。3. 底层运动控制树莓派直连电机驱动还是走串口下位机3.1 两种控制架构的对比和我的选择在电机控制架构上我见过不少树莓派机器人直接把GPIO接到电机驱动模块上靠树莓派的软件PWM输出调速。这种方案优点是简单少一块板子代码也好写。但缺点对救援机器人来说是致命的。对比一下两种方案方案优点缺点树莓派直连电机驱动结构简单少一块控制器代码量少Linux调度抖动导致PWM不稳编码器中断容易丢失树莓派死机后电机无法自动停车树莓派串口下位机下位机实时性好电机响应快堵转保护做在底层树莓派崩溃后下位机可以紧急刹停增加一块主控和通信协议调试工作量略大我选的是第二种。下位机用了一块STM32F103核心板配合TB6612驱动模块。树莓派只管发速度目标值比如“左轮速度100右轮速度-100”下位机负责读编码器、跑PID闭环、输出PWM。树莓派死机了下位机检测到3秒没收到新指令就自动把两个电机刹住避免机器人带着速度冲出去。这个安全逻辑在救援现场太重要了。3.2 通信协议和关键代码树莓派和下位机之间我用USB转串口连接波特率115200。指令格式很简单一行文本S 100 -100第一条数据是左轮速度目标范围-255到255正值前进负值后退。第二条是右轮。末尾换行。文本协议的好处是调试方便出问题可以直接用串口助手手动发数据测试不需要抓包解析。树莓派端的发送代码大概长这样import serial ser serial.Serial(/dev/ttyUSB0, 115200, timeout0.05) def set_motor(left_speed, right_speed): left_speed max(-255, min(255, left_speed)) right_speed max(-255, min(255, right_speed)) msg fS {left_speed:d} {right_speed:d}\n ser.write(msg.encode()) # 示例前进 set_motor(150, 150)下位机STM32这边主循环大概5ms执行一次。每次循环做四件事检查串口有没有新指令、读取左右编码器、计算当前实际速度、跑PID输出PWM。如果发现目标速度和实际速度的差值持续超过一个阈值就认为可能是堵转或者撞墙直接停车并返回一个“T”状态给树莓派。下位机的核心伪代码while (1) { if (serial_available()) { parse_command(); movement_timeout millis(); } left_speed read_encoder_speed(LEFT); right_speed read_encoder_speed(RIGHT); pid_update(pid_left, target_left, left_speed); pid_update(pid_right, target_right, right_speed); set_motor_pwm(pid_left.output, pid_right.output); // 堵转保护 if (abs(target_left - left_speed) 80 abs(target_right - right_speed) 80 millis() - movement_start 1000) { motor_stop(); send_status(T); } // 超时停车 if (millis() - movement_timeout 3000) { motor_stop(); } delay(5); }这里有几个参数值得细说。堵转判断的阈值80是根据编码器脉冲数和轮径算出来的大概是实际速度只有目标速度一半不到的情况。500ms到1s的持续时间是为了避开刚起步阶段的加速过程否则机器人每一次起步都会误报堵转。超时停车设为3秒比树莓派的心跳间隔长保证正常情况下不会误触发。3.3 从GPIO到电机转动的信号延迟实测我专门测过从树莓派发出速度指令到电机实际转起来的时间。用串口发指令115200波特率下一帧7个字节大约0.6msSTM32串口接收中断几乎立刻触发PID控制周期5ms也就是最多等一个控制周期TB6612的PWM输出到电机响应大概也在1ms以内。整体延迟大约在3到8ms之间体感非常跟手。但如果把PWM直接挂在树莓派的GPIO上情况就完全不一样。Linux下用普通线程控制GPIO翻转线程调度的抖动可能达到几十毫秒。更麻烦的是树莓派CPU负载一高PWM频率就会漂移电机声音都会变。所以如果你打算做正经的两轮差速闭环我强烈建议用下位机方案。4. 救援感知链路的组装与调通4.1 摄像头救援机器人最强的主力传感器救援机器人的首要任务是“进去看”。废墟里光线差、灰尘多、空间狭小一个可靠的摄像头比什么都重要。我用的是树莓派官方Camera Module 3IMX708传感器支持自动对焦通过CSI接口连到CM4载板。CSI的好处是不占USB带宽、延迟低用libcamera栈直接推流。先跑个最基础的测试libcamera-hello -t 0能正常出图之后再用Python的picamera2库做视频流。我的做法是主程序里起一个独立线程把摄像头画面压缩成MJPEG通过HTTP持续推给控制端。控制端用浏览器打开页面就能看到实时画面不需要装任何客户端。这个方案在局域网内延迟大约200ms左右野外开阔地用Wi-Fi也够用。如果废墟里Wi-Fi信号差我建议在控制链路里加入自组网模块或者至少用高增益全向天线。实测下来2.4G Wi-Fi穿一两堵混凝土墙就衰减得厉害救援场景中很有可能出现机器人进去了、信号断了的情况。所以我还加了断线自动返航的预案不过这属于上层决策这里先不展开。4.2 传感器温湿度、气压、气体和热成像除了眼睛救援机器人还需要感知环境数据。SHT30温湿度传感器挂在I2C总线上实时监测周围环境的温度和湿度。废墟里如果温度异常升高可能意味着有火源或者设备过热湿度数据则能帮助判断区域是否潮湿对搜救人员的安全评估有用。BMP388气压计也是I2C设备用途是判断机器人的相对高度变化。机器人可能在瓦砾堆上爬坡通过气压变化可以估算爬升高度帮助后台人员了解位置。气体检测我用了一路ADS1115接到MQ-2烟雾传感器上。MQ-2能检测可燃气体和烟雾输出模拟电压树莓派本身没有ADC所以用ADS1115把模拟量转成数字量。注意MQ-2有个预热过程刚上电的前一两分钟读数会漂移程序里要加一个启动延时不要一开机就报警。热成像传感器MLX90640是这台机器人感知系统里最特别的一个。它是32x24像素的红外热像阵列能通过温差发现可见光条件下很难看到的人体。在灰尘大、光线暗的环境里热成像非常靠谱。MLX90640同样走I2C但一帧数据量比较大刷新率不要设太高我设成2Hz左右避免占用I2C总线拖慢其他传感器。4.3 数据上报和控制页面树莓派上我跑了一个Python主程序把所有传感器数据收集起来封装成JSON格式通过WebSocket推送。同时控制端页面用Flask提供页面里的虚拟摇杆或者键盘上下左右键控制机器人运动。视频流是单独的MJPEGJavaScript里直接用img src/video_feed嵌到页面里。一个关键的经验传感器采集和Web服务不要写在一个线程里。我先用threading开了三个线程一个负责视频流一个负责传感器采集一个负责WebSocket服务。树莓派CPU占用率大概在30%到50%之间连续跑一小时不会崩。如果你把视频采集和数据采集混在同一个事件循环里画面一卡传感器数据也会跟着延迟。4.4 人员探测先用热成像再做可见光辅助人员探测这部分很多教程一上来就建议上深度学习YOLO但在救援机器人这个场景里热成像其实是更可靠的工具。废墟里人可能被瓦砾部分遮挡可见光下的行人检测模型很容易失效人体和环境的温差却始终存在。我的实现思路是每0.5秒读一次MLX90640的32x24温度矩阵把温度超过35摄氏度的像素标记出来。如果连续超过3x3的区域温度都高于阈值就判定为热点。这个热点会被画到一张低分辨率热像图上叠加到视频流的角落里。程序同时把热点的数量、最高温度、位置坐标通过WebSocket传给后台。这套逻辑在写代码上比跑一个YOLO模型简单得多而且不用GPU树莓派4B级别的算力绰绰有余。如果你的目标是在户外白天搜救那YOLO类行人检测可以作为一个辅助手段但真正到了废墟环境热成像的鲁棒性明显更高。5. 野外测试踩坑记录5.1 电机启动瞬间电压跌落导致CM4重启第一次把整套系统装到履带底盘上出去测试的时候一推摇杆机器人刚起步树莓派立刻就重启了。我当时以为是代码写崩了后来看了系统日志才发现是掉电。原因很明确电机从静止到全速启动的瞬间启动电流是正常工作电流的好几倍。同一块12V电池既给电机供电又给5V降压模块供电电机一拉电电池端电压被拉低5V降压模块输出跟着掉CM4的供电电压跌破阈值就重启了。解决方式是彻底分离动力电和逻辑电。12V电池直接给电机驱动模块供电树莓派和外设从另一路5V/5A降压模块取电两块板子的地只在电池负极处单点共地。同时我还给电机驱动板输入端加了一个470uF电解电容吸收启动冲击。改完之后连续急停急起、爬坡过障树莓派再没掉过电。5.2 GPIO长线干扰导致碰撞开关误报装好之后在室外跑了几圈发现一个奇怪的现象机器人明明没有碰到任何东西避障程序却频繁触发。排查之后发现是碰撞开关的GPIO输入受到了电磁干扰。碰撞开关装在车头信号线要经过底盘一路走到车尾的主控位置大约一米多长。电机电缆就在旁边电机运转时产生的电磁干扰耦合到长线上导致GPIO电平抖动程序就以为碰撞了。解决方法是三管齐下。第一把信号线换成双绞的屏蔽线屏蔽层单端接地。第二GPIO内部启用上拉外部再加一个10k上拉电阻。第三在软件里做消抖GPIO状态连续保持20ms才算有效变化。我用的是树莓派的gpiozero或者RPi.GPIO中断回调在回调里读取时间戳过滤毛刺。改完之后干扰误报基本消失。5.3 程序崩溃后机器人失去控制救援机器人最不希望发生的事情之一就是程序崩溃后机器人停在废墟中间既不能前进也不能回收。我一开始用SSH远程跑主程序窗口一关、网络一断程序就被挂起机器人失去控制。后来我做了三件事。第一把主程序注册成systemd服务崩溃后由systemd自动重启。第二在CM4上启用硬件看门狗一旦系统无响应看门狗强制重启。第三下位机STM32里实现超时停车逻辑树莓派超过3秒没发心跳就自动刹停电机。这套组合下来即使树莓派完全死机机器人也是停在原地而不是乱跑。systemd服务文件里的关键配置[Unit] DescriptionRescue Robot Main Program Afternetwork.target [Service] ExecStart/home/pi/rescue-robot/main.py Restartalways RestartSec3启用硬件看门狗需要在/boot/config.txt里加一行dtparamwatchdogon然后确保系统里有/dev/watchdog节点让看门狗守护进程在跑。5.4 CM4散热和续航CM4核心板在全负载状态下发热很大。跑视频流、Web服务、热成像采集CPU温度很容易冲到80摄氏度以上。我一开始给CM4装了散热片但没加风扇野外太阳一晒温度更高系统明显变卡。后来换成一个5V的微型涡轮风扇整机温度稳定在60摄氏度左右。续航方面我这台车的电池是12V/5000mAh树莓派侧功耗大约8W两个电机功耗大约20W到30W整机在正常巡游状态下能跑四十分钟以上。如果要长时间搜救备一块电池是必须的。6. 如果重新做一版我要改掉的几个设计第一传感器线缆全部走下位机统一采集。这次把I2C传感器挂在了树莓派GPIO上虽然能用但线缆从车头传感器经过履带骨架绕到车尾电磁干扰让我费了不少功夫。下位机如果带ADC和I2C接口可以把温湿度、气压、碰撞开关全部就近接在下位机上树莓派只通过串口轮询数据信号线短了抗干扰自然就好。第二增加一个硬件急停回路。现在的急停按钮是接在树莓派GPIO上的软件读取后再通知下位机停车。如果树莓派系统完全冻结GPIO状态不更新急停就失效了。真正可靠的做法是急停按钮直接串联在电机驱动的使能脚或者电源回路上按下按钮电机驱动立即断电不经过树莓派处理。这是救援机器人的安全底线我下一版会优先改。第三摄像头做成双镜头。废墟里镜头一旦被灰尘或碎石挡住整个感知系统就瞎了。可以加一个小的雨刷或者用双摄像头一个朝前一个朝上至少保证一路画面可用。第四把图像传输链路换成更抗干扰的无线电数传。Wi-Fi在废墟里穿墙能力有限自组网模块或者图传模块虽然贵一点但在真实救援环境里稳定得多。这个取舍要看预算但如果目标是实战这一步省不了。这轮项目做下来我最大的体感是树莓派救援机器人的难点从来不是某一个传感器或者某一段代码而是把感知、控制、通信、供电这些子系统在恶劣环境里稳定地捏合在一起。CM4的GPIO引脚规划只是第一步真正决定这台车能不能在废墟里跑起来的是你在测试中解决了多少个“为什么一启动就重启”“为什么GPIO乱跳”这类问题。希望这篇文章能让你少踩几个我踩过的坑。
返回列表