diff --git a/software/MATLAB/BpodStepperLive.m b/software/MATLAB/BpodStepperLive.m
index 5431442..85cabad 100644
--- a/software/MATLAB/BpodStepperLive.m
+++ b/software/MATLAB/BpodStepperLive.m
@@ -18,9 +18,9 @@
obj.s.Port.BytesAvailableFcn = @obj.update;
switch obj.s.DriverVersion
- case 2130
+ case 'TMC2130'
obj.vDiv = 13.2E6 / 256;
- case 5160
+ case 'TMC5160'
obj.vDiv = 12.0E6 / 256;
otherwise
error('Driver IC is not supported.')
diff --git a/software/MATLAB/BpodStepperModule.m b/software/MATLAB/BpodStepperModule.m
index 5542662..4a3dd19 100644
--- a/software/MATLAB/BpodStepperModule.m
+++ b/software/MATLAB/BpodStepperModule.m
@@ -1,35 +1,36 @@
-%{
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, version 3.
-
-This program is distributed WITHOUT ANY WARRANTY and without even the
-implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-%}
+% This program is free software: you can redistribute it and/or modify it
+% under the terms of the GNU General Public License as published by the
+% Free Software Foundation, version 3.
+%
+% This program is distributed WITHOUT ANY WARRANTY and without even the
+% implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+% See the GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with this program. If not, see .
classdef BpodStepperModule < handle & matlab.mixin.CustomDisplay
properties (SetAccess = protected)
Port % ArCOM Serial port
+ HardwareRevision % PCB revision of connected module
FirmwareVersion % firmware version of connected module
- HardwareVersion % PCB revision of connected module
DriverVersion % which TMC driver is installed?
end
properties (Dependent)
- RMScurrent % RMS current (mA)
- holdRMScurrent % hold RMS current (mA)
- ChopperMode % 0 = PWM chopper ("spreadCycle")
- % 1 = voltage chopper ("stealthChop")
- % 2 = constant off time
- Acceleration % acceleration (full steps / s^2)
- MaxSpeed % peak velocity (full steps / s)
+ PeakCurrent % peak current (mA)
+ RMScurrent % RMS current (mA)
+ holdRMScurrent % hold RMS current (mA)
+ % ChopperMode
+ % 0 = PWM chopper ("spreadCycle")
+ % 1 = voltage chopper ("stealthChop")
+ % 2 = constant off time
+ ChopperMode
+ Acceleration % acceleration (full steps / s^2)
+ MaxSpeed % peak velocity (full steps / s)
MicroPosition
- Position % absolute position
+ Position % absolute position
EncoderPosition
end
@@ -76,15 +77,15 @@
% get non-dependent parameters from stepper module
obj.Port.write('GH', 'uint8');
- obj.HardwareVersion = double(obj.Port.read(1, 'uint8')) / 10;
+ obj.HardwareRevision = double(obj.Port.read(1, 'uint8')) / 10;
obj.Port.write('GT', 'uint8');
switch obj.Port.read(1, 'uint8')
case 17 % 0x11
- obj.DriverVersion = 2130;
+ obj.DriverVersion = 'TMC2130';
case 48 % 0x30
- obj.DriverVersion = 5160;
+ obj.DriverVersion = 'TMC5160';
otherwise
- obj.DriverVersion = NaN;
+ obj.DriverVersion = 'unknown';
end
obj.Port.write('GA', 'uint8');
obj.privAcceleration = obj.Port.read(1, 'uint16');
@@ -121,25 +122,32 @@
obj.pauseStreaming(false);
end
+ function out = get.PeakCurrent(obj)
+ out = obj.RMScurrent * sqrt(2);
+ end
+ function set.PeakCurrent(obj, newCurrent)
+ obj.RMScurrent = newCurrent / sqrt(2);
+ end
+
function out = get.RMScurrent(obj)
out = obj.privRMScurrent;
end
function set.RMScurrent(obj, newCurrent)
validateattributes(newCurrent,{'numeric'},...
- {'scalar','integer','nonnegative'})
+ {'scalar','nonnegative','real'})
obj.Port.write('I', 'uint8', newCurrent, 'uint16');
obj.pauseStreaming(true);
obj.Port.write('GI', 'uint8');
obj.privRMScurrent = obj.Port.read(1, 'uint16');
obj.pauseStreaming(false);
end
-
+
function out = get.holdRMScurrent(obj)
out = obj.privHoldRMScurrent;
end
function set.holdRMScurrent(obj, newCurrent)
validateattributes(newCurrent,{'numeric'},...
- {'scalar','integer','nonnegative'})
+ {'scalar','nonnegative','real'})
obj.Port.write('i', 'uint8', newCurrent, 'uint16');
obj.pauseStreaming(true);
obj.Port.write('Gi', 'uint8');
@@ -172,13 +180,13 @@
end
function out = get.Position(obj)
obj.pauseStreaming(true);
- obj.Port.write('GP', 'uint8');
- out = obj.Port.read(1, 'int16');
+ obj.Port.write('Gp', 'uint8');
+ out = double(obj.Port.read(1, 'int32')) / 256;
obj.pauseStreaming(false);
end
function set.Position(obj,position)
validateattributes(position,{'numeric'},{'scalar','integer'})
- obj.Port.write('P', 'int8', position, 'int16');
+ obj.Port.write('p', 'int8', round(position * 256), 'int32');
end
function resetPosition(obj)
% Reset value of absolute position to zero.
@@ -205,7 +213,7 @@ function step(obj, nSteps)
end
obj.Port.write('S', 'uint8', nSteps, 'int16');
end
-
+
function microStep(obj, nSteps)
% Move stepper motor a set number of micro-steps. nSteps = positive
% for clockwise steps, negative for counterclockwise
@@ -483,36 +491,71 @@ function pauseStreaming(obj, doPause)
tmp = [typecast(tmp(3:4), 'uint16') tmp([2 1])];
out = obj.verArr2Str(tmp);
end
-
+
function out = verArr2Str(~, in)
out = sprintf('%04d.%02d.%d', in(:));
end
-
+
function out = verArr2Int(~, in)
out = [uint8(in([3 2])) typecast(uint16(in(1)), 'uint8')];
out = typecast(out, 'uint32');
end
- end
+
+ function displayPropGroup(obj, groups, fmts)
+ persistent nPad
+ persistent chopperModes
+ if isempty(nPad)
+ nPad = max(cellfun(@numel,[groups.PropertyList])) + 1;
+ chopperModes = {'PWM chopper', 'voltage chopper', 'constant off time chopper'};
+ end
+ for ii = 1:numel(groups)
+ padProps = pad(groups(ii).PropertyList, nPad, 'left');
+ fprintf(' %s\n',groups(ii).Title)
+ for jj = 1:groups(ii).NumProperties
+ if strcmp(groups(ii).PropertyList{jj}, 'ChopperMode')
+ fprintf([' %s: ' fmts{ii}{jj} ' (%s)\n'], ...
+ padProps{jj}, obj.(groups(ii).PropertyList{jj}), ...
+ chopperModes{1+obj.(groups(ii).PropertyList{jj})})
+ else
+ fprintf([' %s: ' fmts{ii}{jj} '\n'], ...
+ padProps{jj}, obj.(groups(ii).PropertyList{jj}))
+ end
+ end
+ fprintf('\n')
+ end
+ end
- methods (Access = protected)
- function propgrp = getPropertyGroups(obj)
- gTitle1 = 'Module Information';
- propList1 = {'HardwareVersion','DriverVersion','FirmwareVersion'};
- gTitle2 = 'Motor Configuration';
- propList2 = {'RMScurrent','holdRMScurrent','ChopperMode','MaxSpeed','Acceleration'};
- gTitle3 = 'Movement Parameters';
+ function [propgrp, fmt] = getPropGroups(obj)
+ gTitle{1} = 'Module Information';
+ gTitle{2} = 'Motor Configuration';
+ gTitle{3} = 'Movement Parameters';
+
+ pList{1} = {'HardwareRevision','DriverVersion','FirmwareVersion'};
+ pList{2} = {'PeakCurrent','RMScurrent','holdRMScurrent','ChopperMode'};
+ pList{3} = {'MaxSpeed','Acceleration','Position'};
+
+ fmt{1} = {'%.1f', '''%s''', '''%s'''};
+ fmt{2} = {'%d mA', '%d mA', '%d mA', '%d'};
+ fmt{3} = {'%d steps/s', '%d steps/s²', '%.1f steps'};
+
if obj.privUseEncoder
- propList3 = {'Position','EncoderPosition'};
- else
- propList3 = {'Position'};
+ pList{3} = [pList{3} {'EncoderPosition'}];
+ fmt{3} = [fmt{3} {'%d'}];
end
- propgrp(1) = matlab.mixin.util.PropertyGroup(propList1,gTitle1);
- propgrp(2) = matlab.mixin.util.PropertyGroup(propList2,gTitle2);
- propgrp(3) = matlab.mixin.util.PropertyGroup(propList3,gTitle3);
- end
- function s = getFooter(obj)
- s = matlab.mixin.CustomDisplay.getDetailedFooter(obj);
+ propgrp(1) = matlab.mixin.util.PropertyGroup(pList{1},gTitle{1});
+ propgrp(2) = matlab.mixin.util.PropertyGroup(pList{2},gTitle{2});
+ propgrp(3) = matlab.mixin.util.PropertyGroup(pList{3},gTitle{3});
+ end
+ end
+
+ methods (Access = protected)
+ function displayScalarObject(obj)
+ fprintf('%s with properties:\n\n', ...
+ matlab.mixin.CustomDisplay.getClassNameForHeader(obj));
+ [propgroup, fmt] = getPropGroups(obj);
+ displayPropGroup(obj,propgroup,fmt)
+ disp(matlab.mixin.CustomDisplay.getDetailedFooter(obj))
end
end
end