MicroPython: Ультразвуковой датчик HC-SR04 с ESP32 и ESP8266 (Измерение расстояния)
В этом руководстве вы узнаете, как использовать ультразвуковой датчик HC-SR04 с платами ESP32 и ESP8266 для получения расстояния до объекта с помощью прошивки MicroPython. В статье рассматривается подключение датчика к платам ESP32 и ESP8266, а также приводится простой скрипт MicroPython для получения расстояния до объекта и его отображения на OLED-дисплее.
Предварительные требования
Для прохождения этого руководства вам необходима прошивка MicroPython, установленная на платах ESP32 или ESP8266. Также вам потребуется IDE для написания и загрузки кода на плату. Мы рекомендуем использовать Thonny IDE или uPyCraft IDE:
Thonny IDE:
uPyCraft IDE:
Или, если вы знакомы с VS Code, вы можете использовать расширение PyMakr:
Вам также могут быть полезны другие руководства по HC-SR04:
Знакомство с ультразвуковым датчиком HC-SR04
Ультразвуковой датчик HC-SR04 использует сонар для определения расстояния до объекта. Этот датчик измеряет расстояние от 2 см до 400 см (от 0,8 дюйма до 157 дюймов) с точностью 0,3 см (0,1 дюйма), что хорошо подходит для большинства любительских проектов. Кроме того, данный модуль оснащён ультразвуковым передатчиком и приёмником.
На следующем изображении показан ультразвуковой датчик HC-SR04.
На следующем изображении показана обратная сторона датчика.
Технические характеристики HC-SR04
В следующей таблице приведены основные характеристики и спецификации ультразвукового датчика HC-SR04. Для получения дополнительной информации обратитесь к даташиту датчика.
Напряжение питания |
5 В постоянного тока |
Рабочий ток |
15 мА |
Рабочая частота |
40 кГц |
Максимальная дальность |
4 метра |
Минимальная дальность |
2 см |
Угол измерения |
15° |
Разрешение |
0,3 см |
Входной сигнал Trigger |
ТТЛ-импульс 10 мкс |
Выходной сигнал Echo |
ТТЛ-импульс, пропорциональный расстоянию |
Размеры |
45 мм x 20 мм x 15 мм |
Распиновка HC-SR04
Вот распиновка ультразвукового датчика HC-SR04.
VCC |
Питание датчика (5 В) |
Trig |
Вход триггера (Trigger Input Pin) |
Echo |
Выход эха (Echo Output Pin) |
GND |
Общая земля |
Как работает ультразвуковой датчик HC-SR04?
Ультразвуковой датчик использует сонар для определения расстояния до объекта. Вот как это работает:
Ультразвуковой передатчик (пин trig) излучает высокочастотный звук (40 кГц).
Звук распространяется в воздухе. Если он находит объект, то отражается обратно к модулю.
Ультразвуковой приёмник (пин echo) принимает отражённый звук (эхо).
Учитывая скорость звука в воздухе и время прохождения (время, прошедшее с момента передачи и приёма сигнала), мы можем рассчитать расстояние до объекта. Вот формула:
расстояние до объекта = ((скорость звука в воздухе) * время) / 2
скорость звука в воздухе при 20°C (68°F) = 343 м/с
Необходимые компоненты
Для выполнения этого руководства вам понадобятся следующие компоненты:
Схема подключения — ESP32 с HC-SR04
Подключите ультразвуковой датчик HC-SR04 к ESP32 согласно следующей схеме. Мы подключаем пин Trig к GPIO 5, а пин Echo к GPIO 18, но вы можете использовать любые другие подходящие пины. Перейдите к следующему разделу, если вы используете плату ESP8266.
Ультразвуковой датчик |
ESP32 |
|---|---|
VCC |
VIN |
Trig |
GPIO 5 |
Echo |
GPIO 18 |
GND |
GND |
Рекомендуем прочитать: Распиновка ESP32: какие GPIO пины следует использовать?
Схема подключения — ESP8266 с HC-SR04
Подключите ультразвуковой датчик HC-SR04 к ESP8266 согласно следующей схеме. Мы подключаем пин Trig к GPIO 12, а пин Echo к GPIO 14, но вы можете использовать любые другие подходящие пины.
Ультразвуковой датчик |
ESP8266 |
|---|---|
VCC |
VIN |
Trig |
GPIO 12 (D6) |
Echo |
GPIO 14 (D5) |
GND |
GND |
Библиотека HC-SR04 для MicroPython
Существует несколько способов получения расстояния до объекта с помощью HC-SR04 и плат ESP32/ESP8266 с прошивкой MicroPython. Мы будем использовать библиотеку HC-SR04 для MicroPython, которая упрощает работу с датчиком и получение измерений.
Библиотека, которую мы будем использовать, не является частью стандартной библиотеки MicroPython. Поэтому вам нужно загрузить следующую библиотеку на плату ESP32/ESP8266 (сохраните её с именем hcsr04.py).
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
Следуйте инструкциям для используемой вами IDE:
Загрузка библиотеки HC-SR04 с помощью uPyCraft IDE
Загрузка библиотеки HC-SR04 с помощью Thonny IDE
Перед переходом к следующему разделу убедитесь, что прошивка MicroPython загружена на ваши платы ESP32 или ESP8266. Вы можете следовать одному из следующих руководств:
A. Загрузка библиотеки HC-SR04 с помощью uPyCraft IDE
В этом разделе показано, как загрузить библиотеку с помощью uPyCraft IDE. Если вы используете Thonny IDE, читайте следующий раздел.
Сначала убедитесь, что установлено соединение между IDE и вашей платой. Перейдите в Tools > Serial и выберите COM-порт. Перейдите в Tools > Board и выберите плату. Затем нажмите кнопку Connect.
1. Создайте новый файл, нажав кнопку New File (1).
2. Скопируйте код библиотеки HC-SR04 в этот файл. Код библиотеки HC-SR04 можно найти здесь.
3. После копирования кода сохраните файл, нажав кнопку Save (2).
4. Назовите новый файл hcsr04.py и нажмите ok.
5. Нажмите кнопку Download and Run (3).
После этого файл должен появиться в папке устройства с именем hcsr04.py, как показано на следующем рисунке.
Теперь вы можете использовать функции библиотеки в своём коде, импортировав её.
B. Загрузка библиотеки HC-SR04 с помощью Thonny IDE
Если вы используете Thonny IDE, выполните следующие шаги:
1. Скопируйте код библиотеки в новый файл. Код библиотеки HC-SR04 можно найти здесь.
2. Перейдите в File > Save as…
3. Выберите сохранение на MicroPython device:
4. Назовите файл hcsr04.py и нажмите кнопку OK:
Готово. Библиотека загружена на вашу плату. Чтобы убедиться, что загрузка прошла успешно, перейдите в File > Save as… и выберите устройство MicroPython. Ваш файл должен быть в списке:
После загрузки библиотеки на плату вы можете использовать функции библиотеки в своём коде, импортировав её.
Код — Ультразвуковой датчик HC-SR04
После загрузки библиотеки на ESP32 или ESP8266 скопируйте следующий код в файл main.py или boot.py. Он просто выводит расстояние до ближайшего объекта каждую секунду (пример адаптирован со страницы библиотеки).
# Complete project details at https://RandomNerdTutorials.com/micropython-hc-sr04-ultrasonic-esp32-esp8266/
from hcsr04 import HCSR04
from time import sleep
# ESP32
sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)
# ESP8266
#sensor = HCSR04(trigger_pin=12, echo_pin=14, echo_timeout_us=10000)
while True:
distance = sensor.distance_cm()
print('Distance:', distance, 'cm')
sleep(1)
Как работает код
Сначала необходимо импортировать нужные библиотеки: импортируйте класс HCSR04 из библиотеки hcsr04. Также необходимо импортировать модуль time для добавления задержек в код.
from hcsr04 import HCSR04
from time import sleep
Затем создайте объект HCSR04 с именем sensor, который ссылается на датчик HCSR04. Передайте в качестве аргументов пин триггера, пин эха и таймаут (максимальное время распространения звуковой волны — когда датчик, вероятно, вне зоны действия).
sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)
Если вы используете ESP8266, закомментируйте предыдущую строку и раскомментируйте следующую, чтобы использовать другие пины:
sensor = HCSR04(trigger_pin=12, echo_pin=14, echo_timeout_us=10000)
Для получения расстояния в сантиметрах просто вызовите метод distance_cm объекта sensor. Сохраните результат в переменной distance.
distance = sensor.distance_cm()
Библиотека также предоставляет метод для получения расстояния в миллиметрах без операций с плавающей запятой. Просто вызовите:
distance = sensor.distance_mm()
Выведите расстояние в консоль MicroPython.
print('Distance:', distance, 'cm')
В конце добавлена задержка в одну секунду (расстояние обновляется каждую секунду):
sleep(1)
Демонстрация
После загрузки кода на плату нажмите кнопку RST для запуска кода. Расстояние до ближайшего объекта должно отображаться в консоли.
Отображение расстояния (HC-SR04) на OLED-дисплее
Теперь, когда вы знаете, как получить расстояние до ближайшего объекта с помощью ультразвукового датчика HC-SR04, мы отобразим показания датчика на OLED-дисплее.
Необходимые компоненты
Вот список компонентов, необходимых для выполнения этого примера:
Схема подключения
Добавьте OLED-дисплей I2C к предыдущей схеме. Следуйте схеме подключения для вашей платы.
ESP32
ESP8266
Файлы
Для этого примера вам нужны три файла:
hcsr04.py: файл, содержащий все методы для работы с датчиком HC-SR04. Это файл, который вы загрузили ранее.
ssd1306.py: библиотека для OLED-дисплея SSD1306 I2C. Её нужно загрузить на плату для связи и записи на дисплей.
main.py: основной скрипт для получения расстояния и отображения его на OLED-дисплее.
ssd1306.py
Создайте новый файл с именем ssd1306.py и скопируйте следующий код. Затем загрузите его на плату.
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit
import time
import framebuf
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xa4)
SET_NORM_INV = const(0xa6)
SET_DISP = const(0xae)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xa0)
SET_MUX_RATIO = const(0xa8)
SET_COM_OUT_DIR = const(0xc0)
SET_DISP_OFFSET = const(0xd3)
SET_COM_PIN_CFG = const(0xda)
SET_DISP_CLK_DIV = const(0xd5)
SET_PRECHARGE = const(0xd9)
SET_VCOM_DESEL = const(0xdb)
SET_CHARGE_PUMP = const(0x8d)
class SSD1306:
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
# Note the subclass must initialize self.framebuf to a framebuffer.
# This is necessary because the underlying data buffer is different
# between I2C and SPI implementations (I2C needs an extra byte).
self.poweron()
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR, 0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO, self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET, 0x00,
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV, 0x80,
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
# display
SET_CONTRAST, 0xff, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01): # on
self.write_cmd(cmd)
self.fill(0)
self.show()
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))
def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_framebuf()
def fill(self, col):
self.framebuf.fill(col)
def pixel(self, x, y, col):
self.framebuf.pixel(x, y, col)
def scroll(self, dx, dy):
self.framebuf.scroll(dx, dy)
def text(self, string, x, y, col=1):
self.framebuf.text(string, x, y, col)
class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
# Add an extra byte to the data buffer to hold an I2C data/command byte
# to use hardware-compatible I2C transactions. A memoryview of the
# buffer is used to mask this byte from the framebuffer operations
# (without a major memory hit as memoryview doesn't copy to a separate
# buffer).
self.buffer = bytearray(((height // 8) * width) + 1)
self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1
self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
self.i2c.writeto(self.addr, self.temp)
def write_framebuf(self):
# Blast out the frame buffer using a single I2C transaction to support
# hardware I2C interfaces.
self.i2c.writeto(self.addr, self.buffer)
def poweron(self):
pass
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
self.buffer = bytearray((height // 8) * width)
self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs.high()
self.dc.low()
self.cs.low()
self.spi.write(bytearray([cmd]))
self.cs.high()
def write_framebuf(self):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs.high()
self.dc.high()
self.cs.low()
self.spi.write(self.buffer)
self.cs.high()
def poweron(self):
self.res.high()
time.sleep_ms(1)
self.res.low()
time.sleep_ms(10)
self.res.high()
hcsr04.py
Загрузите файл hcsr04.py на плату.
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
main.py
В файле main.py мы получаем расстояние и отображаем его на OLED-дисплее.
# Complete project details at https://RandomNerdTutorials.com/micropython-hc-sr04-ultrasonic-esp32-esp8266/
from machine import Pin, I2C
import ssd1306
from hcsr04 import HCSR04
from time import sleep
# ESP32 Pin assignment
i2c = I2C(scl=Pin(22), sda=Pin(21))
sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)
# ESP8266 Pin assignment
#i2c = I2C(scl=Pin(5), sda=Pin(4))
#sensor = HCSR04(trigger_pin=12, echo_pin=14, echo_timeout_us=10000)
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
while True:
oled.fill(0)
#oled.show()
distance = sensor.distance_mm()
print('Distance:', distance, 'mm')
oled.text("Distance (mm)", 0, 15)
oled.text(str(distance), 0, 35)
oled.show()
sleep(1)
Код достаточно понятен. Чтобы узнать больше об использовании OLED-дисплея с платами ESP32 и ESP8266 на MicroPython, обратитесь к следующим руководствам:
Код начинается с импорта необходимых библиотек.
from machine import Pin, I2C
import ssd1306
from hcsr04 import HCSR04
from time import sleep
Установите пины для OLED-дисплея и ультразвукового датчика.
i2c = I2C(scl=Pin(5), sda=Pin(4))
sensor = HCSR04(trigger_pin=12, echo_pin=14, echo_timeout_us=10000)
Определите ширину и высоту OLED и инициализируйте OLED-дисплей.
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
В цикле while мы получаем расстояние и отображаем его на OLED.
Сначала очищаем дисплей в каждой итерации с помощью oled.fill(0).
oled.fill(0)
Получаем расстояние в мм и сохраняем в переменной distance.
distance = sensor.distance_mm()
Выводим расстояние в консоль.
print('Distance:', distance, 'mm')
Отображаем расстояние на дисплее. Обратите внимание, что необходимо преобразовать расстояние в строку с помощью функции str().
oled.text("Distance (mm)", 0, 15)
oled.text(str(distance), 0, 35)
Наконец, вызываем oled.show() для фактического отображения текста.
oled.show()
Расстояние обновляется каждую секунду.
sleep(1)
Демонстрация
Загрузите все предыдущие файлы на плату ESP32 или ESP8266 в следующем порядке:
ssd1306.py
hcsr04.py
main.py
Если вы не знаете, как загружать код, прочитайте наши руководства по началу работы с uPyCraft IDE, Thonny IDE или VS Code + PyMakr:
Начало работы с Thonny MicroPython (Python) IDE для ESP32 и ESP8266
Начало работы с MicroPython на ESP32 и ESP8266 (uPyCraft IDE)
MicroPython: Программирование ESP32/ESP8266 с VS Code и Pymakr
После загрузки кода он должен начать работу и отображать расстояние в мм на OLED-дисплее, как показано на следующем изображении.
Заключение
Мы надеемся, что это руководство было полезным. У нас есть ещё больше проектов и руководств по MicroPython с другими популярными датчиками, которые могут вас заинтересовать: