OPEN SOURCE DEEP DIVE
ElectroPup:12 自由度 3D 打印开源四足机器人
ElectroPup 是一台 4.5 公斤、12 自由度的 DIY 四足机器人:12 个 MG4010E-i10v3 CAN 无刷电机按腿分成四段 CAN 网络,主控为树莓派 5,整机由约 7700 行纯 Python 单服务驱动,不依赖 ROS。仓库公开了 OnShape CAD、两块 KiCad v8 电路板、物料清单、实测重量与功耗(悬挂 21.6 W、站立 33.8 W),并提供 MuJoCo 仿真、React Native/Expo 浏览器 UI、四种贝塞尔足端轨迹步态与完整搭建指南;作者同时列出了缺许可证、无接触传感、仿真模型缺质量惯量等已知不足。
一台真能自己动手做出来的机器狗
ElectroPup 是 Reuben Struwig 做的 DIY 四足机器人,它回答的是一个很具体的问题:一只会走路的机器狗能做多小、多便宜,同时又不丢掉那些让它值得亲手造出来的东西。作者给出的答案是一台 4.5 公斤、12 自由度的机器,由 12 个 MG4010E-i10v3 CAN 无刷电机驱动,主控是树莓派 5,控制端是一个纯 Python 单服务,整套栈里没有 ROS。docs/bom.ods 里的物料清单合计约 2026 美元,其中光是电机就占 1608 美元(单个 134 美元)。驱动部分吃掉整台机器 79% 的成本,这和所有业余四足项目的经济结构一模一样,也正是作者把电机选型写得那么细的原因。

对一个业余项目来说,这个仓库的资料完整得不太常见。它提供了 OnShape 的 CAD 文档(总装、腿、机身、髋部、工装、零件、PCB、NeoPixel 支架),两块 KiCad v8 电路板设计与生产输出文件,带打印时间与耗材估算的打印件清单,实测重量表,功耗计算表,一份完整的搭建指南,以及约 7700 行 Python 代码,覆盖步态规划、逆运动学、电机驱动、MuJoCo 仿真和浏览器 UI。复现这台机器人需要的东西都在仓库里。唯一缺的是许可证文件——如果你想再分发硬件或做衍生设计,这一点必须先解决:仓库目前没有任何明确的开源许可声明。
电机、CAN 拓扑与 70 Hz 的总线
每条腿三个 LingKong MG4010E-i10v3 电机:外展(abduction)、髋、膝。这款电机额定扭矩 2.5 N·m、峰值扭矩 4.5 N·m,供电范围 7.4-32 V,额定电流 3.5 A,峰值功率 140 W,配 1:10 行星减速器,电机端 18 位编码器、输出端 14 位编码器。直径 53 mm、高 41 mm、重 238 g——这也是为什么 docs/weights.ods 里 12 个电机合计 2856 g,而整机实测总重 4312.6 g。三分之二的重量都在驱动上。
作者把电机的优缺点写得很直白,这比一张参数表更有用。优点:配置软件走的是非专有的 USB 转 UART 硬件、CAN 通信文档可读、物理尺寸正好适配机架、电源与通信接口用标准 JST-ZH 6 针而非厂商私有接口。缺点:配置工具只有 Windows 版、固件闭源、CAN 无法配置全部参数(错误阈值、用于柔顺控制的扭矩限制必须走 UART)、海外采购导致保修麻烦、部分电机手转偏紧且工作电流略高。作者写明后续项目会优先选 ODrive 兼容的驱动器。
| 电机参数 | 数值 | 在系统中的作用 |
|---|---|---|
| 额定 / 峰值扭矩 | 2.5 N·m / 4.5 N·m | 决定站立与 RUN 步态的负载余量 |
| 减速比 | 1:10 | 经 CAN 回读的输出端角度 |
| 编码器 | 电机端 18 位、减速端 14 位 | 为 10 ms 控制环提供位置反馈 |
| 总线 | CAN 1 Mbps,仲裁基址 0x140 | motors.py 以 bitrate 1000000 拉起 socketcan |
| 单通道负载 | 6 个电机,平均更新率约 70 Hz | 读编码器、写目标角度与速度、取错误状态 |
| 位置环 PID | Kp 5、Ki 5(驱动器默认 100) | motor.py 中重调;只存 RAM,每次上电都要重下发 |
| 应答超时 | 50 ms,最多 3 次 | 超过即判定电机失联并进入故障处理 |
总线拓扑是这里最值得抄的一个设计。Power Carrier 电源板做出四条 CAN 网络,一条腿一条,板上留了跳线焊盘,可以把前两条腿合并成一条网络、后两条腿合并成另一条。树莓派 5 上的 Waveshare 双通道隔离 CAN HAT 于是每通道驱动 6 个电机。按腿分段的含义是:线束故障或某个关节干扰大时,只会拖垮一条腿而不是整机;同时每条总线的流量只有 12 个电机挤在一段时的一半。

机架、电池与实测功耗
机架思路来自 James Bruton 的 Open Dog 3:用碳纤维管做结构主梁。四根 12 mm 外径、10 mm 内径、254 mm 长的碳管,两端用瞬干胶粘进 PLA 插件,插件里再热熔 M5 铜螺母。作者指出碳管其实可以做到 250 mm——那是更常见的长度——只要把电源板缩短 2-4 mm,或者在髋板上开槽让板子每端多进去约 1 mm。装配细节写得很实,因为这类地方最容易毁掉一次组装:先装下侧碳管并扣上 PCB 卡扣,髋板压在平面上,然后每根管子每轮只拧一点点,循环收紧,而不是一根一次拧到位。
腿部几何固定在 frame_parameters.py:髋偏移 0.036 m、大腿 0.140 m、小腿 0.140 m、机身宽 0.150 m、机身长 0.338 m、前后足距 0.338 m、左右足距 0.261 m。关节限位为外展 ±45°、髋 -100° 到 90°、膝 ±180°。作者在 docs/design.txt 里记录了 MIT Mini Cheetah 的尺寸作为对照,用来确认 ElectroPup 的比例没有偏离常见四足形态。
电源是自制 6S1P 电池组,用三洋 18650 电芯,每节 3250 mAh,标称约 72 Wh(笔记里按每节 12.21 Wh 乘 6 算出 73.26 Wh),配 HXYP-6S-CW15 带均衡的 BMS。仓库里的照片是电池组装配到一半的状态,作者顺手留了一条真实的安全教训:制作时忘了装电极端面绝缘垫圈,而"任何自制电池组都应该把它当成必做项"。对复现者来说,这种坦白比一张干净的成品图有用得多。
| 工况 | 20 V 直流下电流 | 功率 |
|---|---|---|
| 悬挂、电机断使能(外展归零、腿呈 45°) | 1.08 A | 21.6 W |
| 站立、电机使能 | 1.79 A | 33.8 W |
也就是说,仅仅维持静态站立要比电子设备空转多花约 12 W。对 72 Wh 的电池组来说,这决定了续航是一小时量级还是数小时量级,取决于实际走了多少路;而实测值比作者原本的估算更低。由此引出的结论很有意思:既然功耗低于预期,就可以做更大的机架和更长的腿,从而把膝电机挪到髋部、用同步带驱动小腿,减轻腿部质量并让步态更稳。

刻意为之的单服务 Python 架构
软件是单一服务,而且是有意为之。作者之前做过基于 ROS2 的四足机器人 Zuko,ElectroPup 的设计目标之一就是绕开他在那里踩过的坑。代价也写得很清楚:单体意味着每次改软件都要让机器狗先趴下再站起来,而不能像 ROS 那样只重启某个节点、让电机继续保位。缓解办法是大部分开发都在仿真加 UI 的环境里做,不在真机上做。

main.py 跑固定 10 ms 主循环(0.010 s):读输入、推进运动状态机、算足端目标、解逆运动学、下发电机指令,然后按差值 sleep 以维持恒定节拍。系统状态经 ZeroMQ 的 PUSH/PULL 送到 Flask 服务,再由 Flask-SocketIO 以 threading 模式推给浏览器。UI 用 React Native 加 Expo,以 Web 应用方式运行;Android 版能跑但没有图表。由于仿真与 UI 都支持开发模式,整套栈可以在笔记本上没有真机也能开发调试。
逆运动学取自 mike4192 的 spot_micro_kinematics。变换链由 t_0_to_1 一路乘到 t_0_to_4,ikine(x4, y4, z4, l1, l2, l3) 由足端目标解出三个关节角,肘部构型靠 atan2(±sqrt(1 - D²), D) 的符号分支选择。机体姿态限位放在 ik_parameters.py:横滚 ±30°、俯仰 ±25°、偏航 ±30°,前后平移 ±0.050 m 并常驻 0.025 m 前向补偿以把质心移到更稳的位置,左右 ±0.075 m,高度 0.04 到 0.275 m、中立位 0.2 m,每个轴都有 0.040 的死区。
四种步态与贝塞尔足端轨迹
步态由 trajectory_planner.py 里的工厂函数构造。四种都用 BEZIER_ARC 摆动模式、周期都是 1.0 s,区别在占空比、抬腿高度与相位偏移。
| 步态 | 占空比 | 步长 | 抬腿高度 | 相位偏移(右前、左后、左前、右后) |
|---|---|---|---|---|
| CRAWL 爬行 | 0.75 | 0.10 m | 0.02 m | 0.0、0.25、0.5、0.75 |
| TROT 对角小跑 | 0.50 | 0.10 m | 0.02 m | 0.0、0.0、0.5、0.5 |
| RUN 奔跑 | 0.50 | 0.10 m 可缩放 | 0.06 m | 0.0、0.0、0.5、0.5 |
| CLIMB 攀爬 | 0.50 | 0.10 m | 0.03 m | 0.0、0.0、0.5、0.5 |
CRAWL 是唯一的四拍步态,一次只迈一条腿,占空比 0.75 保证始终有三足着地。TROT、RUN、CLIMB 都是对角双拍。RUN 最值得看:它的步长按指令幅值缩放,取 abs(max(前进, 横移, 转角)),所以同一种步态在小指令下给小步快频、满指令下给完整步幅,相位时钟也按缩放后的速率推进。抬腿高度从 TROT 的 0.02 m 提到 0.06 m,三倍高度用来在高速下越过地面起伏。
摆动轨迹是三次贝塞尔弧;同一文件里还保留了另外两种实现(普通贝塞尔与正弦弧 h = step_height · sin(π · phase_time))以便对比。转向不是单独的步态,而是一次投影:把直线足端轨迹投影到曲线路径上,绕圈取 40 个点。bezier_curve_plot.py 与 projection_plot.py 两个绘图脚本会把控制点与投影结果画出来,让几何先在浏览器里验一遍再下发给电机。站立到行走的切换走 TransitionPlanner,它把每条腿按 DOWN、ARC、HOLD、COMPLETE 四个阶段排好,轨迹取 50 个点。

仿真、UI 与可选的辅助板
仿真用 MuJoCo,./src/sim.sh 启动,模型是 src/model/ElectroPup.xml,目前输入只支持手柄。作者直说模型里没有近似的质量与转动惯量,所以仿真里的机器"挺弹"。对任何想先在仿真里调控制器的人来说这是硬限制:运动学与步态逻辑可以迁移,动力学不行。

UI 是这个项目里最被低估的部分。它显示关节位置、子系统状态、单电机遥测、输入、传感器读数与循环耗时,并且把仿真机体和由电机反馈重建的真实姿态叠在一起——一个运动学错误几秒钟就能看出来,而不是靠一次摔倒发现。它还会把贝塞尔摆动曲线与转向用的圆周足端路径画出来。
可选的辅助板跑在 STM32F401 Black Pill 上,加了 LCD 显示屏、可变音高蜂鸣器、NeoPixel 灯带、一路 RC 舵机通道、I2C 扩展、一个用于控制显示并在断电前正常关闭树莓派的按键,以及直连树莓派排针的多路引出:BNO055 九轴 IMU(I2C)、四路接触输入或 GPIO、留给未来发声驱动的 I2S、以及在蓝牙手柄受射频干扰时接管控制的 SBUS。仓库里已经有 BNO055 与 INA228 电源监测的驱动,还有一个 I2C 扫描工具。作者自己对这块板的评价是复杂度超过了 LCD 的实用价值,因为 Web UI 提供的数据多得多;后续版本要么直接用树莓派驱动 LCD,要么把它去掉。

打印件、CAD 与仍然缺的东西
打印件用 Polymaker PolyMax Tough PLA,选型理由是强度与易打印性;主体红色件估算 25.23 小时、742 g,黑色装饰件 3.58 小时、92 g。CAD 放在 OnShape,非商业用途可用免费的网页端完整功能,链接文档开了导出权限,可以直接复制工作区。文档里区分了三套开发环境:Ubuntu PC 负责绘图、仿真、KiCad 与 OrcaSlicer;无头树莓派 5 跑 Raspberry Pi OS Lite Bookworm 64 位,Python 3.13.5 由 pyenv 管理;STM32 走 VSCode 加 PlatformIO。
诚实的不足清单很长也很具体:没有接触传感,所以地形适应是盲的,未来做强化学习也拿不到足端状态信号;IMU 装了也有驱动,但还没用于平滑步态;没有质心计算;碳管在 RUN 步态下会扭,需要把管子延伸穿过髋板并加端面或对接板;电池与树莓派的位置应该互换以改善质量分布;板上还没有电压电流检测,这正是电源板下一步要加 INA228 与保险丝的原因;也没有 MPC 控制器。列表里还包括翻身后的倒立行走控制——作者认为可行,因为机架在被翻过来之后本身就能支撑行走。此外他计划把整体架构重构成多个服务,恢复单组件重启与单元测试能力。
README 末尾有一段 AI 声明值得引一句,因为它把范围划得很清楚:项目概念、外观、工程设计与原始代码库由作者构思并实现,部分代码在 Claude Code 的协助下审阅、修改与编写。这是一个既不夸大也不隐瞒工具参与度的干净范例。
对正在犹豫要不要做一台的人来说,实用结论是这样:ElectroPup 是一台完整、可复现的中型四足机器人,成本与重量都被 12 个 CAN 无刷电机主导,软件小到可以在一个下午从头读到尾,而它的缺陷是由踩过坑的人自己写下来的。真正要在开工前确认的是两件事:电机固件闭源、配置工具只有 Windows 版,以及仓库目前没有许可证。