ModbusTCP connection between PC and Arduino

Hey Guys,

I am trying to establish a ModbusTCP communication between my PC and Arduino PMC(Portenta Machine Control). SO the basic idea is that my PC(ModbusTCP Server/Slave) would write data to 2 registers and my PMC(ModbusTCP Client/Master) would read the respective registers. Both of the codes run on the same machine.

The major isuue that I have is that "modbusTCPClient.begin(server, 1502)" fails. It returns a 0. So why does this happen? and how could I solve it?

I am quite new to ModbusTCP and I am learning on the go. So any help or guidance would be greatly appreciated!

Server Code:

from pyModbusTCP.server import ModbusServer, DataBank

host = '127.0.0.1'
port = 1502

class mydatabank(DataBank):
    def __init__(self):
        super().__init__()
    
    def get_holding_registers(self, address, number=1, srv_info=None):
        self._h_regs[0] = 5
        self._h_regs[1] = 100

        #repcakage data into a list
        try:
            return[self._h_regs[i] for i in range(address,address + number)]
        except KeyError:
            return
    

if __name__ == '__main__':
    server = ModbusServer(host=host, port=port, data_bank=mydatabank())
    server.start() 

Client code:

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

EthernetClient client;
ModbusTCPClient modbusTCPClient(client);

IPAddress ip(192,168,1,10);    //ip address created for PMC
IPAddress server(127,0,0,1);

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

  Ethernet.begin(NULL,ip);    //Successfull
  
}

void loop()
{
  int f = modbusTCPClient.begin(server, 1502);
  // Serial.println("Attempting to connect to server...");
  Serial.println(f);


  if(modbusTCPClient.connected())
  {
    int value;//g
    value = modbusTCPClient.holdingRegisterRead(0);
    Serial.println(value);
  }

}

Best Regards,
h_se

127.0.0.1 corresponds to the local loopback address.

you probably should use the PC's IP address for server in

modbusTCPClient.begin(server, 1502);

Hi @J-M-L,

Thanks for the reply!
I did try using the IP address of the PC, but still the same result.

I did not notice you had that as well for the PC.

Using 127.0.0.1 as the host IP address for your Modbus TCP server code on your PC probably means that the server will only listen for connections coming from the same machine where it's running. (127.0.0.1 is the loopback address, which refers to the local machine itself).

Try to use the PC's IP's address there too.

is the port open on firewall?

Hi @Juraj,

I am using a Linux machine. I did use this nc -w5 -z -v <ip_address> <port_number> and I got a result ** Connection to <ip_address> <port_number> port [tcp/*] succeeded!**.
So I do think that the firewall does not block the port.

I did make the floowing changes but still get the same result.

Server code:

if __name__ == '__main__':
    server = ModbusServer(host='192.168.1.170', port=1502, data_bank=mydatabank())
    server.start()

Client code:

IPAddress server(192,168,1,170);
.
.
.
int f = modbusTCPClient.begin(server, 1502);

did you run that on the same machine or another machine on the network?

have you verified that your Arduino does get access to the network correctly ?

I ran it on the same machine.
Interestingly, I tried to ping the IP address assigned to the Arduino(192.168.1.10) from my Linux machine(VM) and I got no reply. But when I tried to ping from my Host machine(Windows), i got a reply. But both the codes are running on the Linux machine. So is my Arduino not accessible in the Linux machine?

how is your arduino connected to the network?
(I see ethernet, but are you really in the same network as the PC - what does the network look like?)

could you also just try getting an IP for your client from DHCP?

Yes, I am in the same network as my PC. It uses the same gateway.

I am not quite sure on how to get the dynamic Ip address for my Arduino/Client.

try replacing

  Ethernet.begin(NULL,ip);    //Successfull

with

  if (Ethernet.begin() == 0) {
    Serial.println("Failed to configure Ethernet using DHCP!");
    // Try to configure Ethernet with the predefined static IP address
    Ethernet.begin(ip); // from your line IPAddress ip(192,168,1,10);  
  }
  Serial.print("My IP is ");
  Serial.println(Ethernet.localIP());

It just printed out,
--> Failure to configure Ethernet using DHCP!
--> My IP is 0.0.0.0

that means this line

did not succeed either

in your original code, if you add

  Serial.print("My IP is ");
  Serial.println(Ethernet.localIP());

what do you see?

It shows,
--> My IP is 192.168.1.10

However still not able to ping from Linux cmd line.

may be you need to pass the full data

Ethernet.begin(mac, ip, dns, gateway, subnet);

Ethernet - Ethernet.begin() - Arduino Reference

I tried it and still no success. I don't think it makes a difference as I am able to ping from Host machine(Windows) but not able to ping from Virtual Machine(Linux)

do you have the right routes from Windows to the VM ?

How do we check that? If you mean the change in Network settings that have to be made in the VM(eg, NAT to Bridged Adapter), then yeah, I have made it correctly.

Yes that's what I had in mind.

Do you have any way to validate that another machine on the network (a PC / another Linux VM) could see the ModbusTCP server ?

it feels like a routing issue