Modbus is a very simple protocol but you will need to set it up properly.
In this case, you want to have your Rpi Pico working as a slave and your Rpi 4 will be the master. For the latter, the Azure container should take care of almost everything (as you already know you will have to set up some parameters, more on that later).
Similarly, for the Pico to act as a slave you need to have something (code) running on it to listen for the Modbus queries coming from the master and be able to prepare and send the responses.
To do that you have several options: you can use a MicroPython library, an Arduino library, or even FreeRTOs as I said in my comment above. Which one should you choose? Well, it depends on what you are doing. Since you seem to be working with MicroPython I would try that first. Feel free to explore other options.
First of all, I think (I'm not sure because I've never tested it) you cannot use the USB UART for this purpose so what follows assumes you have a hardware UART on both the Rpi 4 and the Pico and you are wiring them correctly (RX and TX crossed over and GND connected together). If you don't know anything about that, then Google is your friend. See, for instance, this nice post which coincidentally also mentions a trick to use the USB port directly with no hardware UARTS (at this point I think it would be easier to spend some time wiring the UARTS instead but that's up to you).
Once you have that sorted, you need to install the micropython-modbus library following the instructions in the link.
Then, head to the Modbus slave example and prepare to get your hands dirty.
Yes, indeed, lots of things in there. But it should not be that difficult. If you read the code carefully you'll see you only have to set up the right UART and set up some registers for testing. You can even keep all default values in this example and change the Azure IoT configuration.
On the Azure side, I think you might be missing some things. See here for more details. If you kept the default on the MicroPython slave you need something like this for the configuration file:
{
"PublishInterval": "2000",
"Version":"2",
"SlaveConfigs": {
"Slave10": {
"SlaveConnection": "ttyS0",
"HwId": "exampleslave-0a:01:01:01:01:02",
"BaudRate": "9600",
"DataBits": "8",
"StopBits": "1",
"Parity": "ODD",
"FlowControl": "NONE",
"Operations": {
"Op01": {
"PollingInterval": "2000",
"UnitId": "10",
"StartAddress": "40094",
"Count": "1",
"DisplayName": "EXAMPLE_HREG"
}
}
}
}
}
As you can see I've made some changes. I've kept only one operation Op01
that reads register 93 ("StartAddress": "40094"
) from slave 10 (as in the MicroPython slave code, hence "UnitId": "10"
) every 2 seconds ("PollingInterval": "2000"
). If you are able to get a response on the Azure IoT you should get value 19 on register 93 ("val": 19
on the MicroPython code).
You might need to change "SlaveConnection": "ttyS0"
to the right serial port you are using on your RPi 4 (maybe ttyACM0
, see the link above on the serial port wiring).
I know this is not a step-by-step guide, just some pointers; if I have the time I might be able to test with my own gear and improve my answer a bit. But in the meantime: have fun!