@@ -101,7 +101,7 @@ int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction
101
101
if (sensor){
102
102
exit_flag *= alignSensor ();
103
103
// added the shaft_angle update
104
- shaft_angle = sensor->getAngle ();
104
+ shaft_angle = sensor->updateSensor ();
105
105
}else if (monitor_port) monitor_port->println (F (" MOT: No sensor." ));
106
106
107
107
// aligning the current sensor - can be skipped
@@ -164,14 +164,14 @@ int BLDCMotor::alignSensor() {
164
164
_delay (2 );
165
165
}
166
166
// take and angle in the middle
167
- float mid_angle = sensor->getAngle ();
167
+ float mid_angle = sensor->updateSensor ();
168
168
// move one electrical revolution backwards
169
169
for (int i = 500 ; i >=0 ; i-- ) {
170
170
float angle = _3PI_2 + _2PI * i / 500.0 ;
171
171
setPhaseVoltage (voltage_sensor_align, 0 , angle);
172
172
_delay (2 );
173
173
}
174
- float end_angle = sensor->getAngle ();
174
+ float end_angle = sensor->updateSensor ();
175
175
setPhaseVoltage (0 , 0 , 0 );
176
176
_delay (200 );
177
177
// determine the direction the sensor moved
@@ -201,7 +201,7 @@ int BLDCMotor::alignSensor() {
201
201
// set angle -90(270 = 3PI/2) degrees
202
202
setPhaseVoltage (voltage_sensor_align, 0 , _3PI_2);
203
203
_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));
205
205
_delay (20 );
206
206
if (monitor_port){
207
207
monitor_port->print (F (" MOT: Zero elec. angle: " ));
@@ -217,7 +217,8 @@ int BLDCMotor::alignSensor() {
217
217
// Encoder alignment the absolute zero angle
218
218
// - to the index
219
219
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.
221
222
if (monitor_port) monitor_port->println (F (" MOT: Index search..." ));
222
223
// search the absolute zero with small velocity
223
224
float limit_vel = velocity_limit;
@@ -229,7 +230,7 @@ int BLDCMotor::absoluteZeroSearch() {
229
230
angleOpenloop (1.5 *_2PI);
230
231
// call important for some sensors not to loose count
231
232
// not needed for the search
232
- sensor->getAngle ();
233
+ sensor->updateSensor ();
233
234
}
234
235
// disable motor
235
236
setPhaseVoltage (0 , 0 , 0 );
@@ -247,15 +248,25 @@ int BLDCMotor::absoluteZeroSearch() {
247
248
// Iterative function looping FOC algorithm, setting Uq on the Motor
248
249
// The faster it can be run the better
249
250
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
+
250
255
// if open-loop do nothing
251
256
if ( controller==MotionControlType::angle_openloop || controller==MotionControlType::velocity_openloop ) return ;
257
+
252
258
// 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.
253
263
shaft_angle = shaftAngle (); // read value even if motor is disabled to keep the monitoring updated
254
264
255
265
// if disabled do nothing
256
266
if (!enabled) return ;
257
267
258
268
// electrical angle - need shaftAngle to be called first
269
+ // TODO sensor precision: this will have precision issues because the shaft_angle does...
259
270
electrical_angle = electricalAngle ();
260
271
261
272
switch (torque_controller) {
@@ -300,14 +311,14 @@ void BLDCMotor::loopFOC() {
300
311
// - if target is not set it uses motor.target value
301
312
void BLDCMotor::move (float new_target) {
302
313
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)
304
318
shaft_velocity = shaftVelocity (); // read value even if motor is disabled to keep the monitoring updated
305
319
306
320
// if disabled do nothing
307
321
if (!enabled) return ;
308
- // downsampling (optional)
309
- if (motion_cnt++ < motion_downsample) return ;
310
- motion_cnt = 0 ;
311
322
// set internal target variable
312
323
if (_isset (new_target)) target = new_target;
313
324
@@ -320,11 +331,14 @@ void BLDCMotor::move(float new_target) {
320
331
current_sp = target; // if current/foc_current torque control
321
332
break ;
322
333
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.
323
337
// angle set point
324
338
shaft_angle_sp = target;
325
339
// calculate velocity set point
326
340
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
328
342
current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if voltage torque control
329
343
// if torque controlled through voltage
330
344
if (torque_controller == TorqueControlType::voltage){
@@ -335,7 +349,7 @@ void BLDCMotor::move(float new_target) {
335
349
}
336
350
break ;
337
351
case MotionControlType::velocity:
338
- // velocity set point
352
+ // velocity set point - sensor precision: this calculation is numerically precise.
339
353
shaft_velocity_sp = target;
340
354
// calculate the torque command
341
355
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) {
348
362
}
349
363
break ;
350
364
case MotionControlType::velocity_openloop:
351
- // velocity control in open loop
365
+ // velocity control in open loop - sensor precision: this calculation is numerically precise.
352
366
shaft_velocity_sp = target;
353
367
voltage.q = velocityOpenloop (shaft_velocity_sp); // returns the voltage that is set to the motor
354
368
voltage.d = 0 ;
355
369
break ;
356
370
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.
358
375
shaft_angle_sp = target;
359
376
voltage.q = angleOpenloop (shaft_angle_sp); // returns the voltage that is set to the motor
360
377
voltage.d = 0 ;
@@ -572,6 +589,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
572
589
// quick fix for strange cases (micros overflow + timestamp not defined)
573
590
if (Ts <= 0 || Ts > 0.5 ) Ts = 1e-3 ;
574
591
592
+ // sensor precision: this calculation is numerically precise since we re-normalize
593
+ // the shaft-angle to the range 0-2PI
575
594
// calculate the necessary angle to achieve target velocity
576
595
shaft_angle = _normalizeAngle (shaft_angle + target_velocity*Ts);
577
596
// for display purposes
@@ -581,6 +600,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
581
600
float Uq = voltage_limit;
582
601
if (_isset (phase_resistance)) Uq = current_limit*phase_resistance;
583
602
603
+ // sensor precision: this calculation is numerically precise, since shaft_angle is
604
+ // in the range 0-2PI
584
605
// set the maximal allowed voltage (voltage_limit) with the necessary angle
585
606
setPhaseVoltage (Uq, 0 , _electricalAngle (shaft_angle, pole_pairs));
586
607
@@ -603,6 +624,9 @@ float BLDCMotor::angleOpenloop(float target_angle){
603
624
604
625
// calculate the necessary angle to move from current position towards target angle
605
626
// 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.
606
630
if (abs ( target_angle - shaft_angle ) > abs (velocity_limit*Ts)){
607
631
shaft_angle += _sign (target_angle - shaft_angle) * abs ( velocity_limit )*Ts;
608
632
shaft_velocity = velocity_limit;
@@ -616,6 +640,10 @@ float BLDCMotor::angleOpenloop(float target_angle){
616
640
float Uq = voltage_limit;
617
641
if (_isset (phase_resistance)) Uq = current_limit*phase_resistance;
618
642
// 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.
619
647
setPhaseVoltage (Uq, 0 , _electricalAngle (shaft_angle, pole_pairs));
620
648
621
649
// save timestamp for next call
0 commit comments