1
1
#include " BLDCMotor.h"
2
2
3
- // BLDCMotor( int phA, int phB, int phC, int pp, int cpr, int en)
3
+ // // BLDCMotor( int phA, int phB, int phC, int pp, int cpr, int en)
4
+ // // - phA, phB, phC - motor A,B,C phase pwm pins
5
+ // // - pp - pole pair number
6
+ // // - cpr - counts per rotation number (cpm=ppm*4)
7
+ // // - enable pin - (optional input)
8
+ // BLDCMotor::BLDCMotor( int phA, int phB, int phC, int pp, int cpr, int en){
9
+ // noop;
10
+ // }
11
+
12
+ // BLDCMotor( int pp)
4
13
// - phA, phB, phC - motor A,B,C phase pwm pins
5
14
// - pp - pole pair number
6
15
// - cpr - counts per rotation number (cpm=ppm*4)
7
16
// - enable pin - (optional input)
8
- BLDCMotor::BLDCMotor (int phA, int phB, int phC, int pp, int en )
17
+ BLDCMotor::BLDCMotor (int pp )
9
18
: FOCMotor()
10
19
{
11
- // Pin initialization
12
- pwmA = phA;
13
- pwmB = phB;
14
- pwmC = phC;
20
+ // save pole pairs number
15
21
pole_pairs = pp;
22
+ }
16
23
17
- // enable_pin pin
18
- enable_pin = en;
19
24
25
+ /* *
26
+ Link the driver which controls the motor
27
+ */
28
+ void BLDCMotor::linkDriver (BLDCDriver* _driver) {
29
+ driver = _driver;
20
30
}
21
31
22
-
23
32
// init hardware pins
24
- void BLDCMotor::init (long pwm_frequency) {
25
- if (monitor_port) monitor_port->println (" MOT: Init pins." );
26
- // PWM pins
27
- pinMode (pwmA, OUTPUT);
28
- pinMode (pwmB, OUTPUT);
29
- pinMode (pwmC, OUTPUT);
30
- if (enable_pin != NOT_SET) pinMode (enable_pin, OUTPUT);
31
-
32
- if (monitor_port) monitor_port->println (" MOT: PWM config." );
33
- // Increase PWM frequency to 32 kHz
34
- // make silent
35
- _setPwmFrequency (pwm_frequency, pwmA, pwmB, pwmC);
36
-
33
+ void BLDCMotor::init () {
34
+ if (monitor_port) monitor_port->println (" MOT: Initialise variables." );
37
35
// sanity check for the voltage limit configuration
38
- if (voltage_limit > voltage_power_supply ) voltage_limit = voltage_power_supply ;
36
+ if (voltage_limit > driver-> voltage_limit ) voltage_limit = driver-> voltage_limit ;
39
37
// constrain voltage for sensor alignment
40
38
if (voltage_sensor_align > voltage_limit) voltage_sensor_align = voltage_limit;
41
39
// update the controller limits
@@ -44,7 +42,7 @@ void BLDCMotor::init(long pwm_frequency) {
44
42
45
43
_delay (500 );
46
44
// enable motor
47
- if (monitor_port) monitor_port->println (" MOT: Enable." );
45
+ if (monitor_port) monitor_port->println (" MOT: Enable driver ." );
48
46
enable ();
49
47
_delay (500 );
50
48
}
@@ -53,18 +51,18 @@ void BLDCMotor::init(long pwm_frequency) {
53
51
// disable motor driver
54
52
void BLDCMotor::disable ()
55
53
{
56
- // disable the driver - if enable_pin pin available
57
- if (enable_pin != NOT_SET) digitalWrite (enable_pin, LOW);
58
54
// set zero to PWM
59
- setPwm (0 , 0 , 0 );
55
+ driver->setPwm (0 , 0 , 0 );
56
+ // disable the driver
57
+ driver->disable ();
60
58
}
61
59
// enable motor driver
62
60
void BLDCMotor::enable ()
63
61
{
62
+ // enable the driver
63
+ driver->enable ();
64
64
// set zero to PWM
65
- setPwm (0 , 0 , 0 );
66
- // enable_pin the driver - if enable_pin pin available
67
- if (enable_pin != NOT_SET) digitalWrite (enable_pin, HIGH);
65
+ driver->setPwm (0 , 0 , 0 );
68
66
69
67
}
70
68
@@ -100,13 +98,13 @@ int BLDCMotor::alignSensor() {
100
98
float start_angle = shaftAngle ();
101
99
for (int i = 0 ; i <=5 ; i++ ) {
102
100
float angle = _3PI_2 + _2PI * i / 6.0 ;
103
- setPhaseVoltage (voltage_sensor_align, angle);
101
+ setPhaseVoltage (voltage_sensor_align, 0 , angle);
104
102
_delay (200 );
105
103
}
106
104
float mid_angle = shaftAngle ();
107
105
for (int i = 5 ; i >=0 ; i-- ) {
108
106
float angle = _3PI_2 + _2PI * i / 6.0 ;
109
- setPhaseVoltage (voltage_sensor_align, angle);
107
+ setPhaseVoltage (voltage_sensor_align, 0 , angle);
110
108
_delay (200 );
111
109
}
112
110
if (mid_angle < start_angle) {
@@ -121,7 +119,7 @@ int BLDCMotor::alignSensor() {
121
119
// set sensor to zero
122
120
sensor->initRelativeZero ();
123
121
_delay (500 );
124
- setPhaseVoltage (0 ,0 );
122
+ setPhaseVoltage (0 , 0 , 0 );
125
123
_delay (200 );
126
124
127
125
// find the index if available
@@ -153,7 +151,7 @@ int BLDCMotor::absoluteZeroAlign() {
153
151
}
154
152
voltage_q = 0 ;
155
153
// disable motor
156
- setPhaseVoltage (0 ,0 );
154
+ setPhaseVoltage (0 , 0 , 0 );
157
155
158
156
// align absolute zero if it has been found
159
157
if (!sensor->needsAbsoluteZeroSearch ()){
@@ -172,7 +170,7 @@ void BLDCMotor::loopFOC() {
172
170
// shaft angle
173
171
shaft_angle = shaftAngle ();
174
172
// set the phase voltage - FOC heart function :)
175
- setPhaseVoltage (voltage_q, _electricalAngle (shaft_angle,pole_pairs));
173
+ setPhaseVoltage (voltage_q, voltage_d, _electricalAngle (shaft_angle,pole_pairs));
176
174
}
177
175
178
176
// Iterative function running outer loop of the FOC algorithm
@@ -219,30 +217,85 @@ void BLDCMotor::move(float new_target) {
219
217
}
220
218
221
219
222
- // Method using FOC to set Uq to the motor at the optimal angle
220
+ // Method using FOC to set Uq and Ud to the motor at the optimal angle
223
221
// Function implementing Space Vector PWM and Sine PWM algorithms
224
222
//
225
223
// Function using sine approximation
226
224
// regular sin + cos ~300us (no memory usaage)
227
225
// approx _sin + _cos ~110us (400Byte ~ 20% of memory)
228
- void BLDCMotor::setPhaseVoltage (float Uq, float angle_el) {
226
+ void BLDCMotor::setPhaseVoltage (float Uq, float Ud, float angle_el) {
227
+
228
+ const bool centered = true ;
229
+ int sector;
230
+ float _ca,_sa;
231
+
229
232
switch (foc_modulation)
230
233
{
234
+ case FOCModulationType::Trapezoid_120 :
235
+ // see https://www.youtube.com/watch?v=InzXA7mWBWE Slide 5
236
+ static int trap_120_map[6 ][3 ] = {
237
+ {0 ,1 ,-1 },{-1 ,1 ,0 },{-1 ,0 ,1 },{0 ,-1 ,1 },{1 ,-1 ,0 },{1 ,0 ,-1 } // each is 60 degrees with values for 3 phases of 1=positive -1=negative 0=high-z
238
+ };
239
+ // static int trap_120_state = 0;
240
+ sector = 6 * (_normalizeAngle (angle_el + PI/6.0 + zero_electric_angle) / _2PI); // adding PI/6 to align with other modes
241
+
242
+ Ua = Uq + trap_120_map[sector][0 ] * Uq;
243
+ Ub = Uq + trap_120_map[sector][1 ] * Uq;
244
+ Uc = Uq + trap_120_map[sector][2 ] * Uq;
245
+
246
+ if (centered) {
247
+ Ua += (driver->voltage_limit )/2 -Uq;
248
+ Ub += (driver->voltage_limit )/2 -Uq;
249
+ Uc += (driver->voltage_limit )/2 -Uq;
250
+ }
251
+ break ;
252
+
253
+ case FOCModulationType::Trapezoid_150 :
254
+ // see https://www.youtube.com/watch?v=InzXA7mWBWE Slide 8
255
+ static int trap_150_map[12 ][3 ] = {
256
+ {0 ,1 ,-1 },{-1 ,1 ,-1 },{-1 ,1 ,0 },{-1 ,1 ,1 },{-1 ,0 ,1 },{-1 ,-1 ,1 },{0 ,-1 ,1 },{1 ,-1 ,1 },{1 ,-1 ,0 },{1 ,-1 ,-1 },{1 ,0 ,-1 },{1 ,1 ,-1 } // each is 30 degrees with values for 3 phases of 1=positive -1=negative 0=high-z
257
+ };
258
+ // static int trap_150_state = 0;
259
+ sector = 12 * (_normalizeAngle (angle_el + PI/6.0 + zero_electric_angle) / _2PI); // adding PI/6 to align with other modes
260
+
261
+ Ua = Uq + trap_150_map[sector][0 ] * Uq;
262
+ Ub = Uq + trap_150_map[sector][1 ] * Uq;
263
+ Uc = Uq + trap_150_map[sector][2 ] * Uq;
264
+
265
+ // center
266
+ if (centered) {
267
+ Ua += (driver->voltage_limit )/2 -Uq;
268
+ Ub += (driver->voltage_limit )/2 -Uq;
269
+ Uc += (driver->voltage_limit )/2 -Uq;
270
+ }
271
+
272
+ break ;
273
+
231
274
case FOCModulationType::SinePWM :
232
275
// Sinusoidal PWM modulation
233
276
// Inverse Park + Clarke transformation
234
277
235
278
// angle normalization in between 0 and 2pi
236
279
// only necessary if using _sin and _cos - approximation functions
237
280
angle_el = _normalizeAngle (angle_el + zero_electric_angle);
281
+ _ca = _cos (angle_el);
282
+ _sa = _sin (angle_el);
238
283
// Inverse park transform
239
- Ualpha = - _sin (angle_el) * Uq; // -sin(angle) * Uq;
240
- Ubeta = _cos (angle_el) * Uq; // cos(angle) * Uq;
284
+ Ualpha = _ca * Ud - _sa * Uq; // -sin(angle) * Uq;
285
+ Ubeta = _sa * Ud + _ca * Uq; // cos(angle) * Uq;
241
286
242
287
// Clarke transform
243
- Ua = Ualpha + voltage_power_supply/2 ;
244
- Ub = -0.5 * Ualpha + _SQRT3_2 * Ubeta + voltage_power_supply/2 ;
245
- Uc = -0.5 * Ualpha - _SQRT3_2 * Ubeta + voltage_power_supply/2 ;
288
+ Ua = Ualpha + driver->voltage_limit /2 ;
289
+ Ub = -0.5 * Ualpha + _SQRT3_2 * Ubeta + driver->voltage_limit /2 ;
290
+ Uc = -0.5 * Ualpha - _SQRT3_2 * Ubeta + driver->voltage_limit /2 ;
291
+
292
+ if (!centered) {
293
+ float Umin = min (Ua, min (Ub, Uc));
294
+ Ua -= Umin;
295
+ Ub -= Umin;
296
+ Uc -= Umin;
297
+ }
298
+
246
299
break ;
247
300
248
301
case FOCModulationType::SpaceVectorPWM :
@@ -259,15 +312,15 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
259
312
angle_el = _normalizeAngle (angle_el + zero_electric_angle + _PI_2);
260
313
261
314
// find the sector we are in currently
262
- int sector = floor (angle_el / _PI_3) + 1 ;
315
+ sector = floor (angle_el / _PI_3) + 1 ;
263
316
// calculate the duty cycles
264
- float T1 = _SQRT3*_sin (sector*_PI_3 - angle_el) * Uq/voltage_power_supply ;
265
- float T2 = _SQRT3*_sin (angle_el - (sector-1.0 )*_PI_3) * Uq/voltage_power_supply ;
317
+ float T1 = _SQRT3*_sin (sector*_PI_3 - angle_el) * Uq/driver-> voltage_limit ;
318
+ float T2 = _SQRT3*_sin (angle_el - (sector-1.0 )*_PI_3) * Uq/driver-> voltage_limit ;
266
319
// two versions possible
267
- // centered around voltage_power_supply/2
268
- float T0 = 1 - T1 - T2;
269
- // pulled to 0 - better for low power supply voltage
270
- // float T0 = 0;
320
+ float T0 = 0 ; // pulled to 0 - better for low power supply voltage
321
+ if (centered) {
322
+ T0 = 1 - T1 - T2; // centered around driver->voltage_limit/2
323
+ }
271
324
272
325
// calculate the duty cycles(times)
273
326
float Ta,Tb,Tc;
@@ -310,27 +363,15 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
310
363
}
311
364
312
365
// calculate the phase voltages and center
313
- Ua = Ta*voltage_power_supply ;
314
- Ub = Tb*voltage_power_supply ;
315
- Uc = Tc*voltage_power_supply ;
366
+ Ua = Ta*driver-> voltage_limit ;
367
+ Ub = Tb*driver-> voltage_limit ;
368
+ Uc = Tc*driver-> voltage_limit ;
316
369
break ;
370
+
317
371
}
318
372
319
- // set the voltages in hardware
320
- setPwm (Ua, Ub, Uc);
321
- }
322
-
323
-
324
-
325
- // Set voltage to the pwm pin
326
- void BLDCMotor::setPwm (float Ua, float Ub, float Uc) {
327
- // calculate duty cycle
328
- // limited in [0,1]
329
- float dc_a = constrain (Ua / voltage_power_supply, 0 , 1 );
330
- float dc_b = constrain (Ub / voltage_power_supply, 0 , 1 );
331
- float dc_c = constrain (Uc / voltage_power_supply, 0 , 1 );
332
- // hardware specific writing
333
- _writeDutyCycle (dc_a, dc_b, dc_c, pwmA, pwmB, pwmC );
373
+ // set the voltages in driver
374
+ driver->setPwm (Ua, Ub, Uc);
334
375
}
335
376
336
377
@@ -348,7 +389,7 @@ void BLDCMotor::velocityOpenloop(float target_velocity){
348
389
shaft_angle += target_velocity*Ts;
349
390
350
391
// set the maximal allowed voltage (voltage_limit) with the necessary angle
351
- setPhaseVoltage (voltage_limit, _electricalAngle (shaft_angle, pole_pairs));
392
+ setPhaseVoltage (voltage_limit, 0 , _electricalAngle (shaft_angle, pole_pairs));
352
393
353
394
// save timestamp for next call
354
395
open_loop_timestamp = now_us;
@@ -371,7 +412,7 @@ void BLDCMotor::angleOpenloop(float target_angle){
371
412
shaft_angle = target_angle;
372
413
373
414
// set the maximal allowed voltage (voltage_limit) with the necessary angle
374
- setPhaseVoltage (voltage_limit, _electricalAngle (shaft_angle, pole_pairs));
415
+ setPhaseVoltage (voltage_limit, 0 , _electricalAngle (shaft_angle, pole_pairs));
375
416
376
417
// save timestamp for next call
377
418
open_loop_timestamp = now_us;
0 commit comments