Skip to content

Commit a661ea5

Browse files
committed
update MATLAB class
- improved legibility of object properties - switch to higher precision positioning - formatting
1 parent 55d8dc2 commit a661ea5

File tree

2 files changed

+96
-53
lines changed

2 files changed

+96
-53
lines changed

software/MATLAB/BpodStepperLive.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
obj.s.Port.BytesAvailableFcn = @obj.update;
1919

2020
switch obj.s.DriverVersion
21-
case 2130
21+
case 'TMC2130'
2222
obj.vDiv = 13.2E6 / 256;
23-
case 5160
23+
case 'TMC5160'
2424
obj.vDiv = 12.0E6 / 256;
2525
otherwise
2626
error('Driver IC is not supported.')

software/MATLAB/BpodStepperModule.m

Lines changed: 94 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
1-
%{
2-
This program is free software: you can redistribute it and/or modify
3-
it under the terms of the GNU General Public License as published by
4-
the Free Software Foundation, version 3.
5-
6-
This program is distributed WITHOUT ANY WARRANTY and without even the
7-
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8-
See the GNU General Public License for more details.
9-
10-
You should have received a copy of the GNU General Public License
11-
along with this program. If not, see <http://www.gnu.org/licenses/>.
12-
%}
1+
% This program is free software: you can redistribute it and/or modify it
2+
% under the terms of the GNU General Public License as published by the
3+
% Free Software Foundation, version 3.
4+
%
5+
% This program is distributed WITHOUT ANY WARRANTY and without even the
6+
% implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7+
% See the GNU General Public License for more details.
8+
%
9+
% You should have received a copy of the GNU General Public License along
10+
% with this program. If not, see <http://www.gnu.org/licenses/>.
1311

1412
classdef BpodStepperModule < handle & matlab.mixin.CustomDisplay
1513

1614
properties (SetAccess = protected)
1715
Port % ArCOM Serial port
16+
HardwareRevision % PCB revision of connected module
1817
FirmwareVersion % firmware version of connected module
19-
HardwareVersion % PCB revision of connected module
2018
DriverVersion % which TMC driver is installed?
2119
end
2220

2321
properties (Dependent)
24-
RMScurrent % RMS current (mA)
25-
holdRMScurrent % hold RMS current (mA)
26-
ChopperMode % 0 = PWM chopper ("spreadCycle")
27-
% 1 = voltage chopper ("stealthChop")
28-
% 2 = constant off time
29-
Acceleration % acceleration (full steps / s^2)
30-
MaxSpeed % peak velocity (full steps / s)
22+
PeakCurrent % peak current (mA)
23+
RMScurrent % RMS current (mA)
24+
holdRMScurrent % hold RMS current (mA)
25+
% ChopperMode
26+
% 0 = PWM chopper ("spreadCycle")
27+
% 1 = voltage chopper ("stealthChop")
28+
% 2 = constant off time
29+
ChopperMode
30+
Acceleration % acceleration (full steps / s^2)
31+
MaxSpeed % peak velocity (full steps / s)
3132
MicroPosition
32-
Position % absolute position
33+
Position % absolute position
3334
EncoderPosition
3435
end
3536

@@ -76,15 +77,15 @@
7677

7778
% get non-dependent parameters from stepper module
7879
obj.Port.write('GH', 'uint8');
79-
obj.HardwareVersion = double(obj.Port.read(1, 'uint8')) / 10;
80+
obj.HardwareRevision = double(obj.Port.read(1, 'uint8')) / 10;
8081
obj.Port.write('GT', 'uint8');
8182
switch obj.Port.read(1, 'uint8')
8283
case 17 % 0x11
83-
obj.DriverVersion = 2130;
84+
obj.DriverVersion = 'TMC2130';
8485
case 48 % 0x30
85-
obj.DriverVersion = 5160;
86+
obj.DriverVersion = 'TMC5160';
8687
otherwise
87-
obj.DriverVersion = NaN;
88+
obj.DriverVersion = 'unknown';
8889
end
8990
obj.Port.write('GA', 'uint8');
9091
obj.privAcceleration = obj.Port.read(1, 'uint16');
@@ -121,25 +122,32 @@
121122
obj.pauseStreaming(false);
122123
end
123124

125+
function out = get.PeakCurrent(obj)
126+
out = obj.RMScurrent * sqrt(2);
127+
end
128+
function set.PeakCurrent(obj, newCurrent)
129+
obj.RMScurrent = newCurrent / sqrt(2);
130+
end
131+
124132
function out = get.RMScurrent(obj)
125133
out = obj.privRMScurrent;
126134
end
127135
function set.RMScurrent(obj, newCurrent)
128136
validateattributes(newCurrent,{'numeric'},...
129-
{'scalar','integer','nonnegative'})
137+
{'scalar','nonnegative','real'})
130138
obj.Port.write('I', 'uint8', newCurrent, 'uint16');
131139
obj.pauseStreaming(true);
132140
obj.Port.write('GI', 'uint8');
133141
obj.privRMScurrent = obj.Port.read(1, 'uint16');
134142
obj.pauseStreaming(false);
135143
end
136-
144+
137145
function out = get.holdRMScurrent(obj)
138146
out = obj.privHoldRMScurrent;
139147
end
140148
function set.holdRMScurrent(obj, newCurrent)
141149
validateattributes(newCurrent,{'numeric'},...
142-
{'scalar','integer','nonnegative'})
150+
{'scalar','nonnegative','real'})
143151
obj.Port.write('i', 'uint8', newCurrent, 'uint16');
144152
obj.pauseStreaming(true);
145153
obj.Port.write('Gi', 'uint8');
@@ -172,13 +180,13 @@
172180
end
173181
function out = get.Position(obj)
174182
obj.pauseStreaming(true);
175-
obj.Port.write('GP', 'uint8');
176-
out = obj.Port.read(1, 'int16');
183+
obj.Port.write('Gp', 'uint8');
184+
out = double(obj.Port.read(1, 'int32')) / 256;
177185
obj.pauseStreaming(false);
178186
end
179187
function set.Position(obj,position)
180188
validateattributes(position,{'numeric'},{'scalar','integer'})
181-
obj.Port.write('P', 'int8', position, 'int16');
189+
obj.Port.write('p', 'int8', round(position * 256), 'int32');
182190
end
183191
function resetPosition(obj)
184192
% Reset value of absolute position to zero.
@@ -205,7 +213,7 @@ function step(obj, nSteps)
205213
end
206214
obj.Port.write('S', 'uint8', nSteps, 'int16');
207215
end
208-
216+
209217
function microStep(obj, nSteps)
210218
% Move stepper motor a set number of micro-steps. nSteps = positive
211219
% for clockwise steps, negative for counterclockwise
@@ -483,36 +491,71 @@ function pauseStreaming(obj, doPause)
483491
tmp = [typecast(tmp(3:4), 'uint16') tmp([2 1])];
484492
out = obj.verArr2Str(tmp);
485493
end
486-
494+
487495
function out = verArr2Str(~, in)
488496
out = sprintf('%04d.%02d.%d', in(:));
489497
end
490-
498+
491499
function out = verArr2Int(~, in)
492500
out = [uint8(in([3 2])) typecast(uint16(in(1)), 'uint8')];
493501
out = typecast(out, 'uint32');
494502
end
495-
end
503+
504+
function displayPropGroup(obj, groups, fmts)
505+
persistent nPad
506+
persistent chopperModes
507+
if isempty(nPad)
508+
nPad = max(cellfun(@numel,[groups.PropertyList])) + 1;
509+
chopperModes = {'PWM chopper', 'voltage chopper', 'constant off time chopper'};
510+
end
511+
for ii = 1:numel(groups)
512+
padProps = pad(groups(ii).PropertyList, nPad, 'left');
513+
fprintf(' <strong>%s</strong>\n',groups(ii).Title)
514+
for jj = 1:groups(ii).NumProperties
515+
if strcmp(groups(ii).PropertyList{jj}, 'ChopperMode')
516+
fprintf([' %s: ' fmts{ii}{jj} ' (%s)\n'], ...
517+
padProps{jj}, obj.(groups(ii).PropertyList{jj}), ...
518+
chopperModes{1+obj.(groups(ii).PropertyList{jj})})
519+
else
520+
fprintf([' %s: ' fmts{ii}{jj} '\n'], ...
521+
padProps{jj}, obj.(groups(ii).PropertyList{jj}))
522+
end
523+
end
524+
fprintf('\n')
525+
end
526+
end
496527

497-
methods (Access = protected)
498-
function propgrp = getPropertyGroups(obj)
499-
gTitle1 = '<strong>Module Information</strong>';
500-
propList1 = {'HardwareVersion','DriverVersion','FirmwareVersion'};
501-
gTitle2 = '<strong>Motor Configuration</strong>';
502-
propList2 = {'RMScurrent','holdRMScurrent','ChopperMode','MaxSpeed','Acceleration'};
503-
gTitle3 = '<strong>Movement Parameters</strong>';
528+
function [propgrp, fmt] = getPropGroups(obj)
529+
gTitle{1} = 'Module Information';
530+
gTitle{2} = 'Motor Configuration';
531+
gTitle{3} = 'Movement Parameters';
532+
533+
pList{1} = {'HardwareRevision','DriverVersion','FirmwareVersion'};
534+
pList{2} = {'PeakCurrent','RMScurrent','holdRMScurrent','ChopperMode'};
535+
pList{3} = {'MaxSpeed','Acceleration','Position'};
536+
537+
fmt{1} = {'%.1f', '''%s''', '''%s'''};
538+
fmt{2} = {'%d mA', '%d mA', '%d mA', '%d'};
539+
fmt{3} = {'%d steps/s', '%d steps/s²', '%.1f steps'};
540+
504541
if obj.privUseEncoder
505-
propList3 = {'Position','EncoderPosition'};
506-
else
507-
propList3 = {'Position'};
542+
pList{3} = [pList{3} {'EncoderPosition'}];
543+
fmt{3} = [fmt{3} {'%d'}];
508544
end
509-
propgrp(1) = matlab.mixin.util.PropertyGroup(propList1,gTitle1);
510-
propgrp(2) = matlab.mixin.util.PropertyGroup(propList2,gTitle2);
511-
propgrp(3) = matlab.mixin.util.PropertyGroup(propList3,gTitle3);
512-
end
513545

514-
function s = getFooter(obj)
515-
s = matlab.mixin.CustomDisplay.getDetailedFooter(obj);
546+
propgrp(1) = matlab.mixin.util.PropertyGroup(pList{1},gTitle{1});
547+
propgrp(2) = matlab.mixin.util.PropertyGroup(pList{2},gTitle{2});
548+
propgrp(3) = matlab.mixin.util.PropertyGroup(pList{3},gTitle{3});
549+
end
550+
end
551+
552+
methods (Access = protected)
553+
function displayScalarObject(obj)
554+
fprintf('%s with properties:\n\n', ...
555+
matlab.mixin.CustomDisplay.getClassNameForHeader(obj));
556+
[propgroup, fmt] = getPropGroups(obj);
557+
displayPropGroup(obj,propgroup,fmt)
558+
disp(matlab.mixin.CustomDisplay.getDetailedFooter(obj))
516559
end
517560
end
518561
end

0 commit comments

Comments
 (0)