diff --git a/examples/MotorBraking.m b/examples/MotorBraking.m deleted file mode 100644 index 47b6f2cb1e999dcef377c0bda4fe43274007cd93..0000000000000000000000000000000000000000 --- a/examples/MotorBraking.m +++ /dev/null @@ -1,21 +0,0 @@ -b = EV3('debug', 2); -b.connect('bt', 'serPort', '/dev/rfcomm0'); -m = b.motorA; -sl = b.motorB; - -m.tachoLimit = 1000; -m.brakeMode = 'Coast'; - -counts = []; -power = [60, 65, 70, 75, 80, 85, 90, 95, 100]; - -for i=1:length(power) - m.resetTachoCount; - m.reset; - m.power = power(i); - m.syncedStart(sl); - m.waitFor(); - counts = [counts, m.tachoCount]; - b.beep; - b.debug = false; -end \ No newline at end of file diff --git a/examples/distancePlotting.m b/examples/distancePlotting.m index 416e8a5c4e5bc441cd3e8f7a778ba84b3106e248..c0c2c3c731ce23f2ae956f1217b344fef903b17e 100644 --- a/examples/distancePlotting.m +++ b/examples/distancePlotting.m @@ -1,3 +1,12 @@ +% This script has two purposes: +% * Plotting distance to ultrasonic sensor (for fun and as an example) +% * Analyse runtime of sensor readings (comment out marked part of code to get useful +% results) +% Necessary: +% * USB-connection +% * UltraSonic-Sensor at Port 4 +clear all + b = EV3('debug', 0); b.connect('usb'); @@ -15,8 +24,11 @@ hold on; while toc < 20 readings = [readings, s.value]; time = [time, toc]; -% plot(time, readings) -% drawnow + + %% Plotting + % Should be commented out if you analyse latency of sensor readings + plot(time, readings) + drawnow end hold off; @@ -24,6 +36,8 @@ fprintf('\nSensor readings per sec: %f\n', length(readings)/time(length(time))); b.disconnect(); +clear all + %% Results % Bluetooth % debug=2, sensor-typ-kontrolle an: 7.5 Readings/sec % worst case diff --git a/examples/testProfiling.m b/examples/testProfiling.m new file mode 100644 index 0000000000000000000000000000000000000000..0f806055d45870d98f4731f4fd14dbf9e88079a3 --- /dev/null +++ b/examples/testProfiling.m @@ -0,0 +1,24 @@ +% In order to generally examine the runtime-distribution, start this script +% with the 'Run and Time'-Button in MATLAB. +% Necessary: +% * USB-connection +% * Motor at Port A +clear all + +b = EV3(); +b.connect('usb'); +ma = b.motorA; +ma.setProperties('Power', 50, 'LimitValue', 2000); + +t = 0; +flag = 0; +tacho = 0; + +tic; +ma.start(); +while(toc < 7) + flag = [flag, ma.isRunning]; + tacho = [tacho, ma.tachoCount]; +end + +clear all \ No newline at end of file diff --git a/examples/testToolbox.m b/examples/testToolbox.m deleted file mode 100644 index a04346e0a81a98aa306ccd4318fc04d05b0225b8..0000000000000000000000000000000000000000 --- a/examples/testToolbox.m +++ /dev/null @@ -1,42 +0,0 @@ -b = EV3(); -b.connect('bt', 'serPort', '/dev/rfcomm0'); -b.sensor3.mode = DeviceMode.Color.Col; -b.sensor4.mode = DeviceMode.UltraSonic.DistCM; -tic; -t = 0; - -b.motorA.setProperties('power', 50, 'speedRegulation', 'on', 'smoothStart', 10, 'limitMode', ... - 'Time', 'limitValue', 3000); -b.motorA.start(); - -pause(0.5); -while b.motorA.isRunning() - b.sensor3.value - b.sensor4.value - b.motorA.tachoCount -end - -b.motorB.power = 50; -b.motorB.limitValue = 4*360; -b.motorB.start(); -b.motorB.waitFor(); -b.beep(); - -b.motorA.speedRegulation = false; -pause(1); -b.motorA.syncedStart(b.motorB, 'turnRatio', 200); -b.motorA.waitFor(); - -for i=1:10 - b.sensor3.value - b.motorA.tachoCount - b.sensor3.reset - b.motorA.tachoCount -end - -b.beep -b.beep - - -b.disconnect -b.delete \ No newline at end of file diff --git a/source/Command.m b/source/Command.m index 94d1fb069b66cdd97ff1192fb619017e3f959890..663f528c7c10f4dcc57a2391ad23a5fa8f956348 100755 --- a/source/Command.m +++ b/source/Command.m @@ -2202,7 +2202,7 @@ classdef Command < handle cmd.GV0(speed); end - function opOUTPUT_TEST(cmd,layer,nos,value) + function opOUTPUT_TEST(cmd,layer,nos,busy) % Command.opOUTPUT_TEST Add a opOUTPUT_TEST % % Command.opOUTPUT_READ(layer,nos) adds a opOUTPUT_TEST opcode @@ -2222,7 +2222,7 @@ classdef Command < handle cmd.addDirectCommand(ByteCodes.OutputTest); cmd.LC0(layer); cmd.LC0(nos); - cmd.GV0(value); + cmd.GV0(busy); end function opOUTPUT_READY(cmd,layer,nos) diff --git a/source/CommunicationInterface.m b/source/CommunicationInterface.m index 18bca6c83d0eca00caf62e2d609c66f9743454fb..1eb982a4049d45f501632327142a09fbe7f8413f 100755 --- a/source/CommunicationInterface.m +++ b/source/CommunicationInterface.m @@ -307,8 +307,8 @@ classdef CommunicationInterface < handle corrupt = 1; if ~isempty(strfind(ME.identifier, 'CorruptPacket')) % Read packet was corrupt - retry - id = [ID(), ':', 'CorruptPacket']; - warning(id, 'Read corrupt packet. Retrying...'); + %id = [ID(), ':', 'CorruptPacket']; + %warning(id, 'Read corrupt packet. Retrying...'); if brick.debug fprintf('received (corrupt) (hex): [ '); for ii=1:length(rmsg) diff --git a/source/Motor.m b/source/Motor.m index 592ec28b178671362e47274753a822df5047b67b..5e2431415a3bf74f3e3d21f7c009ca315949da53 100755 --- a/source/Motor.m +++ b/source/Motor.m @@ -94,16 +94,17 @@ classdef Motor < MaskedHandle & dynamicprops % to be sent, is saved (hidden from the user). brakeMode_; - %% Miscallenous flags - - connectedToBrick = false; % Connection to physical Brick? - sendPowerOnNextStart = false; % Indicates whether current power parameter should be sent - % to the Brick right before starting it next time - sendPowerOnSet = false; % Indicates whether power parameter should be sent to the Brick - % immediately after setting it - limitSetToZero = false; % Indicates whether limitValue has been set to zero - % (workaround for a bug, see motor.start, Note 2) + %% Flags + + connectedToBrick = false; % Connection to physical Brick? init = true; % Indicates 'init-phase' (True as long as constructor is running) + sendPowerOnSet = false; % If true, OUTPUT_POWER is sent when setting power + + % Bitfield representing which opCodes should be sent on Motor.start() + % The corresponding opCodes for each bit are (in Big Endian): + % * 1st Bit: OUTPUT_POWER (sets power on physical Brick) + % * 2nd Bit: OUTPUT_STOP (stops Brick; workaround for a bug, see motor.start, Note 2) + sendOnStart = 0; end properties (Hidden, Dependent, Access = 'private') % Hidden, dependent properties for internal use only @@ -112,6 +113,8 @@ classdef Motor < MaskedHandle & dynamicprops isSynced; % Is motor running in synced mode? physicalMotorConnected; % Physical motor connected to this port? + + internalTachoCount; % Internal tachocount used for positioning the motor with tacholimit end methods % Standard methods @@ -150,13 +153,12 @@ classdef Motor < MaskedHandle & dynamicprops % Check connection and if motor is already running if ~motor.connectedToBrick - error(['Motor::start: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::start: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected error('Motor::start: No physical motor connected to Port %s',... port2str('Motor', motor.port)); elseif motor.isRunning - error('Motor::start: Motor is already runnning!'); + error('Motor::start: Motor is already running!'); end % If motor has been started synced with another, and it stopped 'itself' (when @@ -164,26 +166,34 @@ classdef Motor < MaskedHandle & dynamicprops % would do so) if motor.isSynced delete(motor.findprop('syncCache')); + motor.internalReset(); % Better safe than sorry end - % Trigger warning if power = 0 (as it still sets the motor internally in a - % 'running' mode -% if motor.power == 0 -% warning('Motor::start: Motor starting with power=0.'); -% end - - if motor.brakeMode_ == BrakeMode.Coast - motor.reset(); + % If the motor coasts into its stops, the internal tachocount has to be reset + % before each start for it to behave predictable + if motor.brakeMode_ == BrakeMode.Coast + motor.internalReset(); end - % Call right function in commInterface depending on limitValue and limitMode + % Call appropriate function in commInterface depending on limitValue and limitMode if motor.limitValue==0 - if motor.sendPowerOnNextStart - if motor.limitSetToZero - motor.stop(); - motor.limitSetToZero = false; + if motor.sendOnStart > 0 + % If stop-flag is set: call stop() and reset flag + if bitget(motor.sendOnStart, SendOnStart.Stop) + motor.stop(); + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Stop, 0); end - motor.setPower(motor.power); + + % If power-flag is set: call setPower() and reset flag if successful + if bitget(motor.sendOnStart, SendOnStart.Power) + success = motor.setPower(motor.power); + if ~success + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1); + else + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 0); + end + end + end motor.commInterface.outputStart(0, motor.port); @@ -246,8 +256,7 @@ classdef Motor < MaskedHandle & dynamicprops %stop Stops the motor if ~motor.connectedToBrick - error(['Motor::stop: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::stop: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected error('Motor::stop: No physical motor connected to Port %s',... port2str('Motor', motor.port)); @@ -322,8 +331,7 @@ classdef Motor < MaskedHandle & dynamicprops % Check connection and motor parameter if ~motor.connectedToBrick || ~syncMotor.connectedToBrick - error(['Motor::syncedStart: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::syncedStart: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected error('Motor::syncedStart: No physical motor connected to Port %s or %s.',... port2str('Motor', motor.port), port2str('Motor', syncMotor.port)); @@ -337,7 +345,21 @@ classdef Motor < MaskedHandle & dynamicprops if motor.power == 0 warning('Motor::syncedStart: Synchronized motors starting with power=0.'); end - + + % If the motor coasts into its stops, the internal tachocount has to be reset + % before each start for it to behave predictable + if motor.brakeMode_ == BrakeMode.Coast + motor.internalReset(); + end + + if motor.sendOnStart > 0 + % If stop-flag is set: call stop() and reset flag + if bitget(motor.sendOnStart, SendOnStart.Stop) + motor.stop(); + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Stop, 0); + end + end + % Cache old values to make it possible to reset them on stopSynced % Note: the existence of 'syncCache' is also used to determine whether motor is % running synchronized or not, see get.isSynced() @@ -397,8 +419,7 @@ classdef Motor < MaskedHandle & dynamicprops syncMotor = motor.syncCache.slave; if ~motor.connectedToBrick || ~syncMotor.connectedToBrick - error(['Motor::syncedStop: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::syncedStop: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected error('Motor::syncedStop: No physical motor connected to either Port %s or %s.',... port2str('Motor', motor.port), port2str('Motor', syncMotor.port)); @@ -406,18 +427,24 @@ classdef Motor < MaskedHandle & dynamicprops % Retrieve other values from cache and delete it motor.sendPowerOnSet = motor.syncCache.master_oldSendPowerOnSet; - syncMotor.sendPowerOnSet = motor.syncCache.slave_oldSendPowerOnSet; + %syncMotor.sendPowerOnSet = motor.syncCache.slave_oldSendPowerOnSet; + syncMotor.sendPowerOnSet = motor.syncCache.master_oldSendPowerOnSet; delete(motor.findprop('syncCache')); % Synced stopping motor.commInterface.outputStop(0, motor.port+syncMotor.port, motor.brakeMode_); % On next start, both motors have to send power-opcode again - motor.sendPowerOnNextStart = true; - syncMotor.sendPowerOnNextStart = true; + if motor.sendPowerOnSet + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1); + end + if syncMotor.sendPowerOnSet + syncMotor.sendOnStart = bitset(syncMotor.sendOnStart, SendOnStart.Power, 1); + end + if motor.debug - fprintf('(DEBUG) Motor::stop: Called outputStop on Ports %s and %s\n.', ... + fprintf('(DEBUG) Motor::syncedStop: Called outputStop on Ports %s and %s.\n', ... port2str('Motor', motor.port), port2str('Motor', syncMotor.port)); end end @@ -436,17 +463,16 @@ classdef Motor < MaskedHandle & dynamicprops % outputReady returns in less than a second, another while-loop iterates until % the motor has stopped, this time using motor.isRunning() (this only works as % long as not both OutputTest and OutputReady are buggy). - % * Workaround: Poll isRunning (which itself return (speed>0)) until it is false + % * (OLD)Workaround: Poll isRunning (which itself return (speed>0)) until it is false % -> No need to check if motor is connected as speed correctly % returns 0 if it's not % if ~motor.connectedToBrick - error(['Motor::waitFor: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::waitFor: Motor-Object not connected to comm handle.'); end - pause(0.1); + %pause(0.1); while motor.isRunning pause(0.03); end @@ -481,37 +507,39 @@ classdef Motor < MaskedHandle & dynamicprops % end end - function reset(motor) - %reset Resets internal tacho count - % The internal tacho count is used for positioning the motor. For example, when the + function internalReset(motor) + % internalReset Resets internal tacho count + % Use this if motor behaves weird (i.e. not starting at all, or not correctly + % running to limitValue) + % + % The internal tacho count is used for positioning the motor. When the % motor is running with a tacho limit, internally it uses another counter than the % one read by tachoCount. This internal tacho count needs to be reset if you - % physically change the motor's position. + % physically change the motor's position or it coasted into a stop. If the motor's + % brakemode is 'Coast', this function is called automatically. % % See also MOTOR.RESETTACHOCOUNT % if ~motor.connectedToBrick - error(['Motor::reset: Motor-Object not connected to brick handle.',... + error(['Motor::internalReset: Motor-Object not connected to brick handle.',... 'You have to call motor.connect(brick) first!']); elseif ~motor.physicalMotorConnected - error('Motor::reset: No physical motor connected to Port %s',... + error('Motor::internalReset: No physical motor connected to Port %s',... port2str('Motor', motor.port)); end motor.commInterface.outputReset(0, motor.port); if motor.debug - fprintf('(DEBUG) Motor::reset: Called outputReset on Port %s\n',... + fprintf('(DEBUG) Motor::internalReset: Called outputReset on Port %s\n',... port2str('Motor', motor.port)); end end function resetTachoCount(motor) - if ~motor.connectedToBrick - error(['Motor::resetTachoCount: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::resetTachoCount: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected error('Motor::resetTachoCount: No physical motor connected to Port %s',... port2str('Motor', motor.port)); @@ -525,6 +553,28 @@ classdef Motor < MaskedHandle & dynamicprops end end + function setBrake(motor, brake) + %setBrake Apply or release brake of motor + % + % Arguments + % * brake (0/1/off/on/'false'/'true') + + if ~isBool(brake) + error('Motor::setBrake: Given parameter is not a valid bool.'); + else + brake = str2bool(brake); + end + + + if brake + motor.applyBrake(); + else + motor.releaseBrake(); + end + + motor.sendOnStart = SendOnStart.Power + SendOnStart.Stop; + end + %% Setter function set.power(motor, power) if ~isnumeric(power) @@ -535,22 +585,37 @@ classdef Motor < MaskedHandle & dynamicprops end motor.power = power; % Set power parameter. - motor.sendPowerOnNextStart = true; % Indicate that virtual and physical brick have different power - % parameters right now. See 'setPower' for more info. - if motor.sendPowerOnSet && motor.connectedToBrick && ... - motor.physicalMotorConnected - motor.setPower(power); % Update physical brick's power parameter. + if motor.sendPowerOnSet + success = motor.setPower(power); + if ~success + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1); + else + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 0); + end end end function set.speedRegulation(motor, speedRegulation) if ~isBool(speedRegulation) error('Motor::set.speedRegulation: Given parameter is not a bool.'); +% elseif motor.connectedToBrick && motor.physicalMotorConnected +% pause(0.5); +% if motor.currentSpeed ~= 0 +% error(['Motor::set.speedRegulation: Cannot change speed regulation while ', ... +% 'is motor is moving.']); +% end end - motor.speedRegulation = str2bool(speedRegulation); - motor.sendPowerOnNextStart = true; + speedRegulation = str2bool(speedRegulation); + + if ~isempty(motor.speedRegulation) && (speedRegulation ~= motor.speedRegulation) + if motor.sendPowerOnSet + motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1); + end + end + + motor.speedRegulation = speedRegulation; end function set.smoothStart(motor, steps) @@ -561,11 +626,6 @@ classdef Motor < MaskedHandle & dynamicprops error('Motor::set.smoothStart: Smooth start steps are out of bounds.'); end -% if ~isempty(motor.limitValue) && steps>motor.limitValue -% warning(['Motor::set.smoothStart: Smooth start steps are greater than ',... -% 'limitValue.']); -% end - motor.smoothStart = steps; end @@ -577,33 +637,26 @@ classdef Motor < MaskedHandle & dynamicprops error('Motor::set.smoothStop: Smooth stop steps are out of bounds.'); end -% if ~isempty(motor.limitValue) && steps>motor.limitValue -% error(['Motor::set.smoothStop: Smooth stop steps are greater than ',... -% 'limitValue.']); -% end - motor.smoothStop = steps; end function set.brakeMode(motor, brakeMode) - validModes = {'Coast', 'Brake'}; - if ~motor.init - oldMode = motor.brakeMode_; - end - - if ~ischar(brakeMode) || ~ismember(brakeMode, validModes) + if ~ischar(brakeMode) || ... + (~strcmpi(brakeMode, 'coast') && ~strcmpi(brakeMode, 'brake')) error('Motor::set.brakeMode: Given parameter is not a valid brake mode.'); end - motor.brakeMode = brakeMode; - motor.brakeMode_ = str2brake(brakeMode); - - - if ~motor.init && motor.brakeMode_~=oldMode && ... + % If new brakeMode is 'Brake': reset internal tachocount once + % Note: if new brakeMode is 'Coast', internal tachocount is always reset + % right before starting, so it's not necessary here + if ~motor.init && strcmpi(brakeMode,'Brake') && ... motor.connectedToBrick && motor.physicalMotorConnected - motor.reset(); -% motor.setBrakeMode(); + motor.internalReset(); end + + + motor.brakeMode = brakeMode; + motor.brakeMode_ = str2brake(brakeMode); end function set.limitMode(motor, limitMode) @@ -621,16 +674,16 @@ classdef Motor < MaskedHandle & dynamicprops elseif limitValue<0 warning('Motor::set.limitValue: limitValue has to be positive!'); error('Motor::set.limitValue: Given limitValue is out of bounds.'); - elseif any(motor.limitValue) - if limitValue==0 && motor.limitValue~=0 - motor.sendPowerOnNextStart = true; - motor.limitSetToZero = true; - end - end - + end + if limitValue == 0 + motor.sendOnStart = SendOnStart.Power; + if ~isempty(motor.limitValue) && motor.limitValue > 0 + motor.sendOnStart = motor.sendOnStart + SendOnStart.Stop; + end motor.sendPowerOnSet = true; else + motor.sendOnStart = 0; motor.sendPowerOnSet = false; end @@ -737,9 +790,9 @@ classdef Motor < MaskedHandle & dynamicprops motor.smoothStart = p.Results.smoothStart; motor.smoothStop = p.Results.smoothStop; - if motor.limitValue == 0 - motor.sendPowerOnSet = true; - end +% if motor.limitValue == 0 +% motor.sendPowerOnSet = true; +% end end %% Getter @@ -763,6 +816,18 @@ classdef Motor < MaskedHandle & dynamicprops end end + function cnt = get.internalTachoCount(motor) + cnt = 0; + if motor.connectedToBrick + cnt = motor.getInternalTachoCount(); + if isnan(cnt) + warning('Motor::get.internalTachoCount: Could not detect motor at port %s.', ... + port2str('Motor', motor.port)); + cnt = 0; + end + end + end + function speed = get.currentSpeed(motor) speed = 0; if motor.connectedToBrick @@ -776,7 +841,10 @@ classdef Motor < MaskedHandle & dynamicprops end function running = get.isRunning(motor) - running = (motor.currentSpeed~=0); + running = 0; + if motor.connectedToBrick + running = motor.getBusyFlag(); + end end function synced = get.isSynced(motor) @@ -802,8 +870,8 @@ classdef Motor < MaskedHandle & dynamicprops end end - methods (Access = 'private') % Private brick functions that are wrapped by dependent params - function setPower(motor, power) + methods (Access = 'private') % Private functions that directly interact with commLayer + function success = setPower(motor, power) %setPower Sets given power value on the physical Brick. % % Notes: @@ -813,9 +881,10 @@ classdef Motor < MaskedHandle & dynamicprops % with the new value instantly. However, this sometimes leads to unexpected behaviour. % Therefore, if motor is running with a limit, setPower aborts with a warning. % - if ~motor.connectedToBrick - error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + if ~motor.connectedToBrick || ~motor.physicalMotorConnected +% error('Motor::getTachoCount: Motor-Object not connected to comm handle.'); + success = false; + return; end % assert(motor.physicalMotorConnected==true); @@ -834,13 +903,14 @@ classdef Motor < MaskedHandle & dynamicprops fprintf('(DEBUG) Motor::setPower: Called outputPower on Port %s\n', port2str('Motor', motor.port)); end end - motor.sendPowerOnNextStart = false; - end + %motor.sendPowerOnNextStart = false; + success = true; + return; + end function setMode(motor, mode) %% DEPRECATED if ~motor.connectedToBrick - error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::getTachoCount: Motor-Object not connected to comm handle.'); elseif ~motor.physicalMotorConnected error('Motor::getTachoCount: No physical motor connected to Port %s',... port2str('Motor', motor.port)); @@ -857,8 +927,7 @@ classdef Motor < MaskedHandle & dynamicprops function [type,mode] = getTypeMode(motor) if ~motor.connectedToBrick - error(['Motor::getTypeMode: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::getTypeMode: Motor-Object not connected to comm handle.'); end [typeNo,modeNo] = motor.commInterface.inputDeviceGetTypeMode(0, motor.portInput); @@ -873,8 +942,7 @@ classdef Motor < MaskedHandle & dynamicprops function status = getStatus(motor) if ~motor.connectedToBrick - error(['Motor::getStatus: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::getStatus: Motor-Object not connected to comm handle.'); end statusNo = motor.commInterface.inputDeviceGetConnection(0, motor.portInput); @@ -888,8 +956,7 @@ classdef Motor < MaskedHandle & dynamicprops function cnt = getTachoCount(motor) if ~motor.connectedToBrick - error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::getTachoCount: Motor-Object not connected to comm handle.'); end cnt = motor.commInterface.outputGetCount(0, motor.portNo); @@ -898,10 +965,16 @@ classdef Motor < MaskedHandle & dynamicprops end end + function cnt = getInternalTachoCount(motor) + [~, cnt] = motor.commInterface.outputRead(0, motor.portNo); + if motor.debug + fprintf('(DEBUG) Motor::getInternalTachoCount: Called outputRead on Port %s\n', port2str('Motor', motor.port)); + end + end + function speed = getSpeed(motor) if ~motor.connectedToBrick - error(['Motor::getSpeed: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); + error('Motor::getSpeed: Motor-Object not connected to comm handle.'); end speed = motor.commInterface.inputReadSI(0, motor.portInput, DeviceMode.Motor.Speed); @@ -911,26 +984,71 @@ classdef Motor < MaskedHandle & dynamicprops end end - function running = getMotorStatus(motor) - %getMotorStatus Returns whether motor is running (WITH TACHOLIMIT) or not. + function busy = getBusyFlag(motor) + %getMotorStatus Returns whether motor is busy or not. % % Notes: % * This *mostly* works. Sometimes this falsely returns 0 if isRunning() gets % called immediately after starting the motor. + % * Busy is set to true if motor is running with tacholimit or synced % if ~motor.connectedToBrick - error(['Motor::isRunning: Motor-Object not connected to comm handle.',... - 'You have to call motor.connect(commInterface) first!']); - elseif ~motor.tachoLimit - warning(['Motor::isRunning: Motor has no tacho limit. ' ,... - 'Can''t reliably determine whether it is running or not.']); + error('Motor::getBusyFlag: Motor-Object not connected to comm handle.'); end - running = motor.commInterface.outputTest(0, motor.port); + busy = motor.commInterface.outputTest(0, motor.port); + + if motor.debug + fprintf('(DEBUG) Motor::getBusyFlag: Called outputTest on Port %s\n', port2str('Motor', motor.port)); + end + end + + function applyBrake(motor) + if ~motor.connectedToBrick + error('Motor::applyBrake: Motor-Object not connected to comm handle.'); + elseif ~motor.physicalMotorConnected + error('Motor::applyBrake: No physical motor connected to Port %s',... + port2str('Motor', motor.port)); + elseif motor.currentSpeed~=0 + error('Motor::applyBrake: Can''t apply brake because Motor is moving'); + end + + if motor.speedRegulation + motor.commInterface.outputPower(0, motor.port, 0); + else + motor.commInterface.outputSpeed(0, motor.port, 0); + end + motor.commInterface.outputStart(0, motor.port); + motor.commInterface.outputStop(0, motor.port, BrakeMode.Brake); + + if motor.debug + fprintf(['(DEBUG) Motor::applyBrake: Called outputPower, outputStart and' ,... + 'outputStop on Port %s\n'], port2str('Motor', motor.port)); + end + end + + function releaseBrake(motor) + if ~motor.connectedToBrick + error('Motor::releaseBrake: Motor-Object not connected to comm handle.'); + elseif ~motor.physicalMotorConnected + error('Motor::releaseBrake: No physical motor connected to Port %s',... + port2str('Motor', motor.port)); + elseif motor.currentSpeed~=0 + error('Motor::releaseBrake: Can''t releaseBrake brake because Motor is moving'); + end + + if motor.speedRegulation + motor.commInterface.outputPower(0, motor.port, 0); + else + motor.commInterface.outputSpeed(0, motor.port, 0); + end + motor.commInterface.outputStart(0, motor.port); + motor.commInterface.outputStop(0, motor.port, BrakeMode.Coast); if motor.debug - fprintf('(DEBUG) Motor::isRunning: Called outputReady on Port %s\n', port2str('Motor', motor.port)); + fprintf(['(DEBUG) Motor::releaseBrake: Called outputPower, outputStart and' ,... + 'outputStop on Port %s\n'], port2str('Motor', motor.port)); end end end @@ -961,8 +1079,7 @@ classdef Motor < MaskedHandle & dynamicprops 'comm handle is invalid. Deleting invalid handle and ' ,... 'resetting Motor.connectedToBrick now...']); - motor.commInterface = 0; - motor.connectedToBrick = false; + motor.disconnect(); error('Motor::connect: Disconnected due to internal error.'); end diff --git a/source/SendOnStart.m b/source/SendOnStart.m new file mode 100644 index 0000000000000000000000000000000000000000..ee7423d17b2a98083c73005057e111db487f2197 --- /dev/null +++ b/source/SendOnStart.m @@ -0,0 +1,7 @@ +classdef SendOnStart < uint8 + enumeration + Power (1) + Stop (2) + end +end + diff --git a/source/Sensor.m b/source/Sensor.m index 78d9ce6080bd2b7ad2bc91620b8e16abafa56dd4..dc12c91ee81442ee867bb17af76365a0649ed79e 100755 --- a/source/Sensor.m +++ b/source/Sensor.m @@ -72,15 +72,14 @@ classdef Sensor < MaskedHandle %reset Resets value on sensor % Note: This clears ALL the sensors right now, no other Op-Code available... :( if ~sensor.connectedToBrick - error(['Sensor::reset: Sensor-Object not connected to comm handle.',... - 'You have to call sensor.connect(commInterface) first!']); + error('Sensor::reset: Sensor-Object not connected to comm handle.'); elseif ~sensor.physicalSensorConnected error('Sensor::reset: No physical sensor connected to Port %d.',... sensor.port+1); end - warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',... - 'all motor tacho counts and all other sensor counters!']); +% warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',... +% 'all motor tacho counts and all other sensor counters!']); sensor.commInterface.inputDeviceClrAll(0); if sensor.debug @@ -225,8 +224,7 @@ classdef Sensor < MaskedHandle methods (Access = 'private') % Private brick functions that are wrapped by dependent params function setMode(sensor, mode) if ~sensor.connectedToBrick - error(['Sensor::getTachoCount: Sensor-Object not connected to comm handle.',... - 'You have to call sensor.connect(commInterface) first!']); + error('Sensor::getTachoCount: Sensor-Object not connected to comm handle.'); elseif ~sensor.physicalSensorConnected error('Sensor::getTachoCount: No physical sensor connected to Port %d',... sensor.port+1); @@ -261,8 +259,7 @@ classdef Sensor < MaskedHandle end if ~sensor.connectedToBrick - error(['Sensor::getValue: Sensor-Object not connected to comm handle.',... - 'You have to call sensor.connect(commInterface) first!']); + error('Sensor::getValue: Sensor-Object not connected to comm handle.'); end if defaultMode ~= -1 @@ -294,8 +291,7 @@ classdef Sensor < MaskedHandle function status = getStatus(sensor) if ~sensor.connectedToBrick - error(['Sensor::getStatus: Sensor-Object not connected to comm handle.',... - 'You have to call sensor.connect(commInterface) first!']); + error('Sensor::getStatus: Sensor-Object not connected to comm handle.'); end statusNo = sensor.commInterface.inputDeviceGetConnection(0, sensor.port); @@ -309,8 +305,7 @@ classdef Sensor < MaskedHandle function [type,mode] = getTypeMode(sensor) if ~sensor.connectedToBrick - error(['Sensor::getTypeMode: Sensor-Object not connected to comm handle.',... - 'You have to call sensor.connect(commInterface) first!']); + error('Sensor::getTypeMode: Sensor-Object not connected to comm handle.'); end [typeNo,modeNo] = sensor.commInterface.inputDeviceGetTypeMode(0, sensor.port); diff --git a/source/btBrickIO.m b/source/btBrickIO.m index 90a3e51ccbff4545bd74a1ea5ddc5410f50ecd8b..02946f677e153d650af1a0195670a0e426e59df0 100755 --- a/source/btBrickIO.m +++ b/source/btBrickIO.m @@ -180,7 +180,7 @@ classdef btBrickIO < BrickIO id = [ID(), ':', 'UnknownError']; newException = MException(id, msg); newException = addCause(newException, ME); - throw(newException);b.bee + throw(newException); end end