News:

  • October 16, 2026, 06:28:26 PM

Login with username, password and session length

Author Topic: Ubuntu Serial RTU Communication via PyModbus with H2-DM1 (CPU) & DL205 (Base)  (Read 9900 times)

ProfessorMcD

  • Newbie
  • *
  • Posts: 3
So I am new to working with PLCs, and am struggling to establish communication between my H2-DM1 internal serial port, and a python script running on Ubuntu linux. I am using a DL205 base with with a few I/O modules (AI, AO). I already have a fully-functional ladder and system, but I am trying to query my output bits using the Serial RTU protocol with the pyModbus AsyncIO Serial client https://pymodbus.readthedocs.io/en/latest/source/example/async_asyncio_serial_client.html

The code is used as is, commenting out all but the serial RTU client reading discrete inputs.

The settings of the serial port are Modbus RTU Server (Slave), baudrate 9600 parity none, data bits/bytesize 8, stopbits 1, with Transmit Control Unconditional and RTS set to follow transmitter (but I am not sure what I need here).

The pymodbus client has the same.

The idea is to use a PC host as a master (for use in an EPICS IOC) and we're testing protocols: reading (and eventually writing) data (with python for now, with EPICS/MDSplus later).

We want the Xs and Ys for now but need some help.

What needs to go into the ladder to get this working?

I get a timeout error from the AsyncIO python module (looking there for answers to that) but do we have to set up something in the configs? 

RBPLC

  • Hero Member
  • *****
  • Posts: 586
Modbus registers are sandboxed for security. You'll need to write the values to the Modbus registers in the controller. Help topic DMD0251 in Do More Designer discusses this.

ProfessorMcD

  • Newbie
  • *
  • Posts: 3
Ok great, we did this by assigning our output bits to the correct data location (in our instance MC0-255).  Excuse our clumsy questions. What we're struggling to determine is the addressing scheme. It has been noticed that in other plc's (we're using dl205 and the H2-DM1 CPU module) a choice of mode is offered, but it's difficult to determine how this plc addresses these Modbus Memory blocks. The manual mentions for the Modbus Network Read and Write operations and the addressing being decimal. In other places I've seen hex and decimal (starting from 16640 for the output coils).

Help end our misery?

Does stablishing a link to the serial port have anything to do with this?

Thanks,

yours,

2 jr engineers/technicians lost in the woods

franji1

  • Bit Weenie
  • Host Moderator
  • Hero Member
  • *****
  • Posts: 3850
    • Host Engineering
The 205 PLC line has 2 different CPU types, but same I/O.

DirectLOGIC (30 year old technology, octal addressing, 1 block of numeric that contains BCD, Real, decimal, etc. that also maps to I/O, and one block of memory bits.  It does Modbus through mapping of octal V addressing to Modbus memory, and the I/O is exposed (Modbus master can directly manipulate I/O).

Do-more is more recent and supports Modbus as a Slave natively through Modbus memory (do not confused MRX/MWX where Do-more is the Master).  There is no direct access to I/O, just internal "Modbus" data blocks.

Since you have a PC that is the Master, the PC will look at Modbus Coil memory (MC), Modbus Input memory (MI), Modbus Input Register memory (MIR) and Modbus Holding Register memory (MHR) - NATIVELY.  No mapped V.  No mapped octal addressing to decimal stuff.  No spreadsheet (don't ask).

In Do-more Modbus memory offsets start at 1, e.g. Modbus Holding Register 40001 maps to MHR1.  Modbus Input Register 30001 maps to MIR1.  Modbus Coil 00001 map to MC1.  Modbus (discrete) Input 10001 maps to MI1.

So, from your PC, you write to Holding Register 40001, that data ends up in MHR1.  If you want that to be an analog output, say WY0, use a MOVE instruction to copy MHR1 to WY0.  Your PC, when it writes to 40001, will write to MHR1 and that value get copied to analog output WY0 via ladder logic.

Say you want Input Register 30007 to be a Timer Accumulator T2.Acc, use a MOVE instruction to copy T2.Acc to MIR7.  When the PC reads Input Register 30007, it will get that timer accumulator value.

Rather than do a bunch of MOVE's, I recommend sticking your INPUT logic in $tTopOfScan code-block, inside a single table based COPY instruction.  Similarly, stick your OUTPUT logic in $tBottomOfScan code-block in another COPY instruction.  COPY is a nice compact table based "move" where you can easily copy lists of blocks of values.  Very compact.

If for some reason you need to swap words or do BCD, look at PUBLISH (for outputs) and SUBSCRIB (for inputs) to get the data in the desired format from/to Do-more to what your PC needs.

Controls Guy

  • Internal Dev
  • Hero Member
  • ****
  • Posts: 3628
  • Darth Ladder
Mo spreadsheet (don't ask).

Argh, I can't sleep at my desk for all the wailing and gnashing of teeth.    You really didn't need the spreadsheet, at least the official one.   The address translation was just

DEC(octal address) + type dependent offset

For example, for V's the offset was 0, and for C's d3072.   Don't remember the others cause I didn't use them as much.   Shoot, Excel even has a OCT2DEC() function.   Easy peasy.

Now, none of this should be interpreted to say the DM approach isn't better, just saying the old way wasn't as arduous as it sounds.
I retract my earlier statement that half of all politicians are crooks.  Half of all politicians are NOT crooks.  There.

ProfessorMcD

  • Newbie
  • *
  • Posts: 3
Thanks to everyone for the help so far. We are still working on establishing this comm link. Got pulled onto other things, and we'll report back when we have a solution or the right questions to ask. I feel like the issue is right under our nose.