Rare error in code, how to spot

Itrim

Member
Join Date
Apr 2017
Location
Scotland
Posts
22
Hi!

Is there any way to spot error in the code that works right 99% of time?

For those who want to dive deeper into my code:

I got program which sends a product to the machines in First in First out manner, but sometimes one of them get stuck and won't accept demand call.

Basically there are 2 variables who deal with it. One to which keeps the signal after push button is released, second to tell that machine is in already in queue and ignore following calls.

Problem occurs when one of them isn't back to false at the end of the cycle, so the program thinks that machine is in queue, when actually it is not.

It is a minor thing, operators have simply to restart production, that's basically 20s break(or I can reset it by writing said variables to false, but I'm not always available).

Easy solution is that I can simply put a reset button, but this won't sate my ego. Any ideas?


The variables which end _unit are cycling between 0 or 1 and their MAX constant.

FVL. is global variable list

Code:
//Production Mode

FVL.Status_Cleaning := 0;

CASE FVL.Status_Production OF
	0:(*Initialisation*)
		FVL.Termination_TON(IN := UVL.Start_Production_Mode AND UVL.Safety_OK, PT := T#11S);
		IF FVL.Termination_TON.Q THEN
			FVL.Termination_TON(IN := FALSE);
			FVL.Status_Production := 1;
		END_IF 
	1:(*Work*)
		
	(*Conveyors*)
		
		IF UVL.Current_InFeed_Conveyor_Unit >= 2 AND UVL.Current_InFeed_Conveyor_Unit <= 5 THEN
			FVL.Conveyor[UVL.Current_InFeed_Conveyor_Unit](Force_Start_1 := TRUE, Force_Soft := FALSE, 
		ifWiping := FALSE, tTON := T#0S, tTOF := T#0S, tTW := T#0S);
		END_IF
		
		FVL.Conveyor[1](Force_Start_1 := FVL.TerminateFirstIn <> 0, Force_Soft := FALSE, 
		ifWiping := TRUE, tTON := T#3S, tTOF := T#0S, tTW := TVL.InFeed_Load);
		
		FVL.Conveyor[6](Force_Start_1 := FVL.Conveyor_6_Timer.Q, Force_Soft := FALSE, 
		ifWiping := FALSE, tTON := T#0S, tTOF := T#0S, tTW := T#0S);
		
		FVL.Conveyor[7](Force_Start_1 := FVL.Conveyor_7_Button_Control.Q, Force_Soft := FALSE, 
		ifWiping := FALSE, tTON := T#0S, tTOF := T#0S, tTW := T#0S);
		
		FVL.Conveyor[8](Force_Start_1 := FVL.Conveyor_8_Button_Control.Q, Force_Soft := FALSE, 
		ifWiping := FALSE, tTON := T#0S, tTOF := T#0S, tTW := T#0S);
		
	[B](*InFeed FIFO*)
		actFIFO();
		(*Button holders*)
		IF UVL.InFeedDevice_Unit_Enabler THEN
			IF  FVL.BaaderDevices[UVL.Current_InFeedDevice_Unit].Call_Button.Q AND FVL.BaaderDevices[UVL.Current_InFeedDevice_Unit].FeedBack.Q AND NOT FVL.Button_isQueued[UVL.Current_InFeedDevice_Unit] THEN
				FVL.Button_Holder[UVL.Current_InFeedDevice_Unit] := TRUE;
			END_IF
		END_IF[/B]
		(*Flipper Control*)
		IF FVL.Queue_Clock >= 1 AND FVL.Queue_Clock <= UVL.MAX_InFeedDevices_Units AND FVL.Queue[1] <> 0 THEN
			IF FVL.Queue_Clock <= FVL.Queue[1] AND FVL.Queue[1] <> UVL.MAX_InFeedDevices_Units THEN
				FVL.BaaderDevices[FVL.Queue_Clock].Flipper.in := TRUE;
			ELSE
				FVL.BaaderDevices[FVL.Queue_Clock].Flipper.in := FALSE;
			END_IF
		END_IF

		IF NOT UVL.Start_Production_Mode OR NOT UVL.Safety_OK THEN
			FVL.Status_Production := 2;
		END_IF
		
	2:(*Termination*)
		(*Terminate Flippers*)
		IF UVL.InFeedDevice_Unit_Enabler THEN
		FVL.BaaderDevices[UVL.Current_InFeedDevice_Unit].Flipper(in := FALSE, tTOF := T#0S,
		tTON := T#0S, tTW := T#0S, ifWiping := FALSE);
		END_IF
		(*Terminate Conveyors*)
		IF UVL.InFeedConveyor_Unit_Enabler THEN
			FVL.Conveyor[UVL.Current_InFeed_Conveyor_Unit](Force_Start_1 := FALSE, Force_Soft := FALSE, 
		ifWiping := FALSE, tTON := T#0S, tTOF := T#0S, tTW := T#0S);
		END_IF
		[B](*Terminate FIFO*)
		FVL.Queue[UVL.Current_InFeedDevice_Unit] := 0;
		FVL.Button_Holder[UVL.Current_InFeedDevice_Unit] := FALSE;
		FVL.Button_isQueued[UVL.Current_InFeedDevice_Unit] := FALSE;
		FVL.Queue_Clock := 1;
		FVL.Queue_Lowest := 0;
		FVL.TerminateFirstIn := 0;
		FVL.TerminateFirstIn_TON(IN := FALSE);[/B]
			
		(*EOT*)
		FVL.Termination_TON(IN := TRUE, PT := T#5S);
		IF FVL.Termination_TON.Q THEN
			FVL.Termination_TON(IN := FALSE);
			FVL.Status_Production := 0;
		END_IF
END_CASE

Code:
(*actFIFO()*)
(*InFeed FIFO*)

FVL.Queue[0] := UVL.MAX_InFeedDevices_Units + 1;
FVL.Queue[UVL.MAX_InFeedDevices_Units + 1] := 0;

IF FVL.Queue_Clock >= 1 AND FVL.Queue_Clock <= UVL.MAX_InFeedDevices_Units THEN
(*Move queue*)	
	IF FVL.Queue[FVL.Queue_Clock] = 0 AND FVL.Queue[FVL.Queue_Clock + 1] <> 0 THEN
		FVL.Queue[FVL.Queue_Clock] := FVL.Queue[FVL.Queue_Clock + 1];
		FVL.Queue[FVL.Queue_Clock + 1] := 0;
	END_IF
(*Find lowest vacant*)
	IF FVL.Queue_Lowest < 1 AND FVL.Queue_Lowest > UVL.MAX_InFeedDevices_Units THEN
		FVL.Queue_Lowest := 1;
	ELSIF FVL.Queue[FVL.Queue_Clock] = 0 AND FVL.Queue[FVL.Queue_Clock - 1] <> 0 THEN
		FVL.Queue_Lowest := FVL.Queue_Clock;
	END_IF
	
	IF FVL.BaaderDevices[FVL.Queue_Clock].Call_Button.Q AND FVL.BaaderDevices[FVL.Queue_Clock].FeedBack.Q THEN
		FVL.Button_Holder[FVL.Queue_Clock] := TRUE;
	END_IF
(*Assign button number to the vacant lowest queue *)
	FVL.Button_R_TRIG[FVL.Queue_Clock](CLK := FVL.Button_Holder[FVL.Queue_Clock]);
	IF FVL.Button_R_TRIG[FVL.Queue_Clock].Q AND NOT FVL.Button_isQueued[FVL.Queue_Clock] THEN
		FVL.Button_isQueued[FVL.Queue_Clock] := TRUE;
		FVL.Queue[FVL.Queue_Lowest] := FVL.Queue_Clock;
		FVL.Button_Holder[FVL.Queue_Clock] := FALSE;
	END_IF
	
	IF FVL.Queue[FVL.Queue_Clock] = UVL.MAX_InFeedDevices_Units AND FVL.Queue[FVL.Queue_Clock + 1] <> 0 AND FVL.Queue[1] <> UVL.MAX_InFeedDevices_Units THEN
		FVL.Queue[FVL.Queue_Clock] := FVL.Queue[FVL.Queue_Clock + 1];
		FVL.Queue[FVL.Queue_Clock + 1] := UVL.MAX_InFeedDevices_Units;
	END_IF
	FVL.Queue_Clock := FVL.Queue_Clock + 1;
ELSE
	FVL.Queue_Clock := 1;
END_IF

(*Terminate First Place*)
IF FVL.Queue[1] <> 0 THEN	
	CASE FVL.TerminateFirstIn OF
		0:	IF NOT FVL.BaaderDevices[FVL.Queue[1]].FeedBack.Q THEN
				FVL.TerminateFirstIn := 2;
			ELSE
				FVL.TerminateFirstIn := 1;
			END_IF
		1:	FVL.TerminateFirstIn_TON(IN := TRUE, PT := TVL.InFeed_Next_Cycle);
			IF FVL.TerminateFirstIn_TON.Q THEN
				FVL.TerminateFirstIn_TON(IN := FALSE);
				FVL.TerminateFirstIn := 2;
			END_IF
		2:	FVL.Button_isQueued[FVL.Queue[1]] := FALSE;
			FVL.Button_Holder[FVL.Queue[1]] := FALSE;
			FVL.TerminateFirstIn := 0;
			FVL.Queue[1] := 0;
	END_CASE
END_IF
 
Last edited:
I'll put in monitoring logic, that is completely separate from the suspect logic, to monitor its actions and variables looking for conditions that are not "correct", flag it, and record all of the variables values that created the "bad" condition.
 
Check what data you are passing in. Make sure you don't pass in any operator characters. Its possible your code is perfectly fine, but when a operator is passed in it'll goof things up as part of whats passed in causes a unexpected error. Math, comparitor, etc characters are ones to watch out for.
 
Division by zero and indexing beyond the limits of an array are things to look out for in cases like this.



At first glance I see no divisions in your code.



I do see quite some flexible array indexing, and at least one line with array within array. Not saying anything is wrong there but may I suggest you specifically monitor the array indexing?
 
Thanks for all the answers!

It is the same task. I got multiple global variable lists for different part of the process.

UVL. means this variable deal with things like arrays and overall process control(Universal variable list).

FVL. deals with devices and variables essential for the inFeed part of the process.(inFeed Variable List),

Given that each program is basically big while loop:

Instead of using:
VL.ExampleDevice[1]();
VL.ExampleDevice[2]();
VL.ExampleDevice[3]();
VL.ExampleDevice[4]();
VL.ExampleDevice[5]();

I'm using(I dont remember exactly, dont have my work laptop with me):
IF 1 =< VL.Current_Device_Unit < VL.MAX
VL.Current_Device_Unit + 1;
Else
VL.Current_Device_Unit := 1;

VL.Current_Device_Enabler := 1 =< VL.Current_Device_Unit <= VL.MAX

IF 1 =< VL.Current_Device_Unit <= VL.MAX
VL.ExampleDevice[VL.Current_Device_Unit]();
(pardon me bad syntax)


This is done on the at the begging and there is no issue with this part of program, otherwise itll throw page faults all over the place.

I hope I explained it clear enough :)
 
Last edited:
Not sure what platform this is, but I find text based programming definitely a little harder to troubleshoot. definitely willing to consider that its just a symptom of siemens SCL though.

This may be a huge pain in the ***, but would it be possible to implement a sequencer with actions/reactions to figure out where its getting stuck?

Use an integer or other numerical value to track the logic until it gets stuck, or something doesn't respond as expected. Could even do multiple sequences if necessary.

Just an idea, and could require a lot of time.
 
Looking at the code I was thinking about the tag index updating between the instructions, but if they are not overwritten this is unlikely.


I find it more likely that the value does not reset rather than being set once more.


Is it possible that the tag tested for case value goes from 1 to 0 without never passing to 2 ?
 
It's Twincat 3

I find it more likely that the value does not reset rather than being set once more.

Is it possible that the tag tested for case value goes from 1 to 0 without never passing to 2 ?

Do you mean the CASE with FVL.TerminateFirstIn?

It may happen. It may happen only when production stops (FVL.Status_Production = 2), but in that case everything is reset anyway.

I thought I have done everything to protect it from any mistakes. That's why it is so confusing. Every time I'm trying to analyse it, I'm reassuring myself that there is nothing wrong with it, yet I still got two random errors like that over last week.

I wanted to post that(^), but I just spot something and I'm gonna test it tomorrow.
 

Similar Topics

Hi all, i was serching unsuccessfully something relationed with this issue. I have a screen with several labels, some of them with the same "Y"...
Replies
3
Views
2,687
I've given up on the FSGateway because it just doesn't want to create a connection (continuous errors in logger about OPCEnum), so I decided to...
Replies
3
Views
1,807
When open offline project on rs5000, if go to online with the controllogix, there is no prompt windows to say if you need to download or upload...
Replies
20
Views
6,595
Does anyone have experience with the Siemens 6ES5-776-7LA13 Power Output Module? It was generally used on thermo-forming machines to control a...
Replies
3
Views
10,271
if i wanna do a fb made of some ladder and anothers fb inside. can i pun a fb inside in other one??? if yes. wich db i declare to the ones...
Replies
9
Views
3,132
Back
Top Bottom