While loop not breaking even though condition is met.

I have an issue where my while loop continues to run even though my if statement, containing a break, inside the loop is met. I have tested this by displaying strings. It does print 'moving stage' when a push the button as well as 'stop stage' when i push it again. The flags I have defined changes between 1 or 0 depending on a button i push in a GUI. How can I terminate my loop?
function Standa_cmd(Stage_functions_settings)
while 1
pause(1)
disp('moving stage')
flag = Stage_functions_settings.move_x; % This struct field changes value between 1 or 0 depending on the button push in the gui
if(flag == 0)
disp('stop stage')
break
end
end
end

3 件のコメント

VBBV
VBBV 2022 年 11 月 11 日
if strcmp(flag,'0')
Check with strcmp. May be button pressed is returning char
Jiri Hajek
Jiri Hajek 2022 年 11 月 11 日
Hi, what you have described does not prove that the break command does not work, which you seem to suggest. Please put a breakpoint inside the if block and then use the F10 key to see what happens... This way, if you are able to get the process to the breakpoint, you will verify the correct functioning of the break command.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
@VBBV I checked the class of the "Stage_functions_settings.move_x" field and it is a double, so I'm not sure that is the problem. In the app, I just use the value of the button to set the field of the struct to either 0 or 1. So the value of the button is not passed on to any other function.

サインインしてコメントする。

 採用された回答

Bruno Luong
Bruno Luong 2022 年 11 月 11 日
編集済み: Bruno Luong 2022 年 11 月 11 日

1 投票

Just guessing; Might be it breaks but your function is entered again or there are many instances of function in queue, log more
function Standa_cmd(Stage_functions_settings)
disp('Standa_cmd is called')
while 1
pause(1)
disp('moving stage')
flag = Stage_functions_settings.move_x; % This struct field changes value between 1 or 0 depending on the button push in the gui
if(flag == 0)
disp('stop stage')
break
end
end
disp('I''m out of the loop and about to quit the function')
end

13 件のコメント

Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
Hmm it does'nt seem to be the issue. Heres the functions again, with the printout in the command window:
function Standa_cmd(Stage_functions_settings)
disp('Standa_cmd is called')
disp(Stage_functions_settings.move_x)
while 1
pause(1)
disp('moving stage')
flag = Stage_functions_settings.move_x;
if(flag == 0)
disp('stop stage')
break
end
%motion_stages_move_x_rel(0.001);
end
disp('I''m out of the loop and about to quit the function')
end
Printout:
Standa_cmd is called
1
moving stage
moving stage
moving stage
moving stage
This is a Stage function/setting
Standa_cmd is called
0
moving stage
stop stage
I'm out of the loop and about to quit the function
moving stage
moving stage
moving stage
moving stage
moving stage
moving stage
Bruno Luong
Bruno Luong 2022 年 11 月 11 日
編集済み: Bruno Luong 2022 年 11 月 11 日
From the log: your function is callled twice, and only one breaks the loop.
To me the break works fine, but just Stage_functions_settings.move_x has unexpected side effect to the logic you believe.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
Ahh okay I see. I think I understand what you are saying. So Is there any way to reference the first call of the function to terminate the loop or should I try with a different approach entirely?
Cheers,
Christoffer
Bruno Luong
Bruno Luong 2022 年 11 月 11 日
I don't know the logic of Stage_functions_settings.move_x, who set it and when to advise you.
If you work with GUI you should take a look at preperty Interruptible and BusyAction of your graphical object.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
The Stage_functions_settings is a struct I use to keep a lot of settings and functions and mediate commands down through the hierachy of execution scripts and equipment libraries. So I set/change the field of the struct everytime I want something specific to happen i.e. move or stop the a stage. In this example I have the function in the GUI:
function MoveTest1ButtonValueChanged(app, event)
value = app.MoveTest1Button.Value;
if value == 1
app.Stage_functions_settings = setfield(app.Stage_functions_settings,'move_x',1);
Equipment_calls(app.Equipment_list,app.Equipment_libs,app.Stage_functions_settings)
else
app.Stage_functions_settings = setfield(app.Stage_functions_settings,'move_x',0);
Equipment_calls(app.Equipment_list,app.Equipment_libs,app.Stage_functions_settings)
end
end
Which is based on a state button press in the gui. Depending on the value I change the field in the struct and pass it to another function: "Equipment_calls(app.Equipment_list,app.Equipment_libs,app.Stage_functions_settings)"
This function figures out what type of struct I have changed the field in and passes the command/changed field to the respective instrument library (function included as attachment). From there the Standa_cmd is triggered. Hope that makes sense.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
編集済み: Christoffer Sørensen 2022 年 11 月 11 日
Oh and I forgot to mention that I checked the function for the button callback (MoveTest1ButtonValueChanged) and it was checkmarked with interruptable so I think it is already interruptable. And I can also see that the BusyAction has been set to "queue" and not "cancel", so that might be the issue?
Bruno Luong
Bruno Luong 2022 年 11 月 11 日
編集済み: Bruno Luong 2022 年 11 月 11 日
As I see the code you made is not robust at all. It all depends when MoveTest1ButtonValueChanged is triggered. Again there are many instance of event that triggered the callback. You can't assume the call is sequential down to your last function.
IMO you have to rework with much more protection than values of different common fields/properties set and get by various places.
The original question of break is answered. I won't reply anymore about GUI workflow and control in this thread, since it is off topic.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
Okay! Thank you for the answers!
Bruno Luong
Bruno Luong 2022 年 11 月 11 日
編集済み: Bruno Luong 2022 年 11 月 11 日
I would put interruptible to 'off' as well.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
Okay I’ll try that!
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 17 日
I have tried quite a lot of different things now, without any luck. I believe you are right that my code is not robust enough to handle this kind of system. Could you point me in a direction as to where I can start learning about building a proper/more robust system?
Cheers,
Christoffer
Bruno Luong
Bruno Luong 2022 年 11 月 17 日
編集済み: Bruno Luong 2022 年 11 月 17 日
General principe : finite state machine
I wouldn't rely at all on push button state to make the state mahine (stage run or stop). I recommed this workflow:
I would create the state machine at the single place (a function to handle it) using for example persistent variable.
A second persistent logical variable called StopRequested.
Inside the while loop of the function calls drawnow then check StopRequested. If it's TRUE breaks the while loop.
Everytime user clicks on the button, the callback does this:
  • If (and only if) the current state is stop it invokes Standa_cmd
At the begining of function Standa_cmd, it switch StopRequested to FALSE and toggles the state to run (in this order)
The function setups an onCleanup callback that is triggered only when the function quits. The onCleanup callback function toggles the state to stop
The function runs the while loop
  • Otherwise (the current state is run) switch StopRequested to TRUE (to signal the while loop to break), do nothing else.
Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 21 日
Thank you for the elaborate answer! I will try to impliment this. In the mean time I managed to make a while loop terminate. But I will try to implement a more robust scheme for the future. Below is my temporary solution:
function StateButtonValueChanged(app, event)
flag = 1;
while(flag)
f = app.StateButton.Value;
app.Stage_functions_settings = setfield(app.Stage_functions_settings,'move_x',1);
Equipment_calls(app.Equipment_list,app.Equipment_libs,app.Stage_functions_settings)
drawnow;
if isequal(f,0)
app.Stage_functions_settings = setfield(app.Stage_functions_settings,'move_x',0);
Equipment_calls(app.Equipment_list,app.Equipment_libs,app.Stage_functions_settings)
flag = 0;
break;
end
end
end

サインインしてコメントする。

その他の回答 (1 件)

Image Analyst
Image Analyst 2022 年 11 月 11 日

0 投票

I think the pushbutton does not set the flag. I've seen this in GUIDE and this is why I use checkboxes instead of a push button. Then simply check the value of the checkbox inside your while loop.
Nonetheless it is possible to use a push button. See attached little demo.

2 件のコメント

Christoffer Sørensen
Christoffer Sørensen 2022 年 11 月 11 日
Thank you! I’ll check it out!
Bruno Luong
Bruno Luong 2022 年 11 月 11 日
"I think the pushbutton does not set the flag" Toggle button yes.

サインインしてコメントする。

カテゴリ

ヘルプ センター および File ExchangeLoops and Conditional Statements についてさらに検索

製品

リリース

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by