colinl / node-red-contrib-pid

A node-red PID loop controller node intended for the control of real world processes
Apache License 2.0
26 stars 17 forks source link

Problem setting values dynamically #9

Closed tiagoclc closed 5 years ago

tiagoclc commented 5 years ago

Hi!

I'm facing a problem and hope someone could help.

Trying to set prop_band, t_integral and t_derivative dynamically with sliders, but it always return NaN. Already tried to use function using parseFloat(), parseInt() and Number(), but nothing seems to work. Tried to change topics respectively and nothing. Changing setpoint this way works flawlessly, like github's instructions. (https://github.com/colinl/node-red-contrib-pid 1)

Am I missing something?

Here goes my flow:

smaller below

colinl commented 5 years ago

Is this actually a problem with the PID node, or is it a problem getting the data into the right format? Please make a small flow with only as many nodes as is needed to show the problem and post that.

tiagoclc commented 5 years ago

I think its a problem with the PID node. Because i tested the data manipulation with other nodes and with debug node. Or i'm missing something... But i tried everything!

reduced flow:

[ { "id": "12fb5918.43acf7", "type": "PID", "z": "57696e5f.f08fb", "name": "", "setpoint": "{{msg.setpoint}}", "pb": "20", "ti": "18", "td": "5", "integral_default": "0", "smooth_factor": "0", "max_interval": 600, "enable": "1", "disabled_op": "0", "x": 850, "y": 500, "wires": [ [ "6c4d5de7.570b9c" ] ] }, { "id": "f25074a4.b57038", "type": "ui_slider", "z": "57696e5f.f08fb", "name": "temperatura", "label": "Temp. alvo", "tooltip": "", "group": "886f1cf5.fe52b", "order": 1, "width": "4", "height": "1", "passthru": true, "outs": "end", "topic": "setpoint", "min": 0, "max": "100", "step": 1, "x": 450, "y": 520, "wires": [ [ "12fb5918.43acf7" ] ] }, { "id": "1e391c76.0ca3fc", "type": "change", "z": "57696e5f.f08fb", "name": "", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "t_derivative", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 660, "y": 780, "wires": [ [ "12fb5918.43acf7" ] ] }, { "id": "182e06f5.bfd2c1", "type": "ui_slider", "z": "57696e5f.f08fb", "name": "ki", "label": "Ki", "tooltip": "", "group": "886f1cf5.fe52b", "order": 3, "width": "0", "height": "0", "passthru": true, "outs": "end", "topic": "", "min": 0, "max": "100", "step": "1", "x": 470, "y": 660, "wires": [ [ "772f5455.de1f54" ] ] }, { "id": "5327f548.afe754", "type": "ui_slider", "z": "57696e5f.f08fb", "name": "kp", "label": "Kp", "tooltip": "", "group": "886f1cf5.fe52b", "order": 2, "width": "0", "height": "0", "passthru": true, "outs": "end", "topic": "prop_band", "min": 0, "max": "100", "step": "1", "x": 470, "y": 580, "wires": [ [ "12fb5918.43acf7" ] ] }, { "id": "a1ae8cd7.c7ccd8", "type": "ui_slider", "z": "57696e5f.f08fb", "name": "kd", "label": "Kd", "tooltip": "", "group": "886f1cf5.fe52b", "order": 4, "width": "0", "height": "0", "passthru": true, "outs": "end", "topic": "t_derivative", "min": 0, "max": "100", "step": "1", "x": 470, "y": 780, "wires": [ [ "1e391c76.0ca3fc" ] ] }, { "id": "6c4d5de7.570b9c", "type": "debug", "z": "57696e5f.f08fb", "name": "Always NaN! WTF?", "active": true, "tosidebar": true, "console": true, "tostatus": false, "complete": "true", "targetType": "full", "x": 1080, "y": 600, "wires": [] }, { "id": "772f5455.de1f54", "type": "function", "z": "57696e5f.f08fb", "name": "", "func": "var temperaturaLida=global.get(\"temperaturaLida\")\nvar valor=parseFloat(msg.payload);\n\nmsg.topic=\"t_integral\";\nmsg.payload=parseInt(temperaturaLida);\nmsg.t_integral=valor;\n\nreturn msg;", "outputs": 1, "noerr": 0, "x": 630, "y": 660, "wires": [ [ "12fb5918.43acf7" ] ] }, { "id": "8d7c46c0.8803a", "type": "ui_button", "z": "57696e5f.f08fb", "name": "", "group": "886f1cf5.fe52b", "order": 1, "width": 0, "height": 0, "passthru": false, "label": "button", "tooltip": "", "color": "", "bgcolor": "", "icon": "", "payload": "20.5", "payloadType": "num", "topic": "", "x": 460, "y": 360, "wires": [ [ "12fb5918.43acf7" ] ] }, { "id": "886f1cf5.fe52b", "type": "ui_group", "z": "", "name": "PID", "tab": "391d5421.9e492c", "disp": true, "width": "8", "collapse": false }, { "id": "391d5421.9e492c", "type": "ui_tab", "z": "", "name": "Bedroom", "icon": "dashboard" } ]

colinl commented 5 years ago

You should not have {{msg.setpoint}} in the setpoint field of the pid. If you feed in a message with msg.setpoint set then it will use that automatically. Or if you feed a message in with topic of setpoint then it will use that. Otherwise it will use the value from the setpoint field in the configuration.

tiagoclc commented 5 years ago

but this is working...

The other values isnt (prop_band, t_integral and t_derivative). As I said on first post... Those other fields always returns NaN

colinl commented 5 years ago

Actually it is working for me, the reason is that once you feed in a setpoint from the slider then it ignores the value in the field. Does it show NaN for you if you move all the sliders and click Button? Every time you deploy it will go to NaN again because of the illegal setpoint in the config.

tiagoclc commented 5 years ago

So, i cannot set it dynamically, right? And i need to set everything else before setpoint...

colinl commented 5 years ago

You cannot set what dynamically? You are doing that already, it is just that you have an illegal value for the default sepoint so until you set it dynamically the node does not know what to do. Change the {{msg.setpoint}} to 0 (or whatever default you want) and all will be well.

tiagoclc commented 5 years ago

The value isnt ilegal and i tried every single possibility. After set the value with the slider, setpoint have a valid value asni can see on debug return. Andni am not using the button its used to simulate a mqtt imput.

I already tried with every possible value, including 0.

colinl commented 5 years ago

Tried every possible value for what? To make it easier for me to see what problem you are having use Inject nodes to feed in values and post another flow showing it not working. And tell me what to press to see the problem

colinl commented 5 years ago

I shan't be able to answer again till the morning (it is getting late here).

tiagoclc commented 5 years ago

Set the sliders then press the button and look at the debug window.

tiagoclc commented 5 years ago

No problem! Thanks a lot for you attention!

tiagoclc commented 5 years ago

Found a way! Just create a function and wire the outputs of all sliders to this function and wire the function's output to PID node.

the variable temperaturaLida came from mqtt input with temperature

`var setpoint = global.get("setpoint"); var prop_band = global.get("prop_band"); var t_integral = global.get("t_integral"); var t_derivative = global.get("t_derivative"); var temperaturaLida=global.get("temperaturaLida");

if (msg.topic=="temp"){ setpoint=msg.payload; global.set("setpoint", setpoint); }

if (msg.topic=='kp'){ prop_band=msg.payload; global.set("prop_band", prop_band); }

if (msg.topic=="ki"){ t_integral=msg.payload; global.set("t_integral", t_integral);

}

if (msg.topic=="kd"){ t_derivative=msg.payload; global.set("t_derivative", t_derivative); }

msg.payload = Number(temperaturaLida); msg.setpoint = Number(setpoint); msg.prop_band = Number(prop_band); msg.t_integral = Number(t_integral); msg.t_derivative = Number(t_derivative);

return msg; `

colinl commented 5 years ago

There is no need for all that complexity, try this. image

[{"id":"51cd26c7.8d53d8","type":"PID","z":"d7ff0732.2f81d8","name":"","setpoint":"10","pb":"20","ti":"18","td":"5","integral_default":"0","smooth_factor":"0","max_interval":600,"enable":"1","disabled_op":"0","x":396.4285888671875,"y":545.2857666015625,"wires":[["c7e53e5d.c80b88"]]},{"id":"c7e53e5d.c80b88","type":"debug","z":"d7ff0732.2f81d8","name":"Never NaN! Yay.","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":520.4285888671875,"y":613.2857666015625,"wires":[]},{"id":"7b90a3b5.51797c","type":"inject","z":"d7ff0732.2f81d8","name":"PV 20.5","topic":"","payload":"20.5","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":139.5,"y":484,"wires":[["51cd26c7.8d53d8"]]},{"id":"eb05310f.3d5508","type":"inject","z":"d7ff0732.2f81d8","name":"setpoint","topic":"setpoint","payload":"25","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":136,"y":528,"wires":[["51cd26c7.8d53d8"]]},{"id":"762c92c8.5f77ac","type":"inject","z":"d7ff0732.2f81d8","name":"prob band","topic":"prop_band","payload":"10","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":147,"y":569,"wires":[["51cd26c7.8d53d8"]]},{"id":"9674c9ae.13e5d","type":"inject","z":"d7ff0732.2f81d8","name":"Ti","topic":"t_integral","payload":"60","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":136,"y":613,"wires":[["51cd26c7.8d53d8"]]},{"id":"547c4f40.7f62d8","type":"inject","z":"d7ff0732.2f81d8","name":"Td","topic":"t_derivative","payload":"5","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":137,"y":655,"wires":[["51cd26c7.8d53d8"]]}]

If your values are coming in from MQTT then you should be able to replace the Inject nodes with MQTT IN. [Edit] followed by change nodes to change the topics obviously.

tiagoclc commented 5 years ago

Only PV come from mqtt in. The other values are setted with sliders.

colinl commented 5 years ago

OK, it makes little difference. image

[{"id":"51cd26c7.8d53d8","type":"PID","z":"d7ff0732.2f81d8","name":"PID","setpoint":"10","pb":"20","ti":"18","td":"5","integral_default":"0","smooth_factor":"0","max_interval":600,"enable":"1","disabled_op":"0","x":396.4285888671875,"y":545.2857666015625,"wires":[["c7e53e5d.c80b88"]]},{"id":"c7e53e5d.c80b88","type":"debug","z":"d7ff0732.2f81d8","name":"Never NaN! Yay.","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":520.4285888671875,"y":613.2857666015625,"wires":[]},{"id":"7b90a3b5.51797c","type":"inject","z":"d7ff0732.2f81d8","name":"PV 20.5","topic":"","payload":"20.5","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":139.5,"y":484,"wires":[["51cd26c7.8d53d8"]]},{"id":"7df50cb1.9ae1c4","type":"ui_slider","z":"d7ff0732.2f81d8","name":"Setpoint","label":"Setpoint","tooltip":"","group":"d6ed8dbc.a12f98","order":1,"width":"4","height":"1","passthru":true,"outs":"end","topic":"setpoint","min":0,"max":"100","step":1,"x":110,"y":531,"wires":[["51cd26c7.8d53d8"]]},{"id":"a9a9b618.859448","type":"ui_slider","z":"d7ff0732.2f81d8","name":"Ti","label":"Ti","tooltip":"","group":"d6ed8dbc.a12f98","order":3,"width":"0","height":"0","passthru":true,"outs":"end","topic":"t_integral","min":0,"max":"100","step":"1","x":119,"y":614,"wires":[["51cd26c7.8d53d8"]]},{"id":"4a296c62.e030c4","type":"ui_slider","z":"d7ff0732.2f81d8","name":"Prob band","label":"Prob band","tooltip":"","group":"d6ed8dbc.a12f98","order":2,"width":"0","height":"0","passthru":true,"outs":"end","topic":"prop_band","min":0,"max":"100","step":"1","x":101,"y":574,"wires":[["51cd26c7.8d53d8"]]},{"id":"8da71348.84978","type":"ui_slider","z":"d7ff0732.2f81d8","name":"Td","label":"Td","tooltip":"","group":"d6ed8dbc.a12f98","order":4,"width":"0","height":"0","passthru":true,"outs":"end","topic":"t_derivative","min":0,"max":"100","step":"1","x":117,"y":658,"wires":[["51cd26c7.8d53d8"]]},{"id":"d6ed8dbc.a12f98","type":"ui_group","z":"","name":"PID","tab":"66bd50bf.e1a158","disp":true,"width":"8","collapse":false},{"id":"66bd50bf.e1a158","type":"ui_tab","z":"","name":"Bedroom","icon":"dashboard"}]
Batigolle commented 5 years ago

Hi colinl I also need to change the Prop Band dynamically I used your example suggestion to change the PB, but I don't get the desired result.

Initially I set the PB = 5 and the SetPoint = 28 in the PID and everything works fine.

When I try to modify the PB from 5 to 3, I verify that also the PID set point has been modified, the PID starts to intervene at 24 and ends at 27 The anomaly that returned is that, the change in the value of the PB took place correctly, but the SetPoint has also decreased by going from 28 to 27

I did other tests ... if I change PB = 2 the SetPoint goes down to 26.5 if I change PB = 1 the SetPoint goes down to 26

Thanks

colinl commented 5 years ago

Put a debug node showing complete message on the input to the pid and another on the output and show me the message you are sending that changes both the PB and the Setpoint. Include the previous message out of the PID so we can see what the Setpoint was previously.

colinl commented 5 years ago

Also I would be interested to know what sort of process you are controlling that requires dynamic changes to the tuning parameters. That is quite unusual.

Batigolle commented 5 years ago

Hi Colinl I am a homebrewing, the process I am trying to control requires the control of an electric pot with 28 liters of water in which some kg of malts are immersed, at different temperature steps.

I enclose a photo of the steps of a recipe, to understand the values ​​at stake ... image

The temperature, between recipes, does not change much ... a step can be omitted ... but, what changes and can affect the management of the temperature control are the liters of water and the kg of immersed malt, which can vary between the various recipes.

My idea is for each recipe to find the right parameters and store them in a 'profile', which I will use when replicing a recipe

For this the 'first time' that I make a new recipe, I must be able to change the parameters dynamically, to make the T oscillate, as little as possible, around the value of the setpoint of each step.

I had tried to calibrate the PID by simulating the complete process with only water, but the real situation is too different

I will try to 'capture' incoming and outgoing messages from the PID to publish them

colinl commented 5 years ago

Did you see my request for the debug output showing the setpoint being messed up?

I can see you might need different tuning parameters if you are significantly changing the volume. What is the heating pot like (in terms of how the heating is arranged for example) and how are you measuring the temperature (with a probe in the liquid or what)? Is the liquid being stirred? If so how is that arranged? Are you sending the data to something like Influxdb and charting with Grafana? For tuning it is vital to be able to see the temperature, setpoint and power in a chart. The advantage of influx and grafana is that you can easily go back and look at previous runs. I am surprised there is a big difference between plain water and water with maltings. I would be interested to see the chart you are currently getting with your best tuning so far, and tell me what the parameters are set to for that chart.

Batigolle commented 5 years ago

Hi colinl many questions .... many answers Do you prefer to continue the discussion in this thread?

colinl commented 5 years ago

Don't mind where. Whichever you prefer.

Batigolle commented 5 years ago

Ok I will create a telegram channel I add a bit of information and answers and then I send you the link to connect. Are you well ?

colinl commented 5 years ago

Sorry, I thought you meant the node-red forum or here. Not something like telegram please.

Batigolle commented 5 years ago

Okay, i'll continue on node-red forum I will notify you when I put the new post Thanks

colinl commented 5 years ago

Don't worry, I will see it.

colinl commented 5 years ago

Continued in https://discourse.nodered.org/t/problem-with-dynamic-pid-parameter-change-node-red-contrib-pid/10829

colinl commented 5 years ago

See also issue #10