Appdesigner Gui issue code
Ältere Kommentare anzeigen
Hello everyone,
i need help concerning a Gui. Basically, İ am running 4 haptic motors at the same time, when the mouse cursor is in the ''band area'' ,the motor are effectively running and is supposed to stop running when it is out of the ''band area''. (When the cursor is in the band area,the ''band area'' becomes green and when it is outside the ''band area'' it turns red and should stop vibrating).
The problem i am facing is that even when it is outside the area it keeps vibrating continuosly. The motor works perfectly since i can stop them and make them run when using arduıno andmatlab script.When you go through the code , i wrote in capital letter THIS IS THE LINE THAT İS SUPPOSED TO STOP İT (IT is in two places and refers to the code).
Attached is a screenshot of the Gui.
properties (Access = public)
arduinoObj % Description
message
end
properties (Access = public)
T % Description
end
properties (Access = public)
region1
%
v_thick1 % Description
v_thick2 % Description
h_thick1 % Description
h_thick2 % Description
v_thickness_1
v_thickness_2
h_thickness_1
h_thickness_2
v_or_h_array
v_or_h
amplitude_array
exp_counter
end
properties (Access = public)
amplitude % Description
end
methods (Access = private)
function mycallback(app,src,event)
display(event.SelectedOption);
end
end
function startupFcn(app)
clc
% Read experiment data from a CSV file
% Plot patch on uiaxes
hold(app.UIAxes, 'on')
% region1 = patch(app.UIAxes,[-10 10 10 -10],[-5 -5 -4.4 -4.4],'r','FaceAlpha',1,...
%'LineWidth',0.01,'LineStyle','-','tag','region1');
load_folder = "C:\Users\student\Desktop\FRANCK\thesis\excel_data\";
load_name = "excel_data.xlsx";
load_addr = load_folder + load_name;
app.T = readtable(load_addr,'NumHeaderLines',1);
app.exp_counter = 1;
app.v_thickness_1 = app.T.Var1;
app.v_thickness_2 = app.T.Var2;
app.h_thickness_1 = app.T.Var3;
app.h_thickness_2 = app.T.Var4;
app.amplitude_array = app.T.Var5;
app.v_or_h_array = app.T.Var6;
app.v_thick1 = app.v_thickness_1(app.exp_counter);
app.v_thick2 = app.v_thickness_2(app.exp_counter);
app.h_thick1 = app.h_thickness_1(app.exp_counter);
app.h_thick2 = app.h_thickness_2(app.exp_counter);
app.v_or_h = app.v_or_h_array(app.exp_counter);
%Vertical line
if app.v_or_h == 0
app.region1 = patch(app.UIAxes, ...
[app.v_thick1 app.v_thick2 app.v_thick2 app.v_thick1], ...
[-10 -10 10 10],'r', ...
'FaceAlpha',1,...
'LineWidth',0.01, ...
'LineStyle','-','tag','region1');
%Horizontal line
elseif app.v_or_h == 1
app.region1 = patch(app.UIAxes,[-10 10 10 -10], ...
[app.h_thick1 app.h_thick1 app.h_thick2 app.h_thick2], ...
'r','FaceAlpha',1,...
'LineWidth',0.01, ...
'LineStyle','-','tag','region1');
end
% Define pointer behavior for patch
pm.enterFcn = @(~,~) cursorPositionFeedback(app, app.region1, 'in');
pm.exitFcn = @(~,~) cursorPositionFeedback(app, app.region1, 'out');
pm.traverseFcn = [];
iptSetPointerBehavior(app.region1, pm)
% Enable pointer manager for app
iptPointerManager(app.UIFigure,'enable');
% Create the Arduino serial object
app.arduinoObj = serialport("COM3", 9600);
configureTerminator(app.arduinoObj,"CR/LF");
%flush(app.arduinoObj);
%
for i=1:8
app.message = readline(app.arduinoObj);
disp(app.message)
end
function cursorPositionFeedback(app, hobj, inout)
% When inout is 'in', change hobj facecolor to green and update textbox.
% When inout is 'out' change hobj facecolor to red, and clear textbox.
% Check tag property of hobj to identify the object.
switch lower(inout)
case 'in'
facecolor = 'g';
txt = 'Motor(s) vibrating';
pointer = 'fleur';
writeline(app.arduinoObj, "4&MOTOR_1_2&0!");
% message = readline(app.arduinoObj);
% disp(message)
case 'out'
facecolor = 'r';
txt = 'No';
pointer = 'crosshair';
writeline(app.arduinoObj, "0&NO_MOTOR&0!"); %% THIS IS THE LINE THAT İS SUPPOSED TO STOP İT
% message = readline(app.arduinoObj);
% disp(message)
end
hobj.FaceColor = facecolor;
app.TextAreaEditField.Value = txt;
set(app.UIFigure, 'Pointer', pointer)
end
% Determine if mouse is within uiaxes
cp = app.UIFigure.CurrentPoint;
isInAxes = cp(1) >= app.UIAxes.Position(1) && ...
cp(1) <= sum(app.UIAxes.Position([1,3])) && ...
cp(2) >= app.UIAxes.Position(2) && ...
cp(2) <= sum(app.UIAxes.Position([2,4]));
if isInAxes
set(app.CurrentPositionEditField, 'Value',...
sprintf('%.2f, %.2f', app.UIAxes.CurrentPoint(1,1:2)))
else
set(app.CurrentPositionEditField, 'Value', '')
end
function NEXTButton_2Pushed(app, event)
uiconfirm(app.UIFigure,'Are You sure?','Confirm Close',...
'CloseFcn',@(src,event)mycallback(app,src,event));
app.exp_counter = app.exp_counter + 1;
app.v_or_h = app.v_or_h_array(app.exp_counter);
if ishandle(app.region1)
delete(app.region1);
end
%Vertical line
if app.v_or_h == 0
app.region1 = patch(app.UIAxes,...
[app.v_thick1 app.v_thick2 app.v_thick2 app.v_thick1],...
[-10 -10 10 10],'r',...
'FaceAlpha',1,...
'LineWidth',0.01,...
'LineStyle','-','tag','region1');
%Horizontal line
elseif app.v_or_h == 1
app.region1 = patch(app.UIAxes,[-10 10 10 -10],...
[app.h_thick1 app.h_thick1 app.h_thick2 app.h_thick2],...
'r','FaceAlpha',1,...
'LineWidth',0.01,...
'LineStyle','-','tag','region1');
end
% Define pointer behavior for patch
pm.enterFcn = @(~,~) cursorPositionFeedback(app, app.region1, 'in');
pm.exitFcn = @(~,~) cursorPositionFeedback(app, app.region1, 'out');
pm.traverseFcn = [];
iptSetPointerBehavior(app.region1, pm);
% Enable pointer manager for app
iptPointerManager(app.UIFigure,'enable');
% Create the Arduino serial object
%app.arduinoObj = serialport("COM6", 9600);
%configureTerminator(app.arduinoObj,"CR/LF");
%flush(app.arduinoObj);
%
for i=1:8
app.message = readline(app.arduinoObj);
disp(app.message)
end
function cursorPositionFeedback(app, hobj, inout)
% When inout is 'in', change hobj facecolor to green and update textbox.
% When inout is 'out' change hobj facecolor to red, and clear textbox.
% Check tag property of hobj to identify the object.
switch lower(inout)
case 'in'
facecolor = 'g';
txt = 'Motor(s) vibrating';
pointer = 'fleur';
writeline(app.arduinoObj, "4&MOTOR_1_2&0!");
% message = readline(app.arduinoObj);
% disp(message)
case 'out'
facecolor = 'r';
txt = 'No';
pointer = 'crosshair';
writeline(app.arduinoObj, "0&NO_MOTOR&0!"); %% THIS IS THE LINE THAT İS SUPPOSED TO STOP İT
% message = readline(app.arduinoObj);
% disp(message)
end
hobj.FaceColor = facecolor;
app.TextAreaEditField.Value = txt;
set(app.UIFigure, 'Pointer', pointer)
end
28 Kommentare
Geoff Hayes
am 21 Dez. 2021
@Franck paulin Ludovig pehn Mayo - does the band turn red when the cursor moves outside the ''band area'' and so just the motor doesn't stop? I'm just wondering which part of
case 'out'
facecolor = 'r';
txt = 'No';
pointer = 'crosshair';
writeline(app.arduinoObj, "0&NO_MOTOR&0!");
is working..or does none of it work?
Franck paulin Ludovig pehn Mayo
am 21 Dez. 2021
Bearbeitet: Franck paulin Ludovig pehn Mayo
am 21 Dez. 2021
Geoff Hayes
am 21 Dez. 2021
@Franck paulin Ludovig pehn Mayo - how wide is the "band area"? Are you waiting for a few seconds of it being green before moving the cursor out of this area? Since the band area turns red and (presumably) the cursor is changing too, then the correct code is being executed. But the line
writeline(app.arduinoObj, "0&NO_MOTOR&0!");
doesn't seem to be doing anything. This could be because there is a message error (I don't know the appropriate/correct messages to use) or because it is being called too soon after the start is being called. That is why I'm wondering if you need to wait for a few seconds (while green) before moving the cursor away.
Franck paulin Ludovig pehn Mayo
am 21 Dez. 2021
Geoff Hayes
am 21 Dez. 2021
@Franck paulin Ludovig pehn Mayo I think you should try to wait a couple of seconds to see what happens. Or, if you could temporarily add a button to start and stop the motors respectively, that might be interesting to see if that functionality works from within app designer. If it does, then we can try to see why it might not work when moving the cursor.
Franck paulin Ludovig pehn Mayo
am 21 Dez. 2021
Franck paulin Ludovig pehn Mayo
am 22 Dez. 2021
Geoff Hayes
am 22 Dez. 2021
@Franck paulin Ludovig pehn Mayo - it isn't clear to me why the line
writeline(app.arduinoObj, "0&NO_MOTOR&0!");
isn't doing what it should be doing. Are there any errors in the console window? Presumably it is being called
See what happens if you put a call to the external function(s) that work inside the AppDesigner callback functions instead of the commands themselves.
Ths would somehow seem to be an issue with callbacks and event queues and the like...
You might also just see if adding a
drawnow
function call after the call to writeline
Franck paulin Ludovig pehn Mayo
am 23 Dez. 2021
Franck paulin Ludovig pehn Mayo
am 23 Dez. 2021
Geoff Hayes
am 23 Dez. 2021
@Franck paulin Ludovig pehn Mayo - can you show us the line of code that stops the motors when called outside of the GUI (i.e. the line of code that works to stop the motors)? So that we can compare the two.
Franck paulin Ludovig pehn Mayo
am 23 Dez. 2021
dpb
am 23 Dez. 2021
I'm suggesting
% Button pushed function: StopButton
function StopButtonPushed(app, event)
motor=app.arduinoObj;
StopMotor(motor);
end
where StopMotor is your test function outside the GUI.
I don't know anything about the addressing/communications with the Arduino, I'd guess somehow the reference to the actual pin/device/whatever isn't right, but I don't have any insight as to just why/how/what that might be.
The idea is that if you can write a StartMotor and StopMotor function and execute them correctly standalone, then if you call those two routines themselves, they certainly should also work from the GUI. I know you you have tried the the equivalent from command line, but this just proves it conclusively with ML function code.
Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Bearbeitet: Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Adam Danz
am 28 Dez. 2021
Hi @Franck paulin Ludovig pehn Mayo, I saw that you pointed me to this thread so I'm trying to catch up with the discussion.
It looks like a section of your code from your question is not within a function block which would cause an error that prevents the app from running. I'm refering to this section below,
% Determine if mouse is within uiaxes
cp = app.UIFigure.CurrentPoint;
isInAxes = cp(1) >= app.UIAxes.Position(1) && ...
cp(1) <= sum(app.UIAxes.Position([1,3])) && ...
cp(2) >= app.UIAxes.Position(2) && ...
cp(2) <= sum(app.UIAxes.Position([2,4]));
if isInAxes
set(app.CurrentPositionEditField, 'Value',...
sprintf('%.2f, %.2f', app.UIAxes.CurrentPoint(1,1:2)))
else
set(app.CurrentPositionEditField, 'Value', '')
end
I could be wrong, it's difficult to follow the structure of the code since proper indentation is not applied (ctrl A to select all, then ctrl i to indent).
Perhaps you could attach the mlapp file. I realize we can't run it as-is without additional files but we can work around that.
Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Adam Danz
am 28 Dez. 2021
Franck, I read through the commentary above and tinkered with your app (commenting-out the arduino commands etc).
I understand that you have no problems when this is run in an m-file and my guess is that you're using regular figures in the m-file whereas apps use uifigures. Perhaps the pointer behavior has slightly longer processing delays in uifigures than regular figures and since the target is so narrow, the trigger caused by leaving the target is too soon after the trigger caused by entering the target.
If the use of uifigures is the cause, moving the cursorPositionFeedback function to an m-file will not fix the problem.
The first step I would take is to make a copy of the m-file script that contains the problem-free version and replace the regular figures with uifigures. If the problem occurs after that change, it supports this hypothesis. If the change to uifigures does not cause a problem in the script, it rules out this hypothesis.
Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Bearbeitet: Franck paulin Ludovig pehn Mayo
am 28 Dez. 2021
Geoff Hayes
am 29 Dez. 2021
@Franck paulin Ludovig pehn Mayo - I don't think the issue is with app designer, it is more how you are linking the starting and stopping of the motors to the movement/location of the cursor. As you have said above, the faster you move the cursor, the more likely you are to have an issue if there is no "waiting time". I don't think it is unreasonable to ignore these cursor events while the motors are starting or stopping. Of course, by doing this you may miss some events that you are actually interested in.
I suppose what you could do is for that short waiting period (while the motors are starting or stopping) show a progress indicator or waitbar...but I'm not sure if that will be enough as the user could move the cursor location outside of your bands. Unless you can some how stop the movement of the cursor or restore it to its original postion once the waiting period is over. But that might lead to other undesireable/confusing behaviour.
Ok, in that case, I agree with Geoff Hayes that the problem is likely caused by the temporal asynchronies between cursor sampling and the control of the motors. As Geoff mentioned, adding a progress bar to stall execution briefly will not prevent the user from moving the cursor, it may also add additional delay, and it will interrupt any natural behavior that you may be trying to capture so I don't think that's a viable solution. I'll add an answer to demonstrate this point.
hi frank
i would suggest to use the following trick from Y. Altman to better tune your GUI app callbacks
persistent lasttime
if isempty(lasttime)
lasttime = clock;
end % if lasttime
if all(clock - lasttime >= [0 0 0 0 0 0.04]) % 25 Hz refreshing
% do your stuff here
% xxxx
% update for next callback entry
lasttime = clock;
end
% exit callback as soon as possible here
several points :
- clock is 50x more efficient on my PC than datetime('now')... so use it or alternatively use cputime instead of datetime('now')
- callbacks keep being triggered so you must control the way they work and exit as soon as possible, you may also prevent reentry if necessary by using uiaxes Interactivity and BusyAction props or similar
- you must tune the refreshing frequency in the callback to match your responsiveness
i hope this will help
happy new year
Adam Danz
am 2 Jan. 2022
Great suggestions, @s pernot. The first two points will definitely speed up the code but, depending on the specific hypothese being tested, the processing delay may still be insufficient.
Using an online cursor speed test, I clocked a mouse movement speed of 5,000 px/sec using moderate mouse control. Let's say the bar width is 20 pixels (from the OP's description, it could be narrower). At a constant 5k px/sec, the mouse crosses the bar in 4 milliseconds. So the duration of the vibration needs to be 4ms and the on/off delay should be much less than 4 ms or the entire vibration will be received after the mouse is outside of the bar region. This is assuming that the cursor sampling rate, display resolution, and DPI are all sufficient.
Franck paulin Ludovig pehn Mayo
am 4 Jan. 2022
Bearbeitet: Franck paulin Ludovig pehn Mayo
am 4 Jan. 2022
Franck paulin Ludovig pehn Mayo
am 4 Jan. 2022
Franck paulin Ludovig pehn Mayo
am 13 Jan. 2022
Akzeptierte Antwort
Weitere Antworten (0)
Kategorien
Mehr zu Develop Apps Using App Designer finden Sie in Hilfe-Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

