RUNNİNG MOTORS ISSUES İN GUİDE
Show older comments
İ have a problem it seems that no one is maybe getting what i am saying.
İ am trying to run some motors when they entered a particular and stop from running when it is out of that region.
To try to understand the issue, ı have designed a new GUİ wıth just 2 push buttons . RUN and STOP. Guess what , they are working as expected. But when i am trying to ımplement the same code ın my main guı it is not working at all. İ am not having any error in the command window btw. My motors just vibrate and stop vibrating randomly.
The motors are connected to driving motors and driving motors are connected to an arduino uno
The line corresponding to the issue is at the very end of the code.
writeline(handles.arduinoObj, '4&MOTOR_1_2&0!'); This line means vibrating
writeline(handles.arduinoObj, '0&MOTOR_1_2&0!'); This line means No vibration
All thıs is done in GUİDE.
İ wıll post the main code here and i will reply with the Test code.
function varargout = franck_guide(varargin)
% FRANCK_GUIDE MATLAB code for franck_guide.fig
% FRANCK_GUIDE, by itself, creates a new FRANCK_GUIDE or raises the existing
% singleton*.
%
% H = FRANCK_GUIDE returns the handle to a new FRANCK_GUIDE or the handle to
% the existing singleton*.
%
% FRANCK_GUIDE('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in FRANCK_GUIDE.M with the given input arguments.
%
% FRANCK_GUIDE('Property','Value',...) creates a new FRANCK_GUIDE or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before franck_guide_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to franck_guide_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help franck_guide
% Last Modified by GUIDE v2.5 22-Feb-2022 13:54:14
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @franck_guide_OpeningFcn, ...
'gui_OutputFcn', @franck_guide_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before franck_guide is made visible.
function franck_guide_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to franck_guide (see VARARGIN)
% Choose default command line output for franck_guide
handles.output = hObject;
% Plot patch on uiaxes
%hold on
% Read experiment data from a CSV file
load_folder = "C:\Users\student\Desktop\FRANCK\thesis\excel_data\";
load_name = "excel_data.xlsx";
load_addr = load_folder + load_name;
handles.T = readtable(load_addr,'NumHeaderLines',1);
handles.exp_counter = 1;
handles.v_thickness_1 = handles.T.Var1;
handles.v_thickness_2 = handles.T.Var2;
handles.h_thickness_1 = handles.T.Var3;
handles.h_thickness_2 = handles.T.Var4;
handles.amplitude_array = handles.T.Var5;
handles.v_or_h_array = handles.T.Var6;
handles.v_thick1 = handles.v_thickness_1(handles.exp_counter);
handles.v_thick2 = handles.v_thickness_2(handles.exp_counter);
handles.h_thick1 = handles.h_thickness_1(handles.exp_counter);
handles.h_thick2 = handles.h_thickness_2(handles.exp_counter);
handles.v_or_h = handles.v_or_h_array(handles.exp_counter);
handles.region1 = [];
% Create the Arduino serial object
handles.arduinoObj = serialport('COM3', 9600);
configureTerminator(handles.arduinoObj,'CR/LF');
%flush(handles.arduinoObj);
%
for i=1:8
handles.message = readline(handles.arduinoObj);
disp(handles.message)
end
create_patch(handles);
% Update handles structure
%guidata(hObject, handles);
% UIWAIT makes Hapticfinal wait for user response (see UIRESUME)
% uiwait(handles.finger);
function create_patch(handles)
if ishandle(handles.region1)
delete(handles.region1);
end
v_or_h = handles.v_or_h_array(handles.exp_counter);
if v_or_h == 0 % Vertical line
v_thick1 = handles.v_thickness_1(handles.exp_counter);
v_thick2 = handles.v_thickness_2(handles.exp_counter);
handles.region1 = patch( ...
'Parent',handles.axes1, ...
'XData',[v_thick1 v_thick2 v_thick2 v_thick1], ...
'YData',[-10 -10 10 10], ...
'FaceColor','red');
set(handles.axes1,'XLim',[-5 0],'YLim',[-10 10]);
else % Horizontal line
h_thick1 = handles.h_thickness_1(handles.exp_counter);
h_thick2 = handles.h_thickness_2(handles.exp_counter);
handles.region1 = patch( ...
'Parent',handles.axes1, ...
'XData',[-10 10 10 -10], ...
'YData',[h_thick1 h_thick1 h_thick2 h_thick2], ...
'FaceColor','red');
set(handles.axes1,'XLim',[0 5],'XLim',[-10 10]);
end
set(handles.axes1,'XGrid','on','YGrid','on');
axis(handles.axes1,'equal');
% Update handles structure
guidata(handles.finger,handles);
% call the button motion fcn to update the new patch's color:
finger_WindowButtonMotionFcn(handles.finger);
% UIWAIT makes franck_guide wait for user response (see UIRESUME)
% uiwait(handles.finger);
% --- Outputs from this function are returned to the command line.
function varargout = franck_guide_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in Start_button.
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ...
'TimerFcn', {@timerCallback, handles.fileID});
start(handles.t);
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
function timerCallback(~,~,fileID)
fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
fprintf('calling timer callback\n');
% --- Executes on button press in Next_button.
function Next_button_Callback(hObject, eventdata, handles)
% hObject handle to Next_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles = guidata(hObject);
f = msgbox('Operation Completed,3 seconds please.','NEXT');
% Read experiment data from a CSV file
% region1 = patch(axes1,[-10 10 10 -10],[-5 -5 -4.4 -4.4],'r','FaceAlpha',1,...
%'LineWidth',0.01,'LineStyle','-','tag','region1');
handles.exp_counter = handles.exp_counter + 1;
if handles.exp_counter > numel(handles.v_thickness_1)
return
end
% delete the old patch and create a new one:
create_patch(handles);
% --- Executes on button press in Yes_button.
function Yes_button_Callback(hObject, eventdata, handles)
% hObject handle to Yes_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
answer = questdlg('ARE YOU SURE?','Confirm close',...
'OK',@(src,event)mycallback(handles,src,event));
clear
clc
fileID= fopen('exp.txt2','a');
YES = "I FEEL IT";
fprintf (fileID, "%s\n",YES);
fclose(fileID);
% --- Executes on button press in Stop_button.
function Stop_button_Callback(hObject, eventdata, handles)
% hObject handle to Stop_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles = guidata(hObject);
stop(handles.t) %whenever we want to stop.
fclose(handles.fileID);
set(handles.Start_button,'Enable','on'); % -> Enable the button
guidata(hObject,handles);
% --- Executes on button press in No_button.
function No_button_Callback(hObject, eventdata, handles)
% hObject handle to No_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
answer1= questdlg('ARE YOU SURE?','Confirm Close',...
'OK',@(src,event)mycallback(handles,src,event));
clear
clc
fileID= fopen('exp.txt2','a');
NO = "I DON'T FEEL IT";
fprintf (fileID, "%s\n",NO);
fclose(fileID);
% --- Executes on mouse motion over figure - except title and menu.
function finger_WindowButtonMotionFcn(hObject, eventdata, handles)
% hObject handle to finger (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles = guidata(hObject);
pos = get(hObject, 'currentpoint'); % get mouse location on figure
global x;
global y;
x = pos(1);
y = pos(2); % assign locations to x and y
set(handles.xloc, 'string', ['x loc:' num2str(x)]); % update text for x loc
set(handles.yloc, 'string', ['y loc:' num2str(y)]); % update text for y loc
% Determine if mouse is within the region
p_x = get(handles.region1,'XData');
p_x = p_x([1 2]);
p_y = get(handles.region1,'YData');
p_y = p_y([1 3]);
ax_xl = get(handles.axes1,'XLim');
ax_yl = get(handles.axes1,'YLim');
ax_units = get(handles.axes1,'Units');
if ~strcmp(ax_units,'pixels')
set(handles.axes1,'Units','pixels')
end
ax_pos = get(handles.axes1,'Position'); % axes1 position in pixels
if ~strcmp(ax_units,'pixels')
set(handles.axes1,'Units',ax_units);
end
% convert the patch XData and YData from axes coordinates to figure coordinates in pixels
p_x = (p_x-ax_xl(1))/(ax_xl(2)-ax_xl(1))*ax_pos(3)+ax_pos(1);
p_y = (p_y-ax_yl(1))/(ax_yl(2)-ax_yl(1))*ax_pos(4)+ax_pos(2);
if x >= p_x(1) && x <= p_x(2) && y >= p_y(1) && y <= p_y(2)
set(handles.region1,'FaceColor','g');
%run the motors
writeline(handles.arduinoObj, '4&MOTOR_1_2&0!');
drawnow;
else
set(handles.region1,'FaceColor','r');
writeline(handles.arduinoObj, '0&MOTOR_1_2&0!');
drawnow;
end
% Create the Arduino serial object
%handles.arduinoObj = serialport("COM3", 9600);
%configureTerminator(handles.arduinoObj,"CR/LF");
%flush(handles.arduinoObj);
%
%%for i=1:8
%handles.message = readline(handles.arduinoObj);
%disp(handles.message)
%end
30 Comments
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Geoff Hayes
on 16 Mar 2022
@Franck paulin Ludovig pehn Mayo - it may not be possible to get the code to do what you want it to do given the mouse speed as it moves in to and out of the region of interest. You may need to do some tests to see what is happening if you move the mouse slowly which may result in fewer events being sent to the finger_WindowButtonMotionFcn function. At least that is what I thought at first glance of your code...but I only see this function being called from the create_patch function. Perhaps you have assigned it as a callback from within GUIDE?
I think that before you try getting the motors to start and stop, you need to confirm that the code is working as expected and is recognizing when the mouse pointer moves in and out of the patch. For example, if you take your code
if x >= p_x(1) && x <= p_x(2) && y >= p_y(1) && y <= p_y(2)
set(handles.region1,'FaceColor','g');
%run the motors
writeline(handles.arduinoObj, '4&MOTOR_1_2&0!');
drawnow;
else
set(handles.region1,'FaceColor','r');
writeline(handles.arduinoObj, '0&MOTOR_1_2&0!');
drawnow;
end
and replace with
if x >= p_x(1) && x <= p_x(2) && y >= p_y(1) && y <= p_y(2)
set(handles.region1,'FaceColor','g');
fprintf('Trying to run the motors!\n');
else
fprintf('Trying to stop the motors!\n');
end
do you see the correct messages in the console window? If you move the mouse faster (in and out of the area of interest) what happens?
I don't know how long it takes for the Aurduino motors to start and stop. It may be that these actions take longer than you would like and so it might be receiving a command to start before it has completed the task to stop. I don't know.
Is there a way for you to determine the state of the motors i.e. running or stopped or transitioning? What you could do is when your code determines that it should (for example) start the motor, then you disconnect the finger_WindowButtonMotionFcn callback from the figure so that it can't respond to any more motion events. When the state of the Arduino finally changes, then you reconnect the callbac. Just a thought. :shrug
Rik
on 16 Mar 2022
Can you explain what is different between this and your other question?
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Edited: Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Edited: Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Geoff Hayes
on 16 Mar 2022
Edited: Geoff Hayes
on 16 Mar 2022
@Franck paulin Ludovig pehn Mayo - I meant could you query the Arduino to determine whether its motor is running or not? I'm not familiar enough with this to know. I'm not surprised that the push button callbacks work since you just push the button once and there is just the one corresponding event whereas there are multiple events when you move the mouse and so long as you are moving the mouse within the region, your code will always try to start the motors. Maybe you need to ignore all events that try to start (or stop) if you have already tried to start (or stop)?
if x >= p_x(1) && x <= p_x(2) && y >= p_y(1) && y <= p_y(2)
if (strcmpi(get(handles.region1,'FaceColor'), 'g') == 0)
set(handles.region1,'FaceColor','g');
%run the motors
writeline(handles.arduinoObj, '4&MOTOR_1_2&0!');
drawnow;
end
else
if (strcmpi(get(handles.region1,'FaceColor'), 'r') == 0)
set(handles.region1,'FaceColor','r');
writeline(handles.arduinoObj, '0&MOTOR_1_2&0!');
drawnow;
end
end
So in the above, if the region1 'FaceColor' has already been set to 'g', then we know that we don't need to start the motor because it is already running. If the mouse position is outside of the region and the region is already 'r', then we know we don't need to stop the motor as the code has already made that request.
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Geoff Hayes
on 16 Mar 2022
@Franck paulin Ludovig pehn Mayo - if you move the mouse slowly in and out of the region, what is the behaviour? i.e. if you move into the region and wait 3-5 seconds before leaving the region, does the motor stop? If so, then you may need to add some sort of waiting period between when the motors start and when they can be stopped. I realize that you may not want to do this, but you may be expecting the software to do someting more than it can do. I think comparing the start/stop buttons with start/stop mouse position is not viable.
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Geoff Hayes
on 16 Mar 2022
@Franck paulin Ludovig pehn Mayo - without having the same setup as yourself (Arduino, etc.) it is kind of hard to understand why the motor isn't stopping when the call to writeline(handles.arduinoObj, '0&MOTOR_1_2&0!'); is made.
I wonder if instead of using the window position callback, you should just create a timer that polls (every second) for the current mouse position. You would then use that position to determine whether you should start or stop the motors (if needed). This would reduce the number of calls to the WindowButtonMotionFcn (I'm not sure how many time a second this function is called.)
Franck paulin Ludovig pehn Mayo
on 16 Mar 2022
Geoff Hayes
on 17 Mar 2022
@Franck paulin Ludovig pehn Mayo you could try something like the attached GUI which has two buttons to start and stop the timer. The timer initialization looks like
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 1.0, ...
'TasksToExecute', Inf, ...
'TimerFcn', {@timerCallback, handles.figure1});
start(handles.t);
guidata(hObject,handles); % <---- do this to save the updated handles object
Note how once the timer t is assigned to the handles structure and that this updated structure is saved with guidata. This is so that other callbacks (like STOP) will have access to the timer and be able to stop it. In the TimerFcn, we pass the handle to the figure/GUI as an input parameter to the timer callback so that it has access to the GUI controls. The timer callback looks like
function timerCallback(hObject, eventdata, hFigure)
% get the handles structure of the GUI
handles = guidata(hFigure);
% get the current mouse position
mousePos = get(0,'PointerLocation');
mouseX = mousePos(1);
mouseY = mousePos(2);
% get the position of the GUI (note how units have been set to pixels)
guiPosition = get(handles.figure1, 'Position');
% check to see if mouse position is within GUI or outside
if mouseX >= guiPosition(1) && mouseX <= (guiPosition(1) + guiPosition(3)) ...
&& mouseY >= guiPosition(2) && mouseY <= (guiPosition(2) + guiPosition(4))
% translate mouse position relative to GUI
mouseXGui = mouseX - guiPosition(1);
mouseYGui = mouseY - guiPosition(2);
fprintf('Mouse position is within GUI at (%f,%f).\n', mouseXGui, mouseYGui);
% sample code that changes colour of GUI start button
startButtonPosition = get(handles.pushbutton1, 'Position');
if mouseXGui >= startButtonPosition(1) && mouseXGui <= (startButtonPosition(1) + startButtonPosition(3)) && ...
mouseYGui >= startButtonPosition(2) && mouseYGui <= (startButtonPosition(2) + startButtonPosition(4))
set(handles.pushbutton1, 'BackgroundColor', 'g');
else
set(handles.pushbutton1, 'BackgroundColor', 'r');
end
else
fprintf('Mouse position is outside of GUI\n');
end
It determines the position of the mouse which is relative to the screen (and not the GUI), It then checks to see if the mouse position is within the GUI. If so, the code then converts this position to one that is relative to the GUI so that you can check for position within an axes or whatever (you will probably need to do some other translating of positon). I included some sample code that changes the colour of the start button depending upon position of mouse. This is for example purposes only and is not relevant to your problem.
Note also that I needed to ensure the units of the GUI and start button were in pixels. I set this in the opening function of the GUI
% <---- Set the figure units to be pixels
set(handles.figure1, 'Units', 'pixels')
set(handles.pushbutton1, 'Units', 'pixels')
Franck paulin Ludovig pehn Mayo
on 17 Mar 2022
Rik
on 17 Mar 2022
If it is indeed a polling rate issue, you could limit that yourself as well:
function callback(hObject,eventdata,handles)
if handles.LimitRateFlag,return,end
handles.LimitRateFlag=true;guidata(hObject,handles)
%rest of your code goes here
handles.LimitRateFlag=false;guidata(hObject,handles)
end
I needed something like this in my WindowLevel function. This way you limit the number of calls your GUI has to process.
Franck paulin Ludovig pehn Mayo
on 17 Mar 2022
Geoff Hayes
on 17 Mar 2022
@Franck paulin Ludovig pehn Mayo does the timer suggestion work? I realize that it may not be apporpriate for your experiment but if it does work, and the motors start and stop as expected, then it might give us an idea of what the problem is...
Franck paulin Ludovig pehn Mayo
on 17 Mar 2022
Edited: Franck paulin Ludovig pehn Mayo
on 20 Mar 2022
Rik
on 18 Mar 2022
The code I showed should be in your callback function. And yes, you should indeed initialize the flag in the opening function.
Franck paulin Ludovig pehn Mayo
on 20 Mar 2022
Rik
on 20 Mar 2022
Why are you editing the code I suggested if you don't understand it? Those calls to guidata are vital to this idea working.
Also, can you confirm you didn't edit the actual motion callback function, but inserted this instead? Because you should have received an error about handles.LimitRateFlag not existing.
%put this in your startup function
handles.LimitRateFlag=false;
Franck paulin Ludovig pehn Mayo
on 21 Mar 2022
Rik
on 22 Mar 2022
You forgot to tell us what 'it' is, and what constitutes 'not working'.
Franck paulin Ludovig pehn Mayo
on 22 Mar 2022
Rik
on 22 Mar 2022
Did you undo your deletions from the code I suggested? Did you either edit the callback property in GUIDE to point to callback, or did you put the code I suggested in the motion callback function? Without the addition in the startup function, the LimitRateFlag field doesn't exist. The fact that you didn't see any errors means that the code was not called at all.
Franck paulin Ludovig pehn Mayo
on 23 Mar 2022
Edited: Franck paulin Ludovig pehn Mayo
on 23 Mar 2022
Rik
on 23 Mar 2022
Then maybe this is a good time to ditch GUIDE and build the GUI from the ground up. That way you have full control. You can still use GUIDE to sketch out your GUI to get the values of the Position property of your objects.
For general advice and examples for how to create a GUI (and avoid using GUIDE), have look at this thread.
Franck paulin Ludovig pehn Mayo
on 23 Mar 2022
Rik
on 23 Mar 2022
I'm suggesting to use neither AppDesigner nor GUIDE. I have posted advice in the previous comment already. Click that link and read the advice on that page.
Your GUI should only be an interface. It should gather inputs and send that off to other functions. Posting essentially the same question several times is not going to help.
What you need to do:
Create a tiny example. Just a figure with one region. Create this with code only (no fig file). Do not implement the Arduino controls yet, first make sure it responds to your cursor correctly.
Once that works, we can implement a rate limiter.
Once that works, you can implement the calls to your Arduino.
You can also do this with key presses instead of mouse controls, the concept is the same: first make a tiny example. The code to create your GUI should only be a handful of lines.
Franck paulin Ludovig pehn Mayo
on 23 Mar 2022
Rik
on 23 Mar 2022
You will be able to recycle many of the parts you have already written. It is not the same as going from AppDesigner to GUIDE.
The point is to start with something small where you can see what works and what doesn't. When you're sure one part works, you can add the next part. You don't have to write those parts from scratch, you can copy them from what you currently have.
Re-writing something that doesn't work can be a worthwhile time investment. You can continue spending days on debugging GUIDE, or you can build up your program part by part, where you know what each part does. I strongly encourage you to read the link I gave you. I suspect GUIDE is holding you back. I know it did for me.
Answers (1)
Franck paulin Ludovig pehn Mayo
on 1 Apr 2022
Moved: Sabin
on 11 Jan 2023
0 votes
Categories
Find more on Update figure-Based Apps in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!