root/trunk/mfiles/@NXTMotor/WaitFor.m @ 1010

Revision 1010, 9.9 KB (checked in by atorf, 17 months ago)

Fixes #87. Thanks for reporting this! As you suspected, the documentation was wrong. When passing HANDLE as last argument, you also have to pass TIMEOUT. You already mentioned the correct way to handle this: Use TIMEOUT = 0 when no time out is needed. The issue is currently fixed in the trunk and will automatically be included in the next toolbox release.

— Linus

Line 
1function [ timedOut ] = WaitFor( obj, timeout, handle)
2% Wait for motor(s) to stop (busy waiting)
3%
4% Syntax
5%     |OBJ.WaitFor|
6%     |TIMEDOUT = OBJ.WaitFor(TIMEOUT)|
7%
8%     |OBJ.WaitFor(TIMEOUT, HANDLE)|
9%     |TIMEDOUT = OBJ.WaitFor(TIMEOUT, HANDLE)|
10%
11%
12% Description
13%     |OBJ.WaitFor| waits for motor specified by |OBJ| to stop.
14%     We do this by reading the motor state from the NXT
15%     brick repeatedly until controlled movement is finished. If the motor
16%     is set to run infinitely, the method returns immediately and displays a
17%     warning.
18%
19%     |TIMEDOUT = OBJ.WaitFor(TIMEOUT)| does the
20%     same as described above but has an additional timeout |TIMEOUT| (given
21%     in seconds). After this time the function stops waiting and
22%     returns |true|. Otherwise it returns |false|. This functionality is
23%     useful to avoid that your robot (and your program) get stuck in case
24%     the motor should somehow get stalled (e.g.by  driving against a wall).
25%     Use |TIMEOUT = 0| to wait infinitely (i.e. no time out desired).
26%
27%     Use |HANDLE| (optional) to identify the connection to use for this command.
28%     In this case, you also have to pass |TIMEOUT|. Use |TIMEOUT = 0| if
29%     this functionality is not needed.
30%
31% Note:
32%     If you specify |TIMEOUT| and the motor is not able to finish its
33%     current movement command in time (maybe because the motor is blocked?),
34%     waiting will be aborted. The motor is probably still busy in this
35%     case, so you have to make sure it is ready to accept commands before
36%     using it again (i.e. by calling |.Stop()|).
37%
38% Examples:
39%
40%+        % If a |SendToNXT| command is immediately followed by a |Stop|
41%+        % command without using |WaitFor| MATLAB does not wait to send
42%+        % the stop command until the motor has finished its rotation.
43%+        % Thus, the motor does not rotate at all, since the stop command
44%+        % reaches the NXT before the motor starts its rotation due to
45%+        % its mechanical inertia.
46%+        motorA = NXTMotor('A', 'Power', 60, 'TachoLimit', 1000);
47%+        motorA.SendToNXT();
48%+        motorA.Stop('off');
49%+        % motor A barely moved at all...
50%+       
51%+        % To avoid this issue, WaitFor has to be used!
52%+        motorC = NXTMotor('C', 'Power', -20, 'TachoLimit', 120);
53%+        motorC.SendToNXT();
54%+        motorC.WaitFor();
55%+        data = motorC.ReadFromNXT();
56%
57%+        % Instantiate motor A and run it
58%+        m = NXTMotor('A', 'Power', 50, 'TachoLimit', 1000);
59%+        m.SendToNXT();
60%+        % Wait for the motor, try waiting for max. 10 seconds
61%+        timedOut = WaitFor(m, 10);
62%+        if timedOut
63%+            disp('Motor timed out, is it stalled?')
64%+            m.Stop('off'); % this needed to "unlock" the motor
65%+        end%if
66%+        % now we can send new motor commands again...
67%
68% See also: NXTMotor, ReadFromNXT, SendToNXT, Stop, StopMotor
69%
70%
71% Signature
72%   Author: Aulis Telle, Linus Atorf (see AUTHORS)
73%   Date: 2009/07/20
74%   Copyright: 2007-2011, RWTH Aachen University
75%
76;
77%
78% ***********************************************************************************************
79% *  This file is part of the RWTH - Mindstorms NXT Toolbox.                                    *
80% *                                                                                             *
81% *  The RWTH - Mindstorms NXT Toolbox is free software: you can redistribute it and/or modify  *
82% *  it under the terms of the GNU General Public License as published by the Free Software     *
83% *  Foundation, either version 3 of the License, or (at your option) any later version.        *
84% *                                                                                             *
85% *  The RWTH - Mindstorms NXT Toolbox is distributed in the hope that it will be useful,       *
86% *  but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS  *
87% *  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
88% *                                                                                             *
89% *  You should have received a copy of the GNU General Public License along with the           *
90% *  RWTH - Mindstorms NXT Toolbox. If not, see <http://www.gnu.org/licenses/>.                 *
91% ***********************************************************************************************
92
93
94
95%NOTE check if this works properly for two motors all the time?!
96
97%TODO currently we sent a request to MotorControl, asking "is motor N
98% ready", and get a reply "N yes" or "N no". We must keep on requesting
99% messages to retrieve our answer: Send a message, get a message. Otherwise
100% an old reply will be left in the outbox and not be collected by us.
101% this is why we restart the NXC program every time a new handle is opened!
102% still, to solve this, we could use a sort of ID in this request, and only
103% react on/interpret messages with the correct ID in the reply...
104
105
106%% initialize
107    InboxNr = 1; % meant is the NXT's inbox (i.e. MATLAB's outbox if you will)
108    OutboxNr = 0; % other way round again :-)
109
110%% check input parameters
111if ~isa(obj,'NXTMotor')
112    error('MATLAB:RWTHMindstormsNXT:InvalidObject',...
113        'No NXTMotor object.');
114end
115
116if ~exist('handle', 'var')
117    handle = COM_GetDefaultNXT();
118end%if
119
120if ~(isfield(handle, 'UseNXCMotorControl') && handle.UseNXCMotorControl)
121    error('MATLAB:RWTHMindstormsNXT:Motor:embeddedMotorControlRequiredForMotorClass', 'The class NXTMotor needs the embedded NXC program MotorControl to be running on the NXT, and according to the currently used NXT-handle, this program is not running. Make sure you download MotorControl.rxe (compile from MotorControl.nxc) to your brick and do not disable the automatic launch when calling COM_OpenNXTEx. Otherwise, you have to use the function DirectMotorCommand with limited functionality!')
122end%if
123
124
125if nargout > 0
126    timedOut = 0;
127end
128
129if ~exist('timeout','var')
130    timeout = 0;
131elseif ~isscalar(timeout) || ~isnumeric(timeout)
132    error('MATLAB:RWTHMindstormsNXT:invalidParameter', 'Given Timeout is not a number.');
133end
134
135%disp(sprintf('New WaitFor, Motor %d', obj.Port(1)));
136%pause(0.1);
137
138
139%% Check agains running infinitely
140% get data from NXT
141data = obj.ReadFromNXT(handle);
142% the implicit nice side effect here is, that
143% NXT_GetOutputState (called by ReadFromNXT) will wait
144% for the NXC timestamp, which is a good thing
145
146% check if motor is running forever
147if data.TachoLimit == 0 && data.IsRunning
148    warning('MATLAB:RWTHMindstormsNXT:Motor:ignoringWaitForWithNoTachoLimit',...
149        'Motor %s seems to be running infinitely. Not waiting for this motor! Exiting WaitFor()...', char(65 + data.Port));
150    return;
151end
152
153
154%% Actual waitfor-loop
155
156warned236 = false;
157mTimedOut = false;
158hGlobalTimeOut = tic();
159hNXCReplyTimeOut = tic();
160
161motorReady = false;
162while(~motorReady)
163   
164    % request info from the NXC program:
165    % #define PROTO_CONTROLLED_MOTORCMD       1
166    % #define PROTO_RESET_ERROR_CORRECTION    2
167    % #define PROTO_ISMOTORREADY              3 <--
168    % #define PROTO_CLASSIC_MOTORCMD          4
169    % #define PROTO_JUMBOPACKET               5
170    msg = sprintf('3%1d', obj.Port(1));
171    NXT_MessageWrite(msg, InboxNr, handle);
172   
173    hMsgSent = tic();
174   
175    pause(0.001); % use this so CTRL + C can break into this loop and for the NXC task to relax a bit
176   
177    while(toc(hMsgSent) < 0.010)
178        % waiting max 10ms
179    end%while
180   
181   
182    reply = '';
183    while(isempty(reply))
184        % this loop is to ALWAYS collect all packets we request!!)
185       
186        % request statusByte so that we don't get flooded with error msgs...
187        [reply dummy statusByte] = NXT_MessageRead(OutboxNr, OutboxNr, true, handle);
188       
189        % ignore error 64
190        if (statusByte ~= 0) && (statusByte ~= 64) % 64 = "Specified mailbox queue is empty"
191            if (statusByte == 236) && (~warned236) % MATLAB:RWTHMindstormsNXT:messageReadWithNoActiveProgram
192                warned236 = true;
193                warning('MATLAB:RWTHMindstormsNXT:embeddedMotorControlSeemsTerminated', 'The embedded NXC program MotorControl should be running on the NXT brick. It seems the program is not running and/or was terminated accidentally. Please restart it or create a new NXT handle! Continuing...')
194            end%if
195            %NOTE we're ignoring all other errors here...
196        end%if
197       
198       
199        %disp(sprintf('    WaitFor, Motor %d, reply = %s', obj.Port(1), reply));
200       
201
202        if ~isempty(reply) % some sort of reply
203            % remember when
204            hNXCReplyTimeOut = tic();
205            % interpret: first char is port, 2nd is state
206            if strcmpi(reply(1), num2str(obj.Port(1))) && strcmpi(reply(2), '1')
207                % done :-)
208                motorReady = true;
209                break;
210            end%if
211            % we discard all replies not matching our port num... security...
212           
213        else % no reply :-(
214            if (toc(hNXCReplyTimeOut) > 5)
215                warning('MATLAB:RWTHMindstormsNXT:noReplyFromEmbeddedMotorControlProgram', 'There has been no reply (time out) for at least 5 seconds from the embedded NXC program MotorControl, which should be running on the NXT brick. Please make sure the program is running and does not get terminated accidentally. Exiting WaitFor() and continuing...')
216                mTimedOut = true;
217                break;
218            end%if
219        end%if
220       
221        % don't put too much stress on the NXT with USB connections:
222        if handle.ConnectionTypeValue == 1 % USB
223            pause(0.010);
224        end%if
225       
226    end%while
227
228    % check if warning236 -> noReplyFromEmbedded... warning was triggered:
229    if mTimedOut
230        break
231    end%if
232   
233    % check "global timeout"
234    if (timeout ~= 0) && (toc(hGlobalTimeOut) > timeout)
235        mTimedOut = true;
236        break;
237    end%if
238   
239end%while
240
241% final relaxation pause...
242pause(0.010);
243
244% if output argument is requested
245if exist('timedOut','var')
246    timedOut = mTimedOut;
247end%if
Note: See TracBrowser for help on using the browser.