小型机器人传感器融合入门

介绍传感器融合的基本概念和实现方法,包括卡尔曼滤波、互补滤波,以及如何在小型机器人上融合摄像头、IMU、激光雷达等传感器数据。

传感器融合 卡尔曼滤波 IMU 激光雷达 机器人
小型机器人传感器融合入门

小型机器人传感器融合入门

在机器人导航和自动驾驶中,单一传感器往往无法提供完整、准确的环境信息。摄像头受光照影响,激光雷达无法识别颜色,IMU 存在累积误差。传感器融合(Sensor Fusion)技术通过结合多种传感器的数据,提供更可靠、更全面的环境感知能力。

本文将介绍传感器融合的基本原理,以及如何在小型机器人(如 DonkeyCar、JetBot)上实现简单的传感器融合。

为什么需要传感器融合?

每种传感器都有其优势和局限性:

传感器优势局限性
摄像头丰富的视觉信息、成本低受光照影响、无深度信息
IMU高频率、不受环境影响累积漂移
激光雷达精确距离测量成本高、无颜色信息
超声波简单可靠范围有限、精度低
GPS全局定位室内不可用、精度有限

通过融合多种传感器,可以互补各自的不足,获得更准确的位姿估计和环境感知。

传感器融合的基本方法

1. 互补滤波(Complementary Filter)

互补滤波是最简单的融合方法,适用于融合两个传感器数据。核心思想是:对高频信号信任一个传感器,对低频信号信任另一个。

典型应用:融合 IMU 的加速度计和陀螺仪数据。

import numpy as np

class ComplementaryFilter:
    def __init__(self, alpha=0.98):
        self.alpha = alpha  # 陀螺仪权重
        self.angle = 0.0
    
    def update(self, gyro_rate, accel_angle, dt):
        """
        gyro_rate: 陀螺仪角速度 (rad/s)
        accel_angle: 加速度计计算的角度 (rad)
        dt: 时间步长 (s)
        """
        # 陀螺仪积分(高频响应好)
        gyro_angle = self.angle + gyro_rate * dt
        
        # 互补融合
        self.angle = self.alpha * gyro_angle + (1 - self.alpha) * accel_angle
        
        return self.angle

# 使用示例
filter = ComplementaryFilter(alpha=0.98)
dt = 0.01  # 100Hz

for i in range(1000):
    gyro_rate = read_gyroscope()  # rad/s
    accel_angle = read_accelerometer_angle()  # rad
    fused_angle = filter.update(gyro_rate, accel_angle, dt)

2. 卡尔曼滤波(Kalman Filter)

卡尔曼滤波是一种最优估计算法,适用于线性系统。它通过预测-更新两个步骤,递归地估计系统状态。

import numpy as np

class KalmanFilter:
    def __init__(self, dt=0.01):
        self.dt = dt
        
        # 状态向量 [位置, 速度]
        self.x = np.array([[0.0], [0.0]])
        
        # 状态转移矩阵
        self.F = np.array([[1, dt],
                           [0, 1]])
        
        # 控制矩阵(如果有加速度输入)
        self.B = np.array([[0.5 * dt**2], [dt]])
        
        # 测量矩阵(只测量位置)
        self.H = np.array([[1, 0]])
        
        # 协方差矩阵
        self.P = np.eye(2) * 100
        
        # 过程噪声
        self.Q = np.eye(2) * 0.1
        
        # 测量噪声
        self.R = np.array([[1.0]])
    
    def predict(self, u=0):
        """预测步骤"""
        self.x = self.F @ self.x + self.B * u
        self.P = self.F @ self.P @ self.F.T + self.Q
        return self.x[0, 0]
    
    def update(self, z):
        """更新步骤"""
        y = z - self.H @ self.x  # 残差
        S = self.H @ self.P @ self.H.T + self.R  # 残差协方差
        K = self.P @ self.H.T @ np.linalg.inv(S)  # 卡尔曼增益
        
        self.x = self.x + K @ y
        self.P = (np.eye(2) - K @ self.H) @ self.P
        
        return self.x[0, 0]

# 使用示例
kf = KalmanFilter(dt=0.01)
measurements = [1.2, 1.5, 1.3, 1.8, 2.1, 2.0, 2.3]  # 带噪声的测量值

for z in measurements:
    kf.predict()
    estimated = kf.update(np.array([[z]]))
    print(f"测量值: {z:.2f}, 估计值: {estimated:.2f}")

3. 扩展卡尔曼滤波(EKF)

对于非线性系统(如机器人运动学模型),需要使用扩展卡尔曼滤波。EKF 通过泰勒展开将非线性函数线性化。

class ExtendedKalmanFilter:
    def __init__(self):
        # 状态 [x, y, theta]
        self.x = np.zeros(3)
        self.P = np.eye(3) * 10
        self.Q = np.eye(3) * 0.01
        self.R = np.eye(2) * 0.5  # 测量噪声
    
    def predict(self, v, omega, dt):
        """非线性运动模型"""
        x, y, theta = self.x
        
        # 状态预测
        self.x[0] = x + v * np.cos(theta) * dt
        self.x[1] = y + v * np.sin(theta) * dt
        self.x[2] = theta + omega * dt
        
        # 雅可比矩阵
        F = np.array([
            [1, 0, -v * np.sin(theta) * dt],
            [0, 1, v * np.cos(theta) * dt],
            [0, 0, 1]
        ])
        
        self.P = F @ self.P @ F.T + self.Q
    
    def update(self, z):
        """z = [x_meas, y_meas]"""
        H = np.array([[1, 0, 0],
                      [0, 1, 0]])
        
        y = z - H @ self.x
        S = H @ self.P @ H.T + self.R
        K = self.P @ H.T @ np.linalg.inv(S)
        
        self.x = self.x + K @ y
        self.P = (np.eye(3) - K @ H) @ self.P

实际应用:融合摄像头和 IMU

在自动驾驶小车中,可以融合摄像头的视觉里程计(Visual Odometry)和 IMU 数据:

class CameraIMUFusion:
    def __init__(self):
        self.kf = KalmanFilter(dt=0.02)  # 50Hz
    
    def update(self, visual_pos, imu_accel, timestamp):
        # 使用 IMU 加速度进行预测
        self.kf.predict(u=imu_accel)
        
        # 使用视觉位置进行更新
        estimated_pos = self.kf.update(np.array([[visual_pos]]))
        
        return estimated_pos

在 Jetson Nano 上实现

使用 Python 和 NumPy 可以在 Jetson Nano 上实时运行简单的卡尔曼滤波。对于更复杂的融合需求,可以使用 ROS(Robot Operating System)的 robot_localization 包:

sudo apt install ros-melodic-robot-localization

配置 ekf_localization_node,输入来自 IMU、轮式里程计和视觉里程计的数据,输出融合后的位姿估计。

传感器同步

多传感器融合的关键挑战之一是时间同步。不同传感器的采样率不同,需要统一时间戳:

from collections import deque

class SensorSyncBuffer:
    def __init__(self, max_delay=0.05):
        self.buffer = deque(maxlen=100)
        self.max_delay = max_delay  # 最大允许延迟(秒)
    
    def add(self, sensor_name, timestamp, data):
        self.buffer.append((sensor_name, timestamp, data))
    
    def get_synchronized(self, target_time):
        """获取最接近目标时间的各传感器数据"""
        result = {}
        for name, ts, data in self.buffer:
            if abs(ts - target_time) < self.max_delay:
                if name not in result or abs(ts - target_time) < abs(result[name][0] - target_time):
                    result[name] = (ts, data)
        return result

总结

传感器融合是机器人感知系统的核心技术。对于小型机器人项目,互补滤波和卡尔曼滤波已经能满足大部分需求。关键是根据应用场景选择合适的融合方法,并注意传感器同步和噪声建模。随着项目复杂度增加,可以逐步引入更高级的融合算法(如粒子滤波、因子图优化)。