Sample flow for exercising node-red-contrib-pid

A sample flow for demonstrating the PID loop controller node-red-contrib-pid (not yet in npm) using a process simulation consisting of a 9 second transport delay followed by 10 second and 30 second lags and an offset.

The node is available on github

[
    {
        "id": "b4973237.46ab6",
        "type": "subflow",
        "name": "Process Simulation",
        "info": "",
        "in": [
            {
                "x": 37,
                "y": 103,
                "wires": [
                    {
                        "id": "ec719d4d.0d54f8"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 700.5,
                "y": 209,
                "wires": [
                    {
                        "id": "7fe4b5c3.32e58c",
                        "port": 0
                    }
                ]
            }
        ]
    },
    {
        "id": "7fe4b5c3.32e58c",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "30 sec RC + 0.2",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 30*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg = {};\nmsg.payload = newValue + 0.2;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 569.5,
        "y": 210,
        "wires": [
            []
        ]
    },
    {
        "id": "1bacd004.9753c",
        "type": "inject",
        "z": "b4973237.46ab6",
        "name": "Inject 0 at start",
        "topic": "",
        "payload": "0",
        "payloadType": "num",
        "repeat": "",
        "crontab": "",
        "once": true,
        "x": 124.5,
        "y": 30,
        "wires": [
            [
                "ec719d4d.0d54f8"
            ]
        ]
    },
    {
        "id": "999a52c2.f465f",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "10 sec RC",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 10*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 394,
        "y": 210,
        "wires": [
            [
                "7fe4b5c3.32e58c"
            ]
        ]
    },
    {
        "id": "ec719d4d.0d54f8",
        "type": "delay",
        "z": "b4973237.46ab6",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 268,
        "y": 104,
        "wires": [
            [
                "a823c9cf.2a6178"
            ]
        ]
    },
    {
        "id": "a823c9cf.2a6178",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "8 msg transport delay",
        "func": "// stores messages in a fifo until the specified number have been received, \n// then releases them as new messages are received.\n// during the filling phase the earliest message is passed on each time \n// a message is received, but it is also left in the fifo\nvar fifoMaxLength = 8;\nvar fifo = context.get('fifo') || [];\n// push the new message onto the top of the array, messages are shifted down and\n// drop off the front\nvar length = fifo.push(msg);  // returns new length\nif (length > fifoMaxLength) {\n    newMsg = fifo.shift();\n} else {\n    // not full yet, make a copy of the msg and pass it on\n    var newMsg = JSON.parse(JSON.stringify(fifo[0]));\n}\ncontext.set('fifo', fifo);\nreturn newMsg;",
        "outputs": 1,
        "noerr": 0,
        "x": 175,
        "y": 210,
        "wires": [
            [
                "999a52c2.f465f"
            ]
        ]
    },
    {
        "id": "e1bf3aca.734988",
        "type": "PID",
        "z": "fd0a1625.33a968",
        "name": "",
        "setpoint": "0.5",
        "pb": ".3",
        "ti": "40",
        "td": "10",
        "integral_default": "0",
        "smooth_factor": "0",
        "max_interval": 600,
        "enable": "1",
        "disabled_op": ".50",
        "x": 377.5,
        "y": 245,
        "wires": [
            [
                "f7aefd83.20a22",
                "4c07462c.fe05e"
            ]
        ]
    },
    {
        "id": "861ef285.9a7a78",
        "type": "change",
        "z": "fd0a1625.33a968",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "pv",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 627.5,
        "y": 146,
        "wires": [
            [
                "44065c99.7edda4",
                "ead403ea.03398"
            ]
        ]
    },
    {
        "id": "f7aefd83.20a22",
        "type": "change",
        "z": "fd0a1625.33a968",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "op",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 626,
        "y": 190,
        "wires": [
            [
                "44065c99.7edda4",
                "ead403ea.03398"
            ]
        ]
    },
    {
        "id": "d9b6279.e94a8d8",
        "type": "inject",
        "z": "fd0a1625.33a968",
        "name": "Setpoint 0.3",
        "topic": "setpoint",
        "payload": "0.3",
        "payloadType": "num",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 119.5,
        "y": 268,
        "wires": [
            [
                "e1bf3aca.734988"
            ]
        ]
    },
    {
        "id": "193d99cd.cc5186",
        "type": "inject",
        "z": "fd0a1625.33a968",
        "name": "Setpoint 0.8",
        "topic": "setpoint",
        "payload": "0.8",
        "payloadType": "num",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 118,
        "y": 317,
        "wires": [
            [
                "e1bf3aca.734988"
            ]
        ]
    },
    {
        "id": "c5fd4a78.71ab2",
        "type": "inject",
        "z": "fd0a1625.33a968",
        "name": "enable",
        "topic": "enable",
        "payload": "true",
        "payloadType": "bool",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 110.5,
        "y": 153,
        "wires": [
            [
                "e1bf3aca.734988"
            ]
        ]
    },
    {
        "id": "4c07462c.fe05e",
        "type": "subflow:b4973237.46ab6",
        "z": "fd0a1625.33a968",
        "x": 377.5,
        "y": 144,
        "wires": [
            [
                "e1bf3aca.734988",
                "861ef285.9a7a78"
            ]
        ]
    },
    {
        "id": "9b4cebbb.bd276",
        "type": "inject",
        "z": "fd0a1625.33a968",
        "name": "disable",
        "topic": "enable",
        "payload": "false",
        "payloadType": "bool",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 111,
        "y": 203,
        "wires": [
            [
                "e1bf3aca.734988"
            ]
        ]
    },
    {
        "id": "ead403ea.03398",
        "type": "ui_chart",
        "z": "fd0a1625.33a968",
        "name": "",
        "group": "3432729.d74b30e",
        "order": 0,
        "width": 0,
        "height": 0,
        "label": "chart",
        "chartType": "line",
        "legend": "false",
        "xformat": "%H:%M:%S",
        "interpolate": "linear",
        "nodata": "",
        "ymin": "0",
        "ymax": "1",
        "removeOlder": "6",
        "removeOlderUnit": "60",
        "x": 824.5,
        "y": 173,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "3432729.d74b30e",
        "type": "ui_group",
        "z": "fd0a1625.33a968",
        "name": "Default",
        "tab": "4a326350.5a3d6c",
        "disp": true,
        "width": "6"
    },
    {
        "id": "4a326350.5a3d6c",
        "type": "ui_tab",
        "z": "fd0a1625.33a968",
        "name": "Home",
        "icon": "dashboard"
    }
]
colinl

Flow Info

created 9 months, 3 weeks ago
updated 9 months, 2 weeks ago

Node Types

Core
  • change (x2)
  • delay (x1)
  • function (x3)
  • inject (x5)
Other
  • PID (x1)
  • subflow (x1)
  • subflow:b4973237.46ab6 (x1)
  • ui_chart (x1)
  • ui_group (x1)
  • ui_tab (x1)

Tags

  • node-red
  • pid
  • loop
  • control
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option