Race condition - will FBD-Light detect this?

Für Themen rund um logi.RTS und logi.CAD 3
Post Reply
Rob65
Posts: 5
Joined: 13 Mar 2018, 11:26

Race condition - will FBD-Light detect this?

Post by Rob65 »

Hi,

I just received my RevPi and started testing with Logi.cals
I used the FBD editor from OpenPLC to create a simple test program from my Function Block Diagram:
fbd.jpg
fbd.jpg (45.18 KiB) Viewed 11706 times
From this FBD I created the following Structured Text:

Code: Select all

PROGRAM Test
	VAR
		Ton0 : TON;
		RS0  : RS;
		RS1  : RS;
		Trig : R_TRIG;
	END_VAR
	VAR_EXTERNAL
		Switch   : BOOL;
		Lamp1    : BOOL;
		relais1  : BOOL;
	END_VAR
	Trig(CLK := Switch);
	RS1(S := Trig.Q, R1 := Ton0.Q);
	Ton0(IN := RS1.Q1, PT := T#2s);
	RS0(S := Trig.Q, R1 := Ton0.Q);
	relais1 := RS0.Q1;
END_PROGRAM
The idea is that the relay output is active for 2s when the switch is pressed. This is true independent of the length of time the switch is pressed (shorter or longer than 2s should not matter) thanks to the R_TRIG.
But now a fun thing happens: I am able to reproduce a situation where I press the switch again just at the moment when the relay is switched off. After this, the output may get stuck forever and the relay will not switch off again.

I found the reason to be the location of the RS1/Ton0 blocks in the structured text.
There seems to be a race condition in the feedback. If I hit the key at the exact moment when the relay is switched off, Ton0.Q is still TRUE when Trig.Q becomes TRUE (for one cycle).
Unfortunately Ton0.Q is TRUE for a complete cycle, resulting in an immediate reset of RS1. This results in Ton0.Q never being set again (since Ton0.IN is FALSE).
So RS0 is never reset and the relay is never switched off(RS0.Q stays TRUE).

In this case the problem was not hard to locate and the fix is easy: change the order of the lines to remove the race condition.
But this does arise a question: I created the ST by hand, walking through the diagram from left to right. I also tested the compiler in PLCOpenEditor and that gives the same order of lines as my original program.
What happens when I do this in the Logi.cals FBD editor? Is that one able to detect such race conditions - or at least give a warning?

and yes, there are likely to be other solutions for this problem, this is just a very simple program to play around a bit with Logi.cals.
I never programmed a PLC using ST or FBD and the only PLC experience I have is with Ladder Diagrams in the pre 1984 era...

Regards,

Rob
User avatar
volker
Posts: 1046
Joined: 09 Nov 2016, 15:41

Re: Race condition - will FBD-Light detect this?

Post by volker »

Hi Rob,
this is a very interesting question and problem you have posted. So first of all thanks for communicating it here. Hopefully other readers may have also benefit from this discussion.
What you call "race condition" is somehow a built in feature of EN61131-3 programing languages. If you program in C or Python or whatever, it's your responsibility to think and program a machine in such a way that its functions are 100% predictable and reproducible. Very often this si done by using Turing machines (state machines). A state machine has only those states which are built in by intention. to gain this predictability a state machine is running in defined cycles the state machine has one defined state per cycle.
EN61131-3 FBD (FUB) is built in a way to force you to this kind of thinking and programming. There is a defined state at the beginning and at the end of a PLC cycle. Inputs are cached at the beginning of a cycle and outputs are switched at the end of this cycle. Thus it is totally predictable what the machine is doing.
BUT!!! During a cycle there is no defined way the machine does its calculations. It is you responsibility to keep this in mind and to set up a logic which does not try to use "sub cycle states". No Editor I know would be able to find logical errors resulting from such "racing conditions" inside a cycle as this is not the scope of EN61131-3. And even if you would try to think of such a warning mechanism, there would be no way to find a defined solution. As program sequences inside the loop are not definable you have no way to tell the interpreting machine what your specifically aim to be done. Take your example: The system behavior could be intended: Why should the system not assume that you want the relays to be on forever if the switch is pressed during an off-switching cycle?
The solution of the problem lies in the kind of programming with FBD / FUB. You need to define states of your machine and then use one cycle for each state. In your example the machine is forced in several states during one cycle (the reset case). If you would give these processes more time and break them down into several states (e.g. rest is going high for 1 cycle and then going low again) you would automatically realize that bringing the reset high for 1 cycle and bringing the switch signal high for 1 cycle could cause trouble if there is a co-incidence of these two events. so The solution would be to define the system reaction for this co-incidence (e.g. reset has higher prio and thus a button switch is only recognized if not earlier than 1 cycle after the "switch off" state).
Okay , sorry this is all a bit theoretical - but hopefully it does make sense to you and it may help you when advancing your FBD skills. At the end you should see this as a great feature of FBD and not as a disadvantage or problem. It helps forcing the programmer to think in states and thus delivers more predictable results if he/she does so.
Unser RevPi Motto: Don't just claim it - make it!
Rob65
Posts: 5
Joined: 13 Mar 2018, 11:26

Re: Race condition - will FBD-Light detect this?

Post by Rob65 »

volker wrote: 22 Mar 2018, 06:30 The solution of the problem lies in the kind of programming with FBD / FUB. You need to define states of your machine and then use one cycle for each state. In your example the machine is forced in several states during one cycle (the reset case).
...
Okay , sorry this is all a bit theoretical - but hopefully it does make sense to you and it may help you when advancing your FBD skills. At the end you should see this as a great feature of FBD and not as a disadvantage or problem. It helps forcing the programmer to think in states and thus delivers more predictable results if he/she does so.
Thanks for hitting me on the head ;)
I've been programming state machines since many years in different languages and it's not too hard to validate and test. State transitions only take place in between cycles.
One of those languages/systems was LabView; a shift register shifts the output of one cycle to the input of the next cycle.
Most likely something like this exists also in FBD.

The theoretical stuff is nice - there are no shortcuts when you want to understand how a language works.
And in order to grasp what I am doing I need to know this.

Rob
Rob65
Posts: 5
Joined: 13 Mar 2018, 11:26

Re: Race condition - will FBD-Light detect this?

Post by Rob65 »

Thanks to Volker's reply I went a complete different way and used a Sequential Function Chart with a state machine describing exactly what I wanted:

If the input is TRUE, then activate the output, wait for the specified time and deactivate the output.
After this, wait for the input to become FALSE before restarting.

In SFC this is:
sfc.JPG
sfc.JPG (53.64 KiB) Viewed 11674 times
Translated into ST:

Code: Select all

FUNCTION_BLOCK Pulse
	VAR
		PTin   : TIME;
		Timer  : TON;
	END_VAR
	VAR_INPUT
		CLK    : BOOL;
		PT     : TIME;
	END_VAR
	VAR_OUTPUT
		Q : BOOL := FALSE;
	END_VAR

	INITIAL_STEP Init:
		initialize(N);
		ComputeFB(S);
	END_STEP
	
	TRANSITION FROM Init TO Start
		:= CLK;
	END_TRANSITION
	
	STEP Start:
		Activate(N);
	END_STEP
	
	TRANSITION FROM Start to Stop
		:= Timer.Q;
	END_TRANSITION
	
	STEP Stop:
		Deactivate(N);
	END_STEP
	
	TRANSITION FROM Stop to Init
		:= NOT(CLK);
	END_TRANSITION
	
	ACTION Initialize:
		PTin := PT;
	END_ACTION
	
	ACTION ComputeFB:
		Timer(IN := Q, PT := PTin);
	END_ACTION
	
	ACTION Activate:
		Q    := TRUE;
	END_ACTION
	
	ACTION Deactivate:
		Q := FALSE;
	END_ACTION
	
	ACTION Delay:
	END_ACTION
	
END_FUNCTION_BLOCK
I was thinking that specifying the deactivate action as Deactivate(D, PT) would result in the Deactivate being executed only after the specified time resulting in a delay without using the TON block. Somehow this does not work - most likely I am still thinking along the wrong way...

Initially I had the TON block inside the Activate action but then I noticed the "S" (Stored) option of starting the action.
Specifying "ComputeFB(S)" makes this action permanent - being executed every cycle.

There is still a feedback loop, using the Q output as an input for the TON block but that is not a problem.
The TON (Timer) could be removed from the ComputeFB action and placed into the Activate action as a simple "Timer(IN := TRUE, PT := PTin)" and a "Timer(In := FALSE)" in Deactivate to stop the timer again. Reason for not doing this is that this is an SFC test and I don't want to play around too much.

There is still an error in the state machine: I am going back to the Init state. A better solution might be to introduce an Initialized/waiting state and return there.

Rob
User avatar
volker
Posts: 1046
Joined: 09 Nov 2016, 15:41

Re: Race condition - will FBD-Light detect this?

Post by volker »

Hi Rob,
if you now look at your state diagram you can see what I was talking about:
If the sequence between "init" and "init" is 1 PLC cycle (e.g. because you clock the transition from init to the next states) you can see 2 states can occur in 1 cycle: start and stop. This is against the rule 1 state per 1 cycle.

Here is an example of how to get a pure 1 state per 1 cycle algorithm. It shows the statemachine in common language. INPUT is your Trig Q which is a debouncer and 1-cycle Monoflop for your switch input signal. Timer 2s is your Ton-Timer's Q output signal. OUTPUT is your Light output signal. TIMER is the Ton-Timer's IN signal. STATE is your Statemachine's actual state which is initially OFF:
(this algorithm does not prolong the Timer's On-Time when retriggered by pressing the button during the ON condition)

Code: Select all

while TRUE
    btn=INPUT
    stp=Timer2s
    case STATE
    OFF:
        if btn then 
             STATE = ON
             OUTPUT = on
             TIMER = on
    ON:
         if stp then
            STATE = RESET
            OUTPUT = off
    RESET:
         TIMER = off
         STATE = OFF
As you can see, there is a 3rd state called RESET. And it is your decision if you ignor any button pressing during this 1 cycle state (directly after switching the light off), just as you do during the ON state - or if you rather prefer to keep tha fact in mind thta the button was pressed. If you go for the 2nd option you would need to save the btn=ON fact in a second variable (= FlipFlop) and OR this variable in the OFF state with the originla btn variable. Of course you would need to reset this second variable when you transit from OFF to ON state.

Hope this makes sense and you can see what I have ment in my first posting when I was talking about 1 cycle 1 state. Because of the Reset of the Tmer's output is done by pulling it's input low, you do need a 3rd state in order to keep the Timer's output high for a full cycle.
Unser RevPi Motto: Don't just claim it - make it!
Post Reply