保姆级教程:用Python手撕S-R-S七轴机器人逆解(附完整代码与避坑指南)

张开发
2026/4/16 16:58:27 15 分钟阅读

分享文章

保姆级教程:用Python手撕S-R-S七轴机器人逆解(附完整代码与避坑指南)
保姆级教程用Python手撕S-R-S七轴机器人逆解附完整代码与避坑指南七自由度机械臂的逆运动学问题一直是机器人学中的经典难题。相比六轴机械臂七轴S-R-S构型球铰-旋转副-球铰由于冗余自由度的存在使得逆解计算更加复杂。本文将带你从零开始用Python实现Shimizu论文中的逆解算法并解决实际编码中可能遇到的矩阵维度、角度单位转换等问题。1. S-R-S机械臂基础与逆解原理S-R-S构型机械臂由三个主要部分组成肩部3个旋转副构成球铰、肘部1个旋转副和腕部3个旋转副构成球铰。这种结构与人类手臂的生理结构高度相似使其在灵活性和运动范围上具有优势。关键参数定义d_bs基座到肩部的距离d_se肩部到肘部的距离d_ew肘部到腕部的距离d_wt腕部到工具点的距离由于七自由度机械臂具有冗余性我们需要引入臂角参数φ来描述这种冗余。臂角定义为由肩部、肘部和腕部组成的平面与参考平面之间的夹角。# 基础参数设置示例 Dbs 50 # 单位mm Dse 200 Dew 250 Dwt 502. 逆解计算核心步骤拆解2.1 肘关节角度计算给定末端执行器的位姿Xd07和旋转矩阵Rd07我们可以先计算腕部相对于肩部的位置Xsw0import numpy as np # 末端位姿示例 Xd07 np.array([120, 80, 50]).reshape(3, 1) Rd07 np.array([[0.707, -0.5, 0.5], [0.5, 0.866, 0], [-0.5, 0, 0.866]]) # 计算Xsw0 Lbs0 np.array([0, 0, Dbs]).reshape(3, 1) Lwt7 np.array([0, 0, Dwt]).reshape(3, 1) Xsw0 Xd07 - Lbs0 - np.matmul(Rd07, Lwt7) Xsw0_norm np.linalg.norm(Xsw0)然后利用余弦定理计算肘关节角度θ₄# 肘关节角度计算 cA4 (Xsw0_norm**2 - Dse**2 - Dew**2) / (2 * Dse * Dew) A4 np.arccos(np.clip(cA4, -1, 1)) # 使用clip防止数值误差注意实际代码中必须对反余弦函数的输入进行裁剪避免因浮点误差导致数值超出[-1,1]范围。2.2 参考关节角度计算参考关节角度是在臂角φ0时的特殊解。我们需要计算θ₂⁰参考平面下的θ₂值# 参考关节角度计算 R34 np.array([[np.cos(A4), -np.sin(A4), 0], [np.sin(A4), np.cos(A4), 0], [0, 0, 1]]) Lew4 np.array([0, 0, Dew]).reshape(3, 1) Vec Lse3 np.matmul(R34, Lew4) # 解方程求θ₂⁰ v0, v1, v2 Vec[0,0], Vec[1,0], Vec[2,0] s0, s1 Xsw0[0,0], Xsw0[1,0] b v0**2 v0*v2 v1*s1 v1**2 v2**2 - v0*v2 c v0*s0 s1*v0 v0*v1 s1*v2 v1*v2 cA20 c / b A20 np.arccos(np.clip(cA20, -1, 1))3. 完整逆解算法实现3.1 肩关节角度计算基于臂角φ我们可以计算肩关节的三个角度θ₁、θ₂和θ₃def calculate_shoulder_angles(Usw0, R030, phi): 计算肩关节角度 Usw0X np.array([[0, -Usw0[2], Usw0[1]], [Usw0[2], 0, -Usw0[0]], [-Usw0[1], Usw0[0], 0]]) As np.matmul(Usw0X, R030) Bs -np.matmul(np.matmul(Usw0X, Usw0X), R030) Cs np.matmul(np.outer(Usw0, Usw0), R030) # θ₁计算 numerator -As[1,1]*np.sin(phi) - Bs[1,1]*np.cos(phi) - Cs[1,1] denominator -As[0,1]*np.sin(phi) - Bs[0,1]*np.cos(phi) - Cs[0,1] A1 np.arctan2(numerator, denominator) # θ₂计算 A2 np.arccos(-As[2,1]*np.sin(phi) - Bs[2,1]*np.cos(phi) - Cs[2,1]) # θ₃计算 numerator As[2,2]*np.sin(phi) Bs[2,2]*np.cos(phi) Cs[2,2] denominator -As[2,0]*np.sin(phi) - Bs[2,0]*np.cos(phi) - Cs[2,0] A3 np.arctan2(numerator, denominator) return np.degrees(A1), np.degrees(A2), np.degrees(A3)3.2 腕关节角度计算腕关节的三个角度θ₅、θ₆和θ₇可以通过以下方式计算def calculate_wrist_angles(R34, As, Bs, Cs, Rd07, phi): 计算腕关节角度 R34T R34.T Aw np.matmul(np.matmul(R34T, As.T), Rd07) Bw np.matmul(np.matmul(R34T, Bs.T), Rd07) Cw np.matmul(np.matmul(R34T, Cs.T), Rd07) # θ₅计算 numerator Aw[1,2]*np.sin(phi) Bw[1,2]*np.cos(phi) Cw[1,2] denominator Aw[0,2]*np.sin(phi) Bw[0,2]*np.cos(phi) Cw[0,2] A5 np.arctan2(numerator, denominator) # θ₆计算 A6 np.arccos(Aw[2,2]*np.sin(phi) Bw[2,2]*np.cos(phi) Cw[2,2]) # θ₇计算 numerator Aw[2,1]*np.sin(phi) Bw[2,1]*np.cos(phi) Cw[2,1] denominator -Aw[2,0]*np.sin(phi) - Bw[2,0]*np.cos(phi) - Cw[2,0] A7 np.arctan2(numerator, denominator) return np.degrees(A5), np.degrees(A6), np.degrees(A7)4. 完整代码实现与优化技巧4.1 完整逆解函数将上述步骤整合为一个完整的逆解计算函数def srs_inverse_kinematics(Xd07, Rd07, phi, Dbs50, Dse200, Dew250, Dwt50): S-R-S七轴机械臂逆运动学计算 参数 Xd07: 末端位置 (3x1向量) Rd07: 末端旋转矩阵 (3x3矩阵) phi: 臂角 (弧度) Dbs, Dse, Dew, Dwt: 机械臂结构参数 返回 包含7个关节角度的numpy数组 (度) # 1. 计算肘关节角度 Lbs0 np.array([0, 0, Dbs]).reshape(3, 1) Lwt7 np.array([0, 0, Dwt]).reshape(3, 1) Xsw0 Xd07 - Lbs0 - np.matmul(Rd07, Lwt7) Xsw0_norm np.linalg.norm(Xsw0) cA4 (Xsw0_norm**2 - Dse**2 - Dew**2) / (2 * Dse * Dew) A4 np.arccos(np.clip(cA4, -1, 1)) # 2. 计算参考关节角度 Lse3 np.array([0, -Dse, 0]).reshape(3, 1) Lew4 np.array([0, 0, Dew]).reshape(3, 1) R34 np.array([[np.cos(A4), -np.sin(A4), 0], [np.sin(A4), np.cos(A4), 0], [0, 0, 1]]) Vec Lse3 np.matmul(R34, Lew4) v0, v1, v2 Vec[0,0], Vec[1,0], Vec[2,0] s0, s1 Xsw0[0,0], Xsw0[1,0] b v0**2 v0*v2 v1*s1 v1**2 v2**2 - v0*v2 c v0*s0 s1*v0 v0*v1 s1*v2 v1*v2 cA20 c / b A20 np.arccos(np.clip(cA20, -1, 1)) # 3. 计算肩关节角度 Usw0 (Xsw0 / Xsw0_norm).flatten() R030 np.array([[np.cos(A20), -np.sin(A20), 0], [np.sin(A20), np.cos(A20), 0], [0, 0, 1]]) A1, A2, A3 calculate_shoulder_angles(Usw0, R030, phi) # 4. 计算腕关节角度 A5, A6, A7 calculate_wrist_angles(R34, As, Bs, Cs, Rd07, phi) return np.array([A1, A2, A3, np.degrees(A4), A5, A6, A7])4.2 性能优化与避坑指南常见问题及解决方案矩阵维度不匹配确保所有向量都是正确的形状3x1或1x3使用reshape(3,1)或flatten()进行必要转换角度单位混淆明确区分弧度与角度使用np.radians()和np.degrees()进行转换奇异位置处理当θ₂接近0°或180°时肩部处于奇异位置添加条件判断和特殊处理逻辑关节限位处理def apply_joint_limits(angles, limits): 应用关节角度限制 limited_angles np.clip(angles, limits[:,0], limits[:,1]) return limited_angles # 关节限位示例 [min, max] (度) joint_limits np.array([ [-180, 180], # θ₁ [-90, 90], # θ₂ [-180, 180], # θ₃ [0, 180], # θ₄ [-180, 180], # θ₅ [-90, 90], # θ₆ [-180, 180] # θ₇ ])数值稳定性优化使用np.clip()限制反余弦函数的输入范围使用np.arctan2()代替np.arctan()提高角度计算精度添加小型ε值防止除以零# 数值稳定版本的向量归一化 def safe_normalize(v, eps1e-10): norm np.linalg.norm(v) if norm eps: return v return v / norm在实际项目中我发现最常出现的问题是矩阵维度不匹配和角度单位混淆。特别是在将论文中的数学公式转换为代码时保持所有中间变量的正确形状至关重要。建议在关键计算步骤后添加断言检查例如assert Xsw0.shape (3,1), fXsw0 shape error: {Xsw0.shape}另一个实用技巧是使用np.allclose()来验证旋转矩阵的正交性def is_valid_rotation(R): 检查矩阵是否是有效的旋转矩阵 return np.allclose(np.dot(R.T, R), np.eye(3), atol1e-6)

更多文章