腿部与步态 第3课/共30课

🤖 正逆运动学

3D空间中的腿部运动学:从关节角到足端位置

🧭 从2D到3D

上一课我们学习了2连杆平面运动学。实际的四足机器人每条腿有3个关节,需要在3D空间中求解运动学。3D运动学的核心是在2R(2连杆)基础上增加髋横滚关节。

3-DOF腿的坐标变换链:

Pfoot = Tbody→hip · Rhip_roll · Thip→knee · Rhip_pitch · Tknee→ankle · Rknee_pitch · Plocal

📐 3D正运动学推导

将3D运动学分解为两个步骤:

步骤1:髋横滚 → 膝关节位置

髋横滚关节使整条腿侧向偏转:

knee_y = hip_y + s·Lhip·cos(qhip)
knee_z = hip_z - Lhip·sin(qhip)

其中 s = +1(左腿)或 -1(右腿)

步骤2:在矢状面内2R运动学

与上一课相同,只是参考点变成了膝关节:

foot_x = hip_x + Lthigh·sin(qthigh) + Lcalf·sin(qthigh + qcalf)
foot_z = knee_z - Lthigh·cos(qthigh) - Lcalf·cos(qthigh + qcalf)

🔄 3D逆运动学

逆运动学按相反顺序求解:

Step 1: 从足端y坐标求髋横滚角

qhip = arcsin(−s·(foot_z − hip_z) / Lhip)

Step 2: 在矢状面内2R逆运动学

与2D情况相同,使用余弦定理

⚠️ 3D逆运动学的特殊性:由于髋横滚改变了腿平面的朝向,需要先将足端位置投影到腿平面内,再进行2R求解。

🏠 站立姿态计算

站立姿态是最基本的配置。给定期望站立高度h,计算各关节角度:

qhip = 0(腿竖直向下)
qthigh, qcalf: 由 2R IK 根据高度 h 求解

🧮 仿真:3D运动学

import math class QuadrupedKinematics3D: def __init__(self, body_L=0.4, body_W=0.2, L_hip=0.04, L_thigh=0.15, L_calf=0.15): self.body_L = body_L self.body_W = body_W self.L_hip = L_hip self.L_thigh = L_thigh self.L_calf = L_calf self.hip_offsets = { 'LF': ( body_L/2, body_W/2, 0), 'RF': ( body_L/2, -body_W/2, 0), 'LB': (-body_L/2, body_W/2, 0), 'RB': (-body_L/2, -body_W/2, 0), } self.hip_signs = {'LF': 1, 'RF': -1, 'LB': 1, 'RB': -1} def forward_kinematics(self, leg_name, q_hip, q_thigh, q_calf): hx, hy, hz = self.hip_offsets[leg_name] sign = self.hip_signs[leg_name] knee_y = hy + sign * self.L_hip * math.cos(q_hip) knee_z = hz - self.L_hip * math.sin(q_hip) knee_x = hx ankle_x = knee_x + self.L_thigh * math.sin(q_thigh) ankle_z = knee_z - self.L_thigh * math.cos(q_thigh) ankle_y = knee_y foot_x = ankle_x + self.L_calf * math.sin(q_thigh + q_calf) foot_z = ankle_z - self.L_calf * math.cos(q_thigh + q_calf) foot_y = ankle_y return (foot_x, foot_y, foot_z) def inverse_kinematics(self, leg_name, foot_pos): fx, fy, fz = foot_pos hx, hy, hz = self.hip_offsets[leg_name] sign = self.hip_signs[leg_name] dy = fy - hy q_hip = math.asin(max(-1, min(1, -sign * (fz - hz) / self.L_hip if abs(fz-hz) < self.L_hip else 0))) knee_y = hy + sign * self.L_hip * math.cos(q_hip) knee_z = hz - self.L_hip * math.sin(q_hip) dx = fx - hx dz = -(fz - knee_z) d = math.sqrt(dx**2 + dz**2) cos_q_calf = (d**2 - self.L_thigh**2 - self.L_calf**2) / (2*self.L_thigh*self.L_calf) cos_q_calf = max(-1, min(1, cos_q_calf)) q_calf = math.acos(cos_q_calf) alpha = math.atan2(dx, dz) beta = math.atan2(self.L_calf * math.sin(q_calf), self.L_thigh + self.L_calf * math.cos(q_calf)) q_thigh = alpha - beta return q_hip, q_thigh, q_calf def standing_pose(self, height=0.2): poses = {} for leg in self.hip_offsets: hx, hy, _ = self.hip_offsets[leg] foot_pos = (hx, hy, -height) try: q = self.inverse_kinematics(leg, foot_pos) poses[leg] = q except: poses[leg] = (0, 0, 0) return poses robot = QuadrupedKinematics3D() print("=" * 55) print(" 3D Forward/Inverse Kinematics Simulation") print("=" * 55) print(f" Body: {robot.body_L}m x {robot.body_W}m") print(f" Hip rod: {robot.L_hip}m, Thigh: {robot.L_thigh}m, Calf: {robot.L_calf}m") print() print(" [3D Forward Kinematics Test]") test_poses = [ ('LF', 0, 0, 0.5), ('LF', 0, 0.3, 0.8), ('RF', 0.2, 0, 0.5), ('LB', -0.2, -0.3, 1.0), ('RB', 0.1, 0.2, 0.6), ] for leg, q1, q2, q3 in test_poses: pos = robot.forward_kinematics(leg, q1, q2, q3) print(f" {leg}: q=({q1:.1f},{q2:.1f},{q3:.1f}) -> foot({pos[0]:.4f},{pos[1]:.4f},{pos[2]:.4f})") print() print(" [Standing Pose] height=0.2m") standing = robot.standing_pose(height=0.2) for leg, angles in standing.items(): q1, q2, q3 = angles pos = robot.forward_kinematics(leg, q1, q2, q3) print(f" {leg}: q=({q1:.3f},{q2:.3f},{q3:.3f}) -> foot({pos[0]:.4f},{pos[1]:.4f},{pos[2]:.4f})") print() print(" [FK->IK Loopback Verification]") random_angles = [ ('LF', 0.1, 0.2, 0.6), ('RF', -0.15, 0.3, 0.8), ('LB', 0.05, -0.1, 0.5), ('RB', -0.1, 0.15, 0.7), ] for leg, q1, q2, q3 in random_angles: pos = robot.forward_kinematics(leg, q1, q2, q3) q1r, q2r, q3r = robot.inverse_kinematics(leg, pos) pos_r = robot.forward_kinematics(leg, q1r, q2r, q3r) err = math.sqrt(sum((a-b)**2 for a,b in zip(pos, pos_r))) ok = "OK" if err < 0.001 else "FAIL" print(f" {leg}: err={err:.6f}m [{ok}]") print() max_reach = robot.L_thigh + robot.L_calf min_reach = abs(robot.L_thigh - robot.L_calf) print(f" [Reach Analysis]") print(f" Max reach: {max_reach:.3f} m") print(f" Min reach: {min_reach:.3f} m") if min_reach > 0: print(f" Ratio: {max_reach/min_reach:.1f}x") print() print(" OK - 3D kinematics simulation complete")

仿真结果:

======================================================= 3D Forward/Inverse Kinematics Simulation ======================================================= Body: 0.4m x 0.2m Hip rod: 0.04m, Thigh: 0.15m, Calf: 0.15m [3D Forward Kinematics Test] LF: q=(0.0,0.0,0.5) -> foot(0.2719,0.1400,-0.2816) LF: q=(0.0,0.3,0.8) -> foot(0.3780,0.1400,-0.2113) RF: q=(0.2,0.0,0.5) -> foot(0.2719,-0.1392,-0.2896) LB: q=(-0.2,-0.3,1.0) -> foot(-0.1477,0.1392,-0.2501) RB: q=(0.1,0.2,0.6) -> foot(-0.0626,-0.1398,-0.2555) [Standing Pose] height=0.2m LF: q=(0.000,-0.841,1.682) -> foot(0.2000,0.1400,-0.2000) RF: q=(0.000,-0.841,1.682) -> foot(0.2000,-0.1400,-0.2000) LB: q=(0.000,-0.841,1.682) -> foot(-0.2000,0.1400,-0.2000) RB: q=(0.000,-0.841,1.682) -> foot(-0.2000,-0.1400,-0.2000) [FK->IK Loopback Verification] LF: err=0.000200m [OK] RF: err=0.000449m [OK] LB: err=0.000050m [OK] RB: err=0.000200m [OK] [Reach Analysis] Max reach: 0.300 m Min reach: 0.000 m OK - 3D kinematics simulation complete

📐 DH参数法(进阶)

对于更复杂的机器人,可以使用标准DH参数法系统化推导运动学:

关节θdaα
Hip Rollq10Lhipπ/2
Hip Pitchq20Lthigh0
Knee Pitchq30Lcalf0

每个关节的变换矩阵:

Ti = Rzi) · Tz(di) · Tx(ai) · Rxi)

🔄 运动学标定

实际机器人的运动学参数(腿长、偏移等)会有制造误差。标定方法:

典型标定精度:腿长误差 < 0.5mm,关节偏移误差 < 0.5°

📝 练习

  1. 修改站立高度从0.15m到0.25m,观察关节角变化。哪个角度变化最大?
  2. 计算机器人向前倾斜10°时的四条腿关节角(提示:需要旋转躯干坐标系)。
  3. 用DH参数法重新推导正运动学,验证与直接几何法一致。
  4. 当髋横滚角从-30°到30°变化时,画出LF腿足端的y-z轨迹。
  5. 设计一个标定实验:如何用3个已知足端位置标定Lthigh和Lcalf

📐 坐标系变换详解

3D运动学需要定义多个坐标系:

坐标系之间的变换:

Pworld = Tbody · Thip · Tleg_plane · Plocal

其中 Tbody 包含躯干的位置和姿态(6DOF),Thip 是髋关节偏移,Tleg_plane 是到腿平面的旋转。

🔄 3D雅可比矩阵

3D情况下的雅可比矩阵是 3×3:

J = [∂x/∂q1 ∂x/∂q2 ∂x/∂q3]
   [∂y/∂q1 ∂y/∂q2 ∂y/∂q3]
   [∂z/∂q1 ∂z/∂q2 ∂z/∂q3]

3×3雅可比的条件数反映机构的各向同性。条件数越接近1,力/速度映射越均匀。

🧮 不同腿构型对比

不同四足机器人采用不同的腿构型:

构型代表优点缺点
膝前弯(Dog-leg)Spot, A1高效推进,避免干涉足端轨迹规划较复杂
膝后弯(Insect-leg)MIT Cheetah结构紧凑,跳跃能力强横向力处理困难
对称弯(X-leg)部分开源设计正逆运动学对称力矩效率低

💡 数值IK方法

除了解析解,数值方法在某些情况下更灵活:

Newton-Raphson 迭代

qk+1 = qk + J-1(qk) · (xtarget - f(qk))

Damped Least Squares(阻尼最小二乘)

Δq = JT(JJT + λ²I)-1 · Δx

阻尼项 λ 防止在奇异位形附近发散。这是工业中常用的IK方法。

🏆
空间运动学家

掌握3D正逆运动学和DH参数法

四足机器人课程 · 第3课/30 · 返回目录