Добавить в корзинуПозвонить
Найти в Дзене
Hydra Games

Побеждаем Modbus RTU через свой сканер регистров на Python, или как приладить к хозяйству дурилку электронную

И так есть задача: нужно понимание движение воздуха внутри корпуса. Не снаружи, не на крыше — а внутри. Понять, как гуляют потоки, где застой, где сквозняк. Для этого потребовалось 12 датчиков скорости ветра. Обычный анемометр с алика не подходит — ему нужен дисплей и батарейка. А нам — чтобы данные уходили в контроллер, потом в ПЛК, потом на сайт. И всё это автоматически, без участия человека. Выбор пал на CYC-FS1-KV-W2. Промышленный датчик с RS-485. Три чашки, пластиковый корпус, питание 9–30 вольт, протокол Modbus RTU. Выход цифровой, по двухпроводной шине. 12 штук можно повесить на одну линию — если у каждого будет свой адрес. Контроллер первой линии — ПР200 от ОВЕН. Именно к нему подключается датчик: он опрашивает, обрабатывает и передаёт дальше. Но это тема второй части. Сейчас — про то, как заставить «дурилку электронную» работать, когда всё идёт не по плану. Датчик пришёл без разъёма — четыре провода: красный, чёрный, жёлтый, зелёный. Инструкция на английском. Распиновка оказал
Оглавление

И так есть задача: нужно понимание движение воздуха внутри корпуса. Не снаружи, не на крыше — а внутри. Понять, как гуляют потоки, где застой, где сквозняк. Для этого потребовалось 12 датчиков скорости ветра.

Обычный анемометр с алика не подходит — ему нужен дисплей и батарейка. А нам — чтобы данные уходили в контроллер, потом в ПЛК, потом на сайт. И всё это автоматически, без участия человека.

Выбор пал на CYC-FS1-KV-W2. Промышленный датчик с RS-485. Три чашки, пластиковый корпус, питание 9–30 вольт, протокол Modbus RTU. Выход цифровой, по двухпроводной шине. 12 штук можно повесить на одну линию — если у каждого будет свой адрес.

Контроллер первой линии — ПР200 от ОВЕН. Именно к нему подключается датчик: он опрашивает, обрабатывает и передаёт дальше. Но это тема второй части. Сейчас — про то, как заставить «дурилку электронную» работать, когда всё идёт не по плану.

Железо и первое «ура»

Датчик пришёл без разъёма — четыре провода: красный, чёрный, жёлтый, зелёный. Инструкция на английском.

Распиновка оказалась нестандартной:

  • Красный — питание + (24В)
  • Чёрный — линия А (RS-485)
  • Жёлтый — линия B (RS-485)
  • Зелёный — земля (GND)

На шильдике крупно: «Power off operation». Производитель предупредил — коммутировать провода только при отключённом питании.

Для настройки: ноутбук, USB-RS485 адаптер, блок питания на 24В. Первый запуск — программа QModMaster. Выставил порт COM4, скорость 9600, 8 бит, без чётности, адрес 1. Нажал «Read Holding Registers» — и увидел данные. Подул — цифры поползли вверх. Первое «ура» — датчик жив.

Теперь главное: адрес у него — 1. Как и у остальных одиннадцати, что лежат в коробке. Повесить их на одну шину нельзя — будет каша. Каждому нужен свой уникальный адрес. И вот тут началось то, ради чего эта статья.

Битва за адрес

План простой: через Modbus-команду записать в регистр новый адрес. По инструкции — регистр 32, значение 124. Функция 06.

Раунд первый. QModMaster. Читает данные — отлично. Пытаюсь записать — ошибка «Invalid CRC». Проверяю настройки. Ещё раз. Та же ошибка. Меняю формат данных — Hex, Dec, Bin. Ошибка. Иду в настройки порта — всё верно. Снова ошибка.

Раунд второй. Modbus Poll — программа посерьёзнее, промышленный стандарт. Настраиваю соединение, читаю Holding Registers — тишина. Таймаут. Датчик просто молчит. Меняю настройки, переподключаю — таймаут. Закрываю, открываю снова — таймаут.

-2

Раунд три. Python, библиотека minimalmodbus. Самый популярный инструмент для работы с Modbus. Подключаюсь, читаю регистр 0 — есть данные, датчик отвечает. Отлично. Пытаюсь записать в регистр 32 — «No communication with the instrument». Датчик отвечает на чтение, но игнорирует запись. Ещё раз. То же самое. Меняю таймауты. Нет ответа.

И вот тут наступил махач без правил.

Мы - это я и нейросеть Deepseek перепробовали, кажется, всё. Сотни попыток. Разные программы, разные настройки, разные подходы. Deepseek начал гонять меня по кругу: попробуй то, попробуй это. QModMaster — ошибка. Modbus Poll — таймаут. Python — нет ответа. Ещё раз QModMaster. Ещё раз Python.

В какой-то момент предложения стали повторяться. Появилось ощущение, что мы упёрлись в стену, и электронный помощник исчерпал себя на совете купить другие анемометры.

Ключевой момент.

Проблема в том что мы не знаем, в какой регистр писать. Мы вообще не знаем, какие регистры есть у этого датчика. Всё, что у нас есть — общая инструкция, которая, возможно, не соответствует прошивке. Значит, надо как то просканировать всё устройство. Пройтись по всем регистрам и посмотреть отклики. Как пинг в компьютерной сети — отправляешь запрос и смотришь, на ответ. Deepseek на тот момент топтался на месте, перебирая одни и те же варианты по кругу.

Решение: не биться головой в стену с готовыми программами, а написать свой сканер регистров. Свой софт на Python. Не потому что я великий программист. А потому что это был единственный способ решить поставленную задачу.

Свой сканер регистров на Python

Идея простая: в цикле перебираем регистры с 0 по 100, отправляем запрос Modbus RTU, ждём ответ. Если ответили — регистр рабочий.

Deepseek выдал код на связке pyserial + ручной расчёт CRC16. Не minimalmodbus (он с этим датчиком не работал), а чистый pyserial, где мы сами формируем пакет и считаем контрольную сумму.

scan2.py:

import serial
import time

def crc16(data):
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 1:
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
return crc

ser = serial.Serial('COM4', 9600, timeout=0.3)
time.sleep(0.1)

print("Сканирую регистры 0...100 на адресе 1\n")
found = []

for reg in range(0, 101):
request = bytearray([1, 3, (reg >> 8) & 0xFF, reg & 0xFF, 0, 1])
crc = crc16(request)
request.append(crc & 0xFF)
request.append((crc >> 8) & 0xFF)

ser.write(request)
time.sleep(0.15)

if ser.in_waiting >= 5:
response = ser.read(ser.in_waiting)
if len(response) >= 5:
value = (response[3] << 8) | response[4]
print(f"Регистр {reg:3d} (0x{reg:04X}) = {value:5d} (0x{value:04X})")
found.append(reg)
time.sleep(0.4)
# пауза 500 мс между запросами — по инструкции

ser.close()
print(f"\nНайдено регистров: {len(found)}")

Запустил. Жду. И — есть!

-3

Четыре рабочих регистра. И регистр 32 содержит значение 1 — это и есть текущий адрес датчика. Всё это время он лежал именно там, где говорила инструкция. Загвоздка была в том что готовые программы не читали этот регистр, поэтому без своего сканера мы бы об этом не узнали точно.

Меняем адрес

Дальше больше. Раз мы знаем, что адрес лежит в регистре 32, нужно как то этот регистр перезаписать, пишем set_addr.py. Та же логика: pyserial, ручной CRC, но вместо функции 03 (чтение) используем 06 (запись одного регистра).

set_addr.py:

import serial
import time

def crc16(data):
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 1:
crc = (crc >> 1) ^ 0xA001
else:
crc >>= 1
return crc

ser = serial.Serial('COM4', 9600, timeout=0.5)
time.sleep(0.1)

# Запись в регистр 32 значения 124 (адрес 1 -> 124)
request = bytearray([1, 6, 0, 32, 0, 124])
crc = crc16(request)
request.append(crc & 0xFF)
request.append((crc >> 8) & 0xFF)

print("Отправляю:", request.hex())
ser.write(request)
time.sleep(0.5)

if ser.in_waiting > 0:
response = ser.read(ser.in_waiting)
print("Ответ:", response.hex())
else:
print("Нет ответа (но команда ушла)")

ser.close()
print("Готово! Проверьте новый адрес.")

Запускаю :

-4

Ответ зеркальный. Адрес 124 присвоен. Даже перезагрузка питания не потребовалась — заработало сразу.

Остальные 11 датчиков прошиваются по той же схеме: подключаешь по одному, запускаешь скрипт с нужным значением (2, 3, 4... 12), маркируешь. Всё.

-5

К чему это привело

Эта история — не про анемометр и не про Python. Она про то, как работают человек и нейросеть и чего мы можем достичь вместе.

Мы прошли через сотни тупиков. Множество программ — и ни одна не справилась. Deepseek честно помогал: разбирался с протоколом, анализировала логи и помогал специфическими техническими знаниями. Но в какой-то момент даже он сдался, он начал ходить по кругу, а когда идеи закончились — посоветовал купить новые датчики )). Тут и проявилась разница между инструментом и человеком.

Инструмент — даже самый мощный — работает в рамках данных, которые ему дали. Он не может принять сложное решение в условиях неопределённости.

Человек — может.

Решение написать свой сканер регистров и своё ПО на Python было непростым. Это был осознанный выбор: не искать десятую программу, а взять ситуацию под контроль и написать код самому. Нейросеть помогла — быстро набросала структуру, посчитала CRC, оформила скрипт.

Главный навык при работе с нейросетью: не знать все ответы, а уметь правильно донести информацию, предложить идею, сформулировать гипотезу, проверить результат своими руками, а техническую часть нейросеть поможет вам реализовать.

Нейросеть не заменит голову и руки. Но в паре с человеком, который умеет принимать решения, она способна на то, что каждый из нас по отдельности не потянет.

В следующей части — подключаем этот датчик к ПР200 ОВЕН и настраиваем опрос в Owen Logic.
Часть 2 тут.