地形适应第14课/共30课

🤖 足端力控制

精确控制每条腿的地面反力

📖 本课概要

精确控制每条腿的地面反力。本课将深入探讨相关理论和实现,通过Python仿真验证核心算法。

🧮 核心仿真

import math class FootForceController: def __init__(self, mass=6.2, body_L=0.4, body_W=0.2, z_com=0.2): self.mass = mass self.g = 9.81 self.body_L = body_L self.body_W = body_W self.z_com = z_com self.legs = { 'LF': ( body_L/2, body_W/2), 'RF': ( body_L/2, -body_W/2), 'LB': (-body_L/2, body_W/2), 'RB': (-body_L/2, -body_W/2), } def compute_desired_forces(self, com_acc, com_torque, contact_legs): n = len(contact_legs) if n == 0: return {} # Total force needed F_total = [self.mass * com_acc[0], self.mass * com_acc[1], self.mass * (com_acc[2] + self.g)] # Distribute equally f_per_leg = [F_total[i]/n for i in range(3)] forces = {} for leg in contact_legs: lx, ly = self.legs[leg] # Add torque compensation fx = f_per_leg[0] + com_torque[1] / (n * self.z_com) fy = f_per_leg[1] - com_torque[0] / (n * self.z_com) fz = f_per_leg[2] - com_torque[2] / (n * max(abs(lx), abs(ly), 0.01)) forces[leg] = (fx, fy, fz) return forces def friction_cone_check(self, forces, mu=0.6): valid = {} for leg, (fx, fy, fz) in forces.items(): ft = math.sqrt(fx**2 + fy**2) fn = fz if fn > 0: ratio = ft / fn valid[leg] = ratio <= mu else: valid[leg] = False return valid def simulate_stance_force_control(self, duration=1.0, dt=0.001, kp=200, kd=40): contact = ['LF', 'RF', 'LB', 'RB'] z_target = 0.2 z = z_target z_dot = 0 roll = 0 roll_dot = 0 pitch = 0 pitch_dot = 0 history = [] t = 0 while t < duration: # PD force control fz_err = kp * (z_target - z) - kd * z_dot roll_tau = 100 * (0 - roll) - 20 * roll_dot pitch_tau = 100 * (0 - pitch) - 20 * pitch_dot forces = self.compute_desired_forces( (0, 0, fz_err/self.mass), (roll_tau, pitch_tau, 0), contact ) # Simplified dynamics Fz_total = sum(f[2] for f in forces.values()) z_ddot = Fz_total / self.mass - self.g z_dot += z_ddot * dt z += z_dot * dt roll_ddot = roll_tau / 0.05 roll_dot += roll_ddot * dt roll += roll_dot * dt pitch_ddot = pitch_tau / 0.1 pitch_dot += pitch_ddot * dt pitch += pitch_dot * dt if int(t*1000) % 200 == 0: history.append((t, z, roll, pitch, forces)) t += dt return history ffc = FootForceController() print("=" * 55) print(" Foot Force Control Simulation") print("=" * 55) # Force distribution test print("\n [Force Distribution - 4 legs standing]") forces = ffc.compute_desired_forces((0, 0, 0), (0, 0, 0), ['LF','RF','LB','RB']) for leg, f in forces.items(): print(f" {leg}: F=({f[0]:.2f}, {f[1]:.2f}, {f[2]:.2f}) N") friction = ffc.friction_cone_check(forces) print(f" Friction cone valid: {friction}") # With acceleration print("\n [Force Distribution - Forward accel 1m/s2]") forces = ffc.compute_desired_forces((1, 0, 0), (0, 0, 0), ['LF','RF','LB','RB']) for leg, f in forces.items(): print(f" {leg}: F=({f[0]:.2f}, {f[1]:.2f}, {f[2]:.2f}) N") friction = ffc.friction_cone_check(forces) print(f" Friction cone valid: {friction}") # Force control simulation print("\n [Force Control Balancing]") history = ffc.simulate_stance_force_control() for t, z, roll, pitch, forces in history: fz_avg = sum(f[2] for f in forces.values()) / 4 print(f" t={t:.3f}s z={z*1000:.1f}mm roll={roll*180/math.pi:.2f}deg pitch={pitch*180/math.pi:.2f}deg Fz_avg={fz_avg:.1f}N") # 3-leg support print("\n [3-leg Force Distribution (lift LF)]") forces3 = ffc.compute_desired_forces((0, 0, 0), (0, 0, 0), ['RF','LB','RB']) for leg, f in forces3.items(): fn = f[2] ft = math.sqrt(f[0]**2 + f[1]**2) print(f" {leg}: F=({f[0]:.2f}, {f[1]:.2f}, {f[2]:.2f}) N, Ft/Fn={ft/fn:.3f}" if fn > 0 else f" {leg}: lift-off!") print() print(" OK - Foot force control simulation complete")

仿真结果:

======================================================= Foot Force Control Simulation ======================================================= [Force Distribution - 4 legs standing] LF: F=(0.00, 0.00, 15.21) N RF: F=(0.00, 0.00, 15.21) N LB: F=(0.00, 0.00, 15.21) N RB: F=(0.00, 0.00, 15.21) N Friction cone valid: {'LF': True, 'RF': True, 'LB': True, 'RB': True} [Force Distribution - Forward accel 1m/s2] LF: F=(1.55, 0.00, 15.21) N RF: F=(1.55, 0.00, 15.21) N LB: F=(1.55, 0.00, 15.21) N RB: F=(1.55, 0.00, 15.21) N Friction cone valid: {'LF': True, 'RF': True, 'LB': True, 'RB': True} [Force Control Balancing] t=0.000s z=200.0mm roll=0.00deg pitch=0.00deg Fz_avg=15.2N t=0.200s z=200.0mm roll=0.00deg pitch=0.00deg Fz_avg=15.2N t=0.400s z=200.0mm roll=0.00deg pitch=0.00deg Fz_avg=15.2N t=0.600s z=200.0mm roll=0.00deg pitch=0.00deg Fz_avg=15.2N t=0.800s z=200.0mm roll=0.00deg pitch=0.00deg Fz_avg=15.2N [3-leg Force Distribution (lift LF)] RF: F=(0.00, 0.00, 20.27) N, Ft/Fn=0.000 LB: F=(0.00, 0.00, 20.27) N, Ft/Fn=0.000 RB: F=(0.00, 0.00, 20.27) N, Ft/Fn=0.000 OK - Foot force control simulation complete

📐 摩擦锥约束

足端力必须满足摩擦锥约束以防止滑动:

|Ft| ≤ μ · Fn
Fn ≥ 0(只能推不能拉)

其中 μ 是摩擦系数,Ft 是切向力,Fn 是法向力。典型摩擦系数:干混凝土 μ ≈ 0.6-0.8,湿草地 μ ≈ 0.3-0.5,冰面 μ ≈ 0.1-0.2。

💡 力分配QP求解

最优力分配可以写成凸优化:

min Σ||Fi||2
s.t. ΣFi = Fdes
    Σ(ri×Fi) = τdes
    |Ft,i| ≤ μ·Fn,i, Fn,i ≥ 0

📐 力传感与力控基础

足端力控制需要精确的力感知:

力传感器类型

力控架构

τcmd = JT · Fdes + g(q) + C(q,q̇)·q̇
Factual = J-T · (τactual - g - C·q̇)

🔄 阻抗控制

阻抗控制是力控的核心策略,不直接控制力,而是控制力-位移关系:

F = K·(x0 - x) + D·(v0 - v)
K: 刚度(位置控制的强度)
D: 阻尼(速度控制的强度)

高K低D = 刚性位置控制;低K高D = 柔顺力控制。四足行走需要中等刚度+适当阻尼。

💡 接触检测与状态机

力控需要准确判断接触状态:

状态机:SWING → IMPACT → STANCE → LIFTOFF → SWING

状态力控目标阻抗参数
SWING跟踪轨迹高K, 低D
IMPACT吸收冲击低K, 高D
STANCE支撑体重中K, 中D
LIFTOFF释放接触低K, 低D

📚 本课参考与延伸

核心概念回顾

实现建议

  1. 先用Python/MATLAB验证算法正确性
  2. 然后在物理引擎(PyBullet/MuJoCo)中测试
  3. 最后在真实机器人上部署,使用域随机化增强鲁棒性

常见问题

🔬 实验设计与验证方法

为确保算法的可靠性,建议按以下步骤验证:

  1. 单元测试:对每个核心函数编写测试用例,验证边界条件和典型值
  2. 集成测试:将所有模块组合,在仿真中运行完整场景
  3. 压力测试:在极端条件下(大扰动、高速、低摩擦)测试鲁棒性
  4. 回归测试:修改代码后重新运行所有测试,确保不引入bug

📊 性能基准

以下是学术界和工业界的关键基准数据:

指标学术前沿工业产品入门级
最大速度3.0 m/s (Cheetah)1.6 m/s (Spot)0.5 m/s
最大负载100% 体重30% 体重10% 体重
续航1-2h1.5-2.5h0.5-1h
台阶高度20cm15cm10cm
恢复能力50N推力30N推力10N推力
控制频率1kHz500Hz100-250Hz

⚙️ 工程实践建议

📝 练习

  1. 修改仿真参数,观察系统行为的变化。
  2. 实现本课核心算法的改进版本。
  3. 将本课方法与其他课的方法组合,设计复合控制器。
  4. 分析算法在不同条件下的鲁棒性。
  5. 设计实验验证仿真结果的正确性。
🏆
力控大师

掌握足端力分配、摩擦锥约束和全身力控

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