root/branches/staas/64Bit_libusb/mfiles/@NXTMotor/WaitFor.m @ 952

Revision 952, 9.7 KB (checked in by staas, 20 months ago)

more preparations for next milestone release

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