Ультразвуковой дальномер

Датчик JSN-SR04T представляет собой водонепроницаемый ультразвуковой дальномер, широко используемый в различных проектах, связанных с измерением расстояний в условиях повышенной влажности или прямого контакта с водой. Это делает его идеальным для таких решений, как уровнемеры для воды, робототехника и автомобильные системы помощи при парковке.
Основные характеристики JSN-SR04T:
Диапазон измерения: от 20 см до 600 см, что обеспечивает достаточную гибкость для большинства приложений.
Водонепроницаемость: Модуль способен функционировать во влажной среде, что расширяет возможности его применения.
Точность измерения: Высокая точность измерений благодаря ультразвуковой технологии, которая позволяет избежать ошибок, связанных с изменением температуры и других условий окружающей среды.
Рабочее напряжение: 5 В, что делает его совместимым с большинством микроконтроллеров, включая Arduino и Raspberry Pi.
Простота интеграции: Использует стандартные цифровые сигналы для связи, что упрощает подключение к большинству систем управления.
Принцип работы:
JSN-SR04T работает по принципу эхолокации — излучает ультразвуковой сигнал и измеряет время, за которое эхо сигнала возвращается от препятствия. Это время пропорционально расстоянию до объекта, позволяя точно определять его положение.
Применение:
Датчик JSN-SR04T часто используется в таких проектах, как:
Автоматизация и контроль уровня жидкости: Измерение уровня воды в баках, резервуарах и других емкостях.
Робототехника: Навигация и избегание препятствий для подводных или влажных сред.
Автомобильные приложения: Ультразвуковая парковочная система, которая помогает водителю оценивать расстояние до ближайших объектов при парковке.
Настройка дальномеров в ровере
Дальномер нужно подключить в порты gpio uart в соответствии со схемой в разделе "Одноплатный компьютер". Для настройки дальномеров потребуется программа putty или mobaxterm
Откройте программу для настройки образа и зайдите на ip адрес вашего Orange pi 5
Введите команду sudo
vim /boot/orangepiEnv.txt

Строка overlays в вашем файле должна выглядеть так же как и на фотографии. После изменений сохраните и выйдите из файла (Ctrl C + Ctrl X)
Просмотрите доступные вам порты командой
ls /dev/ttyS*

Если список показывается подобным образом, значит порты настроены правильно.
Код для проверки дальномеров
from serial import Serial
import time
import threading
ports_in = ["COM18"]
ports = []
IP= "192.168.10.116"
PORT=7851
ifing=False
def connect():
global ports_in
for port in ports_in:
temp_port = Serial(
port,
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1
)
try:
print('[JSN-SR04T] Connected')
ports.append({
'dataChannel': temp_port,
'message': [],
'savedData': [],
'distance': 0
})
if len(ports) == len(ports_in):
start_collect_data()
except Exception as err:
print('[JSN-SR04T] Connection ERROR', err)
def set_ports():
connect()
def question(prompt):
return input(prompt)
set_ports()
def average(arr):
return sum(arr) / len(arr)
def get_jsn():
return [port['distance'] for port in ports]
def collect_data(port):
try:
while True:
data = port['dataChannel'].read(4) # Чтение данных
# Если используете bytes, то:
distance = int.from_bytes(data[1:3], byteorder='big') # Преобразование в целое число
# print(f'Distance: {distance/10} cm') # Вывод расстояния на экране
port['distance'] =distance/10
print(f'Distance: {port["distance"]:.2f} cm') # Вывод расстояния на экране
except Exception as e:
print(e)
def start_collect_data():
for port in ports:
thread=threading.Thread(target=collect_data,daemon=True,args=(port,)) # Вызов функции в новом потоке
thread.start()
global ifing
while True:
time.sleep(0.1)
mass=get_jsn()
ifing = any(num < 50 for num in mass)
# print(ifing)
start_collect_data()
Код состоит из следующих основных частей:
Импорт библиотек:
from serial import Serial import time import threadin
Настройка портов:
ports_in = ["COM18"] # Для Windows ports = []
ports_in
: Список последовательных портов, к которым подключены датчики. Важно: Для Linux используются пути вида"/dev/tty..."
, для Windows -"COM..."
. Пример показывает один COM-порт для Windows (COM18).ports
: Пустой список, который будет содержать объектыSerial
и дополнительную информацию для каждого порт
Эти строки закомментированы и, вероятно, предназначались для отправки данных по сети (через сокеты). В текущей версии кода сетевая передача данных не реализована.
Глобальная переменная
ifing
:ifing=False
Эта глобальная переменная используется для индикации, есть ли датчики, показывающие расстояние меньше порогового значения (50 см).
Функция
connect()
:def connect(): global ports_in for port in ports_in: temp_port = Serial( port, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1 ) try: print('[JSN-SR04T] Connected') ports.append({ 'dataChannel': temp_port, 'message': [], 'savedData': [], 'distance': 0 }) if len(ports) == len(ports_in): start_collect_data() except Exception as err: print('[JSN-SR04T] Connection ERROR', err)
Эта функция устанавливает соединение с каждым последовательным портом, указанным в
ports_in
.Для каждого порта создается объект
Serial
с заданными параметрами:port
: Имя порта (например, “COM18” или “/dev/ttyUSB0”).baudrate=9600
: Скорость передачи данных (бод).bytesize=8
: Размер байта данных (8 бит).parity='N'
: Отсутствие контроля четности.stopbits=1
: Один стоп-бит.timeout=1
: Максимальное время ожидания ответа (1 секунда).
В случае успешного подключения создается словарь (dictionary) для хранения информации о порте и добавляется в список
ports
. Словарь содержит:'dataChannel'
: ОбъектSerial
для связи с портом.'message'
: Список для хранения входящих сообщений (в данном коде не используется активно).'savedData'
: Список для хранения сохраненных данных (в данном коде не используется).'distance'
: Значение расстояния, полученное с датчика.
После подключения ко всем портам, вызывает функцию
start_collect_data()
для запуска сбора данных.В случае ошибки подключения, выводит сообщение об ошибке.
Функция
set_ports()
:def set_ports(): connect()
Эта функция просто вызывает функцию
connect()
, т.е. выполняет подключение к портам. В коде присутствует для возможного расширения функциональности в будущем (например, для повторных попыток подключения).
Функция
question(prompt)
(не используется):def question(prompt): return input(prompt)
Эта функция принимает запрос и возвращает ввод пользователя. В данном коде не используется.
Функция
average(arr)
(не используется):def average(arr): return sum(arr) / len(arr)
Эта функция принимает массив чисел и возвращает среднее арифметическое. В данном коде не используется.
Функция
get_jsn()
:def get_jsn(): return [port['distance'] for port in ports]
Эта функция возвращает список расстояний, полученных с каждого датчика. Она использует списковое включение (list comprehension) для извлечения значения
'distance'
из каждого словаря в спискеports
.
Функция
collect_data(port)
:def collect_data(port): try: while True: data = port['dataChannel'].read(4) # Чтение данных # Если используете bytes, то: distance = int.from_bytes(data[1:3], byteorder='big') # Преобразование в целое число # print(f'Distance: {distance/10} cm') # Вывод расстояния на экране port['distance'] =distance/10 print(f'Distance: {port["distance"]:.2f} cm') # Вывод расстояния на экране except Exception as e: print(e)
Эта функция отвечает за чтение данных с конкретного последовательного порта в цикле.
data = port['dataChannel'].read(4)
: Читает 4 байта данных из последовательного порта. Предполагается, что датчик посылает 4 байта данных, представляющих расстояние.distance = int.from_bytes(data[1:3], byteorder='big')
: Преобразует байты, полученные из последовательного порта, в целое число, представляющее расстояние. В данном случае, используются байтыdata[1]
иdata[2]
, которые интерпретируются как большое (big-endian) целое число.port['distance'] =distance/10
: Преобразует значение расстояния из миллиметров в сантиметры (делит на 10) и сохраняет его в словареport
.print(f'Distance: {port["distance"]:.2f} cm')
: Выводит расстояние в сантиметрах на экран с двумя знаками после запятой.В случае ошибки, выводит сообщение об ошибке.
Функция
start_collect_data()
:def start_collect_data(): for port in ports: thread=threading.Thread(target=collect_data,daemon=True,args=(port,)) # Вызов функции в новом потоке thread.start() global ifing while True: time.sleep(0.1) mass=get_jsn() ifing = any(num < 50 for num in mass) # print(ifing)
Эта функция создает и запускает отдельные потоки для функции
collect_data()
для каждого порта в спискеports
. Это позволяет считывать данные со всех датчиков одновременно.thread=threading.Thread(target=collect_data,daemon=True,args=(port,))
: Создает объектThread
.target=collect_data
: Указывает функцию, которую нужно запустить в потоке.daemon=True
: Устанавливает поток как даймон (daemon thread). Это означает, что поток автоматически завершится, когда завершится основная программа.args=(port,)
: Передает словарьport
в качестве аргумента в функциюcollect_data()
. Обратите внимание на запятую послеport
. Это необходимо, чтобы передать аргумент в виде кортежа (tuple).
thread.start()
: Запускает поток.Затем, в бесконечном цикле, эта функция получает данные с каждого датчика, проверяет, есть ли расстояние менее 50 см, и устанавливает глобальную переменную
ifing
.
Вызов
set_ports()
иstart_collect_data()
:set_ports() start_collect_data()
Эти строки запускают процесс подключения к портам и сбора данных. (на самом деле
start_collect_data
уже вызывается внутри connect так что строкаstart_collect_data()
избыточна и никогда не достигнется).
Для работы с кодом требуется установить библиотеку pyserial: pip install pyserial
В порт для проверки требуется подключить один из портов со списка выше (ttyS*)
Файл с кодом требуется закинуть на Orange pi и запустить командой python3 your_filename.py
Если все сделано по инструкции, в консоли побегут данные с дальномера.
Last updated