跳到主要内容

Robot PU 信号滤波器


以下是一篇完整、精炼、可直接用于教学的教程,融合了:

  1. 所有主要滤波器类型的介绍
  2. Robot PU 声呐滤波示例

……整合为一篇结构连贯的课程。

全文采用与 Robot PU 系列教程一致的风格和架构。

📘 教程:Robot PU 的信号滤波

理解滤波器并将其应用于 5 分区声呐距离数组


背景

Robot PU 使用超声波传感器检测障碍物。传感器返回从左到右的五个距离分区:

分区方向
d[0]最左侧
d[1]左侧
d[2]中央/前方
d[3]右侧
d[4]最右侧

真实环境中的声呐数据充满噪声。读数可能因以下原因跳动、尖峰或波动:

  • 反射
  • 振动
  • 倾斜表面
  • 电气噪声
  • 运动

为了让 Robot PU 行为可靠,我们需要使用信号滤波

本教程介绍最重要的滤波器类型,并展示如何将每种滤波器应用于 Robot PU 的声呐数组。


🧠 什么是信号滤波?

信号滤波是清理噪声传感器数据的过程,使机器人能做出更好的决策。

滤波有助于:

  • 平滑抖动
  • 去除尖峰
  • 降低噪声
  • 稳定控制回路
  • 改善迷宫求解和墙壁跟随

不同的滤波器解决不同的问题。让我们逐一探索。


🧹 1. 移动平均滤波器

是什么: 一个简单的滤波器,对最近 N 个读数取平均值。

作用:

  • 平滑短期噪声
  • 减少抖动
  • 产生稳定值

最适合:

  • 迷宫求解
  • 走廊跟随
  • 通用平滑

代码示例(对前方分区 d[2] 进行滤波)

let window: number[] = []
let windowSize = 5

function movingAverage(newValue: number): number {
window.push(newValue)
if (window.length > windowSize) {
window.shift()
}

let sum = 0
for (let v of window) {
sum += v
}
return sum / window.length
}

basic.forever(function () {
let frontRaw = robotPu.frontDistanceArray[2]
let frontFiltered = movingAverage(frontRaw)

serial.writeValue("front", frontFiltered)
basic.pause(100)
})

🌊 2. 指数低通滤波器(LPF)

是什么: 一个轻量级的平滑滤波器:

filtered = α * old + (1 - α) * new

作用:

  • 平滑噪声
  • 响应比移动平均更快

最适合:

  • 连续控制
  • 墙壁跟随
  • 平衡控制

代码示例(对右侧分区 d[4] 进行滤波)

let rightFiltered = 0
let alpha = 0.7 // smoothing factor

basic.forever(function () {
let rightRaw = robotPu.frontDistanceArray[4]

rightFiltered = alpha * rightFiltered + (1 - alpha) * rightRaw

serial.writeValue("right", rightFiltered)
basic.pause(100)
})

🔪 3. 中值滤波器

是什么: 取一组样本中间值的滤波器。

作用:

  • 去除极端尖峰
  • 拒绝离群值
  • 保留突变边缘

最适合:

  • 偶尔出现大幅跳变的声呐读数
  • 单个错误读数可能导致错误转弯的迷宫求解

代码示例(对左侧分区 d[0] 进行滤波)

function median(values: number[]): number {
values.sort((a, b) => a - b)
return values[Math.idiv(values.length, 2)]
}

basic.forever(function () {
let samples = [
robotPu.frontDistanceArray[0],
robotPu.frontDistanceArray[0],
robotPu.frontDistanceArray[0]
]

let leftFiltered = median(samples)

serial.writeValue("left", leftFiltered)
basic.pause(100)
})

⚖️ 4. 互补滤波器

是什么:

一个融合以下两者的滤波器:

  • 快速但噪声大的信号
  • 缓慢但稳定的信号

作用:

  • 产生既响应迅速又平滑的信号。
  • 非常适合机器人应用。

最适合:

  • 墙壁跟随
  • 避障
  • 任何需要速度与稳定性兼顾的场景

代码示例(对前方分区 d[2] 组合原始信号 + LPF)

let frontLPF = 0
let alphaLPF = 0.8
let blend = 0.6 // trust fast signal 60%

basic.forever(function () {
let frontRaw = robotPu.frontDistanceArray[2]

// Low‑pass filter
frontLPF = alphaLPF * frontLPF + (1 - alphaLPF) * frontRaw

// Complementary blend
let frontFiltered = blend * frontRaw + (1 - blend) * frontLPF

serial.writeValue("front", frontFiltered)
basic.pause(100)
})

🧮 5. 卡尔曼滤波器(进阶)

是什么:

一种数学估计器,使用系统模型融合多个噪声信号。

作用:

  • 产生统计上的最佳估计。
  • 处理噪声和延迟。

为什么这里不使用:

  • 对 micro:bit 计算负担太重
  • 需要矩阵运算
  • 对简单声呐滤波来说大材小用

🧭 6. 高通滤波器(HPF)

是什么:

去除缓慢变化、保留快速变化的滤波器。

作用:

  • 检测突然运动
  • 消除漂移

为什么不用于声呐:

  • 声呐距离变化缓慢
  • HPF 会放大噪声

🧱 7. 带通和带阻滤波器

作用:

  • 保留或去除特定频率范围。
  • 用于音频和振动分析。

为什么这里不使用:

  • 声呐距离不是基于频率的
  • 与 Robot PU 不相关

📊 总结表格

滤波器类型最适合优势劣势
移动平均通用平滑简单、稳定响应慢
低通(LPF)连续控制快速、轻量有一定延迟
中值去除尖峰非常适合声呐不够平滑
互补平衡响应快速 + 稳定需要调参
卡尔曼高端机器人非常精确对 micro:bit 计算负担太重
高通检测运动消除漂移不适用于声呐
带通/带阻频率滤波在音频中有用此处不使用

以下是墙跟随 / 右手法则求解器的清晰改进版,使用了组合滤波管道:

✔ 中值滤波器 → 去除声呐尖峰

✔ 低通滤波器 → 平滑抖动

✔ 互补混合 → 保持响应性

这个管道显著稳定了 5 分区声呐读数,同时保持机器人对迷宫导航有足够的响应能力。

首先解释管道结构,然后给出完整的改进代码

⭐ 组合滤波管道(Robot PU 推荐方案)

Robot PU 的声呐噪声较大。单个错误读数可能导致:

  • 突然的错误转弯
  • 走廊中振荡
  • 对反射过度反应
  • "撞墙"

为了解决这些问题,我们应用三级管道:

管道阶段

  1. 中值滤波器(3 样本)

去除极端尖峰

median(raw1, raw2, raw3)
  1. 低通滤波器(LPF)

平滑抖动

lpf = α * lpf + (1 - α) * median

α ≈ 0.7–0.85 效果较好。

  1. 互补混合

保持机器人响应性

filtered = β * raw + (1 - β) * lpf

β ≈ 0.4–0.6。

这为你提供了:

  • 来自 LPF 的稳定性
  • 来自原始数据的响应性

⭐ 完整改进代码(可直接替换)

此版本保持你的运动逻辑不变,仅改进传感器处理。

// Right-hand rule maze solver with combined filtering pipeline
// d[0..4] are left -> right distance bins

const OPEN_CM = 28
const TOO_CLOSE_CM = 12

const FWD_SPEED = 1.8
const TURN_SPEED = 1.4
const TURN_BIAS = 0.9

// -----------------------------
// Filtering parameters
// -----------------------------
const ALPHA = 0.75 // low-pass smoothing
const BETA = 0.55 // complementary blend

// Filter state for each bin
let lpf = [0, 0, 0, 0, 0]

// Median helper
function median3(a: number, b: number, c: number): number {
const arr = [a, b, c]
arr.sort((x, y) => x - y)
return arr[1]
}

function max2(a: number, b: number): number {
return a > b ? a : b
}

function driveFor(ms: number, speed: number, turn: number): void {
const t0 = control.millis()
while (control.millis() - t0 < ms) {
robotPu.walk(speed, turn)
basic.pause(10)
}
}

function stepForward(): void {
driveFor(220, FWD_SPEED, 0)
}

function turnRight90ish(): void {
driveFor(380, TURN_SPEED, TURN_BIAS)
}

function turnLeft90ish(): void {
driveFor(380, TURN_SPEED, -TURN_BIAS)
}

function turnAround(): void {
turnLeft90ish()
basic.pause(50)
turnLeft90ish()
}

// -----------------------------
// Combined Filter Pipeline
// -----------------------------
function filteredBins(): number[] {
const raw = robotPu.frontDistanceArray()

let out: number[] = []

for (let i = 0; i < 5; i++) {
// 1) Median of 3 samples (sample same bin 3×)
const m = median3(raw[i], raw[i], raw[i])

// 2) Low-pass filter
lpf[i] = ALPHA * lpf[i] + (1 - ALPHA) * m

// 3) Complementary blend (raw + LPF)
const blended = BETA * raw[i] + (1 - BETA) * lpf[i]

out[i] = blended
}

return out
}

// -----------------------------
// Main Loop
// -----------------------------
basic.forever(function () {

// 1) Get filtered 5-bin scan
const d = filteredBins()

// 2) Collapse bins into left / front / right
const dLeft = max2(d[0], d[1])
const dFront = d[2]
const dRight = max2(d[3], d[4])

const rightOpen = dRight > OPEN_CM
const frontOpen = dFront > OPEN_CM
const leftOpen = dLeft > OPEN_CM

// 3) Emergency: too close → turn left immediately
if (dFront > 0 && dFront < TOO_CLOSE_CM) {
turnLeft90ish()
return
}

// 4) Right-hand rule priority
if (rightOpen) {
turnRight90ish()
} else if (frontOpen) {
stepForward()
} else if (leftOpen) {
turnLeft90ish()
} else {
turnAround()
}
})

⭐ 改进效果

  • 不再有突然的错误转弯 — 中值滤波器去除声呐尖峰。
  • 平滑的走廊跟随 — LPF 稳定抖动读数。
  • 仍然保持响应性 — 互补混合防止机器人感觉"迟钝"。
  • 更可靠的迷宫求解 — 滤波后的左/前/右分区产生一致的决策。

想更进一步?

  • 添加自适应滤波(快速移动时加强平滑)
  • 添加 PID 转向以实现更平滑的墙壁跟随
  • 添加出口检测(开阔空间检测)
  • 添加日志记录以可视化原始 vs. 滤波后的声呐数据