在机械臂点位补偿调试中我们经常会遇到一个看似反直觉的问题明明只是调整了Rx倾斜角为什么在 Web 示教器里切换Base和Tool后末端姿态变化效果完全不一样根本原因是Base.Rx和Tool.Rx虽然都叫Rx但它们绕的不是同一根轴。1. 问题背景在工件模板的二号工位机械臂点位补偿中我们希望对加工点位做三类补偿ΔZ 到位高度补偿 ΔRx 倾斜角补偿 ΔJ6 第六轴水平补偿最初的实现方式是直接修改 TCP 姿态中的RxcartesianTarget.Rx compensation.TiltAngleDeg;这看起来像是在“绕 X 轴旋转”但现场测试时发现它的效果更像 Tool 坐标系下的旋转而不是我们想要的 Base 坐标系下的旋转。2. Base 坐标系和 Tool 坐标系的区别机械臂中常见的两个坐标系Base 坐标系 机器人基座坐标系固定不动。 Tool 坐标系 工具坐标系跟随当前 TCP 姿态一起运动。可以这样理解Base 坐标系像地面坐标 Tool 坐标系像工具自己身上的坐标。图示Base 坐标系固定不动 Z ↑ | | o --------→ X / / Y而 Tool 坐标系会随着末端姿态变化当前 TCP 姿态 Tool-Z ↑ / / Tool-X ← TCP \ → Tool-Y所以Base 下 Rx 绕固定的 Base-X 轴旋转。 Tool 下 Rx 绕当前工具自身的 Tool-X 轴旋转。这两个旋转轴在工具姿态发生变化后通常并不重合因此最终效果必然不同。3. 为什么不能简单写 Rx ΔRx很多人会直觉地认为pose.Rx delta;就等价于绕 X 轴旋转 delta 度但这并不严谨。Rx / Ry / Rz是姿态矩阵的一种欧拉角表达方式。欧拉角不是三个彼此独立的线性分量。直接修改某一个欧拉角字段可能会受到控制器姿态定义、旋转顺序、当前姿态以及逆解算法的影响。也就是说直接改 Rx 数值 ≠ 严格意义上的 Base 坐标系 X 轴旋转因此下面这种写法并不能稳定表达“Base 下 Rx 旋转”cartesianTarget.Rx compensation.TiltAngleDeg;4. 正确表达 Base 下 Rx矩阵左乘如果我们希望明确表示绕 Base 坐标系 X 轴旋转 ΔRx应该使用旋转矩阵计算。核心公式是R_final R_base_x_delta × R_current其中R_current 当前 TCP 姿态对应的旋转矩阵 R_base_x_delta Base 坐标系下绕 X 轴旋转 ΔRx 的旋转矩阵 R_final 补偿后的最终姿态矩阵关键点是左乘 Base 坐标系旋转 右乘 Tool 坐标系旋转也就是说Base 下旋转 R_final R_base_x_delta × R_currentTool 下旋转 R_final R_current × R_tool_x_delta两者顺序不同含义完全不同。5. 补偿流程对比旧逻辑原始关节 ↓ 原始关节 ΔJ6 ↓ 正解 当前 TCP 姿态 Rx/Ry/Rz ↓ Rx Rx ΔRx ↓ 逆解 最终执行关节旧逻辑的问题是直接修改 Rx 欧拉角不严格等价于 Base-X 旋转。新逻辑原始关节 ↓ 原始关节 ΔJ6 ↓ 正解 当前 TCP 姿态 R_current ↓ 构造 Base-X 旋转矩阵 R_base_x_delta ↓ R_final R_base_x_delta × R_current ↓ R_final 转回 Rx/Ry/Rz ↓ 逆解 最终执行关节新逻辑的含义更明确ΔRx 一定表示 Base 坐标系下绕 X 轴的倾斜补偿。6. 代码实现思路核心调用ApplyBaseCoordinateRxTilt(cartesianTarget, compensation.TiltAngleDeg);而不是cartesianTarget.Rx compensation.TiltAngleDeg;核心实现逻辑private static void ApplyBaseCoordinateRxTilt(RobotArmPosition pose, double angleDeg) { if (pose null || Math.Abs(angleDeg) 1e-9) { return; } double[,] currentRotation BuildRotationMatrixFromRpy( pose.Rx, pose.Ry, pose.Rz); double[,] baseRxRotation BuildBaseRxRotationMatrix(angleDeg); double[,] finalRotation MultiplyRotationMatrix( baseRxRotation, currentRotation); (pose.Rx, pose.Ry, pose.Rz) ConvertRotationMatrixToRpy(finalRotation); }重点是这行double[,] finalRotation MultiplyRotationMatrix( baseRxRotation, currentRotation);这里是左乘。如果写成currentRotation × baseRxRotation含义就变成了 Tool 坐标系下的局部旋转。7. 为什么最终 J1~J6 仍然会联动变化即使我们定义的是 Base 下ΔRx最终执行仍然要经过逆解最终 TCP 姿态 ↓ 逆解 最终 J1~J6因此最终关节角可能会发生联动变化。这不是错误而是机械臂逆解的正常结果。也就是说ΔRx 定义的是 TCP 姿态补偿方向 J1~J6 是控制器为达到该 TCP 姿态解出来的关节结果。所以我们不能用“J6 有没有变化”来判断ΔRx是否正确。更应该看最终 TCP 姿态是否符合 Base-X 倾斜补偿的预期。8. 最终补偿语义当前二号工位点位补偿语义可以定义为ΔZ 加工到位高度补偿。 ΔRx Base 坐标系下绕 X 轴的倾斜角补偿。 ΔJ6 关节空间下第六轴水平补偿。对应流程1. 原始示教点 2. 原始关节 ΔJ6 3. 正解得到当前 TCP 4. 在 Base 坐标系下叠加 ΔZ / ΔRx 5. 逆解得到最终执行关节 6. 下发最终点位图示原始示教点 │ ▼ 原始关节 ΔJ6 │ ▼ 正解得到当前 TCP 姿态 │ ▼ Base 坐标系下叠加 ΔZ / ΔRx │ ▼ 逆解得到最终关节 J1~J6 │ ▼ 执行最终点位9. 结论如果业务要求的是在 Base 坐标系下调整倾斜角那么不能简单地写pose.Rx delta;而应该使用矩阵左乘R_final R_base_x_delta × R_current这样才能明确表达绕固定 Base-X 轴旋转而不是绕当前 Tool-X 轴旋转这也是机器人点位补偿中区分 Base / Tool 坐标系的关键。
机器人点位补偿中 Base 坐标系 Rx 与 Tool 坐标系 Rx 的区别
发布时间:2026/6/26 17:53:30
在机械臂点位补偿调试中我们经常会遇到一个看似反直觉的问题明明只是调整了Rx倾斜角为什么在 Web 示教器里切换Base和Tool后末端姿态变化效果完全不一样根本原因是Base.Rx和Tool.Rx虽然都叫Rx但它们绕的不是同一根轴。1. 问题背景在工件模板的二号工位机械臂点位补偿中我们希望对加工点位做三类补偿ΔZ 到位高度补偿 ΔRx 倾斜角补偿 ΔJ6 第六轴水平补偿最初的实现方式是直接修改 TCP 姿态中的RxcartesianTarget.Rx compensation.TiltAngleDeg;这看起来像是在“绕 X 轴旋转”但现场测试时发现它的效果更像 Tool 坐标系下的旋转而不是我们想要的 Base 坐标系下的旋转。2. Base 坐标系和 Tool 坐标系的区别机械臂中常见的两个坐标系Base 坐标系 机器人基座坐标系固定不动。 Tool 坐标系 工具坐标系跟随当前 TCP 姿态一起运动。可以这样理解Base 坐标系像地面坐标 Tool 坐标系像工具自己身上的坐标。图示Base 坐标系固定不动 Z ↑ | | o --------→ X / / Y而 Tool 坐标系会随着末端姿态变化当前 TCP 姿态 Tool-Z ↑ / / Tool-X ← TCP \ → Tool-Y所以Base 下 Rx 绕固定的 Base-X 轴旋转。 Tool 下 Rx 绕当前工具自身的 Tool-X 轴旋转。这两个旋转轴在工具姿态发生变化后通常并不重合因此最终效果必然不同。3. 为什么不能简单写 Rx ΔRx很多人会直觉地认为pose.Rx delta;就等价于绕 X 轴旋转 delta 度但这并不严谨。Rx / Ry / Rz是姿态矩阵的一种欧拉角表达方式。欧拉角不是三个彼此独立的线性分量。直接修改某一个欧拉角字段可能会受到控制器姿态定义、旋转顺序、当前姿态以及逆解算法的影响。也就是说直接改 Rx 数值 ≠ 严格意义上的 Base 坐标系 X 轴旋转因此下面这种写法并不能稳定表达“Base 下 Rx 旋转”cartesianTarget.Rx compensation.TiltAngleDeg;4. 正确表达 Base 下 Rx矩阵左乘如果我们希望明确表示绕 Base 坐标系 X 轴旋转 ΔRx应该使用旋转矩阵计算。核心公式是R_final R_base_x_delta × R_current其中R_current 当前 TCP 姿态对应的旋转矩阵 R_base_x_delta Base 坐标系下绕 X 轴旋转 ΔRx 的旋转矩阵 R_final 补偿后的最终姿态矩阵关键点是左乘 Base 坐标系旋转 右乘 Tool 坐标系旋转也就是说Base 下旋转 R_final R_base_x_delta × R_currentTool 下旋转 R_final R_current × R_tool_x_delta两者顺序不同含义完全不同。5. 补偿流程对比旧逻辑原始关节 ↓ 原始关节 ΔJ6 ↓ 正解 当前 TCP 姿态 Rx/Ry/Rz ↓ Rx Rx ΔRx ↓ 逆解 最终执行关节旧逻辑的问题是直接修改 Rx 欧拉角不严格等价于 Base-X 旋转。新逻辑原始关节 ↓ 原始关节 ΔJ6 ↓ 正解 当前 TCP 姿态 R_current ↓ 构造 Base-X 旋转矩阵 R_base_x_delta ↓ R_final R_base_x_delta × R_current ↓ R_final 转回 Rx/Ry/Rz ↓ 逆解 最终执行关节新逻辑的含义更明确ΔRx 一定表示 Base 坐标系下绕 X 轴的倾斜补偿。6. 代码实现思路核心调用ApplyBaseCoordinateRxTilt(cartesianTarget, compensation.TiltAngleDeg);而不是cartesianTarget.Rx compensation.TiltAngleDeg;核心实现逻辑private static void ApplyBaseCoordinateRxTilt(RobotArmPosition pose, double angleDeg) { if (pose null || Math.Abs(angleDeg) 1e-9) { return; } double[,] currentRotation BuildRotationMatrixFromRpy( pose.Rx, pose.Ry, pose.Rz); double[,] baseRxRotation BuildBaseRxRotationMatrix(angleDeg); double[,] finalRotation MultiplyRotationMatrix( baseRxRotation, currentRotation); (pose.Rx, pose.Ry, pose.Rz) ConvertRotationMatrixToRpy(finalRotation); }重点是这行double[,] finalRotation MultiplyRotationMatrix( baseRxRotation, currentRotation);这里是左乘。如果写成currentRotation × baseRxRotation含义就变成了 Tool 坐标系下的局部旋转。7. 为什么最终 J1~J6 仍然会联动变化即使我们定义的是 Base 下ΔRx最终执行仍然要经过逆解最终 TCP 姿态 ↓ 逆解 最终 J1~J6因此最终关节角可能会发生联动变化。这不是错误而是机械臂逆解的正常结果。也就是说ΔRx 定义的是 TCP 姿态补偿方向 J1~J6 是控制器为达到该 TCP 姿态解出来的关节结果。所以我们不能用“J6 有没有变化”来判断ΔRx是否正确。更应该看最终 TCP 姿态是否符合 Base-X 倾斜补偿的预期。8. 最终补偿语义当前二号工位点位补偿语义可以定义为ΔZ 加工到位高度补偿。 ΔRx Base 坐标系下绕 X 轴的倾斜角补偿。 ΔJ6 关节空间下第六轴水平补偿。对应流程1. 原始示教点 2. 原始关节 ΔJ6 3. 正解得到当前 TCP 4. 在 Base 坐标系下叠加 ΔZ / ΔRx 5. 逆解得到最终执行关节 6. 下发最终点位图示原始示教点 │ ▼ 原始关节 ΔJ6 │ ▼ 正解得到当前 TCP 姿态 │ ▼ Base 坐标系下叠加 ΔZ / ΔRx │ ▼ 逆解得到最终关节 J1~J6 │ ▼ 执行最终点位9. 结论如果业务要求的是在 Base 坐标系下调整倾斜角那么不能简单地写pose.Rx delta;而应该使用矩阵左乘R_final R_base_x_delta × R_current这样才能明确表达绕固定 Base-X 轴旋转而不是绕当前 Tool-X 轴旋转这也是机器人点位补偿中区分 Base / Tool 坐标系的关键。