SimPyLC HowTo

© 2013-2015 GEATEC engineering

Author: Jacques de Hooge

Date: June 3rd 2015

 

 

 

 

 

 

Table of contents

 

GUI quick reference. 2

Putting together a simulation. 2

Basic control elements. 3

The PLC programming paradigm.. 5

Robot controls and safety. 7

PLC programming rules. 8

What is wrong with encapsulation and control structures?. 10

But what makes controlling a robot system so different?. 11

Control levels. 12

Putting a robot system into active operation. 13

The SimPyLC simulator. 14

 


 

GUI quick reference

 

[LEFT CLICK] on a field to freeze, type to edit, [RETURN]  or [LEFT CLICK] to accept, [ESC] or [RIGHT CLICK] to accept and thaw.

Set the 'run' marker to 0 to stop the clock, set it to 1 to start the clock again.

[PGDN] to go to next control page, [PGUP] to go to previous one.

Putting together a simulation

 

Two  example simulations are part of the SimPyLC distribution.

The one to start with is in the blinkingLight directory. To understand what is happening, run the example in that directory from the command line: python world.py. Look at the sourcecode in blinkingLight.py and at the sequence diagram of the running application to see causes and effects. Also take a look at timing.py to see how the sequence diagram is defined and at world.py to see how the parts of the simulation are tied together.

The second example is in the oneArmedRobot  directory, and consists of the following files:

world.py                             Defines the parts that make up the simulation

robot.py                             A SimPyLC module that simulates the physics of a production robot

control.py                          A SimPyLC module that contains the control software for the robot

visualisation.py                               Contains an OpenGL visualisation of the robot

timing.py                            Draws sequence diagrams of selected signals

Start the example simulation from the command line in the same way as the first example: python world.py. Play around with it. A control element gets in the input state by a [left click] or by pressing [enter]. Then you can input a value. [Left click]ing or pressing [enter] again will force the control element to retain the value you specified. [Right click]ing or pressing [esc] will release the control element, allowing it to be overwritten.

Start by reading through robot.py using the circuit descriptions above, and try to find out what makes it tick. Then shift your attention to control.py for a little more complexity. Pay special attention to the input methods of both the Robot and Control class, to gain insight in how these modules (both inherit from class Module) exchange control signals.

Then take a brief look to into visualisation.py to find out how a so called hierarchical model works. Peek into the file graphics.py to see how OpenGL is involved. Google for "OpenGL Hierarchical Modeling" to find many explanations of how this works.

Also take a look at timing.py to see how the channels of the sequence diagram are configured.

Basic control elements

 

class Marker:

                def __init__ (self, condition = False):

                               # Sets the boolean value of the marker to  condition

                def mark (self, trueValue, condition = True, falseValue = None):

# Sets the boolean value of the register to trueValue if condition is True

# Sets the boolean value of the register to falseValue if:

#             - condition is False

#             and

#             - parameter falseValue is present and not None

# Leaves the boolean value of the register unaltered if:

#             - condition is False

#             and

#             - parameter falseValue is absent or None

 

class Oneshot:

                def __init__ (self, condition = False):

                                # Initializes the boolean value of the oneshot to condition     

                def trigger (self, condition):

                               # Sets the boolean value of the oneshot to True if:

                               #             - it was False previously

                               #             and

                               #             - condition is True

                               # Resets theboolean value of the oneshot to False in all other cases

                               # So a oneshot can only remain True for at most one sweep

 

class Latch:

                def __init__ (self, condition = False):

                               # Sets the boolean value of the latch to condition

                def latch (self, condition):

                               # Sets the boolean value of the latch to True if condition is True

                               # Leaves it unaltered if condition is False

                def unlatch (self, condition):

                               # Sets the boolean value of the latch to  False if condition is True

                               # Leaves it unaltered if condition is False

 

class Register :

                def __init__ (self, value = 0):

                               # Sets the numerical value of the register to value

                def set (self, trueValue, condition = True, falseValue = None):

# Sets the numerical value of the register to trueValue if condition is True

# Sets the numerical value of the register to falseValue if:

#             - condition is False

#             and

#             - parameter falseValue is present and not None

# Leaves the numerical value of the register unaltered if:

#             - condition is False

#             and

#             - parameter falseValue is absent or None

 

class Timer:

                def __init__ (self):

                               # Resets the seconds value of timer to 0

                def reset (self, condition):

                               # Resets the seconds value of timer to 0 if condition is True

 

class Runner:

                # Special singleton Marker allows freezing operation of SimPyLC

                def __init__ (self, condition = True):

                               # Sets the boolean value of the runner to True


 

The PLC programming paradigm

 

PLC software, whether running on special hardware or on a PC, adheres to some very simple rules that seem overly strict at first sight. However in practice it has turned out that following these rules lead to stable, predictable system behavior. So for one moment let's forget the richness of modern programming languages and operating systems and delve into a very different world: The world of real time control software.

Central in each PLC program is a loop that is executed forever. In a general purpose programming language the code is something like:

 

while True:

readInputFromSensorsAndControls ()         # Controls can be switches, commands etc.

calculateOutputFromInputAndPreviousState ()

writeOutputToActuatorsAndIndicators ()   # Indic. can be lamps, meters, status reports etc.

 

PLC's have their own terminology. Going through the above loop once is called a sweep. The time it takes to perform one sweep is called the sweeptime. In the simulator, the sweeptime is available in the variable World.period. The sweeptime determines the reaction time of the PLC. It may range from a few to a few dozen milliseconds.

·         Within one sweep, at first all input from sensors, operator controls and external control systems is read. This is indicated by the function readInputFromSensorsAndControls ().

·         Next all output signals are computed from the inputs and from the previous control state. This is indicated by the function calculateOutputFromInputAndPreviousState ().

·         Finally, in the function writeOutputToActuatorsAndIndicators (), the outputs are transferred to the outside world, e.g. servo motors, electromagnets, indicator lamps to inform human s or signals and reports for external control systems.

After this, the whole sequence starts all over again: the next sweep. In a real world PLC, the sweeptime is guarded by a watch dog timer. If it exceeds a maximum, the system is brought to a halt in a safe manner.

What is crucial to the way PLC programs operate, is that all inputs are read at the start of every sweep. So what e.g. is bad style for a PLC program, is to have a sensor report transient information. For instance as long as the robot does not hit limit switch s1, this leads to a continuous input s1Enabled rather than having a brief spike s1Hit at the moment the robot hits the limit switch. The advantage is that is case of sensor malfunction or software glitches, the system will come to a halt, rather than run out of control.

To get a better feeling for the benefits of this approach, lets look for a moment at the oil level indicator light in a car. The worst design is a lamp that only briefly lights up if the car runs out of oil. The driver will almost certainly miss this transient information. A little better is a lamp that will remain burning as long as the oil level remains too low. From the standpoint of system failure however, a green lamp that burns as long as the oil level is ok, is preferable, for if the lamp itself fails, the driver will halt the car, thereby avoiding the risk of damaging the engine by lack of lubrication. Since a lamp switching off draws less attention than a lamp switching on, a solution where a green light indicates enough oil and a red or blinking light or no light at all (lamp failure) indicates a problem, is probably the optimum.


 

Robot controls and safety

 

This document briefly describes the functions of the SimPyLC robot control simulator. Purpose of the simulator is to allow students to get acquainted with the design of real time controls for automated production and transportation systems. The controlled systems may range from out of the box assembly line robots to special purpose robot cranes and automatically controlled transportation vehicles.

Real time control of such systems often utilize a PLC (Programmable Logic Controller). A PLC has to perform a lot of tasks in parallel. It does so using design patterns that are very different from the ones used in mainstream design of non-control programs. When it comes to performing tasks in parallel, traditionally things like interprocess communication, threads, semaphores, queues en critical sections may come to mind.

Synchronizing tasks by means of these facilities is error prone. Problems may range from deadlocks, where processes are waiting for each other forever, to race conditions, where it's unclear which action will be performed first. Use of queues as means of interprocess communication opens the possibility of control commands being accumulated unwantedly, taking effect at an unexpected moment. Suddenly the system (which may be as small as an electronics welding robot, but also as big as a container crane) starts executing a movement, which may  be very dangerous.

Safety plays a major role in designing real time control systems. Even a small production robot may cause harm in an environment where also human labor is being performed. The main demand to be made on a robot control system is that the environment is being watched constantly and that actions are not solely dictated by supervisory commands and previous program state, but also by constant evaluation of sensor input from the environment.


 

PLC programming rules

 

The first step in programming safe controls is to follow a couple of rules. As said, these rules seem very strict, even unworkable and draconic at first. But let firsthand experience be your teacher here. Follow them consequently in your designs and  it will quite soon become clear what the benefits are. Here are the rules:

1.       No loops other than the main sweep. So no while, for, repeat, goto etc.

2.       No conditional statements. So no if, elif, else, switch, case etc.

3.       Be brief and concise

In short: No control structures at all!

How can anyone make any real world computer program like this? Surely control structures have not been a part of every mainstream language right from the advent of computing for no purpose... All that you can do without them is evaluate and assign expressions. How to control anything by doing only that?

Well, the answer is that there certainly is a category of languages that lacks imperative control structures, in fact it lacks imperative statements at all. This category is the category of functional languages. Functional languages boil down to stating functional dependencies between input and output. Functional languages are generally considered to hold great promise when it comes to system reliability. But they are also considered to be strange beasts, only to be comprehended by mathematicians that talk to their wives in formulae.

It is the functional programming paradigm that PLC controls borrow their reliability from. The most reliable PLC control is a PLC control where the output of one sweep is a mere function of its instantaneous input, not relying on any state from previous  sweeps. This statelessness is what makes functional programs reliable and easily testable.

In practice, PLC programs do retain state from previous sweeps in the form of registers, latches and oneshots, to be discussed later. However, the less state is retained, the more reliable the control, even when this  means that some seemingly redundant computations are done over and over again in every sweep.

The golden bullet of designing reliable control programs is to know when to retain state and when not. This is a matter of common sense and experience. The former boils down to a choice: get acquainted with the textbook way of programming in any 3rd generation language (C, C++, Python, C#, Java, JavaScript, Fortran, Basic, Pascal, Modula, Ada) using all the bells and whistles that these ever growing languages offer. After that, imagine yourself standing next to a 40 ton coal grab unloader, swaying at full speed at four meter distance from your head, controlled by a robot crane. And ask yourself: how much program complexity do I dare to trust my life to. The latter, experience, is what you hopefully will gain by building robot controls using the simulator.

The third point of the PLC programming rules, be brief and concise, is probably the most important one. One way to obtain reliable software is intervision. Such intervision, called deskchecking or peer reviewing if software is involved, relies on the observation that explaining something to another person is a very good way to reach a thorough understanding of it yourself. You and a colleague go through the program step by step. Explain to your colleague what you have done and why, and you'll discover your own mistakes. And maybe your colleague will discover some too, but that's just a bonus.

To be able to go through a program in this way, it must not be too bulky. Reading through ten pages of sourcecode and keeping track of the interactions is doable. Reading through twohundred pages will make you lose track. Encapsulation techniques like object oriented programming are one way to tackle complexity. Another way is simplicity. PLC programs tend to be simple, and, strange enough, they tend to be brief. This is counterintuitive. Certainly being restricted to a small subset of program structures will lead to lengthy sourcecode? In practice this turns out not to be the case. Why this is so is the subject of the next two paragraphs.


 

What is wrong with encapsulation and control structures?

 

What is wrong with encapsulation and control structures? Well, nothing of course, encapsulation is hiding local and volatile design decisions behind a well defined stable interface. It is the cornerstone of object oriented programming and is quite successful if applied at the right occasions.

PLC's use encapsulation intensively. The "electrical circuit"-like elements that make up a PLC program (timers, registers, latches, oneshots etc.) are all instances of classes, hiding their internal complexity behind a very simple and well defined interface.

But this is system software, which means: it is thoroughly tested part of the PLC itself, not of the ever changing control programs you write for it. So encapsulation does its work behind the scenes.

Something similar holds for control structures like loops (while, for, repeat, goto) and conditional statements (if, elif, else, switch, case). The whole PLC concept revolves around one central loop, the sweep. And to facilitate efficient IO, even the dreaded multithreading and interprocess communication are utilized by the PLC itself. And of course the system software that is a fixed, non user programmable part of any  PLC, uses conditional statements. But as said: this complexity is restricted to exhaustively tested system software in any real PLC (as opposed to a simulator for learning purposes).

The control program running on top of this system software should be simple, straight and brief. Fortunately, switching from a typical object oriented programming style to the straight and simple style that is the norm for real time controls, lessens the amount of sourcecode. Program size tends so shrink from hundreds of pages of sourcecode to tens of pages. The fact that this is so, is not caused by any flaw of object oriented programming, but by the rather unusual characteristics of robot controls, as explained in the next paragraph.


 

But what makes controlling a robot system so different?

 

Good question! Real time control programs are different from mainstream programming. In a nutshell, here's why. A robot control generally has the following properties:

1.       The amount of sensor signals (inputs from the outside world) typically is four times the amount of actuator signals (outputs to motors, magnets, welding electrodes, paint sprayers etc.). So a control system e.g. needs input from forty sensors to control only ten actuators.

2.       To determine any of the outputs, typically almost all sensor signals are needed, either directly or indirectly. Look at yourself as a robot. For even a routine task like determining when to put the fire low when roasting meat, you'll use sight, hearing, smell and tactile input. For automated control systems it turns out to be the same in practice.

Let's see what this means for noble concepts like encapsulation on the application (rather than internal PLC system) level. Since every output depends upon tens or hundreds of inputs, the public interface of classes in object oriented controls (or the parameter lists in function structured controls) turns out to be excessively large.

Another observation is that while control program parts for e.g. the upper arm, the forearm and the wrist of a robot control at first sight look similar, in practice they differ in minute but essential ways. So at best they can be modeled by related classes using inheritance. But the differences are ad hoc and may change completely during the productive life of the control system, if e.g. safety switches are added or a new sequence of robot acts becomes necessary to manufacture an altered or new product. There's a tendency for changes like that to completely wreck even the most carefully designed inheritance hierarchy.

The only weapon here is simplicity. Work straight towards the task at hand without additional restrictions like stable interfaces, since they will make the program grow manifold, to be prepared for an unknown future.

At this point some relativation and reservation is needed. Program design is striking the right compromises. All the rules so forcefully advocated above have exceptions. Pragmatism is to be preferred over dogmatism, especially with control systems.  And there are control systems that do not fit well with the rules stated above. Keep reading.

Control levels

 

In order to determine what approach will work best, it's needed to be aware of the following control hierarchy:

4

Logistic control level

Planning sequences to achieve a final goal: Load all the boxes from the stockpile on the left upon the palette on the right.

3

Sequence control level

Chaining atomary commands to achieve an intermediate goal. E.g. displacement: Grab that box and put it overthere.

2

Direct control level

Execute atomary commands like: Grab that box. Or: Put it over there.

1

Hardwired locking level

Maintain safety by means of hard wired negative (often tactile) sensors. No signal means: Stop .

0

Inherent safety level

Physical prevention of accidents: Arm not long enough to reach operator. Concrete buffer at the end of the track.

 

It's the levels 2 and 3 that the PLC programming style treated in the previous paragraphs is most suitable for. Level 4 is better tackled using mainstream object- or data-oriented programming. Level 1 is the domain of special purpose hard wired electrical circuits and a limited amount of simple and robust sensors. Level 0 is the level where the quay turns the ship.

Apart from the above hierarchy, there's a tendency for functionality to move from the control itself into the sensors and actuators. High speed feedback loops are part of the servo motors driving the robot's movements, rather than of the central program. The same holds e.g. for numerical integration of accelerometer data to obtain speed and position. As far as these intelligent actuators and sensors are robust, the trend towards decentralization is beneficial, since it replaces expensive and vulnerable special purpose software by out-of-the-box components. However it may be desirable for the central control to keep a watchful eye on these intelligent components, since the central control is the one able to combine all input information and draw conclusions, e.g. about sensor failure.

Keeping the possibility of sensor failure in mind, it may seem like a good idea to have lots of redundancy in the sensorical capabilities of the robot, but there's a downside to this. If sensors differ of opinion, what should the control do? Halt the system? But that often means halting production. The more sensors are present, the more sensor failure will occur. In some situations a minor chance on limited damage is to be preferred over a robot that regularly blocks a whole production line for no reason other than failure of a redundant sensor.


 

Putting a robot system into active operation

 

Imagine a production line of a car manufacturer. The keyword here is: uptime. Every unproductive quarter costs a car worth of money. So you carefully design your control program and, even better, you test it in advance by means of simulation, typically reducing the time to get the robot up and running from weeks to hours. But still.

Real world circumstances differ from the information (requirements)  you got in advance. The adjustment of the conveyor belt is more inexact than was specified. Reflections and direct sunlight misguide your optical sensors. Temperature changes of the environments lead to needless emergency stops, as the control is fooled into thinking that the welding transformer is overheated. And so on. It shouldn't be so, but it is. Always.

There are two ways of dealing with this. One way is hiding behind hundred page contracts, drawn up by your companies law department. Any differences from specification? Tough luck for the customer. Claims won't apply, it's all excluded by the legal guys. As an unfortunate side effect however, there will be no more assignments from this customer. Tough luck for your company. Because that's what industrial control programming practice is like. Either live in the real, physical, unpredictable, ever changing world in which your robot control has to live, or don't.

Fortunately most companies are aware of that customers are not merely a nuisance. So their practical needs will have to be met. And those needs include ad hoc change and minimal disruption of production.

What this means for robot control programs is the need for efficient debugging and alteration. You will have to be able to experiment and repair on the spot, under the real circumstances, interacting with real hardware and other automated systems.

To this end, every PLC control allows for real time inspection and alteration of all control objects (timers, latches, oneshots, registers etc.). Arbitrary values can be input during active operation, all values can constantly be monitored by the operator and, last but not least, values can be forced permanently. This means that rather than acquiring an input signal value from a sensor, or computing an intermediate value or outputing a signal value to an actuator, these signals are coerced to have a certain value. This makes rapid, real time, testing and debugging feasible.

That's  what all the blinking lights and fluctuating numbers on a control rack are about, not about trying to look like StarTrek, but to both know what's going on and be able to influence it in real time.

The SimPyLC simulator

 

There are many PLC simulators available for free. Most of them good looking and feature rich. Why another simulator? The Sim in SimPyLC stands for simulation, but it also stands for simple. SimPyLC is a simplified version of its C++ counterpart SimPLC, in use for real world controls ranging from harbour cranes  to chemical production facilities. It is completely written in Python. What this means is that there's so little sourcecode, that you can read through every line of it, if you want.

You can dissect it, alter it to your needs and taste and understand every single line of code. The amount of insight this will give cannot be matched be any theoretical explanation of what such code should do. At first try to write some simple controls using SimPyLC. Use the example code (one-armed production robot) as tutorial material.

Then go on with the more complex assignments. And, if there's a need or an opportunity, take a peek at the sourcecode of SimPyLC itself. So you'll know that there's no magic involved. The goal is to gain the insight and confidence that you could have written it yourself and that you understand exactly how it behaves and why. This is how PLC's work. And hopefully the assignments make clear why these simple and robust control devices are ubiquitous in the world of industrial production and logistics.

--//--