传感器系列(一)——超声波测距传感器 HC-SR04 模块的避障小车实战应用 1. 超声波测距传感器入门指南第一次接触HC-SR04超声波测距模块时我完全被它简单的工作原理和强大的功能吸引了。这个看起来只有火柴盒大小的模块居然能精确测量2厘米到4米范围内的物体距离精度可以达到惊人的0.3厘米这让我想起了蝙蝠在黑暗中飞行的原理——通过发射声波并接收回波来判断障碍物的位置。HC-SR04模块的核心部件是一对超声波换能器一个负责发射40kHz的超声波另一个负责接收回波。工作时我们只需要给Trig引脚一个10微秒以上的高电平脉冲模块就会自动发射8个周期的超声波脉冲然后通过Echo引脚返回一个高电平信号这个高电平的持续时间就是超声波从发射到返回的总时间。模块的基本参数工作电压DC 5V工作电流15mA测量角度15度测量周期60ms尺寸45mm×20mm×15mm在实际项目中我发现这个模块特别适合用于智能小车的避障系统。相比红外传感器超声波测距不受环境光线影响而且测量范围更大。不过要注意的是超声波在空气中的传播速度会受温度影响在精度要求高的场合可能需要加入温度补偿。2. HC-SR04模块的硬件连接连接HC-SR04到开发板其实非常简单但第一次使用时我还是踩了几个坑。模块只有4个引脚VCC、GND、Trig和Echo。VCC接5V电源GND接地这两个引脚接反会导致模块损坏我就因此烧坏过一个模块。与不同开发板的连接方式2.1 Arduino连接方案VCC - 5V GND - GND Trig - 任意数字引脚(如11) Echo - 任意数字引脚(如12)2.2 STM32连接方案VCC - 5V GND - GND Trig - PA0(TIM2_CH1) Echo - PA1(TIM2_CH2)我建议在VCC和GND之间加一个0.1uF的滤波电容可以显著提高模块的稳定性。另外Echo引脚的输出是5V电平如果连接到3.3V系统的MCU比如STM32F103最好加一个电平转换电路或者使用电阻分压。实测中发现当电源质量不好时模块的测量结果会出现跳变。这时可以在VCC和GND之间并联一个100uF的电解电容效果立竿见影。还有一个常见问题是多个超声波模块同时工作时会相互干扰解决方法要么是分时工作要么给每个模块单独供电。3. 驱动代码编写与优化3.1 Arduino基础驱动最简单的Arduino驱动代码如下适合新手快速上手const int trigPin 11; const int echoPin 12; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration pulseIn(echoPin, HIGH); float distance duration * 0.034 / 2; Serial.print(Distance: ); Serial.print(distance); Serial.println( cm); delay(100); }这段代码虽然简单但在实际使用中我发现几个可以优化的地方pulseIn()函数有超时限制默认1秒没有做多次测量取平均没有处理超出量程的情况3.2 STM32高级驱动对于STM32我们可以利用定时器实现更精确的测量。下面是我在项目中实际使用的代码片段// hcsr04.h #ifndef __HCSR04_H #define __HCSR04_H #include sys.h void Hcsr04Init(void); float Hcsr04GetLength(void); #endif// hcsr04.c #include hcsr04.h #include stm32f10x.h #include delay.h #define TRIG_Send PAout(0) #define ECHO_Reci PAin(1) u32 GetEchoTimer(void) { u32 t TIM_GetCounter(TIM2); TIM2-CNT 0; return t; } float Hcsr04GetLength(void) { u32 t 0; float lengthTemp 0; float sum 0; for(int i0; i5; i) { TRIG_Send 1; delay_us(20); TRIG_Send 0; while(ECHO_Reci 0); TIM_Cmd(TIM2, ENABLE); while(ECHO_Reci 1); TIM_Cmd(TIM2, DISABLE); t GetEchoTimer(); lengthTemp ((float)t/58.0); sum lengthTemp; delay_ms(60); } return sum/5.0; }这个实现做了五点优化使用硬件定时器(TIM2)精确计时采用5次测量取平均值每次测量间隔60ms以上直接操作寄存器提高响应速度加入了超时保护机制4. 避障算法设计与实现4.1 基础避障逻辑最简单的避障逻辑就是设置一个距离阈值当检测到障碍物距离小于这个阈值时小车就转向。代码实现如下void avoidObstacle(float distance) { if(distance 20) { // 20cm阈值 stopCar(); delay(100); turnRight(90); // 右转90度 delay(100); } else { moveForward(); } }但这种简单算法在实际测试中表现不佳特别是在复杂环境中容易陷入震荡——反复检测到障碍物左右摇摆就是出不去。4.2 改进的多传感器融合算法更成熟的方案是使用多个超声波传感器比如左、中、右三个配合状态机实现智能避障。下面是我在智能小车项目中使用的一种算法typedef enum { STATE_FORWARD, STATE_TURN_LEFT, STATE_TURN_RIGHT, STATE_BACK } State; State currentState STATE_FORWARD; void decisionMaking(float leftDist, float centerDist, float rightDist) { static uint32_t lastChangeTime 0; switch(currentState) { case STATE_FORWARD: if(centerDist 30) { if(leftDist rightDist) { currentState STATE_TURN_LEFT; } else { currentState STATE_TURN_RIGHT; } lastChangeTime HAL_GetTick(); } break; case STATE_TURN_LEFT: if(HAL_GetTick() - lastChangeTime 500) { // 转向500ms currentState STATE_FORWARD; } break; case STATE_TURN_RIGHT: if(HAL_GetTick() - lastChangeTime 500) { currentState STATE_FORWARD; } break; case STATE_BACK: if(HAL_GetTick() - lastChangeTime 300) { currentState STATE_FORWARD; } break; } // 执行当前状态对应的动作 executeState(currentState); }这个算法引入了状态机概念使小车的决策更加合理。我还加入了时间控制确保每个动作执行足够的时间避免了频繁切换状态导致的抖动问题。5. 常见问题与调试技巧5.1 测量不稳定的解决方法在实际使用中可能会遇到测量值跳动大的问题。经过多次测试我总结了以下几个解决方法电源滤波在模块的VCC和GND之间并联一个100uF电解电容和一个0.1uF陶瓷电容多次采样连续测量5次取中间值适当延时两次测量之间至少间隔60ms环境因素避免在风扇附近或空气流动大的地方使用5.2 超出量程的处理当没有检测到障碍物时模块可能会返回错误的大数值。可以在代码中加入合理性判断float safeGetDistance() { float dist Hcsr04GetLength(); if(dist 400 || dist 2) { // 有效范围2-400cm return NAN; // 返回无效值 } return dist; }5.3 多模块干扰问题如果需要使用多个HC-SR04模块比如在小车的前、左、右各装一个会出现相互干扰的问题。我的解决方案是分时工作轮流激活各个模块确保同一时间只有一个在工作物理隔离模块之间保持一定距离最好大于50cm软件滤波对异常数据做特殊处理6. 进阶应用与扩展6.1 三维环境建模通过舵机带动超声波传感器旋转可以构建二维甚至三维的环境地图。这需要结合步进电机控制和数据融合算法#include Servo.h Servo myServo; const int servoPin 9; void setup() { myServo.attach(servoPin); Serial.begin(115200); } void scanEnvironment() { for(int angle 0; angle 180; angle 10) { myServo.write(angle); delay(100); float dist getDistance(); Serial.print(angle); Serial.print(,); Serial.println(dist); } }6.2 与其他传感器融合将超声波与红外、IMU等传感器数据融合可以大大提高系统的可靠性。例如结合MPU6050的加速度计数据可以在小车倾斜时补偿距离测量值。6.3 低功耗设计对于电池供电的应用可以通过间歇工作的方式降低功耗void loop() { float dist getDistance(); if(dist 100) { // 检测到附近有障碍物 // 进入高频率检测模式 highFrequencyMode(); } else { // 进入低功耗模式 lowPowerMode(); delay(1000); // 每秒检测一次 } }7. 项目实战智能避障小车7.1 硬件组装制作一个完整的避障小车需要以下部件Arduino或STM32开发板HC-SR04超声波模块L298N电机驱动模块直流电机和车轮7.4V锂电池车体框架组装时要注意将超声波模块安装在小车前方适当高度避免地面反射干扰。我在第一次组装时就把模块装得太低导致一直检测到地面。7.2 完整代码框架下面是一个基于Arduino的避障小车完整代码框架#include NewPing.h #define TRIGGER_PIN 11 #define ECHO_PIN 12 #define MAX_DISTANCE 200 NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); void setup() { pinMode(5, OUTPUT); // 电机控制引脚 pinMode(6, OUTPUT); pinMode(9, OUTPUT); pinMode(10, OUTPUT); Serial.begin(115200); } void loop() { int distance sonar.ping_cm(); Serial.print(Distance: ); Serial.print(distance); Serial.println(cm); if(distance 20 distance ! 0) { avoidObstacle(); } else { moveForward(); } delay(50); } void avoidObstacle() { stopCar(); delay(100); if(random(2) 0) { turnLeft(); } else { turnRight(); } delay(300); } void moveForward() { digitalWrite(5, HIGH); digitalWrite(6, LOW); digitalWrite(9, HIGH); digitalWrite(10, LOW); } // 其他运动函数类似...7.3 性能优化建议经过多次测试我总结了以下几点优化建议使用中断方式读取Echo信号减少CPU占用采用PID控制算法实现平滑转向添加蓝牙或WiFi模块实现远程监控使用3D打印定制传感器支架在复杂环境中可以增加超声波模块数量8. 替代方案与进阶选择虽然HC-SR04性价比很高但在某些特殊场景下可能需要考虑其他方案VL53L0X激光测距模块精度更高但测量距离较短约2米US-100串口输出使用更方便支持温度补偿TeraRanger工业级测距模块最大测距可达14米红外测距如Sharp GP2Y0A系列适合短距离测量对于需要精确测距的项目我推荐尝试VL53L0X。它的精度可以达到毫米级而且体积更小。不过价格是HC-SR04的5-10倍需要根据项目预算权衡。