Skip to content
Snippets Groups Projects
Commit 38cfc40b authored by Tim Stadtmann's avatar Tim Stadtmann
Browse files

Merge branch 'develop'

Patches master to version 0.3-rc.3.
parents 8c7aca87 88f22201
No related branches found
No related tags found
No related merge requests found
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
% 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 = EV3('debug', 0);
b.connect('usb'); b.connect('usb');
...@@ -15,8 +24,11 @@ hold on; ...@@ -15,8 +24,11 @@ hold on;
while toc < 20 while toc < 20
readings = [readings, s.value]; readings = [readings, s.value];
time = [time, toc]; time = [time, toc];
% plot(time, readings)
% drawnow %% Plotting
% Should be commented out if you analyse latency of sensor readings
plot(time, readings)
drawnow
end end
hold off; hold off;
...@@ -24,6 +36,8 @@ fprintf('\nSensor readings per sec: %f\n', length(readings)/time(length(time))); ...@@ -24,6 +36,8 @@ fprintf('\nSensor readings per sec: %f\n', length(readings)/time(length(time)));
b.disconnect(); b.disconnect();
clear all
%% Results %% Results
% Bluetooth % Bluetooth
% debug=2, sensor-typ-kontrolle an: 7.5 Readings/sec % worst case % debug=2, sensor-typ-kontrolle an: 7.5 Readings/sec % worst case
......
% 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
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
...@@ -2202,7 +2202,7 @@ classdef Command < handle ...@@ -2202,7 +2202,7 @@ classdef Command < handle
cmd.GV0(speed); cmd.GV0(speed);
end end
function opOUTPUT_TEST(cmd,layer,nos,value) function opOUTPUT_TEST(cmd,layer,nos,busy)
% Command.opOUTPUT_TEST Add a opOUTPUT_TEST % Command.opOUTPUT_TEST Add a opOUTPUT_TEST
% %
% Command.opOUTPUT_READ(layer,nos) adds a opOUTPUT_TEST opcode % Command.opOUTPUT_READ(layer,nos) adds a opOUTPUT_TEST opcode
...@@ -2222,7 +2222,7 @@ classdef Command < handle ...@@ -2222,7 +2222,7 @@ classdef Command < handle
cmd.addDirectCommand(ByteCodes.OutputTest); cmd.addDirectCommand(ByteCodes.OutputTest);
cmd.LC0(layer); cmd.LC0(layer);
cmd.LC0(nos); cmd.LC0(nos);
cmd.GV0(value); cmd.GV0(busy);
end end
function opOUTPUT_READY(cmd,layer,nos) function opOUTPUT_READY(cmd,layer,nos)
......
...@@ -307,8 +307,8 @@ classdef CommunicationInterface < handle ...@@ -307,8 +307,8 @@ classdef CommunicationInterface < handle
corrupt = 1; corrupt = 1;
if ~isempty(strfind(ME.identifier, 'CorruptPacket')) if ~isempty(strfind(ME.identifier, 'CorruptPacket'))
% Read packet was corrupt - retry % Read packet was corrupt - retry
id = [ID(), ':', 'CorruptPacket']; %id = [ID(), ':', 'CorruptPacket'];
warning(id, 'Read corrupt packet. Retrying...'); %warning(id, 'Read corrupt packet. Retrying...');
if brick.debug if brick.debug
fprintf('received (corrupt) (hex): [ '); fprintf('received (corrupt) (hex): [ ');
for ii=1:length(rmsg) for ii=1:length(rmsg)
......
...@@ -94,16 +94,17 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -94,16 +94,17 @@ classdef Motor < MaskedHandle & dynamicprops
% to be sent, is saved (hidden from the user). % to be sent, is saved (hidden from the user).
brakeMode_; brakeMode_;
%% Miscallenous flags %% Flags
connectedToBrick = false; % Connection to physical Brick? 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)
init = true; % Indicates 'init-phase' (True as long as constructor is running) 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 end
properties (Hidden, Dependent, Access = 'private') % Hidden, dependent properties for internal use only properties (Hidden, Dependent, Access = 'private') % Hidden, dependent properties for internal use only
...@@ -112,6 +113,8 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -112,6 +113,8 @@ classdef Motor < MaskedHandle & dynamicprops
isSynced; % Is motor running in synced mode? isSynced; % Is motor running in synced mode?
physicalMotorConnected; % Physical motor connected to this port? physicalMotorConnected; % Physical motor connected to this port?
internalTachoCount; % Internal tachocount used for positioning the motor with tacholimit
end end
methods % Standard methods methods % Standard methods
...@@ -150,13 +153,12 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -150,13 +153,12 @@ classdef Motor < MaskedHandle & dynamicprops
% Check connection and if motor is already running % Check connection and if motor is already running
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::start: Motor-Object not connected to comm handle.',... error('Motor::start: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected elseif ~motor.physicalMotorConnected
error('Motor::start: No physical motor connected to Port %s',... error('Motor::start: No physical motor connected to Port %s',...
port2str('Motor', motor.port)); port2str('Motor', motor.port));
elseif motor.isRunning elseif motor.isRunning
error('Motor::start: Motor is already runnning!'); error('Motor::start: Motor is already running!');
end end
% If motor has been started synced with another, and it stopped 'itself' (when % If motor has been started synced with another, and it stopped 'itself' (when
...@@ -164,26 +166,34 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -164,26 +166,34 @@ classdef Motor < MaskedHandle & dynamicprops
% would do so) % would do so)
if motor.isSynced if motor.isSynced
delete(motor.findprop('syncCache')); delete(motor.findprop('syncCache'));
motor.internalReset(); % Better safe than sorry
end end
% Trigger warning if power = 0 (as it still sets the motor internally in a % If the motor coasts into its stops, the internal tachocount has to be reset
% 'running' mode % before each start for it to behave predictable
% if motor.power == 0
% warning('Motor::start: Motor starting with power=0.');
% end
if motor.brakeMode_ == BrakeMode.Coast if motor.brakeMode_ == BrakeMode.Coast
motor.reset(); motor.internalReset();
end 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.limitValue==0
if motor.sendPowerOnNextStart if motor.sendOnStart > 0
if motor.limitSetToZero % If stop-flag is set: call stop() and reset flag
if bitget(motor.sendOnStart, SendOnStart.Stop)
motor.stop(); motor.stop();
motor.limitSetToZero = false; motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Stop, 0);
end
% 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
motor.setPower(motor.power); end
end end
motor.commInterface.outputStart(0, motor.port); motor.commInterface.outputStart(0, motor.port);
...@@ -246,8 +256,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -246,8 +256,7 @@ classdef Motor < MaskedHandle & dynamicprops
%stop Stops the motor %stop Stops the motor
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::stop: Motor-Object not connected to comm handle.',... error('Motor::stop: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected elseif ~motor.physicalMotorConnected
error('Motor::stop: No physical motor connected to Port %s',... error('Motor::stop: No physical motor connected to Port %s',...
port2str('Motor', motor.port)); port2str('Motor', motor.port));
...@@ -322,8 +331,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -322,8 +331,7 @@ classdef Motor < MaskedHandle & dynamicprops
% Check connection and motor parameter % Check connection and motor parameter
if ~motor.connectedToBrick || ~syncMotor.connectedToBrick if ~motor.connectedToBrick || ~syncMotor.connectedToBrick
error(['Motor::syncedStart: Motor-Object not connected to comm handle.',... error('Motor::syncedStart: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected
error('Motor::syncedStart: No physical motor connected to Port %s or %s.',... error('Motor::syncedStart: No physical motor connected to Port %s or %s.',...
port2str('Motor', motor.port), port2str('Motor', syncMotor.port)); port2str('Motor', motor.port), port2str('Motor', syncMotor.port));
...@@ -338,6 +346,20 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -338,6 +346,20 @@ classdef Motor < MaskedHandle & dynamicprops
warning('Motor::syncedStart: Synchronized motors starting with power=0.'); warning('Motor::syncedStart: Synchronized motors starting with power=0.');
end 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 % 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 % Note: the existence of 'syncCache' is also used to determine whether motor is
% running synchronized or not, see get.isSynced() % running synchronized or not, see get.isSynced()
...@@ -397,8 +419,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -397,8 +419,7 @@ classdef Motor < MaskedHandle & dynamicprops
syncMotor = motor.syncCache.slave; syncMotor = motor.syncCache.slave;
if ~motor.connectedToBrick || ~syncMotor.connectedToBrick if ~motor.connectedToBrick || ~syncMotor.connectedToBrick
error(['Motor::syncedStop: Motor-Object not connected to comm handle.',... error('Motor::syncedStop: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected elseif ~motor.physicalMotorConnected || ~syncMotor.physicalMotorConnected
error('Motor::syncedStop: No physical motor connected to either Port %s or %s.',... error('Motor::syncedStop: No physical motor connected to either Port %s or %s.',...
port2str('Motor', motor.port), port2str('Motor', syncMotor.port)); port2str('Motor', motor.port), port2str('Motor', syncMotor.port));
...@@ -406,18 +427,24 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -406,18 +427,24 @@ classdef Motor < MaskedHandle & dynamicprops
% Retrieve other values from cache and delete it % Retrieve other values from cache and delete it
motor.sendPowerOnSet = motor.syncCache.master_oldSendPowerOnSet; 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')); delete(motor.findprop('syncCache'));
% Synced stopping % Synced stopping
motor.commInterface.outputStop(0, motor.port+syncMotor.port, motor.brakeMode_); motor.commInterface.outputStop(0, motor.port+syncMotor.port, motor.brakeMode_);
% On next start, both motors have to send power-opcode again % On next start, both motors have to send power-opcode again
motor.sendPowerOnNextStart = true; if motor.sendPowerOnSet
syncMotor.sendPowerOnNextStart = true; motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1);
end
if syncMotor.sendPowerOnSet
syncMotor.sendOnStart = bitset(syncMotor.sendOnStart, SendOnStart.Power, 1);
end
if motor.debug 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)); port2str('Motor', motor.port), port2str('Motor', syncMotor.port));
end end
end end
...@@ -436,17 +463,16 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -436,17 +463,16 @@ classdef Motor < MaskedHandle & dynamicprops
% outputReady returns in less than a second, another while-loop iterates until % 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 % the motor has stopped, this time using motor.isRunning() (this only works as
% long as not both OutputTest and OutputReady are buggy). % 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 % -> No need to check if motor is connected as speed correctly
% returns 0 if it's not % returns 0 if it's not
% %
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::waitFor: Motor-Object not connected to comm handle.',... error('Motor::waitFor: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
end end
pause(0.1); %pause(0.1);
while motor.isRunning while motor.isRunning
pause(0.03); pause(0.03);
end end
...@@ -481,37 +507,39 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -481,37 +507,39 @@ classdef Motor < MaskedHandle & dynamicprops
% end % end
end end
function reset(motor) function internalReset(motor)
%reset Resets internal tacho count % internalReset Resets internal tacho count
% The internal tacho count is used for positioning the motor. For example, when the % 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 % 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 % 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 % See also MOTOR.RESETTACHOCOUNT
% %
if ~motor.connectedToBrick 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!']); 'You have to call motor.connect(brick) first!']);
elseif ~motor.physicalMotorConnected 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)); port2str('Motor', motor.port));
end end
motor.commInterface.outputReset(0, motor.port); motor.commInterface.outputReset(0, motor.port);
if motor.debug 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)); port2str('Motor', motor.port));
end end
end end
function resetTachoCount(motor) function resetTachoCount(motor)
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::resetTachoCount: Motor-Object not connected to comm handle.',... error('Motor::resetTachoCount: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected elseif ~motor.physicalMotorConnected
error('Motor::resetTachoCount: No physical motor connected to Port %s',... error('Motor::resetTachoCount: No physical motor connected to Port %s',...
port2str('Motor', motor.port)); port2str('Motor', motor.port));
...@@ -525,6 +553,28 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -525,6 +553,28 @@ classdef Motor < MaskedHandle & dynamicprops
end end
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 %% Setter
function set.power(motor, power) function set.power(motor, power)
if ~isnumeric(power) if ~isnumeric(power)
...@@ -535,22 +585,37 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -535,22 +585,37 @@ classdef Motor < MaskedHandle & dynamicprops
end end
motor.power = power; % Set power parameter. 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 && ... if motor.sendPowerOnSet
motor.physicalMotorConnected success = motor.setPower(power);
motor.setPower(power); % Update physical brick's power parameter. if ~success
motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1);
else
motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 0);
end
end end
end end
function set.speedRegulation(motor, speedRegulation) function set.speedRegulation(motor, speedRegulation)
if ~isBool(speedRegulation) if ~isBool(speedRegulation)
error('Motor::set.speedRegulation: Given parameter is not a bool.'); 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
speedRegulation = str2bool(speedRegulation);
if ~isempty(motor.speedRegulation) && (speedRegulation ~= motor.speedRegulation)
if motor.sendPowerOnSet
motor.sendOnStart = bitset(motor.sendOnStart, SendOnStart.Power, 1);
end
end end
motor.speedRegulation = str2bool(speedRegulation); motor.speedRegulation = speedRegulation;
motor.sendPowerOnNextStart = true;
end end
function set.smoothStart(motor, steps) function set.smoothStart(motor, steps)
...@@ -561,11 +626,6 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -561,11 +626,6 @@ classdef Motor < MaskedHandle & dynamicprops
error('Motor::set.smoothStart: Smooth start steps are out of bounds.'); error('Motor::set.smoothStart: Smooth start steps are out of bounds.');
end end
% if ~isempty(motor.limitValue) && steps>motor.limitValue
% warning(['Motor::set.smoothStart: Smooth start steps are greater than ',...
% 'limitValue.']);
% end
motor.smoothStart = steps; motor.smoothStart = steps;
end end
...@@ -577,33 +637,26 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -577,33 +637,26 @@ classdef Motor < MaskedHandle & dynamicprops
error('Motor::set.smoothStop: Smooth stop steps are out of bounds.'); error('Motor::set.smoothStop: Smooth stop steps are out of bounds.');
end end
% if ~isempty(motor.limitValue) && steps>motor.limitValue
% error(['Motor::set.smoothStop: Smooth stop steps are greater than ',...
% 'limitValue.']);
% end
motor.smoothStop = steps; motor.smoothStop = steps;
end end
function set.brakeMode(motor, brakeMode) function set.brakeMode(motor, brakeMode)
validModes = {'Coast', 'Brake'}; if ~ischar(brakeMode) || ...
if ~motor.init (~strcmpi(brakeMode, 'coast') && ~strcmpi(brakeMode, 'brake'))
oldMode = motor.brakeMode_; error('Motor::set.brakeMode: Given parameter is not a valid brake mode.');
end end
if ~ischar(brakeMode) || ~ismember(brakeMode, validModes) % If new brakeMode is 'Brake': reset internal tachocount once
error('Motor::set.brakeMode: Given parameter is not a valid brake mode.'); % 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.internalReset();
end end
motor.brakeMode = brakeMode; motor.brakeMode = brakeMode;
motor.brakeMode_ = str2brake(brakeMode); motor.brakeMode_ = str2brake(brakeMode);
if ~motor.init && motor.brakeMode_~=oldMode && ...
motor.connectedToBrick && motor.physicalMotorConnected
motor.reset();
% motor.setBrakeMode();
end
end end
function set.limitMode(motor, limitMode) function set.limitMode(motor, limitMode)
...@@ -621,16 +674,16 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -621,16 +674,16 @@ classdef Motor < MaskedHandle & dynamicprops
elseif limitValue<0 elseif limitValue<0
warning('Motor::set.limitValue: limitValue has to be positive!'); warning('Motor::set.limitValue: limitValue has to be positive!');
error('Motor::set.limitValue: Given limitValue is out of bounds.'); 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 if limitValue == 0
motor.sendOnStart = SendOnStart.Power;
if ~isempty(motor.limitValue) && motor.limitValue > 0
motor.sendOnStart = motor.sendOnStart + SendOnStart.Stop;
end
motor.sendPowerOnSet = true; motor.sendPowerOnSet = true;
else else
motor.sendOnStart = 0;
motor.sendPowerOnSet = false; motor.sendPowerOnSet = false;
end end
...@@ -737,9 +790,9 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -737,9 +790,9 @@ classdef Motor < MaskedHandle & dynamicprops
motor.smoothStart = p.Results.smoothStart; motor.smoothStart = p.Results.smoothStart;
motor.smoothStop = p.Results.smoothStop; motor.smoothStop = p.Results.smoothStop;
if motor.limitValue == 0 % if motor.limitValue == 0
motor.sendPowerOnSet = true; % motor.sendPowerOnSet = true;
end % end
end end
%% Getter %% Getter
...@@ -763,6 +816,18 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -763,6 +816,18 @@ classdef Motor < MaskedHandle & dynamicprops
end end
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) function speed = get.currentSpeed(motor)
speed = 0; speed = 0;
if motor.connectedToBrick if motor.connectedToBrick
...@@ -776,7 +841,10 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -776,7 +841,10 @@ classdef Motor < MaskedHandle & dynamicprops
end end
function running = get.isRunning(motor) function running = get.isRunning(motor)
running = (motor.currentSpeed~=0); running = 0;
if motor.connectedToBrick
running = motor.getBusyFlag();
end
end end
function synced = get.isSynced(motor) function synced = get.isSynced(motor)
...@@ -802,8 +870,8 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -802,8 +870,8 @@ classdef Motor < MaskedHandle & dynamicprops
end end
end end
methods (Access = 'private') % Private brick functions that are wrapped by dependent params methods (Access = 'private') % Private functions that directly interact with commLayer
function setPower(motor, power) function success = setPower(motor, power)
%setPower Sets given power value on the physical Brick. %setPower Sets given power value on the physical Brick.
% %
% Notes: % Notes:
...@@ -813,9 +881,10 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -813,9 +881,10 @@ classdef Motor < MaskedHandle & dynamicprops
% with the new value instantly. However, this sometimes leads to unexpected behaviour. % 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. % Therefore, if motor is running with a limit, setPower aborts with a warning.
% %
if ~motor.connectedToBrick if ~motor.connectedToBrick || ~motor.physicalMotorConnected
error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... % error('Motor::getTachoCount: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']); success = false;
return;
end end
% assert(motor.physicalMotorConnected==true); % assert(motor.physicalMotorConnected==true);
...@@ -834,13 +903,14 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -834,13 +903,14 @@ classdef Motor < MaskedHandle & dynamicprops
fprintf('(DEBUG) Motor::setPower: Called outputPower on Port %s\n', port2str('Motor', motor.port)); fprintf('(DEBUG) Motor::setPower: Called outputPower on Port %s\n', port2str('Motor', motor.port));
end end
end end
motor.sendPowerOnNextStart = false; %motor.sendPowerOnNextStart = false;
success = true;
return;
end end
function setMode(motor, mode) %% DEPRECATED function setMode(motor, mode) %% DEPRECATED
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... error('Motor::getTachoCount: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
elseif ~motor.physicalMotorConnected elseif ~motor.physicalMotorConnected
error('Motor::getTachoCount: No physical motor connected to Port %s',... error('Motor::getTachoCount: No physical motor connected to Port %s',...
port2str('Motor', motor.port)); port2str('Motor', motor.port));
...@@ -857,8 +927,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -857,8 +927,7 @@ classdef Motor < MaskedHandle & dynamicprops
function [type,mode] = getTypeMode(motor) function [type,mode] = getTypeMode(motor)
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::getTypeMode: Motor-Object not connected to comm handle.',... error('Motor::getTypeMode: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
end end
[typeNo,modeNo] = motor.commInterface.inputDeviceGetTypeMode(0, motor.portInput); [typeNo,modeNo] = motor.commInterface.inputDeviceGetTypeMode(0, motor.portInput);
...@@ -873,8 +942,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -873,8 +942,7 @@ classdef Motor < MaskedHandle & dynamicprops
function status = getStatus(motor) function status = getStatus(motor)
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::getStatus: Motor-Object not connected to comm handle.',... error('Motor::getStatus: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
end end
statusNo = motor.commInterface.inputDeviceGetConnection(0, motor.portInput); statusNo = motor.commInterface.inputDeviceGetConnection(0, motor.portInput);
...@@ -888,8 +956,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -888,8 +956,7 @@ classdef Motor < MaskedHandle & dynamicprops
function cnt = getTachoCount(motor) function cnt = getTachoCount(motor)
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::getTachoCount: Motor-Object not connected to comm handle.',... error('Motor::getTachoCount: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
end end
cnt = motor.commInterface.outputGetCount(0, motor.portNo); cnt = motor.commInterface.outputGetCount(0, motor.portNo);
...@@ -898,10 +965,16 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -898,10 +965,16 @@ classdef Motor < MaskedHandle & dynamicprops
end end
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) function speed = getSpeed(motor)
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::getSpeed: Motor-Object not connected to comm handle.',... error('Motor::getSpeed: Motor-Object not connected to comm handle.');
'You have to call motor.connect(commInterface) first!']);
end end
speed = motor.commInterface.inputReadSI(0, motor.portInput, DeviceMode.Motor.Speed); speed = motor.commInterface.inputReadSI(0, motor.portInput, DeviceMode.Motor.Speed);
...@@ -911,26 +984,71 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -911,26 +984,71 @@ classdef Motor < MaskedHandle & dynamicprops
end end
end end
function running = getMotorStatus(motor) function busy = getBusyFlag(motor)
%getMotorStatus Returns whether motor is running (WITH TACHOLIMIT) or not. %getMotorStatus Returns whether motor is busy or not.
% %
% Notes: % Notes:
% * This *mostly* works. Sometimes this falsely returns 0 if isRunning() gets % * This *mostly* works. Sometimes this falsely returns 0 if isRunning() gets
% called immediately after starting the motor. % called immediately after starting the motor.
% * Busy is set to true if motor is running with tacholimit or synced
% %
if ~motor.connectedToBrick if ~motor.connectedToBrick
error(['Motor::isRunning: Motor-Object not connected to comm handle.',... error('Motor::getBusyFlag: 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.']);
end end
running = motor.commInterface.outputTest(0, motor.port); busy = motor.commInterface.outputTest(0, motor.port);
if motor.debug if motor.debug
fprintf('(DEBUG) Motor::isRunning: Called outputReady on Port %s\n', port2str('Motor', motor.port)); 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::releaseBrake: Called outputPower, outputStart and' ,...
'outputStop on Port %s\n'], port2str('Motor', motor.port));
end end
end end
end end
...@@ -961,8 +1079,7 @@ classdef Motor < MaskedHandle & dynamicprops ...@@ -961,8 +1079,7 @@ classdef Motor < MaskedHandle & dynamicprops
'comm handle is invalid. Deleting invalid handle and ' ,... 'comm handle is invalid. Deleting invalid handle and ' ,...
'resetting Motor.connectedToBrick now...']); 'resetting Motor.connectedToBrick now...']);
motor.commInterface = 0; motor.disconnect();
motor.connectedToBrick = false;
error('Motor::connect: Disconnected due to internal error.'); error('Motor::connect: Disconnected due to internal error.');
end end
......
classdef SendOnStart < uint8
enumeration
Power (1)
Stop (2)
end
end
...@@ -72,15 +72,14 @@ classdef Sensor < MaskedHandle ...@@ -72,15 +72,14 @@ classdef Sensor < MaskedHandle
%reset Resets value on sensor %reset Resets value on sensor
% Note: This clears ALL the sensors right now, no other Op-Code available... :( % Note: This clears ALL the sensors right now, no other Op-Code available... :(
if ~sensor.connectedToBrick if ~sensor.connectedToBrick
error(['Sensor::reset: Sensor-Object not connected to comm handle.',... error('Sensor::reset: Sensor-Object not connected to comm handle.');
'You have to call sensor.connect(commInterface) first!']);
elseif ~sensor.physicalSensorConnected elseif ~sensor.physicalSensorConnected
error('Sensor::reset: No physical sensor connected to Port %d.',... error('Sensor::reset: No physical sensor connected to Port %d.',...
sensor.port+1); sensor.port+1);
end end
warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',... % warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',...
'all motor tacho counts and all other sensor counters!']); % 'all motor tacho counts and all other sensor counters!']);
sensor.commInterface.inputDeviceClrAll(0); sensor.commInterface.inputDeviceClrAll(0);
if sensor.debug if sensor.debug
...@@ -225,8 +224,7 @@ classdef Sensor < MaskedHandle ...@@ -225,8 +224,7 @@ classdef Sensor < MaskedHandle
methods (Access = 'private') % Private brick functions that are wrapped by dependent params methods (Access = 'private') % Private brick functions that are wrapped by dependent params
function setMode(sensor, mode) function setMode(sensor, mode)
if ~sensor.connectedToBrick if ~sensor.connectedToBrick
error(['Sensor::getTachoCount: Sensor-Object not connected to comm handle.',... error('Sensor::getTachoCount: Sensor-Object not connected to comm handle.');
'You have to call sensor.connect(commInterface) first!']);
elseif ~sensor.physicalSensorConnected elseif ~sensor.physicalSensorConnected
error('Sensor::getTachoCount: No physical sensor connected to Port %d',... error('Sensor::getTachoCount: No physical sensor connected to Port %d',...
sensor.port+1); sensor.port+1);
...@@ -261,8 +259,7 @@ classdef Sensor < MaskedHandle ...@@ -261,8 +259,7 @@ classdef Sensor < MaskedHandle
end end
if ~sensor.connectedToBrick if ~sensor.connectedToBrick
error(['Sensor::getValue: Sensor-Object not connected to comm handle.',... error('Sensor::getValue: Sensor-Object not connected to comm handle.');
'You have to call sensor.connect(commInterface) first!']);
end end
if defaultMode ~= -1 if defaultMode ~= -1
...@@ -294,8 +291,7 @@ classdef Sensor < MaskedHandle ...@@ -294,8 +291,7 @@ classdef Sensor < MaskedHandle
function status = getStatus(sensor) function status = getStatus(sensor)
if ~sensor.connectedToBrick if ~sensor.connectedToBrick
error(['Sensor::getStatus: Sensor-Object not connected to comm handle.',... error('Sensor::getStatus: Sensor-Object not connected to comm handle.');
'You have to call sensor.connect(commInterface) first!']);
end end
statusNo = sensor.commInterface.inputDeviceGetConnection(0, sensor.port); statusNo = sensor.commInterface.inputDeviceGetConnection(0, sensor.port);
...@@ -309,8 +305,7 @@ classdef Sensor < MaskedHandle ...@@ -309,8 +305,7 @@ classdef Sensor < MaskedHandle
function [type,mode] = getTypeMode(sensor) function [type,mode] = getTypeMode(sensor)
if ~sensor.connectedToBrick if ~sensor.connectedToBrick
error(['Sensor::getTypeMode: Sensor-Object not connected to comm handle.',... error('Sensor::getTypeMode: Sensor-Object not connected to comm handle.');
'You have to call sensor.connect(commInterface) first!']);
end end
[typeNo,modeNo] = sensor.commInterface.inputDeviceGetTypeMode(0, sensor.port); [typeNo,modeNo] = sensor.commInterface.inputDeviceGetTypeMode(0, sensor.port);
......
...@@ -180,7 +180,7 @@ classdef btBrickIO < BrickIO ...@@ -180,7 +180,7 @@ classdef btBrickIO < BrickIO
id = [ID(), ':', 'UnknownError']; id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg); newException = MException(id, msg);
newException = addCause(newException, ME); newException = addCause(newException, ME);
throw(newException);b.bee throw(newException);
end end
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment