Skip to content

Commit 83798ea

Browse files
committed
adapted motor code to new API, added comments for precision issues
1 parent f86d5c4 commit 83798ea

File tree

3 files changed

+44
-16
lines changed

3 files changed

+44
-16
lines changed

src/BLDCMotor.cpp

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction
101101
if(sensor){
102102
exit_flag *= alignSensor();
103103
// added the shaft_angle update
104-
shaft_angle = sensor->getAngle();
104+
shaft_angle = sensor->updateSensor();
105105
}else if(monitor_port) monitor_port->println(F("MOT: No sensor."));
106106

107107
// aligning the current sensor - can be skipped
@@ -164,14 +164,14 @@ int BLDCMotor::alignSensor() {
164164
_delay(2);
165165
}
166166
// take and angle in the middle
167-
float mid_angle = sensor->getAngle();
167+
float mid_angle = sensor->updateSensor();
168168
// move one electrical revolution backwards
169169
for (int i = 500; i >=0; i-- ) {
170170
float angle = _3PI_2 + _2PI * i / 500.0 ;
171171
setPhaseVoltage(voltage_sensor_align, 0, angle);
172172
_delay(2);
173173
}
174-
float end_angle = sensor->getAngle();
174+
float end_angle = sensor->updateSensor();
175175
setPhaseVoltage(0, 0, 0);
176176
_delay(200);
177177
// determine the direction the sensor moved
@@ -201,7 +201,7 @@ int BLDCMotor::alignSensor() {
201201
// set angle -90(270 = 3PI/2) degrees
202202
setPhaseVoltage(voltage_sensor_align, 0, _3PI_2);
203203
_delay(700);
204-
zero_electric_angle = _normalizeAngle(_electricalAngle(sensor_direction*sensor->getAngle(), pole_pairs));
204+
zero_electric_angle = _normalizeAngle(_electricalAngle(sensor_direction*sensor->updateSensor(), pole_pairs));
205205
_delay(20);
206206
if(monitor_port){
207207
monitor_port->print(F("MOT: Zero elec. angle: "));
@@ -217,7 +217,8 @@ int BLDCMotor::alignSensor() {
217217
// Encoder alignment the absolute zero angle
218218
// - to the index
219219
int BLDCMotor::absoluteZeroSearch() {
220-
220+
// sensor precision: this is all ok, as the search happens near the 0-angle, where the precision
221+
// of float is sufficient.
221222
if(monitor_port) monitor_port->println(F("MOT: Index search..."));
222223
// search the absolute zero with small velocity
223224
float limit_vel = velocity_limit;
@@ -229,7 +230,7 @@ int BLDCMotor::absoluteZeroSearch() {
229230
angleOpenloop(1.5*_2PI);
230231
// call important for some sensors not to loose count
231232
// not needed for the search
232-
sensor->getAngle();
233+
sensor->updateSensor();
233234
}
234235
// disable motor
235236
setPhaseVoltage(0, 0, 0);
@@ -247,15 +248,25 @@ int BLDCMotor::absoluteZeroSearch() {
247248
// Iterative function looping FOC algorithm, setting Uq on the Motor
248249
// The faster it can be run the better
249250
void BLDCMotor::loopFOC() {
251+
// update sensor - do this even in open-loop mode, as user may be switching between modes and we could lose track
252+
// of full rotations otherwise.
253+
if (sensor) sensor->updateSensor();
254+
250255
// if open-loop do nothing
251256
if( controller==MotionControlType::angle_openloop || controller==MotionControlType::velocity_openloop ) return;
257+
252258
// shaft angle
259+
// TODO sensor precision: the shaft_angle actually stores the complete position, including full rotations, as a float
260+
// For this reason it is NOT precise when the angles become large.
261+
// Additionally, the way LPF works on angle is a precision issue, and the angle-LPF is a problem
262+
// when switching to a 2-component representation.
253263
shaft_angle = shaftAngle(); // read value even if motor is disabled to keep the monitoring updated
254264

255265
// if disabled do nothing
256266
if(!enabled) return;
257267

258268
// electrical angle - need shaftAngle to be called first
269+
// TODO sensor precision: this will have precision issues because the shaft_angle does...
259270
electrical_angle = electricalAngle();
260271

261272
switch (torque_controller) {
@@ -300,14 +311,14 @@ void BLDCMotor::loopFOC() {
300311
// - if target is not set it uses motor.target value
301312
void BLDCMotor::move(float new_target) {
302313

303-
// get angular velocity
314+
// downsampling (optional)
315+
if(motion_cnt++ < motion_downsample) return;
316+
motion_cnt = 0;
317+
// get angular velocity - sensor precision: this value is numerically precise. It is filtered by Velocity LPF, and downsamling (depending on sensor)
304318
shaft_velocity = shaftVelocity(); // read value even if motor is disabled to keep the monitoring updated
305319

306320
// if disabled do nothing
307321
if(!enabled) return;
308-
// downsampling (optional)
309-
if(motion_cnt++ < motion_downsample) return;
310-
motion_cnt = 0;
311322
// set internal target variable
312323
if(_isset(new_target)) target = new_target;
313324

@@ -320,11 +331,14 @@ void BLDCMotor::move(float new_target) {
320331
current_sp = target; // if current/foc_current torque control
321332
break;
322333
case MotionControlType::angle:
334+
// TODO sensor precision: this calculation is not numerically precise. The target value cannot express precise positions when
335+
// the angles are large. This results in not being able to command small changes at high position values.
336+
// to solve this, the delta-angle has to be calculated in a numerically precise way.
323337
// angle set point
324338
shaft_angle_sp = target;
325339
// calculate velocity set point
326340
shaft_velocity_sp = P_angle( shaft_angle_sp - shaft_angle );
327-
// calculate the torque command
341+
// calculate the torque command - sensor precision: this calculation is ok, but based on bad value from previous calculation
328342
current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if voltage torque control
329343
// if torque controlled through voltage
330344
if(torque_controller == TorqueControlType::voltage){
@@ -335,7 +349,7 @@ void BLDCMotor::move(float new_target) {
335349
}
336350
break;
337351
case MotionControlType::velocity:
338-
// velocity set point
352+
// velocity set point - sensor precision: this calculation is numerically precise.
339353
shaft_velocity_sp = target;
340354
// calculate the torque command
341355
current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if current/foc_current torque control
@@ -348,13 +362,16 @@ void BLDCMotor::move(float new_target) {
348362
}
349363
break;
350364
case MotionControlType::velocity_openloop:
351-
// velocity control in open loop
365+
// velocity control in open loop - sensor precision: this calculation is numerically precise.
352366
shaft_velocity_sp = target;
353367
voltage.q = velocityOpenloop(shaft_velocity_sp); // returns the voltage that is set to the motor
354368
voltage.d = 0;
355369
break;
356370
case MotionControlType::angle_openloop:
357-
// angle control in open loop
371+
// angle control in open loop -
372+
// TODO sensor precision: this calculation NOT numerically precise, and subject
373+
// to the same problems in small set-point changes at high angles
374+
// as the closed loop version.
358375
shaft_angle_sp = target;
359376
voltage.q = angleOpenloop(shaft_angle_sp); // returns the voltage that is set to the motor
360377
voltage.d = 0;
@@ -572,6 +589,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
572589
// quick fix for strange cases (micros overflow + timestamp not defined)
573590
if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
574591

592+
// sensor precision: this calculation is numerically precise since we re-normalize
593+
// the shaft-angle to the range 0-2PI
575594
// calculate the necessary angle to achieve target velocity
576595
shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts);
577596
// for display purposes
@@ -581,6 +600,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
581600
float Uq = voltage_limit;
582601
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
583602

603+
// sensor precision: this calculation is numerically precise, since shaft_angle is
604+
// in the range 0-2PI
584605
// set the maximal allowed voltage (voltage_limit) with the necessary angle
585606
setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs));
586607

@@ -603,6 +624,9 @@ float BLDCMotor::angleOpenloop(float target_angle){
603624

604625
// calculate the necessary angle to move from current position towards target angle
605626
// with maximal velocity (velocity_limit)
627+
// TODO sensor precision: this calculation is not numerically precise. The angle can grow to the point
628+
// where small position changes are no longer captured by the precision of floats
629+
// when the total position is large.
606630
if(abs( target_angle - shaft_angle ) > abs(velocity_limit*Ts)){
607631
shaft_angle += _sign(target_angle - shaft_angle) * abs( velocity_limit )*Ts;
608632
shaft_velocity = velocity_limit;
@@ -616,6 +640,10 @@ float BLDCMotor::angleOpenloop(float target_angle){
616640
float Uq = voltage_limit;
617641
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
618642
// set the maximal allowed voltage (voltage_limit) with the necessary angle
643+
// TODO sensor precision: this calculation is not numerically precise. The angle is not constrained,
644+
// and can grow large. It first gets multiplied by the number of pole-pairs (in _electrocalAngle()),
645+
// and then gets normalized to 0-2PI (before it gets used in setPhaseVoltage()). At large angles,
646+
// the precision can mean the range 0-2PI is not well represented at the end of that calculation.
619647
setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs));
620648

621649
// save timestamp for next call

src/common/base_classes/Sensor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ float Sensor::updateSensor() {
1111
// if overflow happened track it as full rotation
1212
if(abs(d_angle) > (0.8*_2PI) ) full_rotations += ( d_angle > 0 ) ? -1 : 1;
1313
angle_prev = val;
14-
return val;
14+
return getAngle();
1515
}
1616

1717

src/common/base_classes/Sensor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class Sensor{
8585
* Override in subclasses if alternative behaviours are required for your
8686
* sensor hardware.
8787
*
88-
* Returns the current value of getShaftAngle()
88+
* Returns the same value as getAngle() as its result
8989
*/
9090
virtual float updateSensor();
9191

0 commit comments

Comments
 (0)