@@ -20,7 +20,7 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
20
20
voltage_power_supply = DEF_POWER_SUPPLY;
21
21
22
22
// Velocity loop config
23
- // PI contoroller constant
23
+ // PI controller constant
24
24
PI_velocity.P = DEF_PI_VEL_P;
25
25
PI_velocity.I = DEF_PI_VEL_I;
26
26
PI_velocity.timestamp = _micros ();
@@ -55,6 +55,9 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
55
55
// electric angle of the zero angle
56
56
zero_electric_angle = 0 ;
57
57
58
+ // default modulation is SinePWM
59
+ foc_modulation = FOCModulationType::SinePWM;
60
+
58
61
// debugger
59
62
debugger = nullptr ;
60
63
}
@@ -76,8 +79,8 @@ void BLDCMotor::init() {
76
79
setPwmFrequency (pwmC);
77
80
78
81
// sanity check for the voltage limit configuration
79
- if (PI_velocity.voltage_limit > voltage_power_supply/ 2 ) PI_velocity.voltage_limit = voltage_power_supply/ 2 ;
80
- if (PI_velocity_index_search.voltage_limit > voltage_power_supply/ 2 ) PI_velocity_index_search.voltage_limit = voltage_power_supply/ 2 ;
82
+ if (PI_velocity.voltage_limit > 0.7 * voltage_power_supply) PI_velocity.voltage_limit = 0.7 * voltage_power_supply;
83
+ if (PI_velocity_index_search.voltage_limit > 0.7 * voltage_power_supply) PI_velocity_index_search.voltage_limit = 0.7 * voltage_power_supply;
81
84
82
85
_delay (500 );
83
86
// enable motor
@@ -135,7 +138,7 @@ int BLDCMotor::alignSensor() {
135
138
if (debugger){
136
139
if (exit_flag< 0 ) debugger->println (" DEBUG: Error: Absolute zero not found!" );
137
140
if (exit_flag> 0 ) debugger->println (" DEBUG: Success: Absolute zero found!" );
138
- else debugger->println (" DEBUG: Absolute zero not availabe !" );
141
+ else debugger->println (" DEBUG: Absolute zero not available !" );
139
142
}
140
143
return exit_flag;
141
144
}
@@ -199,7 +202,6 @@ float BLDCMotor::electricAngle(float shaftAngle) {
199
202
/* *
200
203
FOC functions
201
204
*/
202
-
203
205
// FOC initialization function
204
206
int BLDCMotor::initFOC () {
205
207
// sensor and motor alignment
@@ -225,6 +227,7 @@ void BLDCMotor::loopFOC() {
225
227
void BLDCMotor::move (float target) {
226
228
// get angular velocity
227
229
shaft_velocity = shaftVelocity ();
230
+ // choose control loop
228
231
switch (controller) {
229
232
case ControlType::voltage:
230
233
voltage_q = target;
@@ -247,43 +250,121 @@ void BLDCMotor::move(float target) {
247
250
248
251
249
252
// Method using FOC to set Uq to the motor at the optimal angle
253
+ // Function implementing Space Vector PWM and Sine PWM algorithms
254
+ //
255
+ // Function using sine approximation
256
+ // regular sin + cos ~300us (no memory usaage)
257
+ // approx _sin + _cos ~110us (400Byte ~ 20% of memory)
250
258
void BLDCMotor::setPhaseVoltage (float Uq, float angle_el) {
259
+ switch (foc_modulation)
260
+ {
261
+ case FOCModulationType::SinePWM :
262
+ // Sinusoidal PWM modulation
263
+ // Inverse Park + Clarke transformation
264
+
265
+ // angle normalization in between 0 and 2pi
266
+ // only necessary if using _sin and _cos - approximation functions
267
+ angle_el = normalizeAngle (angle_el + zero_electric_angle);
268
+ // Inverse park transform
269
+ Ualpha = -_sin (angle_el) * Uq; // -sin(angle) * Uq;
270
+ Ubeta = _cos (angle_el) * Uq; // cos(angle) * Uq;
271
+
272
+ // Clarke transform
273
+ Ua = Ualpha + voltage_power_supply/2 ;
274
+ Ub = -0.5 * Ualpha + _SQRT3_2 * Ubeta + voltage_power_supply/2 ;
275
+ Uc = -0.5 * Ualpha - _SQRT3_2 * Ubeta + voltage_power_supply/2 ;
276
+ break ;
251
277
252
- // angle normalisation in between 0 and 2pi
253
- // only necessary if using _sin and _cos - approximation functions
254
- float angle = normalizeAngle (angle_el + zero_electric_angle);
255
- // Inverse park transform
256
- // regular sin + cos ~300us (no memory usaage)
257
- // approx _sin + _cos ~110us (400Byte ~ 20% of memory)
258
- // Ualpha = -_sin(angle) * Uq; // -sin(angle) * Uq;
259
- // Ubeta = _cos(angle) * Uq; // cos(angle) * Uq;
260
- Ualpha = -_sin (angle) * Uq; // -sin(angle) * Uq;
261
- Ubeta = _cos (angle) * Uq; // cos(angle) * Uq;
262
-
263
- // Clarke transform
264
- Ua = Ualpha;
265
- Ub = -0.5 * Ualpha + _SQRT3_2 * Ubeta;
266
- Uc = -0.5 * Ualpha - _SQRT3_2 * Ubeta;
278
+ case FOCModulationType::SpaceVectorPWM :
279
+ // Nice video explaining the SpaceVectorModulation (SVPWM) algorithm
280
+ // https://www.youtube.com/watch?v=QMSWUMEAejg
281
+
282
+ // if negative voltages change inverse the phase
283
+ // angle + 180degrees
284
+ if (Uq < 0 ) angle_el += M_PI;
285
+ Uq = abs (Uq);
286
+
287
+ // angle normalisation in between 0 and 2pi
288
+ // only necessary if using _sin and _cos - approximation functions
289
+ angle_el = normalizeAngle (angle_el + zero_electric_angle + _PI_2);
290
+
291
+ // find the sector we are in currently
292
+ int sector = floor (angle_el / _PI_3) + 1 ;
293
+ // calculate the duty cycles
294
+ float T1 = _SQRT3*_sin (sector*_PI_3 - angle_el);
295
+ float T2 = _SQRT3*_sin (angle_el - (sector-1.0 )*_PI_3);
296
+ // two versions possible
297
+ // centered around voltage_power_supply/2
298
+ float T0 = 1 - T1 - T2;
299
+ // centered around 0
300
+ // T0 = 0;
301
+
302
+ // calculate the duty cycles(times)
303
+ float Ta,Tb,Tc;
304
+ switch (sector){
305
+ case 1 :
306
+ Ta = T1 + T2 + T0/2 ;
307
+ Tb = T2 + T0/2 ;
308
+ Tc = T0/2 ;
309
+ break ;
310
+ case 2 :
311
+ Ta = T1 + T0/2 ;
312
+ Tb = T1 + T2 + T0/2 ;
313
+ Tc = T0/2 ;
314
+ break ;
315
+ case 3 :
316
+ Ta = T0/2 ;
317
+ Tb = T1 + T2 + T0/2 ;
318
+ Tc = T2 + T0/2 ;
319
+ break ;
320
+ case 4 :
321
+ Ta = T0/2 ;
322
+ Tb = T1+ T0/2 ;
323
+ Tc = T1 + T2 + T0/2 ;
324
+ break ;
325
+ case 5 :
326
+ Ta = T2 + T0/2 ;
327
+ Tb = T0/2 ;
328
+ Tc = T1 + T2 + T0/2 ;
329
+ break ;
330
+ case 6 :
331
+ Ta = T1 + T2 + T0/2 ;
332
+ Tb = T0/2 ;
333
+ Tc = T1 + T0/2 ;
334
+ break ;
335
+ default :
336
+ // possible error state
337
+ Ta = 0 ;
338
+ Tb = 0 ;
339
+ Tc = 0 ;
340
+ }
341
+
342
+ // calculate the phase voltages
343
+ Ua = Ta*Uq;
344
+ Ub = Tb*Uq;
345
+ Uc = Tc*Uq;
346
+ break ;
347
+ }
267
348
268
- // set phase voltages
349
+ // set the voltages in hardware
269
350
setPwm (pwmA, Ua);
270
351
setPwm (pwmB, Ub);
271
352
setPwm (pwmC, Uc);
272
353
}
273
354
274
355
356
+
357
+
275
358
// Set voltage to the pwm pin
276
359
// - function a bit optimized to get better performance
277
360
void BLDCMotor::setPwm (int pinPwm, float U) {
278
361
// max value
279
- float U_max = voltage_power_supply/2.0 ;
280
-
281
- // sets the voltage [-U_max,U_max] to pwm [0,255]
282
- // u_pwm = 255 * (U + U_max)/(2*U_max)
283
- // it can be further optimized
284
- // (example U_max = 6 > U_pwm = 127.5 + 21.25*U)
285
- int U_pwm = 127.5 * (U/U_max + 1 );
286
-
362
+ float U_max = voltage_power_supply;
363
+
364
+ // sets the voltage [0,12V(U_max)] to pwm [0,255]
365
+ // - U_max you can set in header file - default 12V
366
+ int U_pwm = 255.0 * U / U_max;
367
+
287
368
// limit the values between 0 and 255
288
369
U_pwm = (U_pwm < 0 ) ? 0 : (U_pwm >= 255 ) ? 255 : U_pwm;
289
370
@@ -340,9 +421,11 @@ float BLDCMotor::velocityIndexSearchPI(float tracking_error) {
340
421
}
341
422
// P controller for position control loop
342
423
float BLDCMotor::positionP (float ek) {
343
- float velk = P_angle.P * ek;
344
- if (abs (velk) > P_angle.velocity_limit ) velk = velk > 0 ? P_angle.velocity_limit : -P_angle.velocity_limit ;
345
- return velk;
424
+ // calculate the target velocity from the position error
425
+ float velocity_target = P_angle.P * ek;
426
+ // constrain velocity target value
427
+ if (abs (velocity_target) > P_angle.velocity_limit ) velocity_target = velocity_target > 0 ? P_angle.velocity_limit : -P_angle.velocity_limit ;
428
+ return velocity_target;
346
429
}
347
430
348
431
/* *
0 commit comments