SO-100 开源机械臂 DIY 完全指南:零部件、组装、编程 2026

SO-100 是 2026 年最火的低成本开源机械臂项目,本教程涵盖 BOM 清单、3D 打印、组装步骤、舵机校准、LeRobot 集成,附完整代码示例与常见问题解答,助你从零搭建一台可用于机器人学习研究的 6 自由度机械臂。

SO-100 开源机械臂 低成本机器人 3D 打印 LeRobot DIY 舵机
SO-100 开源机械臂 DIY 完全指南:零部件、组装、编程 2026

SO-100 开源机械臂 DIY 完全指南:零部件、组装、编程 2026

SO-100 是 2025 年由 Hugging Face 社区发起的开源机械臂项目,目标是打造一台成本低于 500 元、性能可用于机器人学习研究的 6 自由度机械臂。它采用 3D 打印结构 + 总线舵机方案,配合 LeRobot 框架,可以实现从数据收集到策略训练的全流程。

截至 2026 年,SO-100 已有超过 5000 台被全球研究者和爱好者组装完成,成为机器人学习领域最受欢迎的硬件平台之一。

你将学到:

  • ✅ 完整 BOM 清单与采购指南
  • ✅ 3D 打印件准备与后处理
  • ✅ 机械组装全流程(含视频链接)
  • ✅ 舵机校准与电气连接
  • ✅ 与 LeRobot 集成,训练抓取策略

1. SO-100 设计概述

1.1 为什么选择 SO-100?

市面上机械臂方案众多,SO-100 的优势在于:

特性SO-100工业机械臂其他开源方案
成本~500 元5-50 万元1000-3000 元
自由度6 DOF6-7 DOF4-6 DOF
负载250g5-20kg200-500g
重复精度±1mm±0.02mm±2-5mm
开源程度完全开源封闭部分开源
LeRobot 支持原生需适配部分支持

适用场景:

不适用场景:

  • 工业级精度要求
  • 重载操作(>250g)
  • 户外或恶劣环境

1.2 技术规格

  • 自由度:6(基座旋转、肩关节、肘关节、腕关节俯仰、腕关节翻滚、末端执行器)
  • 驱动:6x ST3215 总线舵机(3.3V/5V,15kg·cm 扭矩)
  • 控制器:ESP32-S3 + 舵机控制板
  • 通信:USB UART / WiFi
  • 结构:3D 打印 PLA/PETG
  • 末端:可更换夹爪/吸盘/电磁铁
  • 工作半径:~250mm
  • 自重:~800g(不含电源)

2. BOM 清单与采购

2.1 核心零部件

零件数量参考价格采购渠道
ST3215 总线舵机635 元/个淘宝/闲鱼
ESP32-S3 开发板125 元立创商城
舵机控制板(Hub)145 元SO-100 官方淘宝店
3D 打印件(全套)1 套50-80 元自建/代打印
轴承 6x10x3mm62 元/个淘宝
M3 螺丝套装1 套15 元淘宝
铜柱 M3x10mm41 元/个淘宝
电源 5V 4A130 元淘宝
USB-C 线缆110 元任意
杜邦线若干5 元任意

总成本:约 400-500 元

2.2 舵机选择

ST3215 是 SO-100 的推荐舵机,关键参数:

  • 电压:5-8.4V
  • 扭矩:15kg·cm @ 6V
  • 通信:TTL 总线(半双工串口)
  • 分辨率:4096 步/圈
  • 反馈:位置、温度、电压、负载
  • 重量:55g

替代方案:

如果 ST3215 缺货,以下舵机也可使用(需调整配置文件):

  • STS3215:ST3215 的升级版,推荐
  • FEETECH SCS15:兼容协议
  • Waveshare Bus Servo:国产兼容方案

注意: 不要使用 PWM 舵机(如 SG90、MG996R),它们不支持位置反馈和总线通信。

2.3 3D 打印件

推荐材料:

  • PLA: easiest to print,适合原型
  • PETG:更好的韧性和耐温性,推荐最终版
  • ABS:不推荐(容易翘边)

打印参数(以 PETG 为例):

  • 层高:0.2mm
  • 填充:30%
  • 壁厚:3 层
  • 支撑:需要(部分零件)
  • 喷嘴温度:235-245°C
  • 热床温度:70-80°C

获取 STL 文件:

# 从 GitHub 下载
git clone https://github.com/SoBot-100/SO-100.git
cd SO-100/hardware/stl/

# 或使用 Thingiverse
# https://www.thingiverse.com/thing:XXXXX

打印后处理:

  1. 去除支撑材料
  2. 用砂纸打磨接触面
  3. 检查轴承孔是否顺畅(必要时用钻头扩孔)
  4. 螺母嵌入孔用烙铁加热嵌入 M3 螺母

3. 组装步骤

3.1 工具准备

  • 十字螺丝刀(PH1)
  • 内六角扳手(2mm)
  • 烙铁 + 焊锡
  • 万用表
  • 热熔胶枪(可选)
  • 扎带若干

3.2 舵机预组装

在组装机械臂之前,需要先对舵机进行零点校准。

步骤 1:舵机 ID 设置

每个舵机需要唯一的 ID(1-6):

#!/usr/bin/env python3
"""舵机 ID 配置工具"""
import serial
import time

def set_servo_id(port, old_id, new_id):
    """设置舵机 ID"""
    # ST3215 协议:写入 ID 寄存器
    # 寄存器地址:0x05
    instruction = [
        0xFF, 0xFF,  # Header
        old_id,      # Current ID
        0x04,        # Length
        0x03,        # Write instruction
        0x05,        # Address (ID register)
        new_id       # New ID value
    ]
    
    # 计算校验和
    checksum = sum(instruction[2:]) & 0xFF
    instruction.append((~checksum) & 0xFF)
    
    ser = serial.Serial(port, 1000000, timeout=1)
    ser.write(bytes(instruction))
    time.sleep(0.1)
    response = ser.read(ser.in_waiting)
    ser.close()
    
    print(f"舵机 ID 已从 {old_id} 改为 {new_id}")
    return len(response) > 0

# 依次设置 6 个舵机
# 先连接一个舵机,设置 ID 为 1,然后换下一个
for i in range(6):
    new_id = i + 1
    input(f"请连接第 {new_id} 个舵机,按回车继续...")
    set_servo_id("/dev/ttyUSB0", 1, new_id)  # 默认 ID 为 1
    print(f"舵机 {new_id} 设置完成")

步骤 2:零点校准

将所有舵机转到中位(2048):

#!/usr/bin/env python3
"""舵机零点校准"""
import serial
import time

def move_to_center(port, servo_id):
    """将舵机转到中位"""
    position = 2048  # 中位
    instruction = [
        0xFF, 0xFF,
        servo_id,
        0x07,        # Length
        0x03,        # Write
        0x1E,        # Goal Position address (0x1E)
        position & 0xFF,
        (position >> 8) & 0xFF,
        0x00,        # Speed
        0x00
    ]
    
    checksum = sum(instruction[2:]) & 0xFF
    instruction.append((~checksum) & 0xFF)
    
    ser = serial.Serial(port, 1000000, timeout=1)
    ser.write(bytes(instruction))
    time.sleep(1.0)
    ser.close()
    print(f"舵机 {servo_id} 已转到中位")

# 依次校准
for i in range(1, 7):
    move_to_center("/dev/ttyUSB0", i)

重要: 在校准中位后再安装舵机臂,确保各关节在中位时对齐。

3.3 机械臂组装

步骤 1:基座(Joint 1 - 旋转)

[底座] → [轴承] → [舵机1] → [舵机臂]
  1. 将轴承压入底座零件
  2. 舵机 1(ID=1)从下方插入,螺丝固定
  3. 安装舵机臂(此时应已在中位)
  4. 用 M3x10 螺丝固定舵机臂

步骤 2:大臂(Joint 2 - 肩关节)

[舵机1臂] → [连接件] → [舵机2] → [大臂零件]
  1. 将连接件固定到舵机 1 的臂上
  2. 舵机 2(ID=2)嵌入大臂零件
  3. 通过连接件将大臂与基座连接
  4. 注意线缆走向,预留余量

步骤 3:小臂(Joint 3 - 肘关节)

[大臂] → [舵机3] → [小臂零件]
  1. 舵机 3(ID=3)安装到小臂根部
  2. 线缆穿过大臂内部
  3. 安装小臂零件

步骤 4:腕部(Joint 4 & 5 - 俯仰 + 翻滚)

[小臂] → [舵机4] → [连接件] → [舵机5] → [腕部零件]
  1. 舵机 4(ID=4)安装到小臂末端
  2. 通过连接件连接舵机 5
  3. 舵机 5(ID=5)实现翻滚运动
  4. 注意两个腕关节的轴线正交

步骤 5:末端执行器(Joint 6 - 夹爪)

[腕部] → [舵机6] → [夹爪]
  1. 舵机 6(ID=6)安装到腕部末端
  2. 安装夹爪零件
  3. 测试开合动作

3.4 电气连接

接线图:

ESP32-S3
├── UART_TX → 舵机控制板 RX
├── UART_RX → 舵机控制板 TX
├── GPIO_2  → 舵机控制板 DIR(方向控制)
└── GND     → 共地

舵机控制板
├── 5V 输入 → 电源 5V 4A
├── GND     → 电源 GND
├── 总线    → 舵机 1-6 信号线(菊花链)
└── GND     → 舵机 1-6 GND

接线注意事项:

  1. 电源分离:舵机供电(5V 4A)与 ESP32 供电(USB 5V)分开,避免电流干扰
  2. 共地:所有 GND 必须连接在一起
  3. 总线拓扑:舵机信号线采用菊花链连接,不是星形
  4. 线序:信号线颜色通常为 黄=信号、红=VCC、棕=GND

完整接线检查清单:

□ 电源 5V → 控制板 VCC
□ 电源 GND → 控制板 GND
□ ESP32 TX → 控制板 RX
□ ESP32 RX → 控制板 TX
□ ESP32 GPIO_2 → 控制板 DIR
□ ESP32 GND → 控制板 GND
□ 舵机 1-6 总线连接(菊花链)
□ 舵机 1-6 VCC 连接
□ 舵机 1-6 GND 连接

4. 固件与软件

4.1 ESP32 固件

SO-100 使用基于 ESP32 的固件,提供 USB 串口和 LeRobot 兼容接口。

安装 Arduino CLI:

# 下载 Arduino CLI
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh

# 添加 ESP32 开发板支持
arduino-cli config add board_manager.additional_urls \
  https://espressif.github.io/arduino-esp32/package_esp32_index.json

# 安装 ESP32 核心
arduino-cli core install esp32:esp32

# 安装依赖库
arduino-cli lib install "Servo"
arduino-cli lib install "ArduinoJson"

上传固件:

# 克隆固件仓库
git clone https://github.com/SoBot-100/SO-100-firmware.git
cd SO-100-firmware

# 编译并上传
arduino-cli compile --fqbn esp32:esp32:esp32s3 --upload \
  --port /dev/ttyACM0 so100_firmware.ino

固件功能:

  • USB 串口通信(115200 baud)
  • 舵机总线控制(转发 TTL 指令)
  • 位置/速度/扭矩模式
  • 实时状态反馈
  • 安全保护(过温、过流)

4.2 Python 控制库

# 安装 SO-100 Python 库
pip install so100-controller

# 或从源码安装
git clone https://github.com/SoBot-100/so100-python.git
cd so100-python
pip install -e .

基础控制示例:

#!/usr/bin/env python3
"""SO-100 基础控制"""
from so100_controller import SO100Controller
import time

# 连接机械臂
arm = SO100Controller(port="/dev/ttyACM0")
arm.connect()

# 读取当前关节角度
positions = arm.get_joint_positions()
print(f"当前关节角度: {positions}")

# 移动到目标位置(单位:度)
target = [0, 0, 90, 90, 0, 0]  # 各关节角度
arm.move_to(target, duration=2.0)
time.sleep(2.0)

# 夹爪控制
arm.set_gripper(100)  # 全开
time.sleep(1.0)
arm.set_gripper(0)    # 全关

# 读取状态
for servo_id in range(1, 7):
    pos = arm.get_position(servo_id)
    temp = arm.get_temperature(servo_id)
    load = arm.get_load(servo_id)
    print(f"舵机 {servo_id}: 位置={pos}, 温度={temp}°C, 负载={load}%")

# 断开连接
arm.disconnect()

高级控制 - 轨迹规划:

from so100_controller import SO100Controller
from so100_controller.trajectory import LinearPlanner
import numpy as np

arm = SO100Controller(port="/dev/ttyACM0")
arm.connect()

# 创建轨迹规划器
planner = LinearPlanner(max_velocity=60)  # 度/秒

# 定义路径点
waypoints = [
    [0, 0, 90, 90, 0, 0],     # 初始位姿
    [45, -30, 60, 60, 0, 0],  # 中间位姿
    [45, -30, 30, 90, 0, 50], # 目标位姿(夹爪半闭)
]

# 生成平滑轨迹
trajectory = planner.plan(waypoints, dt=0.033)  # 30 Hz

# 执行轨迹
for point in trajectory:
    arm.set_joint_positions(point)
    time.sleep(0.033)

arm.disconnect()

5. LeRobot 集成

5.1 配置 LeRobot 支持

SO-100 是 LeRobot 原生支持的机器人之一。关于 LeRobot 框架的详细介绍,参见 LeRobot 完全指南。

# 安装 LeRobot(含 SO-100 支持)
pip install "lerobot[so100]"

创建配置文件:

# configs/robot/so100.yaml
robot_type: so100
port: /dev/ttyACM0
fps: 30

# 关节配置
joints:
  - id: 1
    name: shoulder_pan
    offset: 0
    inverted: false
    min: -90
    max: 90
  - id: 2
    name: shoulder_lift
    offset: 0
    inverted: true
    min: -90
    max: 90
  - id: 3
    name: elbow
    offset: 0
    inverted: false
    min: -120
    max: 0
  - id: 4
    name: wrist_pitch
    offset: 0
    inverted: false
    min: -90
    max: 90
  - id: 5
    name: wrist_roll
    offset: 0
    inverted: false
    min: -90
    max: 90
  - id: 6
    name: gripper
    offset: 0
    inverted: false
    min: 0
    max: 100

# 摄像头
camera:
  type: usb
  device: /dev/video0
  width: 640
  height: 480
  fps: 30

5.2 数据收集

使用 LeRobot 的数据收集工具:

# 遥操作模式(用键盘或手柄控制)
python -m lerobot.teleoperate \
  --robot=so100 \
  --config=configs/robot/so100.yaml

# 录制数据集
python -m lerobot.record_dataset \
  --robot=so100 \
  --config=configs/robot/so100.yaml \
  --repo-id=your-username/so100-pick \
  --num-episodes=50 \
  --task="pick up the red cube"

遥操作控制方式:

  • 键盘控制:WASD 移动,QE 旋转,RF 夹爪
  • 手柄控制:左摇杆平移,右摇杆旋转,扳机夹爪
  • 主从模式:用另一台机械臂作为主手(需要额外硬件)

5.3 训练策略

# 使用 ACT 训练
python -m lerobot.train \
  --config-path=configs/act/so100.yaml \
  --dataset=your-username/so100-pick \
  --output-dir=outputs/act_so100_pick

# 训练参数
# batch_size: 32
# steps: 10000
# learning_rate: 0.0001
# eval_freq: 500

5.4 部署执行

#!/usr/bin/env python3
"""部署训练好的策略到 SO-100"""
from so100_controller import SO100Controller
from lerobot.common.policies.act.modeling_act import ACTPolicy
import cv2
import torch
import time

# 加载策略
policy = ACTPolicy.from_pretrained("outputs/act_so100_pick/checkpoints/last")
policy.eval()

# 连接机械臂
arm = SO100Controller(port="/dev/ttyACM0")
arm.connect()

# 打开摄像头
cap = cv2.VideoCapture(0)

print("开始执行策略...")
print("按 Ctrl+C 停止")

try:
    step = 0
    while True:
        # 读取图像
        ret, frame = cap.read()
        if not ret:
            break
        
        # 预处理
        image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image = torch.tensor(image).permute(2, 0, 1).float() / 255.0
        image = torch.nn.functional.interpolate(
            image.unsqueeze(0), size=(480, 640)
        )
        
        # 读取关节状态
        state = torch.tensor(arm.get_joint_positions()).float()
        
        # 推理
        obs = {
            "observation.image": image,
            "observation.state": state.unsqueeze(0)
        }
        
        with torch.no_grad():
            action = policy.select_action(obs)
        
        # 执行动作
        arm.set_joint_positions(action[0].numpy())
        
        step += 1
        if step % 30 == 0:
            print(f"Step {step}, Action: {action[0].numpy()}")
        
        time.sleep(0.033)  # 30 Hz

except KeyboardInterrupt:
    print("停止执行")
finally:
    cap.release()
    arm.disconnect()

6. 常见问题与优化

6.1 机械问题

问题:关节松动/晃动

  • 原因:舵机臂未紧固或轴承间隙过大
  • 解决:重新紧固舵机臂螺丝,更换轴承

问题:夹爪打滑

  • 原因:摩擦力不足
  • 解决:在夹爪表面贴硅胶垫或橡胶皮

问题:线缆干涉

  • 原因:线缆长度不足或走线不合理
  • 解决:重新布线,使用柔性排线

6.2 电气问题

问题:舵机抖动

  • 原因:电源不足或通信干扰
  • 解决:更换 5V 4A 以上电源,检查接线

问题:ESP32 重启

  • 原因:舵机启动电流过大导致电压跌落
  • 解决:为 ESP32 单独供电,添加大容量电容(1000μF)

6.3 软件问题

问题:串口通信超时

  • 原因:波特率不匹配或 USB 线缆质量差
  • 解决:确认波特率为 1000000,更换高质量 USB 线缆

问题:LeRobot 找不到机器人

  • 原因:端口权限或驱动问题
  • 解决:
# 添加用户到 dialout 组
sudo usermod -aG dialout $USER
# 重新登录生效

# 检查端口
ls -la /dev/ttyACM*

总结

SO-100 是目前性价比最高的开源机械臂方案,500 元即可拥有一台可用于机器人学习研究的 6 自由度机械臂。通过本教程,你已完成:

  1. ✅ 采购所有零部件
  2. ✅ 3D 打印并组装机械臂
  3. ✅ 舵机校准与电气连接
  4. ✅ 固件安装与基础控制
  5. ✅ LeRobot 集成与策略训练

下一步建议:

  • 参加 SO-100 社区分享你的作品
  • 尝试不同的训练算法(Diffusion Policy、TD-MPC2)
  • 升级末端执行器(吸盘、电磁铁、软体夹爪)
  • 探索双臂协作(购买第二台 SO-100)

如果你想将 SO-100 与移动机器人结合,可以参考 宇树 Go2 机器狗 ROS2 开发指南 或 ROS2 入门教程。

常见问题(FAQ)

SO-100 机械臂适合初学者吗?

适合。SO-100 的设计目标就是降低机器人学习的门槛,无需专业背景即可组装。只要具备基本的焊接能力和 3D 打印经验,1-2 天即可完成组装。

SO-100 和工业机械臂有什么区别?

主要区别在于精度和负载。SO-100 重复精度约 ±1mm,负载 250g,适合学习和研究;工业机械臂精度可达 ±0.02mm,负载 5-20kg,但价格高达数万至数十万元。

没有 3D 打印机怎么办?

可以选择代打印服务(淘宝上约 50-80 元一套),或者使用激光切割木板/亚克力板替代部分结构件。社区也有铝合金版本的设计方案。

SO-100 可以用于哪些学习场景?

SO-100 支持模仿学习(Imitation Learning)、强化学习(RL)、视觉-语言-动作模型(VLA)等多种机器人学习范式,是学习 LeRobot 框架的理想硬件平台。

参考资料