ArduinoModbus (RS485) with Portenta Machine Control - Basic guide [UPDATED for the new Arduino_PortentaMachineControl library]

[UPDATE: I've now added new examples at the very bottom of this post so that the code runs with the new Arduino_PortentaMachineControl.h library. The code is similar but there are some slight adjustments that are neccesary to get the new library to work. At the moment this library is incomplete and I don't understand why Arduino couldn't just improve the Arduino_MachineControl.h library (???), but it is what it is.]

[UPDATE 2: Feel free to check out my new basic guide on MODBUS TCP with the Portenta Machine Control where I also give an example sketch of running MODBUS TCP and RS485 at the same time.]

Hello everyone,

I feel somewhat pretentious posting a guide since I'm quite the beginner, however I thought I would still post this since there may be other people who are trying to establish RS485 with the PMC and the ArduinoModbus library.
There is also currently very limited information available on this topic.

I have made these sketches based on: a example sketch given to me by the Arduino support team, the examples in the ArduinoModbus library, and by looking through the .cpp files of the RS485 & ArduinoModbus libraries. I have by no means "mastered" these libraries so the sketches will be very basic.

I am assuming everyone reading this knows the basics of Modbus protocol, wiring, IDE, library manager, etc.

So... this will show you how to establish both a simple slave/server and master/client setup with the Portenta Machine Control and the ArduinoModbus library:

Hardware:
Portenta machine control
Computer
USB to RS485 TTL converter
24V Power supply (for PMC)

Software:
Arduino IDE
ModbusTool (http://modbusmaster.com/)
Modbus Tools Modbus Slave (Modbus Slave Simulator) (NOTE: these guys will try to annoy you into giving them your money - DONT GIVE IN!)
Arduino_MachineControl library
ArduinoRS485 library
ArduinoModbus library

The connection configuration in both Modbus simulation softwares should be:
Connection: Serial
Baudrate: 9600
Parity: None
Stop bits: 1
Mode: RTU
Byte order: 4321 (This is for master software only)

Physical connection:

  • 24V Power supply --> PMC
  • Computer --> PMC
  • Computer --> [USB to RS485 TTL]
  • [USB to RS485 TTL] --> PMC :
    (-) --> GND
    A --> TXP 485
    B --> TXN 485

SLAVE/SERVER:
Here is the code for a basic slave/server configuration:

#include <Arduino_MachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

using namespace machinecontrol;

constexpr unsigned long baudrate { 9600 };

void setup() {
  // put your setup code here, to run once
Serial.begin(9600);
delay(10);

comm_protocols.init();
comm_protocols.rs485Enable(true);

comm_protocols.rs485.setDelays(50, 1600);
ModbusRTUServer.begin(comm_protocols.rs485, 1, baudrate, SERIAL_8N1);
/*
The above part is the configuration of the slave:
1) Selection of pins
2) Assigned slave ID
3) Baudrate (as defined above)
4) Byte size: 8, Parity: None, Stop bits: 1
*/

ModbusRTUServer.configureHoldingRegisters(0, 16); //create 16 holding registers starting at address 0 [0-15].
ModbusRTUServer.holdingRegisterWrite(1, 500); //write the value 500 into address 1.
}

void loop() {
  // put your main code here, to run repeatedly:
ModbusRTUServer.poll();
int regVal = ModbusRTUServer.holdingRegisterRead(1);
Serial.print("regVal: "); 
Serial.println(regVal); //This part is here so you can see that the configuration has been done correctly before connecting to master simulation software.
Serial.println("-");
delay(500);
}

After uploading this code start ModbusTool.exe, configure the connection, and connect. You should see the value 500 in address 1.
Here is a .ino file with the above sketch:
PMCSlaveBasic.ino (790 Bytes)

MASTER/CLIENT:
Here is the code for a basic master/client configuration:

#include <Arduino_MachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

using namespace machinecontrol;

constexpr unsigned long baudrate { 9600 };

int readVal;
uint16_t sendVal = 125;

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);

comm_protocols.init();
comm_protocols.rs485Enable(true);
comm_protocols.rs485.setDelays(50, 1600);
ModbusRTUClient.begin(comm_protocols.rs485, baudrate, SERIAL_8N1);
}

void loop() {
// put your main code here, to run repeatedly:
readVal = ModbusRTUClient.holdingRegisterRead(1, 0); //send a read request (one holding register) to slave 1, address 0. 

ModbusRTUClient.holdingRegisterWrite(1, 1, sendVal); //send a write message to slave 1, address 1. Write the value sendVal (125).

Serial.print("Value of holding register 1 in slave: "); 
Serial.println(readVal);
Serial.println();
}

After uploading this code start Modbus Slave, configure the connection, and connect.
You should see that the value of address 1 is 125.
Then write some value (not 0!) into address 0.
Then go back into the IDE and open Serial Monitor - it should display whatever value you wrote into address 0.
Here is a .ino file with the above sketch:
PMCMasterBasic.ino (727 Bytes)

I should also note that there seem to be multiple ways of writing commands with this library.
For instance you could alternatively construct the read request as:

ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0, 1);
readVal = ModbusRTUClient.read();

I hope someone found this helpful in any way! :slight_smile:

Kind regards
/ Einar

SLAVE/SERVER WITH Arduino_PortentaMachineControl.h :

#include "mbed.h"
#include <Arduino_PortentaMachineControl.h>

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

constexpr unsigned long baudrate = 115200;
constexpr int predelay = 50;
constexpr int postdelay = 1600; 

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);

  MachineControl_RS485Comm.begin(baudrate, predelay, postdelay);

  ModbusRTUServer.begin(MachineControl_RS485Comm, 1, baudrate, SERIAL_8N1);
  ModbusRTUServer.configureHoldingRegisters(0, 19); //Configures 18 holding registers.

  ModbusRTUServer.holdingRegisterWrite(1, 153);

}

void loop() {
  // put your main code here, to run repeatedly:

  ModbusRTUServer.poll();

}

MODBUS_server_WORKING.ino (683 Bytes)

MASTER/CLIENT with Arduino_PortentaMachineControl.h":

#include "mbed.h"
#include <Arduino_PortentaMachineControl.h>

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

constexpr unsigned long baudrate = 115200;
constexpr int predelay = 50;
constexpr int postdelay = 1600; 

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);

  MachineControl_RS485Comm.begin(baudrate, predelay, postdelay);

  ModbusRTUClient.begin(MachineControl_RS485Comm, baudrate, SERIAL_8N1);

}

void loop() {
  // put your main code here, to run repeatedly:

  ModbusRTUClient.holdingRegisterWrite(3, 0, 1); //Slave ID (int), Address (int), value

}

MODBUS_client_WORKING.ino (605 Bytes)

8 Likes

Hi @einarbjorkman,

Thanks for posting the guide, I am about to work with RS485 and this has proven very useful.

I do not suppose you have another link to the software at http://modbusmaster.com/ ? The website seems to be down at the moment.

Thanks again!

Hi @thebeest,

You are right that the website is gone - for some reason - and unfortunately I'm unaware as to the status (if it's been removed, is being updated, or has switched domain, etc).
I could however send you the files for the program if you're interested?

Kind regards / Einar

Hi @einarbjorkman,
Yes I did try and look for it elsewhere but the closest I could find was an Arduino Library for Modbus GitHub - 4-20ma/ModbusMaster: Enlighten your Arduino to be a Modbus master.

I would really appreciate it if you could send me the files.

Many thanks!

@thebeest Well, that is to enable to Arduino to act as master. The purpose of the ModbusTool (modbusmaster) is to enable the computer to act as a slave to test if modbus is working on the Arduino.

But sure, I'll shoot you a DM :slight_smile:

/ Einar

You can still access it on the Internet Archive Wayback Machine:
https://web.archive.org/web/20220715000000*/http://modbusmaster.com/

@markd833 huh neat, well then you can ignore my DM @thebeest :smiley:
Thanks for the help Mark!
/Einar

Nice one @markd833, I didn't realise they saved zips as well as webpages!

Thanks for the offer @einarbjorkman, I have ignored you :wink:

Great guide @einarbjorkman, I really hit the ground running thanks to your help. I use Linux primarily and found this Free Modbus Slave Simulator and Test Tool which runs natively on Linux and Windows and may be of use to someone who reads this guide of yours.

Modbus Slave Simulator does offer much more functionality but its nice knowing there isn't just one option to do our testing with.

I am currently using this code as a base for my PMC master: ArduinoModbus/ModbusRTUClientKitchenSink.ino at master · arduino-libraries/ArduinoModbus · GitHub

The only changes needed to work with the Portenta Machine Control are in the header and setup() as follows:

#include <Arduino_MachineControl.h>
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

using namespace machinecontrol;

constexpr unsigned long rs485Baudrate { 9600 };

int counter = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("Modbus RTU Client Kitchen Sink - Portenta Machine Control");

  comm_protocols.init();
  comm_protocols.rs485Enable(true);
  comm_protocols.rs485.setDelays(50, 1600);
  
  // start the Modbus RTU client
  if (!ModbusRTUClient.begin(comm_protocols.rs485, rs485Baudrate, SERIAL_8N1)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  }
}

@thebeest I'm happy that you found my guide useful - your appreciation is really encouraging! :smiley:

And yes, any tool - or tools - which get the job done (allowing the pc to act as slave and master) will do.

Has anyone attempted to use modbus RTU communication with the PLC IDE? I have been succesful with the TCP but not with the RTU... Are there any special considerations other than to check the baud rate, byte configuration and the unitd id?

Thank you!

I have not tried this with the PLC IDE and cannot help you with that unfortunately.

Hi guys!!
I have been working with a project that requests the communication between an OPC Server and the Portenta machine control. This request is made using the modbus TCP/IP. But, the project also requests a RS 485 serial communication to control and monitor a Kuka program. Is it possible use these two protocols at the same time? can anyone share any ideas to develop it.

Hi Leugim,
I am currently working on trying to get MODBUS TCP running with the PMC, and it is also my intention to run it side by side with RS-485. I will keep you posted on my progress (if any is made! :wink:).
Cheers / Einar :coffee: :sweden:

1 Like

hlo guys I am using machine control i want to read the floating points from slave id using arduinomodbus library but the code returning with output -1 is there any way to read the floating points data.

Hi Dinesh,

The modbus protocol does not support floating point values directly to my understanding. This can also be seen indirectly in the src of the ArduinoModbus library:


^As you can see above the input variable type for the register value is an unsigned integer of 16 bits. You will see long as the return type for the modbus read functions:

As you can also see the read function returns -1 on error, which matches with your problem :wink:
If I were you i'd have the slave convert the floats to integers by multiplication and then just divide by the same factor in the master after reading the int value from the slave.

I hope this helps you,
Cheers / Einar :coffee: :sweden:

Hi Leugim,
Are you still working on this situation?
If so, check my new post: ArduinoModbus (TCP) with Portenta Machine Control - Basic Guide (Simultaenous MODBUS RTU & TCP also included)
Although I have not solved the situation where the TCP is a master yet, maybe this can give you a good starting point? :wink:
Also feel free to contribute if you have discovered something along that route...

Cheers/ Einar :coffee: :sweden:

1 Like