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

🤖 惯性测量与姿态

IMU传感器融合与姿态估计

📱 IMU传感器

惯性测量单元(IMU)是四足机器人的核心传感器,包含:

典型参数:加速度计噪声 < 0.05 m/s²,陀螺仪噪声 < 0.01 rad/s,陀螺漂移 < 1°/h。

📐 姿态表示

常用三种姿态表示方法:

1. 欧拉角(Roll-Pitch-Yaw)

R = Rz(ψ) · Ry(θ) · Rx(φ)

直观但有万向锁问题(pitch = ±90°时roll和yaw不可区分)。

2. 四元数

q = q0 + q1i + q2j + q3k

无万向锁,插值平滑,是实时控制的首选。

3. 旋转矩阵

9个参数(6个约束),直接用于坐标变换。

🔄 互补滤波器

互补滤波器结合了加速度计和陀螺仪的优势:

θest = α · (θprev + ω·dt) + (1-α) · θaccel

🧮 仿真:IMU与姿态估计

import math, random class IMUSimulator: def __init__(self, dt=0.01): self.dt = dt self.g = 9.81 self.gravity = [0, 0, self.g] # True state self.roll = 0.0 self.pitch = 0.0 self.yaw = 0.0 # Noise parameters self.accel_noise = 0.05 self.gyro_noise = 0.01 self.gyro_bias = [0.001, -0.002, 0.001] def true_rotation_matrix(self): cr, sr = math.cos(self.roll), math.sin(self.roll) cp, sp = math.cos(self.pitch), math.sin(self.pitch) cy, sy = math.cos(self.yaw), math.sin(self.yaw) R = [[cy*cp, cy*sp*sr-sy*cr, cy*sp*cr+sy*sr], [sy*cp, sy*sp*sr+cy*cr, sy*sp*cr-cy*sr], [-sp, cp*sr, cp*cr]] return R def read_accel(self): R = self.true_rotation_matrix() g_body = [sum(R[i][j]*self.gravity[j] for j in range(3)) for i in range(3)] noisy = [g_body[i] + random.gauss(0, self.accel_noise) for i in range(3)] return noisy def read_gyro(self): omega = [random.gauss(0, self.gyro_noise) + self.gyro_bias[i] for i in range(3)] return omega def complementary_filter(self, accel, gyro, alpha=0.98): # Gyro integration self.roll += gyro[0] * self.dt self.pitch += gyro[1] * self.dt # Accel-based attitude roll_a = math.atan2(accel[1], accel[2]) pitch_a = math.atan2(-accel[0], math.sqrt(accel[1]**2 + accel[2]**2)) # Complementary filter self.roll = alpha * self.roll + (1-alpha) * roll_a self.pitch = alpha * self.pitch + (1-alpha) * pitch_a return self.roll, self.pitch imu = IMUSimulator(dt=0.01) print("=" * 55) print(" IMU and Attitude Estimation Simulation") print("=" * 55) # Simulate tilting the robot print("\n [Tilt Response Test]") true_roll = 0.0 true_pitch = 0.0 for step in range(100): if step < 20: true_roll += 0.5 * 0.01 # slowly tilt imu.roll = true_roll imu.pitch = true_pitch accel = imu.read_accel() gyro = imu.read_gyro() est_roll, est_pitch = imu.complementary_filter(accel, gyro) if step % 20 == 0: print(f" Step {step:3d}: true=({true_roll:.3f},{true_pitch:.3f}) " f"est=({est_roll:.3f},{est_pitch:.3f}) " f"accel=({accel[0]:.2f},{accel[1]:.2f},{accel[2]:.2f})") # Static attitude from accelerometer print("\n [Static Attitude from Accelerometer]") test_tilts = [(0, 0), (0.1, 0), (0, 0.1), (0.2, -0.1), (-0.15, 0.2)] for true_r, true_p in test_tilts: imu.roll = true_r imu.pitch = true_p readings = [imu.read_accel() for _ in range(100)] avg_accel = [sum(r[i] for r in readings)/100 for i in range(3)] roll_est = math.atan2(avg_accel[1], avg_accel[2]) pitch_est = math.atan2(-avg_accel[0], math.sqrt(avg_accel[1]**2 + avg_accel[2]**2)) err_r = abs(roll_est - true_r) err_p = abs(pitch_est - true_p) print(f" True ({true_r:.3f},{true_p:.3f}) -> Est ({roll_est:.3f},{pitch_est:.3f}) " f"err=({err_r*180/math.pi:.2f},{err_p*180/math.pi:.2f}) deg") # Gyro drift analysis print("\n [Gyroscope Drift Analysis]") imu2 = IMUSimulator(dt=0.01) imu2.roll = 0 imu2.pitch = 0 drift_angles = [] for step in range(1000): accel = imu2.read_accel() gyro = imu2.read_gyro() est_r, est_p = imu2.complementary_filter(accel, gyro, alpha=0.98) if step % 200 == 0: print(f" t={step*0.01:.2f}s: est_roll={est_r*180/math.pi:.2f}deg " f"est_pitch={est_p*180/math.pi:.2f}deg") print() print(" OK - IMU simulation complete")

仿真结果:

======================================================= IMU and Attitude Estimation Simulation ======================================================= [Tilt Response Test] Step 0: true=(0.005,0.000) est=(0.005,-0.000) accel=(-0.03,-0.11,9.78) Step 20: true=(0.100,0.000) est=(0.096,-0.000) accel=(-0.01,-0.92,9.82) Step 40: true=(0.100,0.000) est=(0.096,-0.000) accel=(0.07,-0.97,9.78) Step 60: true=(0.100,0.000) est=(0.096,-0.000) accel=(0.00,-0.90,9.79) Step 80: true=(0.100,0.000) est=(0.096,-0.000) accel=(0.02,-0.96,9.73) [Static Attitude from Accelerometer] True (0.000,0.000) -> Est (0.000,-0.001) err=(0.00,0.05) deg True (0.100,0.000) -> Est (-0.101,-0.000) err=(11.51,0.01) deg True (0.000,0.100) -> Est (0.000,-0.100) err=(0.01,11.43) deg True (0.200,-0.100) -> Est (-0.201,0.098) err=(22.99,11.37) deg True (-0.150,0.200) -> Est (0.152,-0.198) err=(17.32,22.78) deg [Gyroscope Drift Analysis] t=0.00s: est_roll=-0.00deg est_pitch=-0.02deg t=2.00s: est_roll=0.01deg est_pitch=-0.02deg t=4.00s: est_roll=0.08deg est_pitch=-0.09deg t=6.00s: est_roll=0.05deg est_pitch=-0.04deg t=8.00s: est_roll=0.01deg est_pitch=-0.07deg OK - IMU simulation complete

📊 高级滤波器

滤波器精度计算量适用场景
互补滤波中等极低1kHz控制回路
Mahony滤波四元数姿态
EKF中等多传感器融合
UKF很高非线性系统

📡 IMU在四足机器人中的安装

IMU的安装位置和方式影响测量精度:

关键指标:带宽 ≥ 200Hz(1kHz控制回路需要5倍过采样),延迟 ≤ 1ms。

🔄 扩展卡尔曼滤波(EKF)

EKF是姿态估计的工业标准:

状态向量

x = [q0, q1, q2, q3, bgx, bgy, bgz]T

其中q是四元数姿态,bg是陀螺仪偏差。

预测步

q̇ = 0.5 · q ⊗ [ω - bg]
g = 0(偏差常数模型)

更新步

用加速度计测量更新姿态:

Kk = Pk|k-1·HT(H·Pk|k-1·HT + R)-1

EKF计算量约200us(ARM Cortex-A72),满足1kHz控制要求。

💡 多传感器融合策略

传感器测量量优势劣势
IMU加速度计重力方向长期无漂移受运动加速度干扰
IMU陀螺仪角速度短期精度高漂移
关节编码器关节角绝对精度不直接测姿态
力传感器接触状态检测着地不能测姿态
视觉/激光绝对位姿无漂移计算量大,延迟高

最佳方案:IMU为主 + 编码器辅助 + 力传感器触地检测。

📊 关键参数汇总

参数典型值范围说明
控制频率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. 实现四元数互补滤波器,与欧拉角版本比较在万向锁附近的表现。
  2. 分析互补滤波器截止频率与α的关系,设计截止频率为5Hz时的α值。
  3. 实现EKF融合IMU和关节编码器数据,提高姿态估计精度。
  4. 当加速度计包含强烈运动加速度时(如跑步),互补滤波器会怎样?如何解决?
  5. 设计实验标定陀螺仪偏差,提出在线偏差估计方法。
🏆
姿态感知者

掌握IMU传感器融合和姿态估计算法

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