动力学与平衡第7课/共30课

🤖 刚体动力学

牛顿-欧拉方程:四足机器人的运动方程

📐 刚体运动描述

四足机器人可以建模为浮动基座刚体+4条腿。躯干的运动由6个自由度描述(3平动+3转动):

q = (x, y, z, roll, pitch, yaw) ∈ SE(3)

运动方程由牛顿-欧拉方程描述:

m·a = Fext(牛顿第二定律)
I·α + ω × (I·ω) = τext(欧拉方程)

🔄 欧拉方程详解

欧拉方程描述刚体在体坐标系中的旋转动力学:

Ixx·ω̇x + (Izz-Iyy)·ωy·ωz = τx
Iyy·ω̇y + (Ixx-Izz)·ωx·ωz = τy
Izz·ω̇z + (Iyy-Ixx)·ωx·ωy = τz

交叉项 ωi·ωj 产生陀螺效应,使得绕一个轴的力矩会影响其他轴的角速度。这对姿态控制至关重要。

⚡ 惯性张量

惯性张量描述质量分布对旋转的抵抗:

I = [Ixx -Ixy -Ixz]
   [-Ixy Iyy -Iyz]
   [-Ixz -Iyz Izz]

对于对称的矩形躯干:

Ixx = m/12 · (W² + H²)
Iyy = m/12 · (L² + H²)
Izz = m/12 · (L² + W²)

🔗 全身动力学

完整的四足机器人动力学包含12个关节+6个浮动基座:

M(q)·q̈ + C(q,q̇)·q̇ + G(q) = ST·τ + JT·Fext

其中:

🧮 仿真:刚体动力学

import math class RigidBodyDynamics: def __init__(self, mass=6.2, Ixx=0.05, Iyy=0.1, Izz=0.1): self.mass = mass self.Ixx = Ixx self.Iyy = Iyy self.Izz = Izz def euler_equations(self, omega, torque): wx, wy, wz = omega tx, ty, tz = torque dwx = (tx - (self.Izz - self.Iyy)*wy*wz) / self.Ixx dwy = (ty - (self.Ixx - self.Izz)*wx*wz) / self.Iyy dwz = (tz - (self.Iyy - self.Ixx)*wx*wy) / self.Izz return (dwx, dwy, dwz) def newton_equations(self, force): ax = force[0] / self.mass ay = force[1] / self.mass az = force[2] / self.mass - 9.81 return (ax, ay, az) def simulate_free_fall(self, dt=0.001, duration=0.5): pos = [0, 0, 0.3] vel = [0, 0, 0] omega = [0, 0, 0] trajectory = [] t = 0 while t < duration: trajectory.append((t, pos[:], vel[:], omega[:])) force = [0, 0, 0] torque = [0, 0, 0] acc = self.newton_equations(force) for i in range(3): vel[i] += acc[i] * dt pos[i] += vel[i] * dt domega = self.euler_equations(omega, torque) for i in range(3): omega[i] += domega[i] * dt t += dt if pos[2] <= 0: break return trajectory def simulate_spin(self, dt=0.001, duration=1.0): pos = [0, 0, 0] vel = [0, 0, 0] omega = [0, 0, 5.0] # initial spin torque = [0.1, 0, 0] # small perturbation torque trajectory = [] t = 0 while t < duration: trajectory.append((t, omega[:])) domega = self.euler_equations(omega, torque) for i in range(3): omega[i] += domega[i] * dt t += dt return trajectory rbd = RigidBodyDynamics() print("=" * 55) print(" Rigid Body Dynamics Simulation") print("=" * 55) print(f" Mass: {rbd.mass} kg") print(f" Ixx={rbd.Ixx}, Iyy={rbd.Iyy}, Izz={rbd.Izz} kg*m^2") print() traj = rbd.simulate_free_fall() print(" [Free Fall from 0.3m]") for i in range(0, len(traj), max(1, len(traj)//8)): t, pos, vel, omega = traj[i] print(f" t={t:.3f}s pos=({pos[0]:.4f},{pos[1]:.4f},{pos[2]:.4f}) vel=({vel[2]:.3f},0,0)") print() spin = rbd.simulate_spin() print(" [Gyroscopic Precession - initial wz=5, torque tx=0.1]") for i in range(0, len(spin), max(1, len(spin)//10)): t, omega = spin[i] print(f" t={t:.3f}s omega=({omega[0]:.4f},{omega[1]:.4f},{omega[2]:.4f})") print() # Lagrangian vs Newton-Euler comparison print(" [Energy Conservation Check]") ke = 0.5 * rbd.mass * 9.81**2 * 0.3**2 / (2*9.81*0.3) print(f" Drop height 0.3m -> impact speed = {math.sqrt(2*9.81*0.3):.3f} m/s") print(f" KE at impact = {0.5*rbd.mass*2*9.81*0.3:.2f} J") print(f" PE at top = {rbd.mass*9.81*0.3:.2f} J") print() print(" OK - Rigid body dynamics simulation complete")

仿真结果:

======================================================= Rigid Body Dynamics Simulation ======================================================= Mass: 6.2 kg Ixx=0.05, Iyy=0.1, Izz=0.1 kg*m^2 [Free Fall from 0.3m] t=0.000s pos=(0.0000,0.0000,0.3000) vel=(0.000,0,0) t=0.030s pos=(0.0000,0.0000,0.2954) vel=(-0.294,0,0) t=0.060s pos=(0.0000,0.0000,0.2820) vel=(-0.589,0,0) t=0.090s pos=(0.0000,0.0000,0.2598) vel=(-0.883,0,0) t=0.120s pos=(0.0000,0.0000,0.2288) vel=(-1.177,0,0) t=0.150s pos=(0.0000,0.0000,0.1889) vel=(-1.472,0,0) t=0.180s pos=(0.0000,0.0000,0.1402) vel=(-1.766,0,0) t=0.210s pos=(0.0000,0.0000,0.0827) vel=(-2.060,0,0) t=0.240s pos=(0.0000,0.0000,0.0163) vel=(-2.354,0,0) [Gyroscopic Precession - initial wz=5, torque tx=0.1] t=0.000s omega=(0.0000,0.0000,5.0000) t=0.100s omega=(0.2000,0.0247,4.9999) t=0.200s omega=(0.4000,0.0995,4.9990) t=0.300s omega=(0.6000,0.2242,4.9950) t=0.400s omega=(0.8000,0.3986,4.9841) t=0.500s omega=(1.0000,0.6221,4.9612) t=0.600s omega=(1.2000,0.8937,4.9197) t=0.700s omega=(1.4000,1.2112,4.8514) t=0.800s omega=(1.6000,1.5711,4.7472) t=0.900s omega=(1.8000,1.9683,4.5970) [Energy Conservation Check] Drop height 0.3m -> impact speed = 2.426 m/s KE at impact = 18.25 J PE at top = 18.25 J OK - Rigid body dynamics simulation complete

📐 拉格朗日力学

另一种建立运动方程的方法是拉格朗日力学:

L = T - V(拉格朗日量)
d/dt(∂L/∂q̇i) - ∂L/∂qi = Qi

其中T是动能,V是势能,Qi是广义力。拉格朗日法系统化、不易出错,但计算量大。

💡 动力学仿真方法

方法复杂度适用场景
牛顿-欧拉递推O(n)实时控制,前向仿真
拉格朗日O(n3)模型推导,分析
复合刚体算法O(n)计算质量矩阵
articulated bodyO(n)前向动力学最快

📐 牛顿-欧拉递推算法

牛顿-欧拉递推是计算动力学最高效的方法,复杂度O(n):

向外递推(基座到末端)

  1. 从基座开始,逐关节传递速度和加速度
  2. ωi+1 = Ri+1i + ẑ·q̇i+1)
  3. αi+1 = Ri+1i + ẑ·q̈i+1 + ωi × ẑ·q̇i+1)

向内递推(末端到基座)

  1. 从末端开始,逐关节累积力和力矩
  2. Fi = fi+1 + mi·ai
  3. τi = ziT·ni(关节力矩)

这个算法是实时控制的基础,可以在1ms内完成18自由度的动力学计算。

💡 质量矩阵的计算

质量矩阵M(q)的元素可以由复合刚体算法高效计算:

Mij = Σ(mk·Jv,k,iT·Jv,k,j + Ik·Jω,k,iT·Jω,k,j)

其中 Jv,k,i 和 Jω,k,i 是第k个连杆的线速度和角速度雅可比的第i列。

质量矩阵是对称正定的,其条件数反映了力/加速度映射的各向同性程度。

📊 科里奥利力和离心力

科里奥利矩阵C(q,q̇)来自质量矩阵的时间导数:

Cij = Σk cijk·q̇k
cijk = 0.5(∂Mij/∂qk + ∂Mik/∂qj - ∂Mjk/∂qi)

这些力在高速运动时不可忽略。在低速行走中约占10-20%的总力矩,在跑步中可达30-40%。

📊 关键参数汇总

参数典型值范围说明
控制频率1 kHz500-2000 Hz越高动态性能越好
IMU带宽200 Hz100-500 Hz5倍过采样
力控精度5%2-10%取决于电流环精度
姿态估计精度0.5 deg0.2-2 deg取决于滤波器
CoM跟踪精度5 mm2-20 mm取决于控制器

📊 关键参数汇总

参数典型值范围说明
控制频率1 kHz500-2000 Hz越高动态性能越好
IMU带宽200 Hz100-500 Hz5倍过采样
力控精度5%2-10%取决于电流环精度
姿态估计精度0.5 deg0.2-2 deg取决于滤波器
CoM跟踪精度5 mm2-20 mm取决于控制器

📝 练习

  1. 计算矩形躯干(0.4m×0.2m×0.05m, 5kg)的完整惯性张量。
  2. 当机器人绕z轴以3rad/s旋转时,施加x方向0.2Nm力矩,计算1秒后的角速度变化(陀螺进动)。
  3. 推导3连杆腿的拉格朗日运动方程(提示:需要计算动能和势能)。
  4. 仿真机器人自由下落0.3m后的冲击力(假设弹性碰撞,恢复系数0.3)。
  5. 比较牛顿-欧拉和拉格朗日方法在12自由度系统中的计算效率。
🏆
动力学先驱

掌握刚体动力学、欧拉方程和全身动力学建模

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