-
Notifications
You must be signed in to change notification settings - Fork 18
/
pid.html
131 lines (107 loc) · 11.5 KB
/
pid.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<!--
Copyright 2016 Colin Law
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/javascript">
RED.nodes.registerType('PID',{
category: 'function',
color: '#a6bbcf',
defaults: {
name: {value:""},
setpoint: {value: 21.0},
pb: {value: 1, required: true},
ti: {value: 9999, required: true},
td: {value: 0, required: true},
integral_default: {value: 0.5},
smooth_factor: {value: 3, required: true},
max_interval: {value: 600, required: true}, // seconds
enable: {value: 1, required: true},
disabled_op: {value: 0}
},
inputs:1,
outputs:1,
icon: "function.png",
label: function() {
return this.name||"PID";
}
});
</script>
<script type="text/x-red" data-template-name="PID">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-setpoint"><i class="icon-tag"></i> Setpoint</label>
<input type="text" id="node-input-setpoint" placeholder="Setpoint">
</div>
<div class="form-row">
<label for="node-input-pb"><i class="icon-tag"></i> Proportional band</label>
<input type="text" id="node-input-pb" placeholder="PB">
</div>
<div class="form-row">
<label for="node-input-ti"><i class="icon-tag"></i> Integral time (secs)</label>
<input type="text" id="node-input-ti" placeholder="Ti">
</div>
<div class="form-row">
<label for="node-input-td"><i class="icon-tag"></i> Derivative time (secs)</label>
<input type="text" id="node-input-td" placeholder="Td">
</div>
<div class="form-row">
<label for="node-input-integral_default"><i class="icon-tag"></i> Initial integral</label>
<input type="text" id="node-input-integral_default" placeholder="I default">
</div>
<div class="form-row">
<label for="node-input-max_interval"><i class="icon-tag"></i> Max sample interval (secs)</label>
<input type="text" id="node-input-max_interval" placeholder=" Secs">
</div>
<div class="form-row">
<label for="node-input-smooth_factor"><i class="icon-tag"></i> Derivative smoothing factor</label>
<input type="text" id="node-input-smooth_factor" placeholder=" Smoothing">
</div>
<div class="form-row">
<label for="node-input-enable"><i class="icon-tag"></i> Enable state (1=Enabled, 0=Disabled))</label>
<input type="text" id="node-input-enable" placeholder=" Enable">
</div>
<div class="form-row">
<label for="node-input-disabled_op"><i class="icon-tag"></i> Output Power when disabled</label>
<input type="text" id="node-input-disabled_op" placeholder=" Disabled Output">
</div>
</script>
<script type="text/x-red" data-help-name="PID">
<p>A PID loop controller node intended for the control of real world processes.</p>
<p>The node is regularly given a process value and is configured (or given) a setpoint and tuning parameters and generates a required power output between 0 and 1 in <b>msg.payload</b> using a Proportional+Integral+Derivative algorithm.</p>
<p>Any message received with a <b>msg.topic</b> other than those defined below is assumed to contain the current process value in <b>msg.payload</b> and the control algorithm will be run, passing on the required power in <b>msg.payload</b>.</p>
<p>Any message received with an attribute <b>msg.<property_name></b> set will change the value of the associated property to the value of that attribute. For example setting <b>msg.setpoint</b> will change the setpoint. Multiple properties can be changed in the same message using this method. Note that messages of this type should still have the process value in <b>msg.payload</b></p>
<p>Any other message properties will be passed through unchanged.</p>
<p>The configuration parameters are as follows:</p>
<ul>
<li><b>Setpoint</b> - This is the process value that the process is aiming for. It may be setup either in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>setpoint</code> and <b>msg.payload</b> set to the required floating point value, or by passing the value in <b>msg.setpoint</b>.</li>
<li><b>Proportional band</b> - This controls the gain of the loop and is the range of process value over which the power output will go from 0 to full power. The units are that of the process and setpoint, so for example in a heating application it might be set to 1.5 degrees. If set to zero then control becomes On/Off with zero hysteresis. It may be setup in configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>prop_band</code> and <b>msg.payload</b> set to the required floating point value, or by passing the value in <b>msg.prop_band</b>.</li>
<li><b>Integral time</b> - This is a setting for the integral time, in seconds. It represents the time constant of the integration effect. The larger the value the slower the integral effect will be. Obviously the slower the process is the larger this should be. For example for a domestic room heated by convection radiators a setting of one or two hours might be appropriate (in seconds). To disable the integral effect set this to a large number. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>t_integral</code> and <b>msg.payload</b> set to the required integer value, or by passing the value in <b>msg.t_integral</b>.</li>
<li><b>Derivative time</b> - This is a setting for the derivative time, in seconds. It represents the time constant of the derivative effect. The larger the value the greater will be the derivative effect. Typically this will be set to somewhat less than 25% of the integral setting, once the integral has been adjusted to the optimum value. To disable the derivative effect set this to 0. When initially tuning a loop it is often sensible to start with derivative zero and wind it in once other parameters have been setup. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>t_derivative</code> and <b>msg.payload</b> set to the required integer value, or by passing the value in <b>msg.t_derivative</b>.</li>
<li><b>Initial integral</b> - This is an initial value which is used to preset the integrated error value when the flow is deployed in order to assist in homing in on the setpoint the first time. It should be set to an estimate of what the power requirement might be in order to maintain the process at the setpoint. For example for a domestic room heating application it might be set to 0.2 indicating that 20% of the available power might be required to maintain the setpoint. The value is of no consequence apart from on deployment of the flow. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>integral_default</code> and <b>msg.payload</b> set to the required integer value, or by passing the value in <b>msg.integral_default</b>. Note that if the property is set via a message then this must be done either before or with the very first process value.</li>
<li><b>Max sample interval</b> - This is the maximum time in seconds that is expected between samples. It is provided to cope with unusual situations such as a faulty sensor that might prevent the node from being supplied with a process value and to prevent the problem of integral wind-up during that time. Each time a process value is received a check is made on the time since the last sample and if too long has elapsed the integral error term is locked at the previous value and the derivative component is set to zero. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>max_interval</code> and <b>msg.payload</b> set to the required integer value, or by passing the value in <b>msg.max_interval</b>.</li>
<li><b>Derivative smoothing factor</b> - In situations where the process sensor has limited resolution (such as the DS18B20), the use of deriviative can be problematic as when the process is changing only slowly the steps in the value cause spikes in the derivative. To reduce the effect of these this parameter can be set to apply a filter to the derivative term. I have found that with the DS18B20 that a value of 3 here can be beneficial, providing effectively a low pass filter on the derivative at 1/3 of the derivative time. This feature may also be useful if the process value is particularly noisy. The smaller the value the greater the filtering effect but the more it will reduce the effectiveness of the derivative. A value of zero disables this feature. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>smooth_factor</code> and <b>msg.payload</b> set to the required value, or by passing the value in <b>msg.smooth_factor</b>.</li>
<li><b>Enable state</b> - This is can be used to enable or disable the control (1=enable, 0=disable). When disabled the output is set the value defined in the parameter below. Enable/disable may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>enable</code> and <b>msg.payload</b> set to 1/0 or true/false, or by passing the value in <b>msg.enable</b>.</li>
<li><b>Output power when disabled</b> - This is the value the output is set to when the loop is disabled. It may be setup in the configuration of the node, by passing the node a message with <b>msg.topic</b> set to <code>disabled_op</code> and <b>msg.payload</b> set to the required floating point value between 0 and 1, or by passing the value in <b>msg.disabled_op</b>.</li>
</ul>
<p><b>Status</b></p>
<p>The status text will normally be empty. In unusual conditions it will show the following values.</p>
<ul>
<li><b>Disabled</b> - Control is currently disabled.</li>
<li><b>Integral Locked</b> - The process is far from the setpoint and the integral term has been locked to prevent integral windup.</li>
<li><b>Bad PV</b> - The process value passed in is not a number.</li>
<li><b>Too long since last sample</b> - A long time has elapsed since the last good sample so the integral term will not be accumulated for this sample.</li>
</ul>
<p><b>Persistence</b></p>
<p>In order to reduce the impact of restarts or redeploys, you can save the integral value in a persistent storage location and feed it back in to the node as it starts. The integral value is available in <code>msg.integral</code> in the output messages. In order to feed it back in set the <code>integral_default</code> setting to <code>0.5 - (cached_integral/prop_band)</code> before the first process value is passed in.</p>
</script>