LINUX.ORG.RU

Опрос устройства по Modbus rtu на Python

 ,


0

3

Здраствуйте, хочу измерять температуру в помещении. Для этого взял ардуинку, прикрутил датчики и записал туда программу на базе библиотеки ModbusRtu.h, которая через виртуальный /dev/ttyUSB0 отдаёт значения. Всё замечательно работает через утилитку опроса модбаса mbpoll. Решил написать скриптик опроса на питоне, чтобы значения выдавались в консоль в удобной для меня форме, и толкнулся с проблемой - никак не хочет рабоать.. Пробывал библиотки modbus_tk и PyModbus - скрипты валятся с ошибкой чтото вроде «немогу получть корректный ответ итд..» Хотя ранее писал что то подобное для опроса устройства через «железный» /dev/ttyS0 - и оно работало.. Решил посмотреть что там происходит, для этого взял снифер ком порта interceptty, который грубо говоря, подключается к исследуемому порту /dev/ttyUSB0, создаёт виртуальный порт /tmp/ttyUSB0 - к которому обращаюсь через скрипт на питоне (в этот момент interceptty выводит в консоль весь обмен данными). Ио чудо! Всё заработало. Такое ощущение, что interceptty возможно буферизирует или мне нужно как то дополнительно настроить порт для работы напрямую.. Нет ли у кого мыслей на эту тему?


Пробывал библиотки modbus_tk и PyModbus - скрипты валятся с ошибкой чтото вроде «немогу получть корректный ответ итд..»

Надо излагать яснее, какая ошибка вываливается. Это важно. «Что-то вроде» не годится. А ванговать по фотографиям такое себе дело.

Нет ли у кого мыслей на эту тему?

Нельзя ничего определенно сказать, что у тебя не так. Первая мысль: включено аппаратное управление потоком (hardware flow control). Возможно, что interceptty его отключает. Вот ничего пока с ходу не могу другого сказать. Отключи явно настройках порта или еще попробуй отключить stty -F /dev/ttyUSB0 -crtscts (надеюсь питоновская библиотека сама потом не включит).

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

[code=Python] import serial

import modbus_tk import modbus_tk.defines as cst from modbus_tk import modbus_rtu

PORT = ‘/dev/ttyUSB0’

def main(): «««main»»» logger = modbus_tk.utils.create_logger(«console»)

try:
    #Connect to the slave
    master = modbus_rtu.RtuMaster(
        serial.Serial(port=PORT, baudrate=9600, bytesize=8, parity='N', stopbits=1, xonxoff=0)
    )
    master.set_timeout(5.0)
    master.set_verbose(True)
    logger.info("connected")

    logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 10))


except modbus_tk.modbus.ModbusError as exc:
    logger.error("%s- Code=%d", exc, exc.get_exception_code())

if name == «main»: main()

[/code]

Выдаёт вот это:

2021-11-02 23:57:07,153 INFO modbus_rtu.init MainThread RtuMaster /dev/ttyUSB0 is opened 2021-11-02 23:57:07,153 INFO modTK.main MainThread connected 2021-11-02 23:57:07,153 DEBUG modbus.execute MainThread -> 1-3-0-0-0-10-197-205 2021-11-02 23:57:12,155 DEBUG modbus.execute MainThread <- Traceback (most recent call last): File «modTK.py», line 41, in main() File «modTK.py», line 34, in main logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 10)) File «/usr/local/lib/python3.7/dist-packages/modbus_tk/utils.py», line 39, in new raise excpt File «/usr/local/lib/python3.7/dist-packages/modbus_tk/utils.py», line 37, in new ret = fcn(*args, **kwargs) File «/usr/local/lib/python3.7/dist-packages/modbus_tk/modbus.py», line 306, in execute response_pdu = query.parse_response(response) File «/usr/local/lib/python3.7/dist-packages/modbus_tk/modbus_rtu.py», line 46, in parse_response raise ModbusInvalidResponseError(«Response length is invalid {0}».format(len(response))) modbus_tk.exceptions.ModbusInvalidResponseError: Response length is invalid 0

rum
() автор топика
Ответ на: комментарий от Zubok

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.client.asynchronous import schedulers
from pymodbus.register_read_message import ReadInputRegistersResponse
import time
client= ModbusClient( port='/dev/ttyUSB0', stopbits=1, bytesize=8, parity='N', timeout=1)
connection=client.connect()
print(connection)
print('**** read_holding_registers ****')
result = client.read_holding_registers(5, 1, unit=1)
print(result.registers)
client.close()

выдёт: Traceback (most recent call last): File «mod.py», line 17, in <module> print(result.registers) AttributeError: 'ModbusIOException' object has no attribute 'registers'

rum
() автор топика
Ответ на: комментарий от Zubok

К сожалению не завелось, пробыва на двух скриптах с разными библиотеками... вот настройки после после отработки скрипта

stty -F /dev/ttyS0 -a
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc

rum
() автор топика
Ответ на: комментарий от rum

echo echoe echok

Вот это тоже все отключи. Возможно, там в serial питоновском есть на это параметры. Или попробуй через stty -echo -echoe -echok -crtscts.

Zubok ★★★★★
()

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

anonymous
()
Ответ на: комментарий от anonymous

Побывал по-разному настраивать порт (stty -echo -echoe -echok -crtscts) Ради интереса попробовал на виндовсе - точно такой же результат (всякие опрашивалки типа qmodbus замечательно работают). Побывал устанавливать разные значения таймаутов, как в настройках порта, так и в запросах.

client.read_holding_registers(5, 1, unit=1, timeout=.2)
Побывал втыкать в разные места кода задержку sleep.. Такой же отрицательный результат.. Похоже что то я всё таки делаю не так... или у меня карма плохая.. Наверное пока как костыль буду подключаться через interceptty, потом возможно придёт озарение.. или попробую на другом каком языке реализовать вот это...

rum
() автор топика
Ответ на: комментарий от rum

Чего-то ты как-то быстро сдаешься. А разобраться не хочешь? Если у тебя через interceptty работает, то с библиотекой все нормально. Ты как запускаешь interceptty?

File «/usr/local/lib/python3.7/dist-packages/modbus_tk/modbus_rtu.py», line 46, in parse_response raise ModbusInvalidResponseError(«Response length is invalid {0}».format(len(response))) modbus_tk.exceptions.ModbusInvalidResponseError: Response length is invalid 0

Не знаю, что это, но предполагаю, что получил какой-то мусор, потому что Response length is invalid 0 (нулевой размер ответа в ответе). Получает мусор. Это может быть из-за неправильных настроек порта.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 2)
Ответ на: комментарий от Zubok

спасибо за сопереживание ), запускал вот так:

interceptty -s 'ispeed 9600 ospeed 9600' /dev/ttyUSB0 /tmp/ttyS0
без явного указания скоростей ispeed 9600 ospeed 9600 - тоже не работало..

В общем запустил на питоне с библиотекой modbus_tk. Нарыл в сети вот такой код и он работает.. Всем спасибо, буду разбирать что тут и как...

import time
from serial import Serial
from modbus_tk.modbus_rtu import RtuMaster
import modbus_tk.defines as cst  # cst = constants
PORT = '/dev/ttyUSB0'
serial_ = Serial(PORT)
modbus_master = RtuMaster(serial_)
modbus_master.set_timeout(5.0)
time.sleep(2.0)

response = modbus_master.execute(
    slave=1,
    function_code=cst.READ_HOLDING_REGISTERS,
    starting_address=1,
    quantity_of_x=10,
    output_value=[1],
)  # type: tuple
print(response)

rum
() автор топика

Ты вообще решил здравый смысл убить что ли? Идиотизм в квадрате же: модбас + пытхон! Жееесть!!!

anonymous
()
Ответ на: комментарий от anonymous

возможно.. ваши предложения, исходные данные: я не программер и языков не знаю; надо быстро и желательно кросплатформенно; готового консольного решения я не нашёл…

rum
() автор топика
Ответ на: комментарий от rum

interceptty -s 'ispeed 9600 ospeed 9600' /dev/ttyUSB0 /tmp/ttyS0

Вот эти параметры, которые после -s, он передает в stty напрямую. А вот fd /tmp/ttyS0 он создает с группой параметров raw

man stty:

raw    same as -ignbrk -brkint -ignpar -parmrk  -inpck  -istrip  -inlcr
       -igncr  -icrnl  -ixon  -ixoff -icanon -opost -isig -iuclc -ixany
       -imaxbel -xcase min 1 time 0

Смотри. У intercetty терминология такая: backend - это /dev/ttyUSB0, а frontend - это ttyS0. Не путаю? При инициализации backend interceptty пытается поставить его в raw. Показываю:

int setup_back_tty(char *backend, int f[2])
{
  int serialfd;
  
  /* Open the serial port */
  serialfd = open(backend, O_RDWR | O_NOCTTY | O_SYNC | O_NOCTTY);
  if (serialfd < 0)
    errorf("error opening backend device '%s': %s\n",backend,strerror(errno));
  if (stty_raw(serialfd) != 0)
    errorf("Error putting serial device '%s' in raw mode: %s\n",backend,strerror(errno));
[...]
 /* Process settings from the -s switch */
  if (settings) {
    fstty(serialfd,settings);
  }
[...]
}

А это stty_raw:

int stty_raw (int fd)
{
[...]
  tty_state.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO);
  tty_state.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON | BRKINT);
  tty_state.c_oflag &= ~OPOST;
  tty_state.c_cflag |= CS8;
[...]
}

Что мы видим по коду? сначала interceptty переводит устройство в режим raw, а потом передает в него параметры, которые ты указал после '-s'. Полагаю, что PySerial этого не делает, но надо покопаться и посмотреть, как это сделать. Возможно, там есть более низкоуровневый класс, чтобы сделать это. В этом, наверное, и отличие инициализации interceptty и PySerial.

Можешь попробовать сделать перед PyModbus. Заработает?

$ stty -F /dev/USB0 raw cs8 -crtscts -echo
Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 2)
Ответ на: комментарий от rum

я не программер и языков не знаю; надо быстро и желательно кросплатформенно; готового консольного решения я не нашёл…

С этого надо было, наверное, начинать рассказ. :) Раз не программер, то и с PyModbus придется возиться как программеру?

Тебе тестировать устройство? Или тебе нужно свой интерфейс писать? Так-то графических программ, которые работают с ModBus пруд-пруди. Вплоть до масштабных система SCADA. Консольная вот есть mbpoll, например. https://github.com/epsilonrt/mbpoll В репозитории Debian вроде есть. Пишут, что кроссплатформенная.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Подправил, -echo еще поставил:

$ stty -F /dev/USB0 raw cs8 -crtscts -echo
Zubok ★★★★★
()
Ответ на: комментарий от rum

Т.е. ты - абсолютно некомпетентен в этом вопросе? И взялся выполнять? Ну-ну…

А потом удивляются, чего это у нас дороги постоянно рассыпаются, дома падают и мосты трескаются. А потому, что вот такие некомпетентные дятлы лезут своими грязными ручонками!

Во-первых, модбас - это дико устаревший протокол, разрабатывающийся еще во времена телефонных линий (поэтому там такие огромные задержки заложены протоколом: чтобы релюхи успели переключиться). Если тебе нужно что-то современное, используй CAN, ethernet и т.п.

Во-вторых, пытхон - это суррогат баша для вантузоидов! У них нет нормальной возможности скрипты писать, вот и лепят горбатого. Если ты - линуксоид, тебе пытхон вообще никогда в жизни не понадобится! Потому что есть вменяемые средства автоматизации. Тот же юниксвей.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.