1
votes

I am failing to communicate with a device using minimalmodbus, Modbus RTU.

I have connected the device to a raspberry pi via a usb to rs-485 adapter (FTDI chip) A to A and B to B.

The device configurations are as follows:

  • Port settings:

    • Baud rate: 9600
    • Parity: No
    • Stop bits: 1
    • Silent Interval: 70 ms.
    • Transmission Mode: RTU
  • Interface 2 Wire RS485

    • Connector of ECM: DB9
    • Connections: A on pins 1, 4. B on pins 6, 9

Modbus Holding registers (simplified for the purpose of this example)

  • Swapped Floating point format:
    • 40001 (address 0) Parameter 1
    • 40003 (address 2) Parameter 2

I have tried using raw serial commands to communicate with the device, as well as using pymodbus, and now on my latest attempt minimal modbus. Please see below my code attempt using minimalmodbus.

Also, i know the serial adapter works as i use it for various other serial sensors. Only difference is that i am working with modbus now.

import minimalmodbus

instrument = minimalmodbus.Instrument('/dev/tty/USB1',1)

instrument.debug = True
instrument.handle_local_echo = True # The serial device echos back every write, hence this
instrument.serial.baudrate = 9600
instrument.serial.timeout = 1

value = instrument.read_register(0,2)

print value

I expected to receive some sort of reply even if an error or incorrect, but i am getting nothing. the debug output of minimalmodbus says "IOError: No communication with the instrument(no answer)"

Is there any obvious mistakes in my code vs the sensor requriements? I confirmed my wiring with the manufacturer, and is correct.

2
Is the function code correct? You could try read_register(0, 2, 3) instead. - Bosz
Can you test you modbus slave with another master an confirm that it is working? - JWo
@Bosz yes the function code should be correct. I tried your solution and still same issue. - LecauseAndThePi
@JWo I only have the raspberry pi (3b+) and my laptop that i can use as a master. Would still be using python either way. i might try to run it from my laptop. - LecauseAndThePi
Can you post a link to your USB-to-RS485 cable? Modbus over half-duplex needs a direction control signal, does your cable has hardware direction control? - Marcos G.

2 Answers

0
votes

Quoting from the manual of your cable:

The USB-RS485-WE cable allows for local echo to be enabled/disabled by changing a bit in the FT232R EEPROM. If CBUS4 in the EEPROM is set for “PWRON#” local echo is enabled. If CBUS4 in the EEPROM is set for “TXDEN” local echo is disabled. Users can set this with MPROG from www.ftdichip.com The default for the local echo is disabled (CBUS4 set for “TXDEN)

Phew! lots of info in there. According to the thread of comments on your question you activated the software echo handling on minimalModbus because otherwise your routine would not wait for the response from the device on the other end. That makes one think whether your cable has the local echo enabled or disabled.

Fortunately, you can check that very easily. As the manual says just go get MPROG here. Extract and run (yeap, you need Windows for this tool, but you can run it on a Virtual Machine).

Connect your cable to the USB port (don't forget to send the device to the virtual machine if you are running one) and select Tools-->Read and Parse on MPROG.

This is what you should get:

MPROG screenshot

Make sure you have TXEN selected on box C4. According to the manual, you should have TXEN by default, if you see PWRON# it means the local echo is active. Disable it and you should be good to go to use Modbus.

0
votes

I don't see an obvious error from your side. That's rather difficult since you are working with hardware. I'll provide some of my code. I used it for a prototype, which was a Raspberry Pi 3B with a USB to RS485 converter (This one).

from modbus import minimalmodbus
import serial
import time
from mqtt.client import Client as mqtt_client

class Slave:

    def __init__(self, serial_port: str = '/dev/ttyUSB0', slave_id: int = 5,
                 baudrate: int = 38400, byte_size: int = 8,
                 parity: str = serial.PARITY_NONE, stopbits: int = 1,
                 timeout: float = 1.0):
        self.slave = minimalmodbus.Instrument(serial_port, slave_id)
        self.slave.serial.baudrate = baudrate
        self.slave.serial.bytesize = byte_size
        self.slave.serial.parity = parity
        self.slave.serial.stopbits = stopbits
        self.slave.serial.timeout = timeout
        self.registers = ["header", "zero", "life_beat",
                          "test_int", "test_float"]
        self.output = mqtt_client()
...

When I read a register I used e.g.:

self.slave.read_register(2)
//or
self.slave.read_float(5)

I'm not sure which python version I used. I think it was 3.6.x.