| 1 | function [ 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: |
|---|
| 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 |
|---|
| 111 | if ~isa(obj,'NXTMotor') |
|---|
| 112 | error('MATLAB:RWTHMindstormsNXT:InvalidObject',... |
|---|
| 113 | 'No NXTMotor object.'); |
|---|
| 114 | end |
|---|
| 115 | |
|---|
| 116 | if ~exist('handle', 'var') |
|---|
| 117 | handle = COM_GetDefaultNXT(); |
|---|
| 118 | end%if |
|---|
| 119 | |
|---|
| 120 | if ~(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!') |
|---|
| 122 | end%if |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | if nargout > 0 |
|---|
| 126 | timedOut = 0; |
|---|
| 127 | end |
|---|
| 128 | |
|---|
| 129 | if ~exist('timeout','var') |
|---|
| 130 | timeout = 0; |
|---|
| 131 | elseif ~isscalar(timeout) || ~isnumeric(timeout) |
|---|
| 132 | error('MATLAB:RWTHMindstormsNXT:invalidParameter', 'Given Timeout is not a number.'); |
|---|
| 133 | end |
|---|
| 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 |
|---|
| 141 | data = 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 |
|---|
| 147 | if 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; |
|---|
| 151 | end |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | %% Actual waitfor-loop |
|---|
| 155 | |
|---|
| 156 | warned236 = false; |
|---|
| 157 | mTimedOut = false; |
|---|
| 158 | hGlobalTimeOut = tic(); |
|---|
| 159 | hNXCReplyTimeOut = tic(); |
|---|
| 160 | |
|---|
| 161 | motorReady = false; |
|---|
| 162 | while(~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 | |
|---|
| 239 | end%while |
|---|
| 240 | |
|---|
| 241 | % final relaxation pause... |
|---|
| 242 | pause(0.010); |
|---|
| 243 | |
|---|
| 244 | % if output argument is requested |
|---|
| 245 | if exist('timedOut','var') |
|---|
| 246 | timedOut = mTimedOut; |
|---|
| 247 | end%if |
|---|