00 机械臂基础概念:从零开始的 20 件事(加厚版)
给谁看:完全零基础、想从事"双臂运动控制算法工程师"的人。
这一版的承诺 :每个概念都做到------
① 用大白话 + 比喻 讲清原理;
② 用六轴、七轴两种机械臂的真实量级数据 代入计算(单位合理、数值可复现);
③ 每个计算都有可运行 Python (
code/00_examples.py);④ 告诉你这个知识在真实机械臂控制系统里处在哪个环节、和谁相连 ;
⑤ 点出工程坑 + 解决方案。
运行配套代码:
python3 code/00_examples.py
1. 机械臂是什么?------一条"能摆姿势的链"
1.1 原理:连杆 + 关节
想象一根根金属杆被"轴"连起来:每一根杆叫连杆(link) ,每一根轴叫关节(joint)。
- 关节转一下 → 后面的杆跟着转 → 末端(hand)就到新位置
- 整条链就像你的手臂:肩、肘、腕是关节,上臂、小臂是连杆
关节类型基本两种:
| 类型 | 像什么 | 机器人里有吗 |
|---|---|---|
| 转动关节(revolute) | 门轴、肩关节 | 几乎全是 |
| 移动关节(prismatic) | 抽屉、推杆 | 少数 |
1.2 真实数据:两种臂的"体检表"
| 参数 | 6 轴工业臂(如发那科 M-20iA 量级) | 7 轴协作臂(通用七轴量级) |
|---|---|---|
| 自由度数 | 6 | 7 |
| 最大臂展 | 约 1.8 m | 约 1.0~1.2 m |
| 额定负载 | 20 kg | 5 kg |
| 重复定位精度 | ±0.02~0.05 mm | ±0.1 mm 级 |
| 关节范围 | 一般 ±170°~±270° | 一般 ±175°~±360° |
| 工作环境 | 隔离护栏 | 人机协作(柔顺 + 碰撞检测) |
注意"负载--臂展--精度"的三角跷跷板:负载越大、臂展越长,末端精度越低------因为关节误差会沿臂展逐级放大。
1.3 在你系统里:它连接哪
机械臂本体只是"肌肉 + 骨架",真正驱动它的是后端一条链:伺服驱动器 → EtherCAT → ros2_control → MoveIt2。本节的"链"是物理链,第 8 节的"控制链"才是灵魂。
1.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 负载超限 | 电机过流、减速机异响、精度下降 | 按"额定负载×安全系数"选型;URDF 里如实填惯量 |
| 关节限位 | 机械限位撞停(硬停伤机) | 设软限位(控制器内 ±limit),规划前检查 |
2. 自由度(DOF):机械臂有"几个动作"
2.1 原理:为什么是 6 个
一个刚体在空间里能做的独立运动有 6 种 :前后、左右、上下(3 个平移)+ 绕这三根轴各转一下(3 个转动)。这 6 种独立运动就叫 6 个自由度。
- 6 轴:6 个关节,刚够让末端到达"任意位置、任意朝向"------刚好够用
- 7 轴 :7 个关节,比"刚好"多 1 个。多出的叫冗余(redundancy)
2.2 真实数据带入:6 轴和 7 轴到底差在哪个"1"
用**空间雅可比(6 行:位置 3 + 姿态 3)**看零空间维数(代码见示例3):
6 轴: 雅可比 6×6, 奇异值≈[1.83 1.71 1.07 0.47 0.29 0.04], 零空间维数 = 0
7 轴: 雅可比 6×7, 奇异值≈[2.21 1.86 1.07 0.51 0.42 0.14], 零空间维数 = 1
↑ 零空间方向: 沿它动关节, J·v_null ≈ 0 → 末端完全不动, 但手臂姿势在变!
白话翻译:
- 6 轴:末端"钉住"在某个位置 + 姿态 → 手臂姿势只有一种(想换姿势必须先挪末端)
- 7 轴:末端钉住 → 手臂还能在零空间里自由调整姿势(肘部可抬高放低)
这第 1 个冗余自由度,就是七轴"绕障碍、躲关节限位、让手腕更灵活"的数学根源。
2.3 在你系统里:它连接哪
- MoveIt2 的
kinematics.yaml里kinematic_solver(KDL/IKFast 等)求解时,冗余让同一目标位姿有无穷多关节解,规划器从中挑满足"避障/限位/接近当前"的那个。 - MoveIt 的实时伺服(servo)也在用零空间:比如"末端不动、肘部自动绕开障碍"。
2.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 冗余导致"解不唯一" | IK 每次算出不同姿势,轨迹不连续 | IK 带"接近上一帧初值"约束;或加零空间优化项 |
| 奇异附近 | 某个方向"够不动",关节速度爆表 | 阻尼伪逆(02 篇)、规划时回避奇异 |
| 自运动撞软限位 | 末端不动但某关节到限位 | 零空间投影加"躲限位"梯度项 |
3. 坐标系:机器人是怎么"知道"自己在哪的
3.1 原理
机器人只有每个关节转了多少度 (编码器读数)。要把"关节角"翻译成"手在哪里",需要统一的"地图"------坐标系。
| 术语 | 一句话解释 |
|---|---|
| 基座坐标系 | 机器人"世界原点",在底座,一切位置的参照 |
| 末端坐标系 | 最后关节(法兰)上的小坐标系,跟着手走 |
| 工具坐标系(TCP) | 工具尖(如喷码头出墨口、贴标头) |
| 世界坐标系 | 机器人所在房间的绝对坐标 |
3.2 真实数据带入:法兰 → 工具尖(TCP)坐标变换
场景:机器人拿喷码工具,工具尖沿法兰 Z 方向伸出 150 mm,末端绕基座 Z 轴转了 30°(示例4):
法兰位置(基座系) = (0.600, 0.200, 0.350) m
旋转矩阵 R = Rz(30°)
工具偏移(法兰系) t = (0, 0, 0.150) m
TCP = p_flange + R·t = (0.600, 0.200, 0.350+0.150) = (0.600, 0.200, 0.500) m
这里工具沿法兰 Z,所以 TCP 的 x、y 不变,z 加 150 mm。
若工具是斜的(比如喷头偏 45°),TCP 的 x、y 也会变------这就是必须精确标定 TCP 的原因。
3.3 在你系统里:它连接哪
- URDF 的 TF 树 就是一连串这样的变换:
base_link → link1 → ... → tool_link → tcp_link - MoveIt2 里"工具坐标原点"(
planning_group的 end-effector / TCP frame)就对应这里的 TCP - 手眼标定时,"相机看到的工件位置"(相机系)也要经相机→基座变换到基座系,才能指挥机器人去抓
3.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| TCP 标定不准 | 喷码/贴标位置偏几 mm | "四点标定法"(工具尖对同一点,四姿态求 TCP) |
| 工具重量没写进 URDF | 力矩/动力学算错 | 把末端工具的适配器质量/质心补进 URDF |
| TF 树断层 | MoveIt 报 tf2 找不到 transform |
检查 robot_state_publisher 是否在发全部 TF |
4. 正运动学 vs 逆运动学:两个方向的问题
4.1 原理
| 问题 | 术语 | 例子 |
|---|---|---|
| 已知关节角 → 末端在哪? | 正运动学(FK) | 每个关节 30°,手在哪? |
| 已知末端要去哪 → 每个关节该转多少? | 逆运动学(IK) | 手要碰杯子,各关节几度? |
- FK:简单、唯一答案(按公式算)
- IK:难、可能多解(七轴甚至无穷多解)
4.2 真实数据带入 1:FK(2 连杆平面臂,示例1)
肩到肘 0.50 m、肘到腕 0.40 m;q1=30°,q2=-45°:
x = L1·cos(q1) + L2·cos(q1+q2) = 0.50·cos30° + 0.40·cos(-15°) ≈ 0.8194 m
y = L1·sin(q1) + L2·sin(q1+q2) = 0.50·sin30° + 0.40·sin(-15°) ≈ 0.1465 m
末端离基座 0.832 m(臂展最大 0.90 m,物理合理)
4.3 真实数据带入 2:IK(同一目标,两个解,示例2)
目标让末端到 (0.60, 0.30) m:
解A(肘下): q1 ≈ -9.83°, q2 ≈ +84.26° → 验证末端 (0.600, 0.300) ✓
解B(肘上): q1 ≈ +62.96°, q2 ≈ -84.26° → 验证末端 (0.600, 0.300) ✓
两个解都能到达同一个点! 六轴在三维空间通常有 8 个解(肩左右 / 肘上下 / 腕翻转),七轴在此基础上还有一整个"连续解空间"(自运动流形)。
4.4 在你系统里:它连接哪
- MoveIt2 IK:
kinematics.yaml里的求解器(KDL/IKFast)、position_only_ik - FK 主要用于显示当前状态 (RViz、TF 发布);IK 用于给目标位姿找关节解,再交给轨迹规划
4.5 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| IK 解不唯一导致"跳" | 同一目标有时这个姿势、有时那个姿势 | 用"接近当前关节角"的初值 + 关节空间连续约束 |
| IK 无解 | 目标位姿够不着 | 检查工作空间;减小姿态约束(先到位再转头) |
| 奇异 | 末端要动但关节"够不动" | 阻尼伪逆;规划时避开奇异流形 |
5. 位形空间:把机器人"压扁"成一个点
5.1 原理
把 7 个关节角写成 7 个数,比如 (30°, -20°, 45°, ...)------这组数决定一个姿势,就是7 维空间里的一个点。
- 机器人的每个姿势 = 7 维空间一个点
- 姿势 A → B = 在 7 维空间画一条线
- 墙、桌子、自己另一只手 = 空间里"被挖掉"的禁区(障碍区 ),剩下的叫自由空间
5.2 真实数据带入:为什么说"避障"在高维里很难
把每个关节量化为 100 格:
6 轴: 100^6 = 10^12 个格点
7 轴: 100^7 = 10^14 个格点
不只是翻倍------是指数级爆炸(维数灾难)。所以不能靠"把空间切碎、一格一格检查"来规划,必须靠采样/搜索算法(04 篇)。
5.3 在你系统里:它连接哪
- MoveIt2 的
PlanningScene+ FCL 碰撞检测,就是在每个候选姿势上做"这个点是不是禁区"的检查 - MoveIt 的实时伺服(servo)的碰撞保护:实时算"下一帧姿势会不会撞",撞就减速/停
5.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 碰撞检测太慢 | 规划要几秒 | 先用包围盒/球粗判,再精确网格细判 |
| 点云太密 | 每帧塞几千上万点,卡死 | 降采样 + 膨胀成障碍体再进 PlanningScene |
| 自碰撞没开 | 手臂自己撞自己 | 打开自碰撞矩阵(SRDF 里定义) |
6. 路径规划 vs 轨迹规划:两个容易混的概念
6.1 原理
| 术语 | 关心什么 | 类比 |
|---|---|---|
| 路径规划 | "走哪条线"(几何路线) | 从家到公司选哪条路 |
| 轨迹规划 | "每个时刻到哪、速度多快"(加时间) | 每段路开多快、什么时候刹车 |
工程顺序:先规划路径 → 再配时间。这一小步"配时间"就是 03 篇(TOPP 时间最优参数化)。
6.2 真实数据带入:一条"路径"配上时间变成"轨迹"(示例5)
关节从 0° 转到 90°,用时 2 秒,起止静止(五次多项式,保证速度、加速度连续):
时间t 角度q(deg) 角速度(deg/s)
0.0s 0.00 0.00 ← 静止出发
0.5s 9.32 47.46
1.0s 45.00 84.38 ← 峰值速度约 84°/s
1.5s 80.68 47.46
2.0s 90.00 0.00 ← 平滑停住
如果速度曲线有"折角"(不连续)→ 加速度突变 → 机械臂"咯噔"一下、机构磨损、振动。
6.3 在你系统里:它连接哪
- MoveIt2 生成轨迹后交给
trajectory_controller(JTC)逐点下发 - MoveIt 的实时伺服(servo)是"实时版":不预规划,边看边算,但仍要输出平滑的速度指令
6.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 轨迹太"陡" | 电机过流/振动 | 加速度限制 + 轨迹平滑(低通/五次多项式) |
| 时间配错 | 伺服跟不上目标 → 跟踪误差大 | TOPP 按电机速度/加速度/力矩上限配时间 |
| 抖动 | 贴标/喷码轨迹抖 | 加 jerk(加加速度)限制 |
7. 运动学 vs 动力学:一个问"到哪",一个问"多大力"
7.1 原理
| 学科 | 问的问题 | 比喻 |
|---|---|---|
| 运动学 | 姿势怎么摆、速度怎么变(不管力) | 画路线的形状 |
| 动力学 | 要多大的力/力矩才能做到(管力) | 算爬坡要踩多深油门 |
- 运动学:
关节角 → 位置/速度,纯几何 - 动力学:
力/力矩 → 加速度,要算质量、惯性、重力
7.2 真实数据带入:抱 5 kg 工件,肩关节要多少力矩(示例6)
静态: τ = m·g·d = 5×9.81×0.6 = 29.4 N·m (工件质心距肩 0.6 m)
动态: 若末端还要以 1 m/s² 上升
τ = m·(g+a)·d = 5×(9.81+1)×0.6 = 32.4 N·m ← 多 3 N·m(10%)
- 六/七轴伺服额定力矩有上限(七轴协作臂肩部约 100 N·m 量级,腕部小得多约 10~20 N·m)
- 抓 5 kg 用腕部硬扛 29 N·m?腕部额定不够 → 报过流 → 这就是先算动力学、避免超载的意义
- 结论:运动学只能告诉你"到不到得了",动力学才能告诉你"带不带动、会不会烧"
7.3 在你系统里:它连接哪
- 位置模式下(关节轨迹控制器 JTC + CiA402 CSP)动力学是"隐含"的(伺服自己扛)
- 一旦上力矩模式(CiA402 CST)或导纳/阻抗控制,你就必须提供动力学(05 篇 RNEA/ABA),否则机器人会"发飘"或"抖"
7.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 模型参数不准 | 力矩模式跟踪差、姿态一变就抖 | 动力学参数辨识(05/08 篇) |
| 摩擦没建模 | 低速时"一顿一顿" | 加库仑/粘滞摩擦模型 |
| 负载变化 | 抓 0.1kg 和 5kg 手感差异大 | 实时估计负载质量,前馈更新 |
8. 控制分层:机器人是怎么"走稳"的
8.1 原理:四层指挥链
最上层 轨迹/算法(决定去哪、多快) 频率最低(几十~几百 Hz)
↓ 位置环(让关节到指定角度) 较高(几百 Hz~1kHz)
↓ 速度环(控制关节转动快慢)
↓ 电流环(输出电流=力矩,最底层) 最高(1kHz+,在驱动器里)
- 越往下越接近"电",响应越快
- 算法工程师主要管最上层:给下面的环"目标位置/速度"
- 记住:算法决定"去哪",控制环决定"能不能稳",动力学决定"能不能带动"
8.2 真实数据带入:各层频率与端到端时延预算(示例7)
| 层 | 频率 | 单周期 |
|---|---|---|
| MoveIt 规划/轨迹生成 | 10~50 Hz | 20~100 ms |
| MoveIt 实时伺服 | 250~1000 Hz | 1~4 ms |
| ros2_control 控制器(位置环) | 250~1000 Hz | 1~4 ms |
| EtherCAT 总线周期 | 1000~4000 Hz | 0.25~1 ms |
最坏路径 :规划(50Hz→20ms) + servo(→4ms) + 控制(→4ms) + 总线(1ms) ≈ 26 ms 。
也就是说:从"决定要动"到"电机真动了"最快也约 26 ms------遥操作、安全急停都要按这个量级设计。
8.3 在你系统里:它连接哪
controller_manager250 Hz 驱动 JTC 和导纳控制器- 常见驱动模式 CiA402 CSP(位置环在驱动器内),所以关节轨迹控制器只管"发目标位置"
- 一旦切 CST(力矩模式),电流环 / 力矩环就在 ros2_control 侧闭环,实时性要求更高
8.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 周期抖动(jitter) | 轨迹跟踪时好时坏 | 用 RT 线程 + 锁内存;确保每周期算完 |
| 上层频率太低 | 伺服吃不到平滑目标 → 步进感 | servo 层插值/滤波(MoveIt servo 已做) |
| 同步丢失 | 多轴不同步 → 末端扭曲 | 检查 EtherCAT 从站状态、DC 分布式时钟 |
9. 机器人软件栈:一套系统的四层架构
9.1 原理
| 层 | 干什么 | 对应你系统里的东西 |
|---|---|---|
| 建模层 | 描述机器人长什么样 | URDF/SRDF(连杆、关节、惯量、规划组) |
| 规划层 | 想清楚怎么动 | MoveIt2(运动学 + 路径/轨迹 + 避障) |
| 控制层 | 把"目标"变成"命令" | ros2_control(JTC、导纳控制器) |
| 驱动层 | 真正输出电信号 | EtherCAT + 伺服驱动器(CiA402 协议) |
9.2 真实数据流:一次"喷码"任务怎么跑下来
相机检测工件位姿(视觉位姿估计模块)
→ MoveIt2: 末端到喷码点(规划 ~20~100ms) [规划层]
→ 生成轨迹 → JTC 逐点下发(250Hz) [控制层]
→ CiA402 CSP 位置命令 → EtherCAT(1ms) [驱动层]
→ 伺服驱动电机 → 编码器读数回传
→ 若碰撞/力异常 → 导纳/急停接管
9.3 在你系统里:它连接哪
- URDF:机器人"体检报告"------每根连杆多重、关节能转多少度
- SRDF :规划配置------
planning_group(哪个关节属于手臂)、TCP 帧、自碰撞矩阵 - ros2_control yaml :控制器列表 + 频率 + 接口(
joint_trajectory_controller/admittance_controller) - MoveIt 实时伺服(servo):"大脑的实时模式"------不预规划,按你推的方向现场算着走(示教、遥操)
9.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| URDF 与实物不一致 | 规划到位但实物差几 cm | 逐连杆核对 URDF 尺寸 + 实测验证 |
| 频率不匹配 | 上层 50Hz、下层 250Hz 对接不顺 | 确认 controller_manager update_rate 与发送端一致 |
| 控制器切换 | JTC ↔ 导纳切换时"猛跳" | 用柔顺过渡(目标值从当前值起步) |
10. 六轴 vs 七轴 vs 双臂:岗位里的关键词
10.1 原理
| 形态 | 特点 | 岗位上的意义 |
|---|---|---|
| 6 轴 | 经典工业臂,IK 一般有固定解 | 单一、确定性任务 |
| 7 轴 | 多 1 个冗余,末端不动也能"自我调整" | 避障、绕限位、更灵活 |
| 双臂 | 两臂 + 抓同一物体 = 闭链,互相约束 | 搬运、装配、人机协作------需要"协同控制" |
10.2 真实数据带入:双臂为什么会"较劲"(内力)
双臂抱 10 kg 物体时,若左臂想快 5 mm/s、右臂按计划走,两末端相对位置就会错开 → 物体被"拉":
例: 物体质量 10 kg → 重力 Fg = 10×9.81 ≈ 98 N(由两臂竖直分量分担)
若两臂水平方向互相挤压 30 N → 内力 F_int = 30 N(物体本身没动,但机构在"较劲")
内力 = 合力之外、被闭链"锁死"的那部分力(挤压/拉扯)
运动学 只能看到"两末端位置";力学才看得到"两臂之间那股互相较劲的力"。这就是 09/10 篇的核心(相对雅可比 + 内力分解)。
10.3 在你系统里:它连接哪
- 两个
planning_group或一个 14 关节联合规划组 + SRDF 自碰撞矩阵 - 双臂协作时需要 F/T 传感器(测内力)+ CST 力矩模式(10 篇硬件基础)
10.4 工程坑 & 方案
| 坑 | 现象 | 方案 |
|---|---|---|
| 两臂不同步 | 物体被拉扯/扭曲 | 时间同步(统一轨迹时间轴)+ 相对位姿约束 |
| 内力过大 | 物体压坏/机构过载 | 内力闭环(F/T 反馈,10 篇) |
| 双臂自碰撞 | 两手在空中打架 | 14 维联合规划 + 自碰撞矩阵 |
11. 术语速查表(看到不懂就回来查)
| 术语 | 一句话解释 | 常见单位 |
|---|---|---|
| 关节角 | 每个关节转的角度,机器人"原始语言" | rad / ° |
| 位姿(Pose) | 位置 + 姿态,共 6 个自由度 | m + rad |
| TCP | 工具尖端,机器人的"笔尖" | m |
| 正/逆运动学 | FK=关节角算手位置;IK=手位置算关节角 | --- |
| 雅可比 J | 关节速度→末端速度的矩阵;看"没劲"方向 | --- |
| 奇异 | 某个方向"卡死"的姿势 | --- |
| 冗余 | 自由度比任务多出的部分 | --- |
| 位形空间 | 一个姿势=一个点的高维空间 | rad |
| 轨迹 | 带时间的运动计划(位置/速度/加速度) | s |
| 阻抗/导纳控制 | 让机器人"柔软":受力会退让 | --- |
| 力矩 | 转动的"力气",驱动器最终输出 | N·m |
| 闭环 | 看目标与实际之差再纠正,稳定性来源 | --- |
| 实时(RT) | 每固定时间必须算完,不能迟到 | s |
| 动量观测器 | 用模型"猜"外力(碰撞/拖动检测) | N·m |
| 零空间 | 不影响末端运动的关节运动(冗余的数学外壳) | --- |
12. 这一套 01-10 到底在教你什么(学习地图预告)
00 概念(本页) ─► 01 数学(翻译工具) ─► 02 运动学(手怎么摆)
│
┌──────────────────┤
▼ ▼
03 轨迹规划(怎么走) 04 路径规划(走哪条路)
└──────┬───────────┘
▼
05 动力学(要多大力)
▼
06 运动控制(让力去执行) ─► 07 最优控制(怎么最优)
│
▼
08 状态估计与遥操作(怎么感知、怎么远程指挥)
│
▼
09 双臂协同(两臂怎么配合) ─► 10 双臂操纵(抓得稳)
下一篇:01_数学基础.md------机器人的数学语言:坐标、旋转、矩阵。