Modbus and Raspberry PLC
This is the second post of the Modbus and Raspberry PLC collection.
This post will be focused on Node-RED, and we will go through everything this browser-based flow editor can provide in Modbus TCP applications.
Requirements
- Raspberry PLC
- Modbus TCP slave device or Industrial Shields PLC
First steps
To use the Modbus protocol with Node-RED, start by running it with:
$ node-red-start
Then, head to your favorite browser and, depending if you are connected to the Raspberry through SSH or connected to the screen using a micro-HDMI cable, type:
- SSH: PI_PLC_IP_ADDR:1880
- micro-HDMI: 127.0.0.1:1880
Once in the Node-RED flow, we will install the Modbus nodes. Press "Alt+Majus+p" to enter the "Manage Palette" window. There, go to the "Install" tab and search for the node-red-contrib-modbus package. Install it.
After that, we are ready to start dragging nodes to the flow.
Also, connect any of the Raspberry's Ethernet ports to the slave and properly configure the interface to match the IP of the device.
Building the flow
The first node will be a "Modbus Write". Double click to configure it, and click on the pencil icon on the "Server" item. Here you will configure the parameters of your Modbus communication:
- Type: Select the "TCP" option, as we are using the Modbus TCP variant in this post.
- Host: Type the IP address of the slave device.
- Port: "502" is the default port for Modbus TCP, but make sure that your device works with that port. Adjust it if necessary.
- TCP Type: "DEFAULT".
Now choose a name for this configuration and click Update. This defines a specific Modbus configuration, and every node with this settings will perform accordingly. In a more complex system, multiple configurations may be needed, so always make sure you have the correct configuration selected.
Next we will configure the "Modbus Write" node itself:
- FC: The Function Code we will be using is the "FC 5: Force Single Coil", but any of the others can be chosen too.
- Address: Type "0".
- Poll Rate: 1 second.
- Server: Select the previous configuration.
After that, click Done. Now we are almost ready to control a Modbus slave device. Finally, drag an "Inject" node and connect it to the "Modbus Write" node, just like the image below:
The "Inject" node can also be configured, so double click it and change the msg.payload value from timestamp to a boolean true. Setting the msg.payload to a boolean false is equivalent to setting the coils / registers to 0 instead of 1.
With that, every time you press the inject node, a Modbus message will be sent through the Ethernet port and the slave will act upon. As you have may noticed, with Modbus TCP there is no need to use the "Unit-Id" identifier anymore. That is because the IP, which is unique for each device, works already as an identifier for the Modbus TCP system.
Reading is also very simple. Drag a "Modbus Read" node and configure if like so:
- FC: Select "FC 1: Read Coil Status".
- Address: Type "0".
- Quantity: Type "1".
- Poll Rate: 1 second.
- Server: Select the previous configuration.
Finally, connect a "Debug" node in the first output of the "Modbus Read" node and Deploy your changes and in the Debug panel you will see how the first element of the list changes:
[{"id":"3c784f724b6bb9da","type":"modbus-write","z":"66f823dbe170e15a","name":"","showStatusActivities":true,"showErrors":true,"showWarnings":true,"unitid":"1","dataType":"Coil","adr":"0","quantity":"1","server":"a0cecbb6e2cd25e8","emptyMsgOnFail":false,"keepMsgProperties":false,"delayOnStart":false,"startDelayTime":"","x":560,"y":220,"wires":[[],[]]},{"id":"3459adaa212c8dd3","type":"inject","z":"66f823dbe170e15a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":390,"y":200,"wires":[["3c784f724b6bb9da"]]},{"id":"526661ccfde56f87","type":"inject","z":"66f823dbe170e15a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":390,"y":240,"wires":[["3c784f724b6bb9da"]]},{"id":"f5c9e191b12f95d7","type":"modbus-read","z":"66f823dbe170e15a","name":"","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"showWarnings":true,"unitid":"31","dataType":"Coil","adr":"0","quantity":"1","rate":"1","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"a0cecbb6e2cd25e8","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":430,"y":320,"wires":[["3ff9cb94cb91b7e8"],[]]},{"id":"3ff9cb94cb91b7e8","type":"debug","z":"66f823dbe170e15a","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":580,"y":320,"wires":[]},{"id":"a0cecbb6e2cd25e8","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"10.10.10.4","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true,"showWarnings":true,"showLogs":true}]
Want to know more about Modbus?
Check out the other posts from the collection here:
Introduction to Modbus and Raspberry PLC. Part 2