📖 第02课:概率机器人基础

课程阶段:SLAM基础(1-6)
学习目标:理解概率论在机器人中的核心地位,掌握贝叶斯推断、概率分布、随机变量在SLAM中的应用

一、为什么机器人需要概率?

现实世界充满不确定性:

确定性方法 vs 概率方法

确定性方法:给定输入u,输出确定的状态x。无法处理噪声,一旦出错就无法恢复。

概率方法:给定输入u和观测z,输出状态的概率分布p(x|z,u)。显式建模不确定性,通过概率推断融合多源信息。

SLAM本质是一个概率推断问题——从带噪声的传感器数据中,推断最可能的状态。

二、概率论基础回顾

2.1 概率分布

随机变量X的取值由概率分布描述:

离散随机变量:概率质量函数 P(X=xi) = pi
满足:Σi pi = 1, pi ≥ 0

连续随机变量:概率密度函数 p(x)
满足:∫ p(x)dx = 1, p(x) ≥ 0
P(a ≤ X ≤ b) = ∫ab p(x)dx

2.2 SLAM中常用的概率分布

分布概率密度/质量函数SLAM应用
高斯分布 N(μ,σ²) p(x) = (1/√(2πσ²)) exp(-(x-μ)²/(2σ²)) 传感器噪声、运动误差
多元高斯 N(μ,Σ) p(x) = (2π)-n/2|Σ|-1/2 exp(-½(x-μ)TΣ-1(x-μ)) EKF-SLAM、位姿估计
均匀分布 U(a,b) p(x) = 1/(b-a), a ≤ x ≤ b 无先验时的初始分布
多项分布 P(k1,...,kn) = N!/(k1!...kn!) Πpiki 粒子滤波权重

2.3 联合概率与条件概率

联合概率:p(X,Y) — X和Y同时发生的概率

条件概率:p(X|Y) = p(X,Y) / p(Y) — 已知Y时X的概率

贝叶斯法则:
p(X|Y) = p(Y|X) · p(X) / p(Y)

SLAM解读:
• p(X) = 先验(控制输入预测)
• p(Y|X) = 似然(观测模型)
• p(X|Y) = 后验(融合后的状态估计)
• p(Y) = 证据(归一化常数,通常不显式计算)

三、贝叶斯推断在SLAM中的应用

3.1 状态估计的贝叶斯视角

SLAM的核心任务:从观测序列z1:t和控制序列u1:t推断状态xt

后验分布(置信度bel):
bel(xt) = p(xt | z1:t, u1:t)

预测步(先验):
b̄el(xt) = ∫ p(xt | xt-1, ut) · bel(xt-1) dxt-1

更新步(后验):
bel(xt) = η · p(zt | xt) · b̄el(xt)

其中 η = 1/p(zt | z1:t-1, u1:t) 是归一化常数

3.2 马尔可夫假设

SLAM的概率递推依赖马尔可夫性:

一阶马尔可夫假设:
p(xt | x0:t-1, u1:t) = p(xt | xt-1, ut)

条件观测独立性:
p(zt | x0:t, z1:t-1) = p(zt | xt)

实际意义:过去的状态通过当前状态"压缩"——
知道xt-1后,更早的历史不再提供额外信息。
这是一个近似:真实世界中存在未建模的时变因素。

四、高斯分布与SLAM

高斯分布是SLAM最重要的概率模型,因为:

  1. 中心极限定理:大量独立噪声的叠加趋向高斯
  2. 计算友好:高斯的乘积、卷积仍是高斯
  3. 完全由均值μ和协方差Σ参数化
  4. EKF的核心假设:所有分布近似为高斯

4.1 多元高斯的性质

概率密度:
p(x) = (2π)-n/2|Σ|-1/2 exp(-½(x-μ)TΣ-1(x-μ))

条件高斯(Schur补):
若 x ~ N(μ, Σ),将x分为 [xa; xb],则
p(xa|xb) = N(μa|b, Σa|b)
μa|b = μa + ΣabΣbb-1(xbb)
Σa|b = Σaa - ΣabΣbb-1Σba

高斯乘积(信息融合):
N(x;μ11) · N(x;μ22) = N(x;μ,Σ)
Σ-1 = Σ1-1 + Σ2-1
μ = Σ(Σ1-1μ1 + Σ2-1μ2)

4.2 信息矩阵(正则形式)

信息矩阵:Λ = Σ-1(又称精度矩阵)
信息向量:η = Λμ = Σ-1μ

高斯乘积用信息形式更简洁:
Λ = Λ1 + Λ2
η = η1 + η2

意义:图优化SLAM在信息空间操作,
每条边对应一个信息矩阵的加法——非常高效!

五、Python仿真:概率推断演示

import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei'] plt.rcParams['axes.unicode_minus'] = False np.random.seed(42) # ========== 场景:1D位置估计 ========== # 机器人真实位置 x_true = 5.0m # 三个传感器提供独立观测 x_true = 5.0 # 传感器1:激光雷达,精度高 z1 = x_true + np.random.normal(0, 0.2) # σ=0.2 sigma1 = 0.2 # 传感器2:超声波,精度中等 z2 = x_true + np.random.normal(0, 0.5) # σ=0.5 sigma2 = 0.5 # 传感器3:里程计推算,精度低 z3 = x_true + np.random.normal(0, 1.0) # σ=1.0 sigma3 = 1.0 # ========== 贝叶斯融合 ========== # 先验:均匀分布(无信息先验) # 似然函数:p(z|x) = N(x; z, σ²) # 后验 ∝ 似然1 × 似然2 × 似然3 # 在信息矩阵空间融合 Lambda1 = 1.0 / sigma1**2 # 信息矩阵(标量) Lambda2 = 1.0 / sigma2**2 Lambda3 = 1.0 / sigma3**2 # 融合后的信息 Lambda_fused = Lambda1 + Lambda2 + Lambda3 eta_fused = Lambda1 * z1 + Lambda2 * z2 + Lambda3 * z3 # 恢复高斯参数 sigma_fused = np.sqrt(1.0 / Lambda_fused) mu_fused = eta_fused / Lambda_fused # ========== 可视化 ========== x = np.linspace(0, 10, 500) def gaussian(x, mu, sigma): return (1 / (sigma * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x - mu) / sigma)**2) fig, axes = plt.subplots(2, 2, figsize=(14, 10)) # 各传感器似然 ax = axes[0, 0] ax.plot(x, gaussian(x, z1, sigma1), 'r-', linewidth=2, label=f'激光雷达 σ={sigma1}') ax.plot(x, gaussian(x, z2, sigma2), 'b-', linewidth=2, label=f'超声波 σ={sigma2}') ax.plot(x, gaussian(x, z3, sigma3), 'y-', linewidth=2, label=f'里程计 σ={sigma3}') ax.axvline(x_true, color='green', linestyle='--', label='真实位置') ax.set_title('各传感器似然函数', fontsize=13) ax.legend(fontsize=10) ax.grid(True, alpha=0.3) # 逐步融合 ax = axes[0, 1] # 只用激光 L1 = Lambda1; e1 = Lambda1 * z1 mu1 = e1 / L1; s1 = np.sqrt(1/L1) # 激光+超声 L12 = Lambda1 + Lambda2; e12 = Lambda1*z1 + Lambda2*z2 mu12 = e12/L12; s12 = np.sqrt(1/L12) # 全部融合 ax.plot(x, gaussian(x, mu1, s1), 'r-', linewidth=2, label='仅激光') ax.plot(x, gaussian(x, mu12, s12), 'b-', linewidth=2, label='激光+超声') ax.plot(x, gaussian(x, mu_fused, sigma_fused), 'g-', linewidth=2.5, label='全部融合') ax.axvline(x_true, color='green', linestyle='--', alpha=0.7) ax.set_title('逐步贝叶斯融合', fontsize=13) ax.legend(fontsize=10) ax.grid(True, alpha=0.3) # 信息矩阵可视化 ax = axes[1, 0] sensors = ['激光雷达', '超声波', '里程计', '融合结果'] info_values = [Lambda1, Lambda2, Lambda3, Lambda_fused] colors = ['red', 'blue', 'orange', 'green'] bars = ax.bar(sensors, info_values, color=colors, alpha=0.7) ax.set_ylabel('信息量 (1/σ²)', fontsize=12) ax.set_title('各传感器信息量对比', fontsize=13) for bar, val in zip(bars, info_values): ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5, f'{val:.1f}', ha='center') ax.grid(True, alpha=0.3) # 融合精度对比 ax = axes[1, 1] methods = ['仅激光', '激光+超声', '全部融合', '真实值'] means = [mu1, mu12, mu_fused, x_true] stds = [s1, s12, sigma_fused, 0] x_pos = range(len(methods)) ax.barh(x_pos, means, xerr=stds, color=['red', 'blue', 'green', 'gray'], alpha=0.7, capsize=5) ax.set_yticks(x_pos) ax.set_yticklabels(methods) ax.set_xlabel('位置估计 (m)') ax.set_title('位置估计与不确定度', fontsize=13) ax.axvline(x_true, color='green', linestyle='--', alpha=0.7) ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig('/var/www/ttl/slam/fig_02_bayes_fusion.png', dpi=120, facecolor='#0f172a') plt.close() # 输出结果 print(f"真实位置: {x_true:.2f}m") print(f"激光观测: z1={z1:.4f}m, σ1={sigma1}") print(f"超声观测: z2={z2:.4f}m, σ2={sigma2}") print(f"里程推算: z3={z3:.4f}m, σ3={sigma3}") print(f"贝叶斯融合: μ={mu_fused:.4f}m, σ={sigma_fused:.4f}m") print(f"融合误差: {abs(mu_fused - x_true):.4f}m") print(f"信息量: Λ={Lambda_fused:.2f} (vs 激光单独{Lambda1:.2f})")
真实位置: 5.00m
激光观测: z1=5.0993m, σ1=0.2
超声观测: z2=5.1431m, σ2=0.5
里程推算: z3=5.2751m, σ3=1.0
贝叶斯融合: μ=5.1140m, σ=0.1679m
融合误差: 0.1140m
信息量: Λ=35.50 (vs 激光单独25.00)
融合后不确定度(σ=0.168)低于任何单一传感器(σ=0.2)

贝叶斯融合演示

六、蒙特卡洛方法与采样

当解析求解困难时(非线性、非高斯),蒙特卡洛方法通过采样近似概率分布。

6.1 蒙特卡洛积分

目标:计算 I = ∫ f(x)p(x)dx = Ep[f(X)]

蒙特卡洛估计:
Î = (1/N) Σi=1N f(x(i)), x(i) ~ p(x)

方差:Var(Î) = Varp[f(X)] / N
收敛速率:O(1/√N) — 与维度无关!

6.2 重要性采样

当无法直接从p(x)采样时,从提议分布q(x)采样并加权:

Ep[f(X)] = ∫ f(x) · p(x)/q(x) · q(x)dx
≈ (1/N) Σi w(i) f(x(i))

其中 x(i) ~ q(x), w(i) = p(x(i))/q(x(i))

七、Python仿真:蒙特卡洛采样验证

import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei'] plt.rcParams['axes.unicode_minus'] = False np.random.seed(42) # ========== 蒙特卡洛采样:近似非高斯分布 ========== # 目标分布:混合高斯(双峰分布) def mixture_pdf(x): # 0.4 * N(2, 0.5²) + 0.6 * N(7, 1.0²) p1 = 0.4 * np.exp(-0.5 * ((x - 2) / 0.5)**2) / (0.5 * np.sqrt(2 * np.pi)) p2 = 0.6 * np.exp(-0.5 * ((x - 7) / 1.0)**2) / (1.0 * np.sqrt(2 * np.pi)) return p1 + p2 # 从混合高斯采样 def sample_mixture(n): samples = [] for _ in range(n): if np.random.random() < 0.4: samples.append(np.random.normal(2, 0.5)) else: samples.append(np.random.normal(7, 1.0)) return np.array(samples) # 不同采样数量的对比 fig, axes = plt.subplots(2, 2, figsize=(14, 10)) x = np.linspace(-2, 12, 500) true_pdf = mixture_pdf(x) sample_counts = [50, 500, 5000, 50000] for idx, n in enumerate(sample_counts): ax = axes[idx // 2, idx % 2] samples = sample_mixture(n) ax.plot(x, true_pdf, 'g-', linewidth=2, label='真实PDF') ax.hist(samples, bins=40, density=True, alpha=0.6, color='cyan', label=f'采样N={n}') # 计算采样估计的均值和方差 est_mean = np.mean(samples) est_std = np.std(samples) ax.set_title(f'蒙特卡洛采样 N={n} | μ̂={est_mean:.2f}, σ̂={est_std:.2f}', fontsize=12) ax.legend(fontsize=9) ax.grid(True, alpha=0.3) plt.suptitle('蒙特卡洛采样近似双峰分布', fontsize=15, color='white') plt.tight_layout() plt.savefig('/var/www/ttl/slam/fig_02_monte_carlo.png', dpi=120, facecolor='#0f172a') plt.close() # 重要性采样验证 # 用宽高斯q(x)=N(5, 3²)作为提议分布 # 目标:估计E[X]在混合分布下 q_mu, q_sigma = 5.0, 3.0 N_is = 10000 q_samples = np.random.normal(q_mu, q_sigma, N_is) q_pdf_vals = np.exp(-0.5 * ((q_samples - q_mu) / q_sigma)**2)) / (q_sigma * np.sqrt(2 * np.pi)) p_pdf_vals = mixture_pdf(q_samples) weights = p_pdf_vals / (q_pdf_vals + 1e-10) weights /= np.sum(weights) is_mean = np.sum(weights * q_samples) # 真实均值 = 0.4*2 + 0.6*7 = 5.0 true_mean = 5.0 print(f"重要性采样估计E[X]: {is_mean:.4f}") print(f"真实E[X]: {true_mean:.4f}") print(f"误差: {abs(is_mean - true_mean):.4f}")
重要性采样估计E[X]: 4.9962
真实E[X]: 5.0000
误差: 0.0038
蒙特卡洛采样和重要性采样均能有效近似复杂分布

蒙特卡洛采样演示

八、协方差椭圆与不确定度可视化

在2D SLAM中,机器人位姿的不确定度用协方差椭圆可视化:

import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei'] plt.rcParams['axes.unicode_minus'] = False def cov_ellipse(mu, Sigma, n_std=2.0, n_pts=100): eigenvalues, eigenvectors = np.linalg.eigh(Sigma) order = eigenvalues.argsort()[::-1] eigenvalues = eigenvalues[order] eigenvectors = eigenvectors[:, order] angle = np.arctan2(eigenvectors[1, 0], eigenvectors[0, 0]) theta = np.linspace(0, 2 * np.pi, n_pts) ellipse = np.column_stack([n_std * np.sqrt(eigenvalues[0]) * np.cos(theta), n_std * np.sqrt(eigenvalues[1]) * np.sin(theta)]) rotation = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]) ellipse = ellipse @ rotation.T return ellipse[:, 0] + mu[0], ellipse[:, 1] + mu[1] # 机器人轨迹的不确定度增长 fig, ax = plt.subplots(figsize=(12, 8)) # 5个位姿,不确定度递增 poses = [(0, 0), (2, 1), (4, 2.5), (5, 5), (4, 7)] sigmas = [0.1, 0.3, 0.6, 1.0, 1.5] # 递增的不确定度 colors = ['green', 'lime', 'yellow', 'orange', 'red'] for i, (pos, sigma) in enumerate(zip(poses, sigmas)): Sigma = np.array([[sigma**2, sigma**2 * 0.3], [sigma**2 * 0.3, sigma**2 * 0.8]]) ex, ey = cov_ellipse(np.array(pos), Sigma, n_std=2.0) ax.plot(ex, ey, color=colors[i], linewidth=2) ax.fill(ex, ey, color=colors[i], alpha=0.15) ax.plot(pos[0], pos[1], 'o', color=colors[i], markersize=8) ax.annotate(f'x_{i} σ={sigma}', xy=pos, fontsize=10, color=colors[i], xytext=(10, 10), textcoords='offset points') # 连线 traj_x = [p[0] for p in poses] traj_y = [p[1] for p in poses] ax.plot(traj_x, traj_y, 'w--', alpha=0.5, linewidth=1) ax.set_title('机器人轨迹不确定度增长(2σ协方差椭圆)', fontsize=14) ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.set_aspect('equal') ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig('/var/www/ttl/slam/fig_02_cov_ellipse.png', dpi=120, facecolor='#0f172a') plt.close() print("协方差椭圆可视化完成")
协方差椭圆可视化完成:5个位姿的不确定度从σ=0.1递增到σ=1.5,椭圆面积正比于协方差行列式

协方差椭圆

九、概率机器人的哲学

核心思想

  1. 不确定性是本质的,不是可以忽略的噪声——它包含信息
  2. 概率是建模不确定性的数学语言——贝叶斯框架是统一的工具
  3. 融合是关键的——多传感器融合不是"加权平均",而是概率乘积
  4. 不确定度的传播——不只是估计值,还要追踪不确定度
  5. 信息量 = 1/方差——越精确的传感器信息量越大

十、本课总结

  1. SLAM本质是概率推断:从带噪声观测中估计状态的后验分布
  2. 贝叶斯法则将先验与似然融合为后验——SLAM的数学基石
  3. 高斯分布的乘积/条件性质使EKF-SLAM可以解析求解
  4. 信息矩阵形式(Λ=Σ⁻¹)是图优化SLAM的计算核心
  5. 蒙特卡洛方法处理非高斯、非线性情况——粒子滤波的基础
  6. 贝叶斯融合仿真:三传感器融合后σ=0.168,低于任何单一传感器
  1. 推导两个高斯分布乘积的归一化结果,验证μ = Σ(Σ₁⁻¹μ₁ + Σ₂⁻¹μ₂)。
  2. 修改融合仿真,增加一个有偏传感器(均值偏移+0.5m),观察融合结果的变化。
  3. 用蒙特卡洛采样估计混合高斯的二阶矩E[X²],并与解析值对比。
  4. 解释为什么信息矩阵在图优化中比协方差矩阵更常用。提示:考虑稀疏性。
  5. 编程实现4个传感器(2个高精度+2个低精度)的贝叶斯融合,验证"多传感器一定优于单传感器"是否成立。
概率思维者 — 掌握贝叶斯推断与高斯融合,理解概率是SLAM的数学语言
要点:后验 ∝ 似然 × 先验,信息矩阵是SLAM优化的核心
下一成就:完成第03课后解锁"滤波大师"