-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invalid CRC on reading multiple COILS #52
Comments
@beyonlo could you try to debug the issue and print the I again assume the flow control pin is turned of to early or to late |
@brainelectronics follow the tests as requested: register_definitions = {
"COILS": {
"RESET_REGISTER_DATA_COIL": {
"register": 42,
"len": 1,
"val": 0
},
"EXAMPLE_COIL": {
"register": 123,
"len": 16,
"val": [1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,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
}
}
} Slave RTU: $ mpremote run rtu_client_example.py
Running ModBus version: 2.3.1-rc26.dev53
Setting up registers ...
Register setup done Master RTU: $ mpremote
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] to exit this shell
>>> from umodbus import version
>>> print('Running ModBus version: {}'.format(version.__version__))
Running ModBus version: 2.3.1-rc26.dev53
>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=16)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
[True, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True]
>>> host.write_multiple_coils(slave_addr=10, starting_address=125, output_values=[1,1,0])
response var from serial.py file is: bytearray(b'\n\x0f\x00}\x00\x03\x84\xa9')
True
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xee')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/lib/umodbus/common.py", line 137, in read_coils
File "/lib/umodbus/serial.py", line 290, in _send_receive
File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=2)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x02'
response var from serial.py file is: bytearray(b'\n\x01\x01\x03\x13\xed')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/lib/umodbus/common.py", line 137, in read_coils
File "/lib/umodbus/serial.py", line 290, in _send_receive
File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=8)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x08'
response var from serial.py file is: bytearray(b'\n\x01\x01\xd8S\xf6')
response var from common.py file is: bytearray(b'\xd8')
[True, True, False, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=8)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x08'
response var from serial.py file is: bytearray(b'\n\x01\x01\xd8S\xf6')
response var from common.py file is: bytearray(b'\xd8')
[True, True, False, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=16)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xd8q\x86\x19')
response var from common.py file is: bytearray(b'\xd8q')
[True, True, False, True, True, False, False, False, False, True, True, True, False, False, False, True]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=3)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x03'
response var from serial.py file is: bytearray(b'\n\x01\x01\x06\xd3\xae')
response var from common.py file is: bytearray(b'\x06')
[True, True, False]
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=7)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x07'
response var from serial.py file is: bytearray(b'\n\x01\x01lS\xe1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/lib/umodbus/common.py", line 137, in read_coils
File "/lib/umodbus/serial.py", line 290, in _send_receive
File "/lib/umodbus/serial.py", line 323, in _validate_resp_hdr
OSError: invalid response CRC
>>> host.read_coils(slave_addr=10, starting_addr=123, coil_qty=7)
modbus_pdu var from common.py file is: b'\x01\x00{\x00\x07'
response var from serial.py file is: bytearray(b'\n\x01\x01lS\x81')
response var from common.py file is: bytearray(b'l')
[True, True, False, True, True, False, False]
>>>
This make sense, because as you can see in the |
Is there a relation between this bug and the #50? |
Good afternoon @brainelectronics Do you have any news (or a roadmap) to fix this issue? Thank you in advance! |
Hello @brainelectronics how are you? 😃 I would like to add 3 more information:
Unfortunately this CRC bug is a big problem for the application. Could you please give a attention for this issue? Off topic: I saw that one user from Belgium talk about how to donate for this project. In the past I told you about that as well. I would be happy do donate for this project helping a bit more than just the tests and support, because this lib is really important for my project. And I think that this lib will be important for many many people that can to donate too and all that donate can help this project for always have back to community a better lib. Thank you very much for your attention! Here a example of RTU with thread just as test: $ cat rtu_client_example_with_callback_with_thread.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
Main script
Do your stuff here, this file is similar to the loop() function on Arduino
Create a Modbus RTU client (slave) which can be requested for data or set with
specific values by a host device.
The RTU communication pins can be choosen freely. The register definitions of
the client as well as its connection settings like bus address and UART
communication speed can be defined by the user.
"""
import network, time, _thread
def testThread():
c = 0
c2 = 0
delta = 0
while True:
start_time = time.ticks_ms()
res = delta
if res > 100:
print(res, c)
for i in range(120):
c2 += i ** i
c2 = 0
c += 1
#time.sleep_ms(100)
end_time = time.ticks_ms()
delta = time.ticks_diff(end_time, start_time)
_thread.start_new_thread(testThread, ())
from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))
# import modbus client classes
from umodbus.serial import ModbusRTU
# ===============================================
# RTU Slave setup
# act as client, provide Modbus data via RTU to a host device
# ModbusRTU can get serial requests from a host device to provide/set data
rtu_pins = (17, 18) # (TX, RX)
slave_addr = 10 # address on bus as client
baudrate = 115200
client = ModbusRTU(
addr=slave_addr, # address on bus
baudrate=baudrate, # optional, default 9600
# data_bits=8, # optional, default 8
# stop_bits=1, # optional, default 1
# parity=None, # optional, default None
pins=rtu_pins,
ctrl_pin=15)
def my_coil_set_cb(reg_type, address, val):
print('Custom callback, called on setting {} at {} to: {}'.
format(reg_type, address, val))
def my_coil_get_cb(reg_type, address, val):
print('Custom callback, called on getting {} at {}, currently: {}'.
format(reg_type, address, val))
def my_hregs_set_cb(reg_type, address, val):
print('Custom callback, called on setting {} at {} to: {}'.
format(reg_type, address, val))
def my_hregs_get_cb(reg_type, address, val):
print('Custom callback, called on getting {} at {}, currently: {}'.
format(reg_type, address, val))
# common slave register setup, to be used with the Master example above
register_definitions = {
"COILS": {
"EXAMPLE_COIL": {
"register": 123,
"len": 1,
"val": 1
},
"COIL_SIGNALS": {
"register": 125,
"len": 16,
"val": [1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1],
"on_get_cb": my_coil_get_cb,
"on_set_cb": my_coil_set_cb
}
},
"HREGS": {
"EXAMPLE_HREG": {
"register": 93,
"len": 1,
"val": 19
},
"HREG_VALUES": {
"register": 130,
"len": 33,
"val": [34, 12, 14, 0, 10, 4, 2, 1345, 34, 8, 1100, 350, 456, 754, 324, 423, 530, 90, 320, 34, 244, 355, 606, 656, 640, 620, 677, 623, 234, 567, 34, 56, 68],
"on_get_cb": my_hregs_get_cb,
"on_set_cb": my_hregs_set_cb
}
},
"ISTS": {
"EXAMPLE_ISTS": {
"register": 67,
"len": 1,
"val": 0
}
},
"IREGS": {
"EXAMPLE_IREG": {
"register": 10,
"len": 2,
"val": 60001
}
}
}
"""
# alternatively the register definitions can also be loaded from a JSON file
import json
with open('registers/example.json', 'r') as file:
register_definitions = json.load(file)
"""
# use the defined values of each register type provided by register_definitions
client.setup_registers(registers=register_definitions)
# alternatively use dummy default values (True for bool regs, 999 otherwise)
# client.setup_registers(registers=register_definitions, use_default_vals=True)
while True:
result = client.process()
print("Finished providing/accepting data as client") Here reading multiple COILS: $ cat read_coils.py
import time
from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))
from umodbus.serial import Serial as ModbusRTUMaster
rtu_pins = (17, 18)
address = 125
qty = 16
host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
print('COIL request test.')
print('Reading qty={} from address {}:'.format(qty, address))
values = host.read_coils(slave_addr=10, starting_addr=address, coil_qty=qty)
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_coils(slave_addr=10, starting_addr=address, coil_qty=qty)
#print(res)
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)) And here reading multiple HOLDING REGISTERS: $ cat read_holding_registers.py
import time
from umodbus import version
print('Running ModBus version: {}'.format(version.__version__))
from umodbus.serial import Serial as ModbusRTUMaster
rtu_pins = (17, 18)
address = 130
qty = 33
host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
print('HOLDING REGISTER request test.')
print('Reading qty={} from address {}:'.format(qty, address))
values = host.read_holding_registers(slave_addr=10, 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=10, starting_addr=address, register_qty=qty, signed=False)
#print(res)
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)) |
About the thread together modbus lib I checked that error response (in addition to CRC error) is $ mpremote run read_coils.py
Running ModBus version: 2.3.1-rc26.dev53
COIL request test.
Reading qty=16 from address 125:
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
Result: [True, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True]
Testing 100 requests, each 30ms. Wait...
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'\n\x01\x02\xf8q\x9f\xd9')
response var from common.py file is: bytearray(b'\xf8q')
modbus_pdu var from common.py file is: b'\x01\x00}\x00\x10'
response var from serial.py file is: bytearray(b'')
Traceback (most recent call last):
File "<stdin>", line 22, in <module>
File "/lib/umodbus/common.py", line 137, in read_coils
File "/lib/umodbus/serial.py", line 290, in _send_receive
File "/lib/umodbus/serial.py", line 314, in _validate_resp_hdr
OSError: no data received from slave Look that it read the first time OK, and after when start the loop to read show error Thank you. |
Hello @brainelectronics Please, ignore that problem with I put a Thread:
ModBus rtu example modified to use thread:
So, the bug is just still with |
@brainelectronics some news for this issue? 😄 |
Hey @beyonlo not yet 😞 |
Hello @brainelectronics
Congratulations. I wish you the best in the new job and the projects 🎈
Anyway, that is so far a good news! Thank you so much! |
Hello @brainelectronics how are doing? I need a help from you, about this CRC errors :) Do you have any news/plans to fix that? It is very difficult to use RS-485 because that CRC errors. Many tests in other issues here (as the new PR #56 for async support and other tests) show always the same CRC errors in sync mode. We was thinking that PR #73 could fix or reduce the CRC errors, but unfortunately as I reported the tests there (#73) it do not help 😢 If you can found a time to dedicate with this bug will be amazing 🥳 And, as you know, any tests that need to do in new code, I can do that! Thank you in advanced! |
Hey @beyonlo may you can give release 2.3.5 a try again? Not sure whether your test in #75 did already cover these issues or not |
@brainelectronics I tested again this issue and I confirm that errors do not happen anymore with 2.3.5 (that shows 0.0.0) 🥳 Follow the tests used in the first thread of this issue: Slave RTU (sync): $ mpremote run rtu_client_example_with_callback.py
Running ModBus version: 0.0.0
Custom callback, called on getting COILS at 125, currently: [1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1]
Custom callback, called on setting COILS at 125 to: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True, True]
Custom callback, called on getting COILS at 125, currently: [False, True]
Custom callback, called on getting COILS at 125, currently: [False]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0]
Custom callback, called on getting COILS at 125, currently: [False, True, True, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, False, False] Master RTU (sync): $ mpremote
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] to exit this shell
>>>
>>> from umodbus.serial import Serial as ModbusRTUMaster
>>> rtu_pins = (17, 18)
>>> host = ModbusRTUMaster(baudrate=115200, data_bits=8, stop_bits=1, parity=None, pins=rtu_pins, ctrl_pin=15)
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=16)
[True, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True]
>>> host.write_multiple_coils(slave_addr=10, starting_address=125, output_values=[1,1,0])
True
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=3)
[False, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=2)
[False, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=1)
[False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=4)
[False, True, True, True]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=8)
[False, True, True, True, True, False, False, False]
>>> host.read_coils(slave_addr=10, starting_addr=125, coil_qty=18)
[False, True, True, True, True, False, False, False, False, True, True, True, False, False, False, True, False, False]
>>> |
Can you share the connection diagram please? |
Hi Friend, Can you share connection diagram please ? |
@brainelectronics unfortunately that error happen with
coil_qty=3
as well. Details below:Slave:
Master:
Originally posted by @beyonlo in #51 (comment)
The text was updated successfully, but these errors were encountered: