超声波测距

罗大富 BigRich大约 6 分钟ESP32Python

本节课来学习使用 MicroPython 控制超声波传感器并获取距离数据,最终搭配一个蜂鸣器实现倒车雷达的效果。

实验原理

超声波是一种频率高于 20000Hz 的声波,超声波的方向性好,反射能力强,易于获得较集中的声能,在水中传播距离比空气中远,可用于测距、测速、清洗、焊接、碎石、杀菌消毒等。

超声波可用于许多不同的领域。超声波设备用于检测物体和测量距离。超声成像或超声检查常用于医学。在产品和结构的无损检测中,超声波用于检测不可见的缺陷。在工业上,超声波用于清洁、混合和加速化学过程。蝙蝠和鼠海豚等动物使用超声波来定位猎物和障碍物。

本实验使用的超声波模块为 HC-SR04 超声波传感器,其原理为利用超声波在遇到障碍物后反射,结合声波在空气中的传播速度,可以得出传播的距离。该模块外观如下图所示:

超声波传感器使用声纳来确定与物体的距离。我们使用的超声波模块由 2 个超声波探头组成:

  1. T:表示 Transmitter(发射),负责发送超声波信号;
  2. R:表示 Receiver(接收),负责接收回响信号;

注意

如果在使用过程中,对其中任意一个探头进行遮挡,都会使超声波无法正常测量距离。

底部有四个引脚:

  1. VCC:5V 供电引脚;
  2. GND:接地;
  3. TRIG:控制信号输入;
  4. ECHO:回响信号输出;

以上时序图表示超声波模块的基本工作原理:

  • 采用 IO 口 TRIG 触发测距,给一个 10us 的高电平信号;
  • 模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
  • 有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2

Trig 引脚是用来输入一个长为 10us 的高电平方波,通过输入这一方波,模块会自动发射 8 个 40KHz 的声波,并在这个时刻,Echo 引脚会由 0 变为 1,此时开启定时器定时。当超声波返回并被模块接收到后,Echo 端引脚电平从 1 变为 0,出现下降沿。这时候结束定时,通过计算定时器的值并乘上 340m/s 的声音传播速度,即可计算所测距离。

回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式如下:

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

硬件电路设计

物料清单(BOM 表):

材料名称数量
有源蜂鸣器1
LED1
1KΩ 电阻1
超声波模块 HC-SR041
杜邦线(跳线)若干
面包板1
202504151305948

软件程序设计

在使用超声波传感器测距时,我们需要用到 machine 模块中的 time_pulse_us(pin, pulse_level, timeout_us=1000000) 方法,具体可以参考 MicroPython 官方手册open in new window

time_pulse_us() 的作用是在给定引脚上为脉冲计时,并返回脉冲持续时长,单位为 us。为低脉冲计时时,pulse_level 参数应为 0;为高脉冲计时时,该参数应为 1。

若引脚的当前输入值与 pulse_level 不同,该函数首先需等待,直至引脚输入与 pulse_level 相等;然后为引脚与 pulse_level 相等的时段计时。若引脚已与 pulse_level 相等,则计时立即开始。

1. 超声波测距

该程序的功能是通过超声波模块测算距离并打印在命令行中,代码如下:

import time
from machine import Pin, time_pulse_us


# 定义echo 与 trig 引脚
echo = Pin(14, Pin.IN)
trig = Pin(27, Pin.OUT)

# 将 trigger 引脚设置为低电平
trig.value(0)

while True:
    # 发送一个 10us 的方波脉冲
    trig.value(1)
    time.sleep_us(10)
    trig.value(0)
    
    # 获取脉冲时间
    pulse_time = time_pulse_us(echo, 1)
    
    # 根据时间计算距离
    distance = pulse_time * 0.3432 / 2
    
    print('距离为: %dmm' % distance)
    time.sleep(0.1)

由于 HCSR04 很常用,因此,网上也有很多别人封装好的模块,比如下面代码:

import machine, time
from machine import Pin

__version__ = '0.2.0'
__author__ = 'Roberto Sánchez'
__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0"

class HCSR04:
    """
    Driver to use the untrasonic sensor HC-SR04.
    The sensor range is between 2cm and 4m.

    The timeouts received listening to echo pin are converted to OSError('Out of range')

    """
    # echo_timeout_us is based in chip range limit (400cm)
    def __init__(self, trigger_pin, echo_pin, echo_timeout_us=500*2*30):
        """
        trigger_pin: Output pin to send pulses
        echo_pin: Readonly pin to measure the distance. The pin should be protected with 1k resistor
        echo_timeout_us: Timeout in microseconds to listen to echo pin. 
        By default is based in sensor limit range (4m)
        """
        self.echo_timeout_us = echo_timeout_us
        # Init trigger pin (out)
        self.trigger = Pin(trigger_pin, mode=Pin.OUT, pull=None)
        self.trigger.value(0)

        # Init echo pin (in)
        self.echo = Pin(echo_pin, mode=Pin.IN, pull=None)

    def _send_pulse_and_wait(self):
        """
        Send the pulse to trigger and listen on echo pin.
        We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received.
        """
        self.trigger.value(0) # Stabilize the sensor
        time.sleep_us(5)
        self.trigger.value(1)
        # Send a 10us pulse.
        time.sleep_us(10)
        self.trigger.value(0)
        try:
            pulse_time = machine.time_pulse_us(self.echo, 1, self.echo_timeout_us)
            return pulse_time
        except OSError as ex:
            if ex.args[0] == 110: # 110 = ETIMEDOUT
                raise OSError('Out of range')
            raise ex

    def distance_mm(self):
        """
        Get the distance in milimeters without floating point operations.
        """
        pulse_time = self._send_pulse_and_wait()

        # To calculate the distance we get the pulse_time and divide it by 2 
        # (the pulse walk the distance twice) and by 29.1 becasue
        # the sound speed on air (343.2 m/s), that It's equivalent to
        # 0.34320 mm/us that is 1mm each 2.91us
        # pulse_time // 2 // 2.91 -> pulse_time // 5.82 -> pulse_time * 100 // 582 
        mm = pulse_time * 100 // 582
        return mm

    def distance_cm(self):
        """
        Get the distance in centimeters with floating point operations.
        It returns a float
        """
        pulse_time = self._send_pulse_and_wait()

        # To calculate the distance we get the pulse_time and divide it by 2 
        # (the pulse walk the distance twice) and by 29.1 becasue
        # the sound speed on air (343.2 m/s), that It's equivalent to
        # 0.034320 cm/us that is 1cm each 29.1us
        cms = (pulse_time / 2) / 29.1
        return cms

2. 自定义 HCSR04 类

我们可以通过学习他人的代码,并将其转化为自己的代码,从而加深学习,提高自己的编程能力,下面是我仿写的代码:

import time
from machine import Pin, time_pulse_us


# 定义 HCSR04 公共类
class HCSR04:
    
    def __init__(self, trigger_pin, echo_pin):
        # 初始化 trigger 与 echo 引脚
        self.trigger = Pin(trigger_pin, Pin.OUT)
        self.echo = Pin(echo_pin, Pin.IN)
        
        # 将 trigger 引脚设置为低电平
        self.trigger.value(0)
        
    def get_distance(self):
        # 初始化传感器
        self.trigger.value(0)
        time.sleep_us(5)
        
        # 通过 T 探头发送 1 个 10us 的脉冲
        self.trigger.value(1)
        time.sleep_us(10)
        self.trigger.value(0)
        
        # 获取脉冲时间
        pulse_time = time_pulse_us(self.echo, 1)
        
        # 根据时间计算距离
        distance = pulse_time * 0.3432 / 2
        
        return distance

提示

第三方代码尽量放在 libs 目录中,自己写的代码放在 common 目录下

然后,我们就可以调用该模块中的 HCSR04 公共类了,代码如下:

import time
from common.hcsr04 import HCSR04


# 定义 HCSR04 对象
sensor = HCSR04(27, 14)


while True:
    # 获取测量距离
    distance = sensor.get_distance()
    print('距离为: %dmm' %distance)
    time.sleep(0.1)

3. 倒车雷达系统

最后,我们可以根据获取的距离来实现倒车雷达的效果,距离近的时候蜂鸣器会报警,LED 闪烁,随着距离越来越近,蜂鸣器发生频率与 LED 的闪烁频率都会越来越频繁,代码如下:

import time
from machine import Pin
from common.hcsr04 import HCSR04


# 定义 HCSR04 对象
sensor = HCSR04(27, 14)

# 定义蜂鸣器与LED对象
buzzer = Pin(15, Pin.OUT)
led = Pin(2, Pin.OUT)

# 初始化
buzzer.value(0)
led.value(0)


while True:
    # 获取距离
    distance = sensor.get_distance()
    print('距离为: %dmm' % distance)
    
    # 如果距离过近则报警,距离越近,报警越频繁
    if distance < 200:
        delay_time = int(distance)
        buzzer.value(1)
        led.value(1)
        time.sleep_ms(delay_time)
        buzzer.value(0)
        led.value(0)
        time.sleep_ms(delay_time)
    else:
        buzzer.value(0)
        led.value(0)
        time.sleep(0.1)
上次编辑于:
贡献者: 罗大富BigRich