Open Lyansun opened 2 years ago
Hey, I haven't tested it on a Pico yet but there should not be any issues.
Lyansun, hello. I do the same thing and I've already understood that this library isn't work on Raspberry Pi Pico without changings or adding external WiFi modules. Did you solve this problem?
Hey buddy, how does this library work on pico?
Hello @AlKoAl
What exactly do not works? Could you paste here the errors?
Good morning, @beyonlo.
At the begining, there is no specific errors. The whole code (from main.py and boot.py) isn't working on Raspberry Pi Pico because this platform doesn't have WiFi module as well as network library among the preinstalled libraries. It definitely should work on Raspberry Pi Pico W, but i don't have it, and it will probably work on W5100S-EVB-Pico. Modbus RTU maybe works if we comment out network library. (Working on it)
But this is not my problem to work with. I've just try to find some micropython lybrary which can give me the simplest way to develope Modbus RTU slave on this platform. My task is to create a simple transceiver, which will get the modbus commands from the higher level and control devices, such as turning on and off LEDs. (I understand, that it is usually done with microcontrollers programmed on C). Should i use UART-RS-485 transiver to create a wire connection with master? (I don't even know that. I'm frustrated.)
As I understand this library is developed to work with two devises: one will be the slave other is master which is "talking" by WiFi. (Maybe i misunderstood something.) Can I just create only slave on Rasberry and control it with for example Modscan32 (or other programs, I don't now) like you do?
This lib should be works without issues in any platform where MicroPython runs, including RPico and RPico-W
At the begining, there is no specific errors. The whole code (from main.py and boot.py) isn't working on Raspberry Pi Pico because this platform doesn't have WiFi module as well as network library among the preinstalled libraries.
You can use the this lib with ModBus RTU
via serial (UART, RS232, RS485, etc) using the RPico
(without WiFi or Ethernet).
It definitely should work on Raspberry Pi Pico W, but i don't have it, and it will probably work on W5100S-EVB-Pico. Modbus RTU maybe works if we comment out network library. (Working on it)
On the RPico-W
(WiFi) or W5100S-EVB-Pico
(Ethernet) you can use this lib with ModBus RTU
and/or ModBus TCP
But this is not my problem to work with. I've just try to find some micropython lybrary which can give me the simplest way to develope Modbus RTU slave on this platform.
This project (great thanks to @brainelectronics) is the mostly simplest and amazing way to do what do you want using MicroPython.
My task is to create a simple transceiver, which will get the modbus commands from the higher level and control devices, such as turning on and off LEDs. (I understand, that it is usually done with microcontrollers programmed on C). Should i use UART-RS-485 transiver to create a wire connection with master? (I don't even know that. I'm frustrated.)
That depends what do you want. If your communication need to be RS485 for example, so you need to use ModBus RTU
. But if is not necessary to use a serial communication, you can use ModBus TCP
via Ethernet and/or WiFi. I think that your problem is not about this library, but to understand a bit more about network communication and about how Modbus
ptotocol works. I suggest you to research about that, but I will explain a bit about this for you below.
As I understand this library is developed to work with two devises: one will be the slave other is master which is "talking" by WiFi. (Maybe i misunderstood something.)
No. You can do choose to use just the Modbus RTU Slave for example and other software can do ModBus RTU Master.
This library implement the ModBus protocol, supporting all 4 types of ModBus types:
So, you choose from this library what type of ModBus do you want to use. And of course, you can to use all that 4 types working together, if is what do you need.
Here a brief summary how ModBus
protocol works and how these 4 types of ModBus
implemention (supported by this library) works:
ModBus
is a protocol that can run on the Serial
communication and TCP
communication.Serial
communication, like as UART, RS232, RS485, RS422
you need to use the ModBus RTU
.TCP
communication, like as Ethernet
and WiFi
you need to use the ModBus TCP
.request -> response
(like as the HTTP
protocol) , where Slave
is who wait for a request
and make a response
, and where the Master
make the request
to the Slave
and wait for a response. ModBus RTU
there is a concept about Slave address
, where each Slave
has a specific ID (number), so the Master
is capable to choose for what Slave address will make the request. So in a RS485 network for example, you can have many Slaves
and just one Master
, where this Master
can make a request to all Slaves
.ModBus TCP
, there is as well the concept about Slave address
, but instead a ID number, the Slave address
is just the IP address and Port that the Slave
are listening. So the Master TCP
need just to send a request to IP and Port where the Slave TCP
is running/listening.Can I just create only slave on Rasberry and control it with for example Modscan32 (or other programs, I don't now) like you do?
Yes
Oh, thank you so much for such a detailed answer! I should have asked my question earlier, you helped me a lot in organizing my thoughts. You are breathtaking! (Keanu Reeves meme)
Oh, thank you so much for such a detailed answer! I should have asked my question earlier, you helped me a lot in organizing my thoughts.
You are welcome!
You are breathtaking! (Keanu Reeves meme)
I saw that video, very good :)
It doesn't work on Pi Pico W. It will init the library class, but after you try to read holding register (for example) it will fail because machine is missing attribute 'wait_tx_done'. It fails because of "ctrl_pin" that is needed on MAX485 chip
Full error:
File "<stdin>", line 18, in <module>
File "/lib/umodbus/serial.py", line 207, in read_discrete_inputs
File "/lib/umodbus/serial.py", line 171, in _send_receive
File "/lib/umodbus/serial.py", line 163, in _send
AttributeError: 'UART' object has no attribute 'wait_tx_done'
It doesn't work on Pi Pico W. It will init the library class, but after you try to read holding register (for example) it will fail because machine is missing attribute 'wait_tx_done'. It fails because of "ctrl_pin" that is needed on MAX485 chip
Full error:
File "<stdin>", line 18, in <module> File "/lib/umodbus/serial.py", line 207, in read_discrete_inputs File "/lib/umodbus/serial.py", line 171, in _send_receive File "/lib/umodbus/serial.py", line 163, in _send AttributeError: 'UART' object has no attribute 'wait_tx_done'
It is true. I was traing to change the code and ctrl_pin is some of those functions that is available in this repo (it will be possible if you change the example), but "wait_tx_done" isn't available on micropython rp2040 version (but it's OK on ESP32 or ESP8266). You could try to change the function, for example to just "wait" for several miliseconds. It will work, but kinda weird. At the end i've just got problems with synchronization and droped whole idea.
Relates to #34
At the begining, there is no specific errors. The whole code (from main.py and boot.py) isn't working on Raspberry Pi Pico because this platform doesn't have WiFi module as well as network library among the preinstalled libraries. It definitely should work on Raspberry Pi Pico W, but i don't have it, and it will probably work on W5100S-EVB-Pico. Modbus RTU maybe works if we comment out network library. (Working on it)
good news @AlKoAl, the package has been cleaned up with version 2.0.0 and serial as well as tcp dependencies have been removed from modbus, see also https://micropython-modbus.readthedocs.io/en/2.0.0/UPGRADE.html#update-imports
Hey @AlKoAl and @volkar1 the bug is now fixed in 2.1.2
@Lyansun you can get some more informations about the usage with a Raspberry Pi Pico in #34 and #43
After modifying serial.py lines 58 and 71 (image 1), I am able to setup the Pico as an RTU slave (image 2). When I set a holding register, it looks like the initial response looks funny and that response isn't liked by the master (throws a frame error, but it seems fine after that. Is there something in the code that would cause that? (see image 3) image 1: image 2: image 3:
The issue should be fixed by #45
@j-broome if you have further issues please create a new issue 😊
I found a discrepancy in the initial response from function code 6 that doesn’t seem to take place with function code 16. I am not near my laptop at the moment, but I took good screenshots I can send on Monday. I’d also like to learn more about got and help contribute to the repo.
Sent from Proton Mail for iOS
On Sat, Dec 31, 2022 at 1:30 AM, Jones @.***> wrote:
The issue should be fixed by #45
@.***(https://github.com/j-broome) if you have further issues please create a new issue 😊
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
Hey @AlKoAl and @volkar1 the bug is now fixed in 2.1.2
@Lyansun you can get some more informations about the usage with a Raspberry Pi Pico in #34 and #43
Hey @AlKoAl, @volkar1 and @Lyansun the bug is now really fixed in 2.1.3 😂 see also #45
I found a discrepancy in the initial response from function code 6 that doesn’t seem to take place with function code 16. I am not near my laptop at the moment, but I took good screenshots I can send on Monday. I’d also like to learn more about got and help contribute to the repo.
No problem you're always welcome! Just one note, if you create an issue please try to paste your code with code highlighting or part of the code so we can support here faster. It's just easier to reproduce than code screenshots 😉
I used Modbus Poll and watched the communication between my PC and the Pico. When I write a single register (FC6), the initial response is messed up, but then it works. When I do the same thing with FC16 (still only writing a single register), the initial response looks great. So I THINK it is not my transceiver flow control but something weird in response code of that particular function code. I ran out of time on Friday, but the obvious thing to do is try a C library and see if the issue goes away.
Feel free to school me on this, but at first I thought the transceiver had a flow control issues because the response included the exact message I sent. But that went away with FC16. I have proper pull-up and pull-up down resistors on the UART lines as well as in the A and B lines (510 ohms) of the 485 bus.
Sent from Proton Mail for iOS
On Sat, Dec 31, 2022 at 1:39 AM, Jones @.***> wrote:
I found a discrepancy in the initial response from function code 6 that doesn’t seem to take place with function code 16. I am not near my laptop at the moment, but I took good screenshots I can send on Monday. I’d also like to learn more about got and help contribute to the repo.
No problem you're always welcome! Just one note, if you create an issue please try to paste your code with code highlighting or part of the code so we can support here faster. It's just easier to reproduce than code screenshots 😉
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
Using an RS-485 Transceiver with automatic flow control (MAX22028) and also tried with THVD-2410 (flow control pin). THVD-2410 works with the flow control code, but when I try to use a transceiver without the flow control pin, the single coil write and single register write responses are duplicated 3 times. Timeout shows to be 8020 microseconds. The issue is masked with the THVD-2410 and likely 95% of people attempting this because the transceiver keeps the responses from reaching the 485 bus. Below is my test code to recreate the issue.
from umodbus.serial import ModbusRTU from machine import Pin tx = machine.Pin(0) rx = machine.Pin(1)
rtu_pins = (tx, rx) # (TX, RX) slave_addr = 3 # address on bus as client baudrate = 9600 client = ModbusRTU( addr=slave_addr, # address on bus baudrate=baudrate, # optional, default 9600 pins=rtu_pins, # given as tuple (TX, RX)
# stop_bits=1, # optional, default 1
# parity=None, # optional, default None
ctrl_pin=None, # optional, control DE/RE
uart_id=0 # optional, see port specific documentation
)
When I do not use flow control I get 3 consecutive response messages on the Rx line with function code 6:
Using function code 16 works though:
THVD-2410 (w/flow control) setup - this works flawlessly - absolutely no errors
MAX22028 (automatic flow control) setup - only fails on the initial response After settings a holding register to say 0, the initial response coming out of the device is wrong, but it does somehow take that value, so when the register is read with FC3, it indeed has the correct value in it.
Wondering if this is happening because the RX buffer is not actually getting cleared somehow, but I can't find any discrepancies in the umodbus code.
Hey can you help me?, I want to connect pico to pico using protocol Modbus RS485 but i got some error, Here is my schematic program
i use code program from examples folder rtu_host_example.py and rtu_client_example.py, i just edit rx tx pins and uart_id
rtu_host_example.py
import time from umodbus.serial import Serial as ModbusRTUMaster IS_DOCKER_MICROPYTHON = False try: import machine machine.reset_cause() except ImportError: raise Exception('Unable to import machine, are all fakes available?') except AttributeError:
IS_DOCKER_MICROPYTHON = True
import sys
slave_addr = 10
rtu_pins = (0, 1)
baudrate = 9600
host = ModbusRTUMaster(
pins=rtu_pins,
baudrate=baudrate,
data_bits=8,
stop_bits=1,
parity=None,
ctrl_pin=12,
uart_id=0
)
if IS_DOCKER_MICROPYTHON:
assert host._uart._is_server is False
register_definitions = { "COILS": { "RESET_REGISTER_DATA_COIL": { "register": 42, "len": 1, "val": 0 }, "EXAMPLE_COIL": { "register": 123, "len": 1, "val": 1 } }, "HREGS": { "EXAMPLE_HREG": { "register": 93, "len": 1, "val": 19 } }, "ISTS": { "EXAMPLE_ISTS": { "register": 67, "len": 1, "val": 0 } }, "IREGS": { "EXAMPLE_IREG": { "register": 10, "len": 1, "val": 60001 } } }
print('Requesting and updating data on RTU client at address {} with {} baud'. format(slave_addr, baudrate)) print()
coil_address = register_definitions['COILS']['EXAMPLE_COIL']['register'] coil_qty = register_definitions['COILS']['EXAMPLE_COIL']['len'] coil_status = host.read_coils( slave_addr=slave_addr, starting_addr=coil_address, coil_qty=coil_qty) print('Status of COIL {}: {}'.format(coil_address, coil_status)) time.sleep(1)
new_coil_val = 0 operation_status = host.write_single_coil( slave_addr=slave_addr, output_address=coil_address, output_value=new_coil_val) print('Result of setting COIL {} to {}'.format(coil_address, operation_status)) time.sleep(1)
coil_status = host.read_coils( slave_addr=slave_addr, starting_addr=coil_address, coil_qty=coil_qty) print('Status of COIL {}: {}'.format(coil_address, coil_status)) time.sleep(1)
print()
hreg_address = register_definitions['HREGS']['EXAMPLE_HREG']['register'] register_qty = register_definitions['HREGS']['EXAMPLE_HREG']['len'] register_value = host.read_holding_registers( slave_addr=slave_addr, starting_addr=hreg_address, register_qty=register_qty, signed=False) print('Status of HREG {}: {}'.format(hreg_address, register_value)) time.sleep(1)
new_hreg_val = 44 operation_status = host.write_single_register( slave_addr=slave_addr, register_address=hreg_address, register_value=new_hreg_val, signed=False) print('Result of setting HREG {} to {}'.format(hreg_address, operation_status)) time.sleep(1)
register_value = host.read_holding_registers( slave_addr=slave_addr, starting_addr=hreg_address, register_qty=register_qty, signed=False) print('Status of HREG {}: {}'.format(hreg_address, register_value)) time.sleep(1)
print()
ist_address = register_definitions['ISTS']['EXAMPLE_ISTS']['register'] input_qty = register_definitions['ISTS']['EXAMPLE_ISTS']['len'] input_status = host.read_discrete_inputs( slave_addr=slave_addr, starting_addr=ist_address, input_qty=input_qty) print('Status of IST {}: {}'.format(ist_address, input_status)) time.sleep(1)
ireg_address = register_definitions['IREGS']['EXAMPLE_IREG']['register'] register_qty = register_definitions['IREGS']['EXAMPLE_IREG']['len'] register_value = host.read_input_registers( slave_addr=slave_addr, starting_addr=ireg_address, register_qty=register_qty, signed=False) print('Status of IREG {}: {}'.format(ireg_address, register_value)) time.sleep(1)
print()
print('Resetting register data to default values...') coil_address = \ register_definitions['COILS']['RESET_REGISTER_DATA_COIL']['register'] new_coil_val = True operation_status = host.write_single_coil( slave_addr=slave_addr, output_address=coil_address, output_value=new_coil_val) print('Result of setting COIL {}: {}'.format(coil_address, operation_status)) time.sleep(1)
print()
print("Finished requesting/setting data on client")
if IS_DOCKER_MICROPYTHON: sys.exit(0)
Error code program
Traceback (most recent call last):
File "
rtu_client_example.py
from umodbus.serial import ModbusRTU
IS_DOCKER_MICROPYTHON = False try: import machine machine.reset_cause() except ImportError: raise Exception('Unable to import machine, are all fakes available?') except AttributeError:
IS_DOCKER_MICROPYTHON = True
import json
rtu_pins = (0, 1)
slave_addr = 10
baudrate = 9600
client = ModbusRTU(
addr=slave_addr,
pins=rtu_pins,
baudrate=baudrate,
data_bits=8,
stop_bits=1,
parity=None,
uart_id=0
)
if IS_DOCKER_MICROPYTHON:
assert client._itf._uart._is_server is True
def reset_data_registers_cb(reg_type, address, val):
global client
global register_definitions
print('Resetting register data to default values ...')
client.setup_registers(registers=register_definitions)
print('Default values restored')
register_definitions = { "COILS": { "RESET_REGISTER_DATA_COIL": { "register": 42, "len": 1, "val": 0 }, "EXAMPLE_COIL": { "register": 123, "len": 1, "val": 1 } }, "HREGS": { "EXAMPLE_HREG": { "register": 93, "len": 1, "val": 19 } }, "ISTS": { "EXAMPLE_ISTS": { "register": 67, "len": 1, "val": 0 } }, "IREGS": { "EXAMPLE_IREG": { "register": 10, "len": 1, "val": 60001 } } }
if IS_DOCKER_MICROPYTHON: with open('registers/example.json', 'r') as file: register_definitions = json.load(file)
register_definitions['COILS']['RESET_REGISTER_DATA_COIL']['on_set_cb'] = \ reset_data_registers_cb
print('Setting up registers ...')
client.setup_registers(registers=register_definitions)
print('Register setup done')
print('Serving as RTU client on address {} at {} baud'. format(slave_addr, baudrate))
while True: try: result = client.process() except KeyboardInterrupt: print('KeyboardInterrupt, stopping RTU client...') break except Exception as e: print('Exception during execution: {}'.format(e))
print("Finished providing/accepting data as client")
Error code program
Traceback (most recent call last):
File "
Serial.py
from machine import UART from machine import Pin import struct import time import machine
from . import const as Const from . import functions from .common import Request, CommonModbusFunctions from .common import ModbusException from .modbus import Modbus
from .typing import List, Optional, Union
class ModbusRTU(Modbus):
def __init__(self,
addr: int,
baudrate: int = 9600,
data_bits: int = 8,
stop_bits: int = 1,
parity: Optional[int] = None,
pins: List[Union[int, Pin], Union[int, Pin]] = None,
ctrl_pin: int = None,
uart_id: int = 0):
super().__init__(
Serial(uart_id=uart_id,
baudrate=baudrate,
data_bits=data_bits,
stop_bits=stop_bits,
parity=parity,
pins=pins,
ctrl_pin=ctrl_pin),
[addr]
)
class Serial(CommonModbusFunctions): def init(self, uart_id: int = 0, baudrate: int = 9600, data_bits: int = 8, stop_bits: int = 1, parity=None, pins: List[Union[int, Pin], Union[int, Pin]] = None, ctrl_pin: int = None):
self._uart = UART(uart_id,
baudrate=baudrate,
bits=data_bits,
parity=parity,
stop=stop_bits,
# timeout_chars=2, # WiPy only
# pins=pins # WiPy only
tx=pins[0],
rx=pins[1]
)
if ctrl_pin is not None:
self._ctrlPin = Pin(ctrl_pin, mode=Pin.OUT)
else:
self._ctrlPin = None
self._t1char = (1000000 * (data_bits + stop_bits + 2)) // baudrate
if baudrate <= 19200:
self._t35chars = (3500000 * (data_bits + stop_bits + 2)) // baudrate
else:
self._t35chars = 1750
def _calculate_crc16(self, data: bytearray) -> bytes:
crc = 0xFFFF
for char in data:
crc = (crc >> 8) ^ Const.CRC16_TABLE[((crc) ^ char) & 0xFF]
return struct.pack('<H', crc)
def _exit_read(self, response: bytearray) -> bool:
if response[1] >= Const.ERROR_BIAS:
if len(response) < Const.ERROR_RESP_LEN:
return False
elif (Const.READ_COILS <= response[1] <= Const.READ_INPUT_REGISTER):
expected_len = Const.RESPONSE_HDR_LENGTH + 1 + response[2] + Const.CRC_LENGTH
if len(response) < expected_len:
return False
elif len(response) < Const.FIXED_RESP_LEN:
return False
return True
def _uart_read(self) -> bytearray:
response = bytearray()
for x in range(1, 40):
if self._uart.any():
response.extend(self._uart.read())
if self._exit_read(response):
break
time.sleep_us(self._t35chars)
return response
def _uart_read_frame(self, timeout: Optional[int] = None) -> bytearray:
received_bytes = bytearray()
if timeout == 0 or timeout is None:
timeout = 2 * self._t35chars
start_us = time.ticks_us()
while (time.ticks_diff(time.ticks_us(), start_us) <= timeout):
if self._uart.any():
last_byte_ts = time.ticks_us()
while time.ticks_diff(time.ticks_us(), last_byte_ts) <= self._t35chars:
r = self._uart.read()
if r is not None:
received_bytes.extend(r)
last_byte_ts = time.ticks_us()
if len(received_bytes) > 0:
return received_bytes
return received_bytes
def _send(self, modbus_pdu: bytes, slave_addr: int) -> None:
serial_pdu = bytearray()
serial_pdu.append(slave_addr)
serial_pdu.extend(modbus_pdu)
crc = self._calculate_crc16(serial_pdu)
serial_pdu.extend(crc)
if self._ctrlPin:
self._ctrlPin(1)
time.sleep_us(1000)
send_start_time = time.ticks_us()
self._uart.write(serial_pdu)
if self._ctrlPin:
total_frame_time_us = self._t1char * len(serial_pdu)
while time.ticks_us() <= send_start_time + total_frame_time_us:
machine.idle()
self._ctrlPin(0)
def _send_receive(self,
modbus_pdu: bytes,
slave_addr: int,
count: bool) -> bytes:
self._uart.read()
self._send(modbus_pdu=modbus_pdu, slave_addr=slave_addr)
return self._validate_resp_hdr(response=self._uart_read(),
slave_addr=slave_addr,
function_code=modbus_pdu[0],
count=count)
def _validate_resp_hdr(self,
response: bytearray,
slave_addr: int,
function_code: int,
count: bool) -> bytes:
if len(response) == 0:
raise OSError('no data received from slave')
resp_crc = response[-Const.CRC_LENGTH:]
expected_crc = self._calculate_crc16(
response[0:len(response) - Const.CRC_LENGTH]
)
if ((resp_crc[0] is not expected_crc[0]) or
(resp_crc[1] is not expected_crc[1])):
raise OSError('invalid response CRC')
if (response[0] != slave_addr):
raise ValueError('wrong slave address')
if (response[1] == (function_code + Const.ERROR_BIAS)):
raise ValueError('slave returned exception code: {:d}'.
format(response[2]))
hdr_length = (Const.RESPONSE_HDR_LENGTH + 1) if count else \
Const.RESPONSE_HDR_LENGTH
return response[hdr_length:len(response) - Const.CRC_LENGTH]
def send_response(self,
slave_addr: int,
function_code: int,
request_register_addr: int,
request_register_qty: int,
request_data: list,
values: Optional[list] = None,
signed: bool = True) -> None:
modbus_pdu = functions.response(
function_code=function_code,
request_register_addr=request_register_addr,
request_register_qty=request_register_qty,
request_data=request_data,
value_list=values,
signed=signed
)
self._send(modbus_pdu=modbus_pdu, slave_addr=slave_addr)
def send_exception_response(self,
slave_addr: int,
function_code: int,
exception_code: int) -> None:
modbus_pdu = functions.exception_response(
function_code=function_code,
exception_code=exception_code)
self._send(modbus_pdu=modbus_pdu, slave_addr=slave_addr)
def get_request(self,
unit_addr_list: List[int],
timeout: Optional[int] = None) -> Union[Request, None]:
req = self._uart_read_frame(timeout=timeout)
if len(req) < 8:
return None
if req[0] not in unit_addr_list:
return None
req_crc = req[-Const.CRC_LENGTH:]
req_no_crc = req[:-Const.CRC_LENGTH]
expected_crc = self._calculate_crc16(req_no_crc)
if (req_crc[0] != expected_crc[0]) or (req_crc[1] != expected_crc[1]):
return None
try:
request = Request(interface=self, data=req_no_crc)
except ModbusException as e:
self.send_exception_response(
slave_addr=req[0],
function_code=e.function_code,
exception_code=e.exception_code)
return None
return request
Did I make a mistake on the pin? Is there something I should change? Please help, any help is very helpful
@NormanStudentRobotic Hello! Your project is very great, and this lib will fit very well for your project! So, of course you need to run the ModBus RTU Slave on the first RPICO board and the ModBus RTU Master on the second RPICO. Well, I see that your schematic you do not using a control pin to send/receive data over RS-485
, so I think that you are using auto control.
Error code program Traceback (most recent call last): File "", line 17, in File "/lib/umodbus/serial.py", line 29, in init File "/lib/umodbus/serial.py", line 58, in init ValueError: expecting a Pin
I see this error in your report. You are using rtu_pins = (0, 1)
but RP2 needs to use rtu_pins = (Pin(0), Pin(1))
like as show on the documentation for this lib.
I hope that this can help you.
Hi I've changed the pin as follows, but I'm getting a new error like this.
Here is my new error
Traceback (most recent call last):
File "
Hi @NormanStudentRobotic
If you want to use Pin(0)
and Pin(1)
for your Modbus communication, you also need to set the uart_id=0
, see RTU example comment and RP2 UART docs. It is also documented in the example docs
UART0 can be mapped to GPIO 0/1, 12/13 and 16/17, and UART1 to GPIO 4/5 and 8/9.
By default, uart_id
is set to 1 in this lib, as UART0 is usually used by the default USB interface or similar.
The following code should fix your issue. I'll also update the documentation and examples accordingly
rtu_pins = (Pin(0), Pin(1)) # (TX, RX)
baudrate = 9600
client = ModbusRTU(
addr=slave_addr, # address on bus
pins=rtu_pins, # given as tuple (TX, RX)
baudrate=9600,
uart_id=1
)
I've changed uart_id = 0 since the beginning in serial.py I have also changed
Why now i got error like this can you help me sir?
Hi @NormanStudentRobotic can you provide me more informations about the system you are using? Simply run the following code on your boards
import os
from umodbus import version
os_info = os.uname()
print('MicroPython infos: {}'.format(os_info))
print('Used micropthon-modbus version: {}'.format(version.__version__))
I've created a RP2-RP2 setup according to your prevoius comments setup with the two RS485 modules. I'm using the RTU client and RTU host example as is. Only these changes have been made
uart_id = 0
rtu_pins = (Pin(0), Pin(1)) # (TX, RX)
client = ModbusRTU(
addr=10, # address on bus
pins=rtu_pins, # given as tuple (TX, RX)
baudrate=9600, # optional, default 9600
uart_id=uart_id # optional, default 1, see port specific docs
)
uart_id = 0
rtu_pins = (Pin(0), Pin(1)) # (TX, RX)
host = ModbusRTUMaster(
pins=rtu_pins, # given as tuple (TX, RX)
baudrate=9600, # optional, default 9600
uart_id=uart_id # optional, default 1, see port specific docs
)
See also #59
Hello everybody, I got problem when reading holding register. I tried to read the problems but i dont understand. I am using modbus rs485 (max485 TTL) to read the holding register of CO2, Temperature and humidity sensor
This is the result of running the program
Running ModBus version: 2.3.4
HOLDING REGISTER request test.
Reading qty=3 from address 0:
Traceback (most recent call last):
File "
I am very sorry folks. Maybe I made a mistake, that is after exchanging the connection from TX outlet from the RS3485 TTL to GPIO 2 and RX to GPIO TX, I got the result and also I got an error. The result is almost identical when I tested with Arduino MEGA and Arduino NANO EVERY. Below is the result from running the program
Running ModBus version: 2.3.4 HOLDING REGISTER request test. Reading qty=3 from address 0: Result: (702, 318, 431) Testing 100 requests, each 30ms. Wait... Error found
This is the programming
import time from machine import Pin, UART from umodbus import version print('Running ModBus version: {}'.format(version.version))
from umodbus.serial import Serial as ModbusRTUMaster rtu_pins = (Pin(0), Pin(1))
address = 0 qty = 3 host = ModbusRTUMaster(uart_id=0,baudrate = 4800, pins=rtu_pins)
print('HOLDING REGISTER request test.') print('Reading qty={} from address {}:'.format(qty, address)) values = host.read_holding_registers(slave_addr=1, starting_addr=address, register_qty=qty, signed=False) print('Result: {}'.format(values))
success = True counter_requests = 100 fred_time = 30 print('Testing {} requests, each {}ms. Wait...'.format(counter_requests, fred_time)) start_time = time.ticks_ms() for i in range(counter_requests): res = host.read_holding_registers(slave_addr=1, starting_addr=address, register_qty=qty, signed=False) time.sleep_ms(fred_time) if res != values: print('Error found') success = False break end_time = time.ticks_ms() delta_time = time.ticks_diff(end_time, start_time) delta_time_div_counter_requests = delta_time/counter_requests modbus_time_operation = delta_time_div_counter_requests - fred_time if success: print('Done ModBus RTU (via RS485) requests without error in {}ms.'.format(delta_time)) print('The total time was {}ms. So {} / {} requests is {}ms. So, {}ms - {}ms (freq_time delay) = {}ms. So the total time operation used by Modbus Protocol is {}ms'.format(delta_time, delta_time, counter_requests, delta_time_div_counter_requests, delta_time_div_counter_requests, fred_time, modbus_time_operation, modbus_time_operation))
Hi Guys, I want to build up a Modbus TCP communication through ethernet on a W5100S-EVB-Pico board, however when I want to import TCP, it says 'MemoryError: memory allocation failed, allocating 505 bytes'. I tried gc.threshold(2000) also, but same with different allocated bytes. Do you have any idea? Thanks
@Reseva Could you please put this code before all others code and paste the result here?
import gc
print(f'mem_alloc: {gc.mem_alloc()} | mem_free: {gc.mem_free()}')
And please, paste always the all output here, so we can help you better.
Sure, here is the code: import gc print(f'mem_alloc: {gc.mem_alloc()} | mem_free: {gc.mem_free()}') import time from umodbus.tcp import TCP as ModbusTCPMaster import network import ethernet
ethernet.w5x00_init()
port = 502 # port to listen to slave_addr = 1 # bus address of modbus_client ist_address = 0 # Input Status Adress input_qty = 1 # Input Status Quantity to Read in Single Request
ip = '192.168.1.20'
modbus_client = ModbusTCPMaster(slave_ip=ip,slave_port=port,timeout=5) print(f'Updating data to Modbus TCP Server at {ip}:{port}')
And here is the output:
MPY: soft reboot
mem_alloc: 5408 | mem_free: 44576
Traceback (most recent call last):
File "
@Reseva There is something wrong on the W5100S-EVB-Pico board, because it has just ~50KB of free memory (mem_alloc: 5408 + mem_free: 44576). As I remember the rp2040 has around 180KB of free memory, maybe the W5100S ethernet is using so much RAM?
Well, problem is that with 50KB free RAM can't run this lib without freeze it in the firmware. So, please, freeze (compile the lib together with MicroPython) the modbus lib inside the firmware to works.
Guyz, any idea? It is working few times and then stuck. modbus_client = ModbusTCPMaster(slave_ip=ip,slave_port=port,timeout=5)
Traceback (most recent call last):
File "<stdin>", line 119, in <module>
File "<stdin>", line 69, in mymodbus
File "/lib/umodbus/tcp.py", line 81, in __init__
OSError: [Errno 12] ENOMEM
after adding
import gc
gc.threshold(4000)
Everything is okay
Hey buddy, how does this library work on pico?