Homemade PLC

Wednesday 4 May 2011

How It Works (Introduction)

PLCs are often programmed in ladder logic. This is because PLCs originally replaced relay control systems, and forty years later, we still haven't quite let go. A PLC, like any microprocessor, executes a list of instructions in sequence. Ladder logic tools abstract this; you can program the PLC by wiring up relay contacts and coils on-screen, and the PLC runtime will simulate the circuit that you've drawn. Some of the relay contacts can be tied to input signals from the real world; some of the coils can be tied to outputs. That way you can make your simulated circuit interact with other devices, and actually control things. That is the point.
Actually it's more general than that, because you can incorporate timers and counters and arithmetic operations that you couldn't (easily) perform with just relays. The circuit concept is still useful though, partly just because it's intuitive, but also because it abstracts the concurrency issues. It looks like this:
||       Xa               Xb              Yout       ||
       1 ||-------] [------+-------] [------+-------( )-------||
         ||                |                |                 ||
         ||                |       Xc       |                 ||
         ||                +-------]/[------+                 ||
This is a simple piece of combinational logic. There are three input terms, Xa, Xb, and Xc. There is one output term, Yout. The expression is Yout := Xa and (Xb or (not Xc)). This makes sense if you think of Xa and Xb as normally open relay contacts, Xc as normally closed relay contacts, and Yout as a relay coil. Of course it gets more complicated than that:
||                                                   ||
         ||                                      Asetpoint    ||
       1 ||-------------------------------------{READ ADC}----||
         ||                                                   ||
         ||                                    Atemperature   ||
         ||-------------------------------------{READ ADC}----||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                        {SUB  min_temp  :=}        ||
       2 ||------------------------{ Asetpoint - 20  }--------||
         ||                                                   ||
         ||                        {ADD  max_temp  :=}        ||
         ||------------------------{ Asetpoint + 20  }--------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||[Atemperature >]                       Yheater     ||
       3 ||[ max_temp     ]+------------------------(R)-------||
         ||                |                                  ||
         ||     Xenable    |                                  ||
         ||-------]/[------+                                  ||
         ||                                                   ||
         ||[Atemperature <]      Xenable          Yheater     ||
         ||[ min_temp     ]--------] [--------------(S)-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                       {SUB  check_temp  :=}       ||
       4 ||-----------------------{ Asetpoint - 30    }-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||[Atemperature >]                       Yis_hot     ||
       5 ||[ check_temp   ]-------------------------( )-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||------[END]----------------------------------------||
         ||                                                   ||
         ||                                                   ||
This is for a simple thermostat. There are two analog inputs; one of them is for the setpoint, so that it might, for example, be connected to a pot that the user turns to select the desired temperature. The other provides the temperature measurement; it might be a semiconductor temperature sensor, or a platinum RTD with suitable interfacing circuitry. There is a digital output, Yheater. That might control a heating element, through a suitable switch (a TRIAC, or a relay, or a solid-state relay, or whatever).
We close the loop with a simple hysteretic (bang-bang) controller. We have selected plus or minus 20 ADC units of hysteresis. That means that when the temperature falls below (setpoint - 20), we turn on the heater, and when it climbs above (setpoint + 20), we turn the heater off.
I chose to add a few small frills. First, there is an enable input: the heater is forced off when Xenable is low. I also added an indicator light, Yis_hot, to indicate that the temperature is within regulation. This compares against a threshold slightly colder than (setpoint - 20), so that the light does not flicker with the normal cycling of the thermostat.
This is a trivial example, but it should be clear that the language is quite expressive. Ladder logic is not a general-purpose programming language, but it is Turing-complete, accepted in industry, and, for a limited class of (mostly control-oriented) problems, surprisingly convenient.

No comments:

Post a Comment