Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
ev3-toolbox-matlab
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Container registry
Model registry
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
mindstorms
ev3-toolbox-matlab
Commits
185ca274
Commit
185ca274
authored
8 years ago
by
Tim Stadtmann
Browse files
Options
Downloads
Patches
Plain Diff
Remove deprecated SyncMotor-class module
parent
a2abf42e
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
source/_SyncMotor.m
+0
-571
0 additions, 571 deletions
source/_SyncMotor.m
with
0 additions
and
571 deletions
source/_SyncMotor.m
deleted
100755 → 0
+
0
−
571
View file @
a2abf42e
classdef
SyncMotor
<
Motor
% High-level class to synchronize two motors.
%
% This class in combination with Motor.m is supposed to make the silmutaneous use of two
% motors easier. In order to have functionality like physically
% blocking one of the two motors, while they are running, makes the other one stop, or
% starting and stopping two motors with one command, this class overrides some methods from
% Motor to deliver a convenient interface for two Motor-objects at once.
% This proves especially useful when e.g. building some kind of LEGO-'car' that should run straight
% on, and stop and start without delay on either motor.
%
% Properties:
% turnRatio - How tight you turn and to what direction you turn
%
% Notes:
% * You don't need to create instances of this class. The EV3-class provides the method
% coupleMotors that creates a SyncMotor-object given two Motor-objects and automatically
% connects it to the physical brick.
% * An instance of this class affects the motor objects of an EV3 instance only when using
% update(). Therefore, the type, status and mode parameters will be set on both the
% motor objects AND the syncMotor object. Other parameters won't be affected.
% * Polling dependent values that cannot be read from both motors at once
% (tachoCount, speed) will only return the resp. value of the first given motor-object,
% instead of throwing an error.
%
% Example
% % This small example should only roughly demonstrate how to work with synced motors.
% % Establish connection, couple motors A & B, set properties on synced motor and wait
% % until both motors are connected. After starting, output current speed every 100ms
% % until motors are turned off. Then output current tachoCounts and disconnect.
%
% b = EV3();
% b = EV3('batteryMode', 'Voltage');
% b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0');
% s = b.coupleMotors('AB', 'useMotorParams', 0);
% s.setProperties('Power', 50, 'speedRegulation', 'on', ...
% 'limitMode', 'Time', 'limitValue', 5000, 'turnRatio', 50);
% s.limitValue = 5000;
% s.brakeMode = 'Coast';
% b.motorA.speedRegulation = 'on';
% b.motorB.speedRegulation = 'on';
% s.mode = DeviceMode.Motor.Rotations;
% while ~s.motorAtPort
% s.update();
% pause(0.5);
% end
% s.start();
% while s.isRunning()
% fprintf('Speed on A: %d\n',b.motorA.speed);
% fprintf('Speed on B: %d\n',b.motorB.speed);
% pause(0.1);
% end
% s.disconnect(); s.delete();
% b.disconnect(); b.delete();
%
%
% Signature
% Author: Tim Stadtmann
% Date: 2016/05/30
properties
% Standard properties to be set by user
%turnRatio (Excerpt of c_output.c): Turn ratio is how tight you turn and to what direction
% you turn (in [+-200]).
% -> 0 value is moving straight forward
% -> Negative values turn to the left
% -> Positive values turn to the right
% -> Value -100 stops the left motor
% -> Value +100 stops the right motor
% -> Values less than -100 makes the left motor run the opposite
% direction of the right motor (Spin)
% -> Values greater than +100 makes the right motor run the opposite
% direction of the left motor (Spin)
turnRatio
;
% keepSynchronized;
end
properties
(
Hidden
,
Access
=
'private'
)
% Hidden to protect the spamming of display()
motor1
;
motor2
;
end
properties
(
Hidden
,
Dependent
,
Access
=
'protected'
)
% Hidden, dependent properties for internal use only
portNo_sec
;
portInput_sec
;
end
methods
% Standard methods
%% Constructor
function
syncMotor
=
SyncMotor
(
varargin
)
syncMotor
@
Motor
(
varargin
{:});
end
%% Connection
function
update
(
motor
)
% Update individual motor objects to keep status, type and mode synchronized.
motor
.
motor1
.
update
();
motor
.
motor2
.
update
();
% SyncMotor is only counted as 'connected' if both synced physical motors are
% connected.
if
motor
.
motor1
.
motorAtPort
+
motor
.
motor2
.
motorAtPort
<
2
motor
.
motorAtPort
=
0
;
else
motor
.
motorAtPort
=
1
;
end
% Set parameters of SyncMotor-object randomly to the numerically 'higher' ones.
if
uint8
(
motor
.
motor1
.
status
)
>
uint8
(
motor
.
motor2
.
status
)
motor
.
status
=
motor
.
motor1
.
status
;
else
motor
.
status
=
motor
.
motor2
.
status
;
end
if
uint8
(
motor
.
motor1
.
type
)
>
uint8
(
motor
.
motor2
.
type
)
motor
.
type
=
motor
.
motor1
.
type
;
else
motor
.
type
=
motor
.
motor2
.
type
;
end
if
uint8
(
motor
.
motor1
.
mode
)
>
uint8
(
motor
.
motor2
.
mode
)
motor
.
mode
=
motor
.
motor1
.
mode
;
else
motor
.
mode
=
motor
.
motor2
.
mode
;
end
% if ~motor.isConnected
% error(['Motor::update: Motor-Object not connected to brick handle.',...
% 'You have to call syncMotor.connect(brick) first!']);
% end
%
% % Get current status at both ports
% [status, status_sec] = motor.getStatus();
% [type, type_sec, mode, mode_sec] = motor.getTypeMode();
%
% % Conclude if both physical motors are connected
% motor.motorAtPort = 0;
% if uint8(status) >= uint8(ConnectionType.OutputDumb) && ...
% uint8(status) <= uint8(ConnectionType.OutputTacho) && ... % Is status of motor1 valid?
% uint8(status_sec) >= uint8(ConnectionType.OutputDumb) && ...
% uint8(status) <= uint8(ConnectionType.OutputTacho) % Is status of motor2 valid?
% if (type == DeviceType.MediumMotor || type == DeviceType.LargeMotor) && ... % Is type of motor1 valid?
% (type_sec == DeviceType.MediumMotor || type_sec == DeviceType.LargeMotor) %Is type of motor2 valid?
% if strcmp(class(mode), 'DeviceMode.Motor') && ... % Is mode of motor1 valid?
% strcmp(class(mode_sec), 'DeviceMode.Motor') % Is mode of motor2 valid?
% motor.motorAtPort = 1;
% end
% end
% end
%
% % Set parameters of SyncMotor-object randomly to the numerically 'higher' ones.
% if uint8(status) > uint8(status_sec)
% motor.status = status;
% else
% motor.status = status_sec;
% end
%
% if uint8(type) > uint8(type_sec)
% motor.type = type;
% else
% motor.type = type_sec;
% end
%
%
% if motor.mode ~= mode && strcmp(class(mode), 'DeviceMode.Motor')
% if mode == DeviceMode.Motor.Speed
% mode = motor.mode; % This trick prevents set.mode from throwing an error if
% % the physical motor's mode has internally been set to
% % DeviceMode.Motor.Speed
% else
% warning(['Motor::update: Physical motor''s mode was not ',...
% 'the specified one. Changing...']);
% end
% end
% if uint8(mode) > uint8(mode_sec)
% motor.mode = mode;
% else
% motor.mode = mode_sec;
% end
end
%% Brick functions
function
start
(
motor
)
if
~
motor
.
isConnected
error
([
'SyncMotor::start: Motor-Object not connected to brick handle. '
,
...
'You have to call syncMotor.connect(brick) first!'
]);
elseif
~
motor
.
motorAtPort
error
([
'SyncMotor::start: One or more physical motors not connected to '
,
...
'respective port.'
]);
end
if
motor
.
power
==
0
warning
(
'Motor::start: Motor starting with power=0.'
);
end
if
strcmpi
(
motor
.
limitMode
,
'Tacho'
)
motor
.
brick
.
outputStepSync
(
0
,
motor
.
port_
,
...
motor
.
power
,
motor
.
turnRatio
,
...
motor
.
limitValue
,
motor
.
brakeMode_
);
if
motor
.
debug
fprintf
(
'(DEBUG) SyncMotor::start: Called outputStepSync on Port %s\n'
,
...
motor
.
port
);
end
elseif
strcmpi
(
motor
.
limitMode
,
'Time'
)
motor
.
brick
.
outputTimeSync
(
0
,
motor
.
port_
,
...
motor
.
power
,
motor
.
turnRatio
,
...
motor
.
limitValue
,
motor
.
brakeMode_
);
if
motor
.
debug
fprintf
(
'(DEBUG) SyncMotor::start: Called outputStepSync on Port %s\n'
,
...
motor
.
port
);
end
end
motor
.
motor1
.
changed
=
1
;
motor
.
motor2
.
changed
=
1
;
end
function
waitFor
(
motor
)
%waitFor Stops execution of program as long as motor is running with tacholimit.
%
% See also: MOTOR.waitFor
if
~
motor
.
isConnected
error
([
'Motor::waitFor: Motor-Object not connected to brick handle.'
,
...
'You have to call motor.connect(brick) first!'
]);
elseif
~
motor
.
motorAtPort
error
(
'Motor::waitFor: No physical motor connected to Port %s'
,
...
motor
.
port
);
elseif
~
motor
.
limitValue
error
([
'Motor::waitFor: Motor has no tacho limit. '
,
...
'Can
''
t reliably determine whether it is running or not.'
]);
end
tic
;
while
1
try
warning
(
'off'
,
'all'
);
motor
.
brick
.
outputReady
(
0
,
motor
.
port_
);
t
=
toc
;
if
t
<
1
while
motor
.
isRunning
()
% If outputReady correctly returned in less
% than a second, isRunning should instantly send 0.
end
end
warning
(
'on'
,
'all'
);
break
;
catch
% TO DO: Catch only timeout exception, otherwise death and destruction (aka infinite loop)
continue
;
end
end
if
motor
.
debug
fprintf
(
'(DEBUG) Motor::waitFor: Called outputReady on Port %s\n'
,
motor
.
port
);
end
end
function
running
=
isRunning
(
motor
)
%isRunning Returns whether motor is running or not.
if
~
motor
.
isConnected
error
([
'Motor::isRunning: Motor-Object not connected to brick handle.'
,
...
'You have to call motor.connect(brick) first!'
]);
elseif
~
motor
.
motorAtPort
error
(
'Motor::isRunning: No physical motor connected to Port %s'
,
...
motor
.
port
);
end
running
=
motor
.
brick
.
outputTest
(
0
,
motor
.
port_
);
if
motor
.
debug
fprintf
(
'(DEBUG) Motor::isRunning: Called outputReady on Port %s\n'
,
motor
.
port
);
end
end
%% Setter
function
set
.
turnRatio
(
syncMotor
,
turnRatio
)
% Check if turnRatio is valid and set syncedMotor.turnRatio if it is.
if
~
isnumeric
(
turnRatio
)
error
(
'SyncedMotor::set.turnRatio: Given parameter is not a numeric.'
);
elseif
turnRatio
<-
200
||
turnRatio
>
200
warning
(
'SyncedMotor::set.turnRatio: Turn ratio has to be an element of [-200,200]!'
);
error
(
'SyncedMotor::set.turnRatio: Given turn ratio is out of bounds.'
);
end
syncMotor
.
turnRatio
=
turnRatio
;
end
% function set.keepSynchronized(syncMotor, keepSync)
% % Check if keepSync is a valid bool and set syncedMotor.keepSynchronized if it is.
% if ~isBool(keepSync)
% error('SyncedMotor::set.keepSynchronized: Given parameter is not a bool.');
% end
%
% if ischar(keepSync)
% syncMotor.keepSynchronized = str2bool(keepSync);
% else
% syncMotor.keepSynchronized = keepSync;
% end
% end
function
set
.
motor1
(
syncMotor
,
motor1
)
% Check if motor1 is valid and set syncMotor.motor1 if it is.
if
~
isMotorValid
(
motor1
)
error
(
'SyncMotor::set.motor1: Handle to Motor-object not valid.'
);
else
syncMotor
.
motor1
=
motor1
;
end
end
function
set
.
motor2
(
syncMotor
,
motor2
)
% Check if motor2 is valid and set syncMotor.motor2 if it is.
if
~
isMotorValid
(
motor2
)
error
(
'SyncMotor::set.motor2: Handle to Motor-object not valid.'
);
else
syncMotor
.
motor2
=
motor2
;
end
end
function
setProperties
(
motor
,
varargin
)
%setProperties Sets multiple Motor properties at once using MATLAB's inputParser.
%
% Arguments
% * 'motor1', instance of Motor-class
% * 'motor2', instance of Motor-class
% * 'turnRatio', integer or double in [-200, 200]
% * all Motor.setProperties arguments
%
% Example
% b = EV3();
% b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0');
% s = b.coupleMotors('AB', 'useMotorParams', 0);
% s.setProperties('power', 70, 'debug', 'true', 'turnRatio', 100, 'brakeMode', 'Coast');
%
p
=
inputParser
();
p
.
KeepUnmatched
=
1
;
% Unmatched parameters are (probably) Motor-parameters.
% Set default values
if
motor
.
init
defaultTurnRatio
=
0
;
else
defaultTurnRatio
=
motor
.
turnRatio
;
end
% Add parameter
if
motor
.
init
p
.
addRequired
(
'motor1'
);
p
.
addRequired
(
'motor2'
);
end
p
.
addParameter
(
'turnRatio'
,
defaultTurnRatio
);
% Parse...
if
motor
.
init
p
.
parse
(
varargin
{
1
:
2
},
varargin
{
4
:
end
});
% Skip 'port' which is only needed
% for Motor::setProperties.
else
p
.
parse
(
varargin
{:});
end
% Set properties
if
motor
.
init
motor
.
motor1
=
p
.
Results
.
motor1
;
motor
.
motor2
=
p
.
Results
.
motor2
;
end
motor
.
turnRatio
=
p
.
Results
.
turnRatio
;
% Set Motor-parameters, SyncMotor-parameters will be ignored.
if
motor
.
init
setProperties
@
Motor
(
motor
,
varargin
{
3
:
end
});
% Skip 'motor1' and 'motor2'
% which are only needed for
% SyncMotor::setProperties
else
setProperties
@
Motor
(
motor
,
varargin
{:});
end
end
%% Getter
function
portNo_sec
=
get
.
portNo_sec
(
motor
)
portNo_sec
=
motor
.
getPortNo_sec
();
end
function
portInput_sec
=
get
.
portInput_sec
(
motor
)
portInput_sec
=
motor
.
getPortInput_sec
();
end
%% Display
function
display
(
syncMotor
)
warning
(
'off'
,
'all'
);
builtin
(
'disp'
,
syncMotor
);
warning
(
'on'
,
'all'
);
end
end
methods
(
Access
=
'protected'
)
% Private brick functions that are wrapped by dependent params
function
setPower
(
motor
,
power
)
if
~
motor
.
isConnected
||
~
motor
.
motorAtPort
% || ~motor.changed
return
;
end
% Save in Motor-objects that their power does not equal the physical Brick's power
% anymore
if
~
motor
.
init
% In init-phase, motors 1&2 have not been set yet
motor
.
motor1
.
changed
=
1
;
motor
.
motor2
.
changed
=
1
;
motor
.
changed
=
0
;
end
if
motor
.
isRunning
()
warning
([
'SyncMotor::setPower: Can
''
t set power if two motors are running '
,
...
'synchronized. Changes will be effective on next start.'
]);
return
;
end
% setPower@Motor(motor,power);
end
function
setMode
(
motor
,
mode
)
setMode
@
Motor
(
motor
,
mode
);
motor
.
brick
.
inputReadSI
(
0
,
motor
.
portInput_sec
,
mode
);
% Reading a value implicitly
% sets the mode.
if
motor
.
debug
fprintf
(
'(DEBUG) Motor::setMode: Called inputReadSI on input port %d\n'
,
...
uint8
(
motor
.
portInput_sec
));
end
% oldMode = motor.mode;
% if oldMode~=newMode
% if ~strcmp(class(oldMode), 'DeviceMode.Error') && ...
% ~strcmp(class(newMode), 'DeviceMode.Error')
% if newMode ~= DeviceMode.Motor.Speed
% warning(['Motor::update: Physical motor''s mode was not ',...
% 'the specified one. Changing...']);
% end
% motor.brick.inputReadSI(0, motor.portInput, newMode); % Reading a value implicitly
% % sets the mode.
%
% if motor.debug
% fprintf('(DEBUG) Motor::setMode: Called inputReadSI on input port %d\n',...
% uint8(motor.portInput));
% end
% end
% end
end
function
[
type
,
type_sec
,
mode
,
mode_sec
]
=
getTypeMode
(
motor
)
if
~
motor
.
isConnected
error
([
'SyncMotor::getTypeMode: Motor-Object not connected to brick handle.'
,
...
'You have to call motor.connect(brick) first!'
]);
end
[
typeNo
,
modeNo
]
=
motor
.
brick
.
inputDeviceGetTypeMode
(
0
,
motor
.
motor1
.
portInput
);
[
typeNo_sec
,
modeNo_sec
]
=
motor
.
brick
.
inputDeviceGetTypeMode
(
0
,
motor
.
motor2
.
portInput
);
type
=
DeviceType
(
typeNo
);
type_sec
=
DeviceType
(
typeNo_sec
);
mode
=
DeviceMode
(
type
,
modeNo
);
mode_sec
=
DeviceMode
(
type_sec
,
modeNo_sec
);
if
motor
.
debug
fprintf
([
'(DEBUG) SyncMotor::getTypeMode: Called inputDeviceGetTypeMode on Ports '
,
...
'%s.\n'
],
motor
.
port
);
end
end
function
[
status
,
status_sec
]
=
getStatus
(
motor
)
if
~
motor
.
isConnected
error
([
'SyncMotor::getStatus: Motor-Object not connected to brick handle.'
,
...
'You have to call motor.connect(brick) first!'
]);
end
statusNo
=
motor
.
brick
.
inputDeviceGetConnection
(
0
,
motor
.
motor1
.
portInput
);
statusNo_sec
=
motor
.
brick
.
inputDeviceGetConnection
(
0
,
motor
.
motor2
.
portInput
);
status
=
ConnectionType
(
statusNo
);
status_sec
=
ConnectionType
(
statusNo_sec
);
if
motor
.
debug
fprintf
(
'(DEBUG) SyncMotor::getStatus: Called inputDeviceGetConnection on Ports %s\n'
,
...
motor
.
port
);
end
end
function
cnt
=
getTachoCount
(
motor
)
warning
([
'SyncMotor::getTachoCount: Tacho count is not valid for SyncMotor! '
,
...
'Return corresponding value of first motor...'
]);
cnt
=
getTachoCount
@
Motor
(
motor
);
% if motor.mode == DeviceMode.Motor.Degrees
% cnt_sec = motor.brick.outputGetCount(0, motor.portNo_sec);
% if motor.debug
% fprintf(['(DEBUG) Motor::getTachoCount: Called outputGetCount on port ' ,...
% 'no %d\n'], motor.portNo_sec);
% end
% elseif motor.mode == DeviceMode.Motor.Rotations
% cnt_sec = motor.brick.inputReadSI(0, motor.portInput_sec, motor.mode);
% if motor.debug
% fprintf('(DEBUG) Motor::getSpeed: Called inputReadSI on input port %d\n', ...
% motor.portInput_sec);
% end
% end
end
function
speed
=
getSpeed
(
motor
)
warning
([
'SyncMotor::getSpeed: Speed is not a valid parameter of SyncMotor!'
,
...
'Return corresponding value of first motor...'
]);
speed
=
getSpeed
@
Motor
(
motor
);
% speed_sec = motor.brick.inputReadSI(0, motor.portInput_sec, DeviceMode.Motor.Speed);
% if motor.debug
% fprintf('(DEBUG) Motor::getSpeed: Called inputReadSI on input port %d\n', ...
% motor.portInput_sec);
% end
end
end
methods
(
Hidden
,
Access
=
'protected'
)
% Wrapper for utility functions, hidden from user
function
portNo
=
getPortNo
(
motor
)
% warning(['SyncMotor::getPortNo: Port number is not valid for SyncMotor!',...
% 'Return corresponding value of first motor...']);
portNo
=
motor
.
motor1
.
portNo
;
% if isempty(motor.port)
% error(['SyncMotor::portNo: This method should only be called AFTER ',...
% 'setting motor.port.']);
% end
%
% [~, portNo, ~, ~, ~] = str2PortParam(class(motor), motor.port);
end
function
portInput
=
getPortInput
(
motor
)
% warning(['SyncMotor::getPortInput: Port input number is not valid for SyncMotor!',...
% 'Return corresponding value of first motor...']);
portInput
=
motor
.
motor1
.
portInput
;
% if isempty(motor.port)
% error(['SyncMotor::portInput: This method should only be called AFTER ',...
% 'setting motor.port.']);
% end
%
% [~, ~, portInput, ~, ~] = str2PortParam(class(motor), motor.port);
end
function
portNo_sec
=
getPortNo_sec
(
motor
)
portNo_sec
=
motor
.
motor2
.
portNo
;
% if isempty(motor.port)
% error(['SyncMotor::portNo: This method should only be called AFTER ',...
% 'setting motor.port.']);
% end
%
% [~, ~, ~, portNo_sec, ~] = str2PortParam(class(motor), motor.port);
end
function
portInput_sec
=
getPortInput_sec
(
motor
)
portInput_sec
=
motor
.
motor2
.
portInput
;
% if isempty(motor.port)
% error(['SyncMotor::portInput: This method should only be called AFTER ',...
% 'setting motor.port.']);
% end
%
% [~, ~, ~, ~, portInput_sec] = str2PortParam(class(motor), motor.port);
end
end
end
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment