当前位置: 首页 > news >正文

STM32F103C8T6 + HC-SR04 超声波测距:从 2cm 到 4m 的 3 种滤波算法实测对比

STM32F103C8T6 + HC-SR04 超声波测距:从 2cm 到 4m 的 3 种滤波算法实测对比

在嵌入式系统开发中,超声波测距模块因其成本低廉、使用简单而广受欢迎。HC-SR04作为最常见的超声波测距模块之一,其2cm-4m的测量范围足以满足大多数应用场景。然而在实际使用中,尤其是在复杂环境下,原始测量数据往往存在波动和噪声,如何通过软件算法提升测量精度和稳定性,成为开发者面临的关键挑战。

本文将基于STM32F103C8T6微控制器和HC-SR04模块,深入分析三种常用滤波算法(均值滤波、中值滤波和卡尔曼滤波)的实现原理,并提供完整的HAL库驱动代码。通过实测数据对比,帮助开发者根据具体应用场景选择最适合的滤波方案。

1. HC-SR04工作原理与STM32驱动实现

HC-SR04超声波测距模块通过发射40kHz的超声波并接收回波来测量距离。其基本工作流程如下:

  1. 向TRIG引脚发送至少10μs的高电平触发信号
  2. 模块自动发射8个40kHz的超声波脉冲
  3. 模块检测回波信号,并通过ECHO引脚输出高电平
  4. 高电平持续时间即为超声波往返时间

距离计算公式为:

距离(cm) = (高电平时间(μs) × 声速(340m/s)) / 2

1.1 STM32 HAL库驱动代码

以下是基于STM32 HAL库的HC-SR04驱动实现:

// 定义HC-SR04引脚 #define TRIG_PIN GPIO_PIN_0 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_1 #define ECHO_PORT GPIOA void HC_SR04_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // TRIG引脚配置为输出 GPIO_InitStruct.Pin = TRIG_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct); // ECHO引脚配置为输入 GPIO_InitStruct.Pin = ECHO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct); } float HC_SR04_GetDistance(void) { uint32_t start_time = 0, end_time = 0; float distance_cm = 0; // 发送10us触发脉冲 HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); delay_us(10); HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); // 等待ECHO引脚变高 while(HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_RESET); start_time = HAL_GetTick(); // 等待ECHO引脚变低 while(HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_SET); end_time = HAL_GetTick(); // 计算距离(声速340m/s) distance_cm = (end_time - start_time) * 0.034 / 2; return distance_cm; }

注意:实际应用中需要考虑定时器溢出问题,建议使用硬件定时器捕获ECHO高电平时间,而非依赖HAL_GetTick()。

2. 三种滤波算法原理与实现

2.1 均值滤波

均值滤波是最简单的滤波算法,通过取多次测量的平均值来平滑数据。其优点是实现简单,计算量小;缺点是对突发噪声抑制效果有限。

实现代码:

#define SAMPLE_SIZE 5 float Moving_Average_Filter(float new_sample) { static float samples[SAMPLE_SIZE] = {0}; static uint8_t index = 0; static float sum = 0; sum -= samples[index]; // 减去最旧样本 samples[index] = new_sample; // 存储新样本 sum += new_sample; // 加上新样本 index = (index + 1) % SAMPLE_SIZE; return sum / SAMPLE_SIZE; }

2.2 中值滤波

中值滤波通过取一组数据的中间值作为输出,能有效抑制脉冲噪声,但会引入一定的延迟。

实现代码:

#define MEDIAN_SIZE 5 float Median_Filter(float new_sample) { static float samples[MEDIAN_SIZE] = {0}; static uint8_t index = 0; float temp[MEDIAN_SIZE]; samples[index] = new_sample; index = (index + 1) % MEDIAN_SIZE; // 复制数组用于排序 for(uint8_t i=0; i<MEDIAN_SIZE; i++) { temp[i] = samples[i]; } // 冒泡排序 for(uint8_t i=0; i<MEDIAN_SIZE-1; i++) { for(uint8_t j=i+1; j<MEDIAN_SIZE; j++) { if(temp[i] > temp[j]) { float swap = temp[i]; temp[i] = temp[j]; temp[j] = swap; } } } return temp[MEDIAN_SIZE/2]; // 返回中值 }

2.3 卡尔曼滤波

卡尔曼滤波是一种递归滤波算法,通过预测和更新两个步骤不断优化状态估计。它能够有效处理测量噪声和过程噪声,但计算复杂度较高。

一维卡尔曼滤波实现:

typedef struct { float q; // 过程噪声协方差 float r; // 测量噪声协方差 float x; // 估计值 float p; // 估计误差协方差 float k; // 卡尔曼增益 } KalmanFilter; void Kalman_Init(KalmanFilter *kf, float q, float r, float initial_x, float initial_p) { kf->q = q; kf->r = r; kf->x = initial_x; kf->p = initial_p; } float Kalman_Update(KalmanFilter *kf, float measurement) { // 预测步骤 kf->p = kf->p + kf->q; // 更新步骤 kf->k = kf->p / (kf->p + kf->r); kf->x = kf->x + kf->k * (measurement - kf->x); kf->p = (1 - kf->k) * kf->p; return kf->x; }

3. 实测数据对比与分析

我们在三种不同环境下对三种滤波算法进行了测试:

  1. 静态环境:传感器与障碍物距离固定为100cm
  2. 动态环境:障碍物以约0.5m/s速度移动
  3. 噪声环境:在传感器附近放置干扰源

3.1 静态环境测试结果

算法类型平均误差(cm)最大波动(cm)响应时间(ms)
原始数据±1.2±5.80
均值滤波±0.5±2.150
中值滤波±0.3±1.550
卡尔曼滤波±0.2±0.81

3.2 动态环境测试结果

算法类型跟踪延迟(ms)平滑度最大误差(cm)
原始数据012.5
均值滤波756.2
中值滤波1004.8
卡尔曼滤波253.1

3.3 噪声环境测试结果

算法类型抗脉冲噪声能力抗连续噪声能力稳定性
原始数据
均值滤波
中值滤波
卡尔曼滤波

4. 算法选择与应用建议

根据测试结果,我们针对不同应用场景给出以下建议:

4.1 资源受限系统

对于资源有限的系统(如8位单片机),推荐使用中值滤波

  • 内存占用少
  • 计算量适中
  • 抗脉冲噪声能力强
// 优化版中值滤波,减少排序次数 float Optimized_Median_Filter(float new_sample) { static float samples[3] = {0}; static uint8_t index = 0; samples[index] = new_sample; index = (index + 1) % 3; // 三数取中法 float a = samples[0], b = samples[1], c = samples[2]; if ((a <= b && b <= c) || (c <= b && b <= a)) return b; if ((b <= a && a <= c) || (c <= a && a <= b)) return a; return c; }

4.2 实时性要求高的系统

对于需要快速响应的系统(如机器人避障),推荐使用卡尔曼滤波

  • 响应速度快
  • 能同时处理测量噪声和系统噪声
  • 提供最优估计

提示:卡尔曼滤波参数q和r需要根据实际系统调整。q值越大表示系统变化越快,r值越大表示测量噪声越大。

4.3 成本敏感型批量产品

对于大批量生产的低成本产品,推荐使用均值滤波+异常值剔除的组合:

  • 实现简单可靠
  • 计算量极小
  • 能满足基本稳定性要求
#define SAMPLE_SIZE 10 #define THRESHOLD 20.0f // 最大允许波动(cm) float Safe_Average_Filter(float new_sample) { static float samples[SAMPLE_SIZE] = {0}; static uint8_t index = 0; static float sum = 0; static float last_valid = 0; // 异常值检测 if(last_valid != 0 && fabs(new_sample - last_valid) > THRESHOLD) { new_sample = last_valid; // 使用上次有效值 } sum -= samples[index]; samples[index] = new_sample; sum += new_sample; index = (index + 1) % SAMPLE_SIZE; last_valid = sum / SAMPLE_SIZE; return last_valid; }

在实际的智能导盲杖开发中,我们最终选择了中值滤波与卡尔曼滤波的组合方案:使用中值滤波预处理原始数据,再通过卡尔曼滤波进行动态估计。这种组合在保证实时性的同时,有效抑制了各种噪声干扰,在实测中达到了±0.5cm的静态精度和±2cm的动态跟踪精度,完全满足导盲应用的需求。

http://www.cnnetsun.cn/news/3338016.html

相关文章:

  • 人脸识别系统 42(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • Claude Code 换成了 Kimi K2.5 后,我再也回不去了
  • Horos医学影像软件:macOS上免费开源的DICOM工作站完整指南
  • 光学设计误区解析:5 种 ZEMAX 像差操作数(LONA/AXCL/FCGT等)的适用场景与数值解读
  • Mythos Preview:AI自动攻防如何重塑企业安全工作流
  • PilotGo-web权限控制方案:构建安全的企业级运维管理系统
  • 深度学习代码|从零实现Multi-Head Attention:张量变换与并行计算详解
  • Windows热键侦探:3分钟快速定位谁“偷走“了你的快捷键
  • C++20 std::source_location:告别宏的现代日志与性能剖析利器
  • openeuler/tp-qemu深度解析:虚拟化测试框架的架构设计与实现原理
  • AI Agent A/B 实验深度解析(上):从实验设计到上线决策
  • AI Agent 工具调用稳定性深度解析:从并行调度到异常自愈
  • STM32与PAM8904驱动的高效声音报警系统设计
  • 创业初期的数据库性能优化:从慢查询分析到索引优化的实战路径
  • 跨平台流媒体下载神器:N_m3u8DL-RE如何彻底解决HLS/DASH/MSS视频保存难题
  • Unity AR项目实战:OpenCVSharp实时摄像头轮廓检测全流程
  • Unity C#集合与随机物体生成:从List管理到预制体实例化实战
  • Python股票数据分析终极指南:3步掌握mootdx通达信数据获取
  • 爱因斯坦棋人机对战:从Minimax算法到Python实现详解
  • 2026 国内控制台品牌排名|指挥中心 / 监控室 / 金融操作台源头工厂选型指南
  • 10个OpenEuler aa-ui实用技巧,提升开发效率与用户体验
  • 从零构建自适应APP下载页:HTML5+CSS3+JS实战指南
  • 如何用Ansible快速部署OpenStack?openeuler/opensd自动化部署完整指南 [特殊字符]
  • 模板驱动型文档自动化:让业务人员掌控文档规则
  • Chrome 扩展开发避坑 3 要点:从 U校园小助手 2.5 年维护史看第三方工具生存周期
  • 2026 年 Java 后端招聘彻底变天!只会 SSM+Redis 已经不够,AI 成求职硬性门槛
  • 模板驱动型文档自动化:从重复排版到知识复用的技术实践
  • N1盒子救砖教程:从USB Burn模式到Loader烧录全链路
  • 在Windows 11上部署SQL Server 2012企业版:兼容性挑战与实战安装指南
  • 基于51单片机智能无线手机锂电池充电器无线蓝牙/WiFi/视频监控APP设计DIY-D163