Groov RIO PID configuration dashboard - Example flow

We have had a few customers ask about setting up and using 1 to 4 PID loops on the groov RIO outside of PAC Control. Optos plan is to ultimately make some PID configuration pages in groov Manage, but there is no solid ETA for this firmware update yet, so here is an example Node-RED flow to help get the creative juices started in the meantime.

Note, this is not a polished finished ‘product’. Its just one way you can go about configuring the PID loops.
You will need to customize it for your application (change the input graph scale and setpoint slider range if nothing else) and tweak it to work the way you expect (For example, when the RIO boots up).

I want to give a big shout out to @gerhardK who did the heavy lifting on this one.

The PID loops on RIO can be accessed via the MMP address using the groov-io nodes.
This is what this flow does, it writes the appropriate values to the PID MMP addresses.

Here is what the flow you are going to import looks like.

As you can probably see, you will need to install the dashboard nodes.

Note, you don’t have to do this, you can hard code all the values in to suit your PID configuration using the inject node if you like. Just swap out all the blue dashboard nodes for inject nodes.

Here is the dashboard we put together.

As you can see, it just builds a nice point and click configuration screen for ONE PID only. Loop zero.
If you want more PID loops, you will need to copy the flow and change all the MMP addresses for each PID loop. (Or get very fancy with the function node and JavaScript).

Since we are using the auto scanning groov-io node, we are limited to a quickest PID scan time of 1 second. You can go slower, but that’s the quickest that node will scan the input and outputs.

Ok, so with all that, here is the flow.
It will create a new flow tab for you, so don’t import it twice without first looking for a tab called ‘PID’!

[{"id":"f1c805f9.69b958","type":"tab","label":"PID","disabled":false,"info":""},{"id":"c311156a.abe638","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100050","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Algorithm","x":670,"y":140,"wires":[[]]},{"id":"abbadc5.6ad622","type":"ui_numeric","z":"f1c805f9.69b958","name":"PID Mode select","label":"PID Mode Select","tooltip":"0=Auto 1=Manual","group":"e3b8de85.0b8d18","order":1,"width":6,"height":1,"wrap":false,"passthru":true,"topic":"","format":"{{value}}","min":"0","max":"1","step":1,"x":440,"y":180,"wires":[["9cd168a4.238738"]]},{"id":"9cd168a4.238738","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100054","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Mode","x":660,"y":180,"wires":[[]]},{"id":"74f7b5df.87d12c","type":"ui_dropdown","z":"f1c805f9.69b958","name":"PID Algorithm select","label":"PID Algorithm","tooltip":"","place":"Select PID Algorithm","group":"e3b8de85.0b8d18","order":2,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"Velocity","value":5,"type":"num"},{"label":"ISA","value":6,"type":"num"},{"label":"Parallel","value":7,"type":"num"},{"label":"Interacting","value":8,"type":"num"}],"payload":"","topic":"","x":420,"y":140,"wires":[["c311156a.abe638"]]},{"id":"6c4345c5.997e24","type":"ui_slider","z":"f1c805f9.69b958","name":"Set Setpoint","label":"Setpoint","tooltip":"Setpoint 20-30°C","group":"e3b8de85.0b8d18","order":6,"width":6,"height":1,"passthru":true,"outs":"end","topic":"","min":"20","max":"30","step":1,"x":450,"y":260,"wires":[["e8f8be2b.ff7878"]]},{"id":"e8f8be2b.ff7878","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100004","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Setpoint","x":660,"y":260,"wires":[[]]},{"id":"9d9cbe22.bb094","type":"ui_numeric","z":"f1c805f9.69b958","name":"Set PID Scantime","label":"PID Scantime","tooltip":"1-30 seconds","group":"e3b8de85.0b8d18","order":5,"width":6,"height":1,"wrap":false,"passthru":true,"topic":"","format":"{{value}} seconds","min":"1","max":"30","step":1,"x":430,"y":220,"wires":[["a89e611e.4e23b8"]]},{"id":"a89e611e.4e23b8","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100038","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Scantime","x":670,"y":220,"wires":[[]]},{"id":"fd17a0fd.b0013","type":"ui_text_input","z":"f1c805f9.69b958","name":"Set Gain","label":"PID Gain:","tooltip":"","group":"e3b8de85.0b8d18","order":7,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":460,"y":320,"wires":[["e14f45ac.1c3e9"]]},{"id":"e14f45ac.1c3e9","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100010","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Gain","x":650,"y":320,"wires":[[]]},{"id":"68ea2798.05088","type":"ui_text_input","z":"f1c805f9.69b958","name":"Set I Term","label":"PID I:","tooltip":"","group":"e3b8de85.0b8d18","order":9,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":450,"y":360,"wires":[["64626fc2.7d3418"]]},{"id":"64626fc2.7d3418","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100014","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID I Term","x":660,"y":360,"wires":[[]]},{"id":"e64db7cf.9403b8","type":"ui_text_input","z":"f1c805f9.69b958","name":"Set D Term","label":"PID D:","tooltip":"","group":"e3b8de85.0b8d18","order":11,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":450,"y":400,"wires":[["8f3e619a.4980e"]]},{"id":"8f3e619a.4980e","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100018","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID D Term","x":660,"y":400,"wires":[[]]},{"id":"9fbb9069.9a45b8","type":"ui_chart","z":"f1c805f9.69b958","name":"PID Input","group":"e3b8de85.0b8d18","order":17,"width":12,"height":4,"label":"PID Input","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":true,"ymin":"22","ymax":"32","removeOlder":"5","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":640,"y":900,"wires":[[]]},{"id":"4739e34.2e7041c","type":"groov-io-input","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"channel-analog","moduleIndex":"0","channelIndex":"3","mmpAddress":"0xF0D81000","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","sendInitialValue":true,"deadband":"1","scanTimeSec":"1.0","name":"PID Input","x":460,"y":900,"wires":[["9fbb9069.9a45b8"]]},{"id":"382aa1dc.9b388e","type":"ui_chart","z":"f1c805f9.69b958","name":"PID Output","group":"e3b8de85.0b8d18","order":18,"width":12,"height":4,"label":"PID Output","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"Waiting for data","dot":true,"ymin":"0","ymax":"100","removeOlder":"5","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":650,"y":960,"wires":[[]]},{"id":"cb365878.577f38","type":"groov-io-input","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"channel-analog","moduleIndex":"0","channelIndex":"7","mmpAddress":"0xF0D81000","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","sendInitialValue":true,"deadband":"1","scanTimeSec":"1.0","name":"PID Output","x":460,"y":960,"wires":[["382aa1dc.9b388e"]]},{"id":"a165130a.063a78","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100044","mmpType":"uint32","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Input","x":830,"y":700,"wires":[[]]},{"id":"1a6e24c0.a860f3","type":"ui_dropdown","z":"f1c805f9.69b958","name":"Select PID Input","label":"PID Input ","tooltip":"Select Input Channel for PID","place":"Select PID Input Channel","group":"e3b8de85.0b8d18","order":3,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"Channel 0","value":"F0260000","type":"str"},{"label":"Channel 1","value":"F0260040","type":"str"},{"label":"Channel 2","value":"F0260080","type":"str"},{"label":"Channel 3","value":"F02600C0","type":"str"},{"label":"Channel 4","value":"F0260100","type":"str"},{"label":"Channel 5","value":"F0260140","type":"str"},{"label":"Channel 6","value":"F0260180","type":"str"},{"label":"Channel 7","value":"F02601C0","type":"str"}],"payload":"","topic":"","x":440,"y":700,"wires":[["fffe58e5.1f9488"]]},{"id":"fffe58e5.1f9488","type":"function","z":"f1c805f9.69b958","name":"HEX to INT","func":"msg.payload = parseInt(\"0x\"+msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":650,"y":700,"wires":[["a165130a.063a78"]]},{"id":"873dfdf1.9c8fa","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF210004C","mmpType":"uint32","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set PID Output","x":840,"y":760,"wires":[[]]},{"id":"1786a91d.8ce15f","type":"ui_dropdown","z":"f1c805f9.69b958","name":"Select PID Output","label":"PID Output","tooltip":"Select Output Channel for PID","place":"Select PID Output Channel","group":"e3b8de85.0b8d18","order":4,"width":6,"height":1,"passthru":true,"multiple":false,"options":[{"label":"Channel 4","value":"F02A0100","type":"str"},{"label":"Channel 5","value":"F02A0140","type":"str"},{"label":"Channel 6","value":"F02A0180","type":"str"},{"label":"Channel 7","value":"F02A01C0","type":"str"}],"payload":"","topic":"","x":430,"y":760,"wires":[["87d4d3f8.94fd1"]]},{"id":"87d4d3f8.94fd1","type":"function","z":"f1c805f9.69b958","name":"HEX to INT","func":"msg.payload = parseInt(\"0x\"+msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":650,"y":760,"wires":[["873dfdf1.9c8fa"]]},{"id":"de373a68.23d3d8","type":"ui_text_input","z":"f1c805f9.69b958","name":"Input Low Range","label":"Input Low Range:","tooltip":"","group":"e3b8de85.0b8d18","order":13,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":430,"y":480,"wires":[["78d6b0.c83f795"]]},{"id":"78d6b0.c83f795","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100028","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set Input Low Range","x":680,"y":480,"wires":[[]]},{"id":"25edc313.a93c7c","type":"ui_text_input","z":"f1c805f9.69b958","name":"Input High Range","label":"Input High Range:","tooltip":"","group":"e3b8de85.0b8d18","order":14,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":430,"y":520,"wires":[["13e0a40b.706fdc"]]},{"id":"13e0a40b.706fdc","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF210002C","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Set Input High Range","x":680,"y":520,"wires":[[]]},{"id":"1a759cf6.0e1633","type":"ui_text_input","z":"f1c805f9.69b958","name":"Output Lower Clamp","label":"Output Lower Clamp:","tooltip":"","group":"e3b8de85.0b8d18","order":15,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":420,"y":560,"wires":[["df89897e.749938"]]},{"id":"df89897e.749938","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100030","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Output Lower Clamp","x":680,"y":560,"wires":[[]]},{"id":"f15c8fe1.92f51","type":"ui_text_input","z":"f1c805f9.69b958","name":"Output Upper Clamp","label":"Output Upper Clamp:","tooltip":"","group":"e3b8de85.0b8d18","order":16,"width":6,"height":1,"passthru":true,"mode":"number","delay":"0","topic":"","x":420,"y":600,"wires":[["b087cd8d.06a8d"]]},{"id":"b087cd8d.06a8d","type":"groov-io-write","z":"f1c805f9.69b958","device":"86920c38.358db","dataType":"mmp-address","moduleIndex":"","channelIndex":"","mmpAddress":"0xF2100034","mmpType":"float","mmpLength":"1","mmpEncoding":"ascii","value":"","valueType":"msg.payload","name":"Output Upper Clamp","x":680,"y":600,"wires":[[]]},{"id":"ef9ed9bf.655688","type":"comment","z":"f1c805f9.69b958","name":"These groov-io nodes scan at 1 second","info":"","x":550,"y":860,"wires":[]},{"id":"86920c38.358db","type":"groov-io-device","z":"","address":"localhost","msgQueueFullBehavior":"DROP_OLD"},{"id":"e3b8de85.0b8d18","type":"ui_group","z":"","name":"PID Loop Configuration","tab":"2e0ee617.a21a12","order":1,"disp":true,"width":"12","collapse":false},{"id":"2e0ee617.a21a12","type":"ui_tab","z":"","name":"PID Loop","icon":"dashboard","disabled":false,"hidden":false}]
7 Likes

This is very interesting. I have a simple application whereby I want to open/close a 120V solenoid valve that controls gas flow to a burner below a tank of water. If I run a Type K thermocouple to the Rio’s input and then use this PID loop and write something to enter a temperature setpoint (e.g. 150 F), then be able to automatically open/close the solenoid using this PID (via the Rio’s Form C 120V relay output). Anything I am missing?

@grant1
I really think that a PID loop is the wrong approach to take for your application.
They are much better at modulating an analog output to maintain a setpoint.
In your application a switch solution would be better… a simple ‘if cold, turn on, if hot, turn off’.

Here is the example flow we use to do that in the RIO Demo Center.

It does exactly what you describe, measures the temperature, if its below the setpoint, turn on the RIO relay (where you have your 120v solenoid wired to), if its above, turn it off.
The only tweak you would need to make is if you wanted your setpoint user adjustable.

Here is the flow.

[{"id":"be365f0.a7023a","type":"groov-io-input","z":"bbdafada.0b108","device":"86920c38.358db","dataType":"channel-analog","moduleIndex":"0","channelIndex":"3","mmpAddress":"0xF0D81000","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","sendInitialValue":true,"deadband":"1","scanTimeSec":"1.0","name":"Read temperature","x":150,"y":200,"wires":[["57a44b1a.662a3c"]]},{"id":"57a44b1a.662a3c","type":"switch","z":"bbdafada.0b108","name":"Control relay","property":"payload","propertyType":"msg","rules":[{"t":"gte","v":"80","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":370,"y":200,"wires":[["d63ed284.3bb9f8"],["5eb2e932.c489d8"]]},{"id":"5708c3ac.8f4144","type":"comment","z":"bbdafada.0b108","name":"Temperature Sensing: Toggle a fan based on temperature reading","info":"","x":290,"y":80,"wires":[]},{"id":"d63ed284.3bb9f8","type":"groov-io-write","z":"bbdafada.0b108","device":"86920c38.358db","dataType":"channel-digital","moduleIndex":"0","channelIndex":"9","mmpAddress":"0xF0D81000","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","value":"true","valueType":"value","name":"Turn on relay","x":630,"y":160,"wires":[[]]},{"id":"5eb2e932.c489d8","type":"groov-io-write","z":"bbdafada.0b108","device":"86920c38.358db","dataType":"channel-digital","moduleIndex":"0","channelIndex":"9","mmpAddress":"0xF0D81000","mmpType":"int32","mmpLength":"1","mmpEncoding":"ascii","value":"false","valueType":"value","name":"Turn off relay","x":630,"y":240,"wires":[[]]},{"id":"86920c38.358db","type":"groov-io-device","z":"","address":"localhost","msgQueueFullBehavior":"DROP_OLD"}]
1 Like

Thank you. I thought a PID loop might be overkill (esp for this application since it’s fairly ‘loose’ in the control window). Ordering a Rio today!

1 Like

Yes, a huge shout out to @gerhardK for the help. When I originally called about our PID options on the RIO I was not expecting this much help, huge shout out to you too @Beno Youve been a major hand in a few of my projects this week! Ill be sinking my teeth into this one later this morning.

1 Like

Hi, Can you share a list of the MMP addresses for the rest of the parameters?

All the documented memory map addresses can be found in Form 1465: Opto22 - 1465 OptoMMP Protocol Guide

Search for PID Configuration and Status in that document and you will find all the relevant addresses for PIDs.

groov Manage now includes a really nice setup page and graph for PIDs.
Is that not enough?
Also groov Manage has all the PID address’s shown in the MMP area. Is that not enough? Any hints as to what else you are looking for?
I’m just looking to help you and future customers find this sort of thing in a smoother manor.

I wanted to see how can I reset the loop when not in use. For example I’m using a peristaltic pump to control a filter inlet pressure. It is controlling fine but when I stop the pump the loop continue to calculate and when I start the pump the output value overshoots until it gets in control. I checked the manual mode but it doesn’t reset the cumulative error. I checked the MMP addresses list and there is a location FFFF F200 0050 4 F PID 1: Current value for Error (Input – Setpoint). I will try to write a 0 when the loop is not in use.

1 Like

After setting manual mode to stop the algorithm calculations, write a 0 to the output of the PID (F210 000C).

Depending on what PID algorithm you are using, you may need to wait a full PID scan time to write the output for it to not get overwritten by the algorithm. I have found that you don’t need to wait with the velocity algorithm (which is my preferred on Opto for many reasons).

1 Like