Presentation 12 April 2017 MPC - Microcontroller User Group
Presentation 12 April 2017 MPC - Microcontroller User Group
These control systems are found in just about every piece of equipment these days.
John Macey
For this example, assume that we want to maintain a target temperature higher than the
ambient. We will use an Arduino Nano3 (or some other microcontroller) to control it.
First, we need some means to set the desired target temperature in this example, a
potentiometer/resistor pair to provide an output voltage [TSET] in the range 0 - 1V .
This voltage feeds one of the microcontroller's ADC inputs to obtain a digital value
Next, we need a temperature sensor which reports the current container temperature [T].
I've drawn an LM35 Centigrade sensor which provides 10mV per degree C output
ie. (in the range 0 - 1V) to another ADC input.
Finally, we need a heater to raise the container's temperature up to the target value. I've
shown a transistor/resistor combination driven by a digital output [H].
Best if [H] is a PWM output (with variable duty cycle) to make a precision servo, but a
simple bang-bang/on-off digital output may be good enough for many applications.
The SCHEMATIC drawing, shows these inputs as function blocks connected to the
controller's I/Os.
---------
Some calculations are needed:-
We want zero error between the target temperature and actual temperature.
We will control the heater power to achieve that result. ie. [ERROR]=(TSET-T)=0
Also, (particularly when using a deadband) uncorrected error can accumulate over time.
To correct this, calculate [INTEG] which integrates/accumulates recent past, uncorrected
errors. A bit of [INTEG] forces the servo to alternately, slightly overshoot and undershoot.
[INTEG] = (T+ OLDT) is the simplest implementation.
To have an optimum servo (which doesn't become unstable and oscillate, or become
sluggish and slowly/never gets to the target value) we need to suitably combine these
three values [ERROR], [RATE] and [INTEG] in the right proportions (defined by A, B and
C modifiers) to derive the heater output [H].
If we are using a [DEADBAND] one more logic stage is needed to decide whether or not to
currently activate the heater (with a bit of delay [D] ), or defer activation.
--------
The CONTROLLER FLOW CHART drawing shows what the microcontroller needs to
do:-
First, as usual, we define all the pin-outs required, all the variables and a few
constants/pre-sets (like A,B,C,D, DEADBAND).
Then we read the target temperature [TSET] and the current temperature [T] with the ADC.
Calculate:- ERROR=(TSET-T)
INTEG=(T+OLDT)
RATE=(T-OLDT)
update OLDT=T
If RAWH is not greater than the DEADBAND, do nothing, but go around the loop again.
If RAWH is greater than DEADBAND, output Hfrom RAWH to drive the heater, then
resume looping.
------
OK! - Fine! - Now the Practicalities!
If you get everything set-up just right, the servo should react quickly to any
environmental change, slightly overshoot the target value, then quickly settle down to be
right on target.
You have little chance of getting everything just right when you first fire-it-up!
Why not? - Well, you don't know what values to use for A,B,C,D or an appropriate
DEADBAND value if you are using that.
Also, there will be inaccuracies in the temperature measurement? ( degree C?).
And in the ADC values? (another 1%? see Note).
If you need high accuracy, you will probably need to do some calibration against a good
temperature reference standard.
However, for most practical purposes, it's possible to get a servo doing what you want,
closely enough, without a great deal of angst.
While absolute temperature accuracy may be difficult to achieve, for a container with good
insulation, obtaining a stable temperature with only small temperature excursions is quite
achievable. (down to fractions of a degree variations?)
A good practical approach is to initially set the B, C and DEADBAND values to zero
(i.e. No RATE or INTEG components included) just use the ERROR value for frequent
corrections.
Adjust the A value up from near zero until you get the most satisfactory result.
That should be stable, but may take a long time to reach the target value and never quite
get there.
With too high an A value it may become unstable and oscillate.
In this application, there will be a modest time constant, formed by the delay between the
time the heater is turned on and a rise in temperature is detected.
The delay [D] is there to compensate for this factor.
For a bang-bang servo, maybe, now introduce a small amount of DEADBAND to reduce
the switching frequency?....... (maybe reduce power consumption too?)
For many applications, using just ERROR (without RATE and INTEG) and simple bang-
bang operation will provide a good enough result.
Using the ERROR value to adjust the duty cycle of a continuous PWM output can make a
much better servo. Then, you won't need a DEADBAND.
To further improve performance, gradually introduce a bit of a bit of INTEG (with a small C
value) and maybe, a bit of RATE (with a small B value) to improve response speed.
Then, with those added inputs, you may need to tweak the A value a bit too.
Too much of these factors will cause the servo to become unstable and oscillate. So make
small changes until you get to an optimum (or good enough!) response time and accuracy.
Enjoy!
Notes:
An Arduino Nano3 has a 10-bit ADC and by default uses Vcc (+5v) as its ADC reference.
So +/-1 LSB represents about 5mV or +/- degree C in this example.
The ADC's precision can be improved by using the available 1.1V ADC reference.