Skip to content

Commit 8acda6f

Browse files
committed
version 1.3.0 intial change
1 parent e4e24ff commit 8acda6f

22 files changed

+1220
-1224
lines changed

arduino_foc_minimal_encoder/BLDCMotor.cpp

Lines changed: 176 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
2424
PI_velocity.P = DEF_PI_VEL_P;
2525
PI_velocity.I = DEF_PI_VEL_I;
2626
PI_velocity.timestamp = _micros();
27-
PI_velocity.voltage_limit = voltage_power_supply/2;
27+
PI_velocity.voltage_limit = voltage_power_supply;
2828
PI_velocity.voltage_ramp = DEF_PI_VEL_U_RAMP;
2929
PI_velocity.voltage_prev = 0;
3030
PI_velocity.tracking_error_prev = 0;
@@ -40,51 +40,46 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
4040
// maximum angular velocity to be used for positioning
4141
P_angle.velocity_limit = DEF_P_ANGLE_VEL_LIM;
4242

43-
// index search PI controller
44-
PI_velocity_index_search.P = DEF_PI_VEL_INDEX_P;
45-
PI_velocity_index_search.I = DEF_PI_VEL_INDEX_I;
46-
PI_velocity_index_search.voltage_limit = voltage_power_supply/2;
47-
PI_velocity_index_search.voltage_ramp = DEF_PI_VEL_INDEX_U_RAMP;
48-
PI_velocity_index_search.timestamp = _micros();
49-
PI_velocity_index_search.voltage_prev = 0;
50-
PI_velocity_index_search.tracking_error_prev = 0;
51-
5243
// index search velocity
53-
index_search_velocity = DEF_INDEX_SEARCH_TARGET_VELOCITY;
44+
velocity_index_search = DEF_INDEX_SEARCH_TARGET_VELOCITY;
45+
// sensor and motor align voltage
46+
voltage_sensor_align = DEF_VOLTAGE_SENSOR_ALIGN;
5447

5548
// electric angle of the zero angle
5649
zero_electric_angle = 0;
5750

5851
// default modulation is SinePWM
5952
foc_modulation = FOCModulationType::SinePWM;
6053

61-
//debugger
62-
debugger = nullptr;
54+
// default target value
55+
target = 0;
56+
57+
//monitor_port
58+
monitor_port = nullptr;
6359
}
6460

6561
// init hardware pins
6662
void BLDCMotor::init() {
67-
if(debugger) debugger->println("DEBUG: Initialize the motor pins.");
63+
if(monitor_port) monitor_port->println("MONITOR: Initialize the motor pins.");
6864
// PWM pins
6965
pinMode(pwmA, OUTPUT);
7066
pinMode(pwmB, OUTPUT);
7167
pinMode(pwmC, OUTPUT);
7268
if(hasEnable()) pinMode(enable_pin, OUTPUT);
7369

74-
if(debugger) debugger->println("DEBUG: Set high frequency PWM.");
70+
if(monitor_port) monitor_port->println("MONITOR: Set high frequency PWM.");
7571
// Increase PWM frequency to 32 kHz
7672
// make silent
7773
setPwmFrequency(pwmA);
7874
setPwmFrequency(pwmB);
7975
setPwmFrequency(pwmC);
8076

8177
// sanity check for the voltage limit configuration
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;
78+
if(PI_velocity.voltage_limit > voltage_power_supply) PI_velocity.voltage_limit = voltage_power_supply;
8479

8580
_delay(500);
8681
// enable motor
87-
if(debugger) debugger->println("DEBUG: Enabling motor.");
82+
if(monitor_port) monitor_port->println("MONITOR: Enabling motor.");
8883
enable();
8984
_delay(500);
9085

@@ -120,11 +115,11 @@ void BLDCMotor::linkSensor(Sensor* _sensor) {
120115

121116
// Encoder alignment to electrical 0 angle
122117
int BLDCMotor::alignSensor() {
123-
if(debugger) debugger->println("DEBUG: Align the sensor's and motor electrical 0 angle.");
118+
if(monitor_port) monitor_port->println("MONITOR: Align the sensor's and motor electrical 0 angle.");
124119
// align the electrical phases of the motor and sensor
125-
setPwm(pwmA, voltage_power_supply/2.0);
126-
setPwm(pwmB,0);
127-
setPwm(pwmC,0);
120+
// set angle -90 degrees
121+
setPhaseVoltage(voltage_sensor_align, _3PI_2);
122+
// let the motor stabilize for 3 sec
128123
_delay(3000);
129124
// set sensor to zero
130125
sensor->initRelativeZero();
@@ -135,10 +130,10 @@ int BLDCMotor::alignSensor() {
135130
// find the index if available
136131
int exit_flag = absoluteZeroAlign();
137132
_delay(500);
138-
if(debugger){
139-
if(exit_flag< 0 ) debugger->println("DEBUG: Error: Absolute zero not found!");
140-
if(exit_flag> 0 ) debugger->println("DEBUG: Success: Absolute zero found!");
141-
else debugger->println("DEBUG: Absolute zero not available!");
133+
if(monitor_port){
134+
if(exit_flag< 0 ) monitor_port->println("MONITOR: Error: Absolute zero not found!");
135+
if(exit_flag> 0 ) monitor_port->println("MONITOR: Success: Absolute zero found!");
136+
else monitor_port->println("MONITOR: Absolute zero not available!");
142137
}
143138
return exit_flag;
144139
}
@@ -150,13 +145,13 @@ int BLDCMotor::absoluteZeroAlign() {
150145
// if no absolute zero return
151146
if(!sensor->hasAbsoluteZero()) return 0;
152147

153-
if(debugger) debugger->println("DEBUG: Aligning the absolute zero.");
148+
if(monitor_port) monitor_port->println("MONITOR: Aligning the absolute zero.");
154149

155-
if(debugger && sensor->needsAbsoluteZeroSearch()) debugger->println("DEBUG: Searching for absolute zero.");
150+
if(monitor_port && sensor->needsAbsoluteZeroSearch()) monitor_port->println("MONITOR: Searching for absolute zero.");
156151
// search the absolute zero with small velocity
157152
while(sensor->needsAbsoluteZeroSearch() && shaft_angle < _2PI){
158153
loopFOC();
159-
voltage_q = velocityIndexSearchPI(index_search_velocity - shaftVelocity());
154+
voltage_q = velocityPI(velocity_index_search - shaftVelocity());
160155
}
161156
voltage_q = 0;
162157
// disable motor
@@ -169,7 +164,7 @@ int BLDCMotor::absoluteZeroAlign() {
169164
// remember zero electric angle
170165
zero_electric_angle = electricAngle(zero_offset);
171166
}
172-
// return bool is zero found
167+
// return bool if zero found
173168
return !sensor->needsAbsoluteZeroSearch() ? 1 : -1;
174169
}
175170

@@ -208,6 +203,9 @@ int BLDCMotor::initFOC() {
208203
_delay(500);
209204
int exit_flag = alignSensor();
210205
_delay(500);
206+
207+
if(monitor_port) monitor_port->println("MONITOR: FOC init finished - motor ready.");
208+
211209
return exit_flag;
212210
}
213211

@@ -224,13 +222,16 @@ void BLDCMotor::loopFOC() {
224222
// Behavior of this function is determined by the motor.controller variable
225223
// It runs either angle, velocity or voltage loop
226224
// - needs to be called iteratively it is asynchronous function
227-
void BLDCMotor::move(float target) {
225+
// - if target is not set it uses motor.target value
226+
void BLDCMotor::move(float new_target) {
227+
// set internal target variable
228+
if( new_target != NOT_SET ) target = new_target;
228229
// get angular velocity
229230
shaft_velocity = shaftVelocity();
230231
// choose control loop
231232
switch (controller) {
232233
case ControlType::voltage:
233-
voltage_q = target;
234+
voltage_q = target;
234235
break;
235236
case ControlType::angle:
236237
// angle set point
@@ -281,7 +282,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
281282

282283
// if negative voltages change inverse the phase
283284
// angle + 180degrees
284-
if(Uq < 0) angle_el += M_PI;
285+
if(Uq < 0) angle_el += _PI;
285286
Uq = abs(Uq);
286287

287288
// angle normalisation in between 0 and 2pi
@@ -296,7 +297,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
296297
// two versions possible
297298
// centered around voltage_power_supply/2
298299
float T0 = 1 - T1 - T2;
299-
// centered around 0
300+
// pulled to 0 - better for low power supply voltage
300301
//T0 = 0;
301302

302303
// calculate the duty cycles(times)
@@ -381,7 +382,7 @@ float BLDCMotor::normalizeAngle(float angle){
381382
}
382383
// determining if the enable pin has been provided
383384
int BLDCMotor::hasEnable(){
384-
return enable_pin != 0;
385+
return enable_pin != NOT_SET;
385386
}
386387

387388

@@ -391,6 +392,7 @@ int BLDCMotor::hasEnable(){
391392
// PI controller function
392393
float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
393394
float Ts = (_micros() - cont.timestamp) * 1e-6;
395+
394396
// quick fix for strange cases (micros overflow)
395397
if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
396398

@@ -406,6 +408,7 @@ float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
406408
float d_voltage = voltage - cont.voltage_prev;
407409
if (abs(d_voltage)/Ts > cont.voltage_ramp) voltage = d_voltage > 0 ? cont.voltage_prev + cont.voltage_ramp*Ts : cont.voltage_prev - cont.voltage_ramp*Ts;
408410

411+
409412
cont.voltage_prev = voltage;
410413
cont.tracking_error_prev = tracking_error;
411414
cont.timestamp = _micros();
@@ -415,10 +418,7 @@ float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
415418
float BLDCMotor::velocityPI(float tracking_error) {
416419
return controllerPI(tracking_error, PI_velocity);
417420
}
418-
// index search PI contoller
419-
float BLDCMotor::velocityIndexSearchPI(float tracking_error) {
420-
return controllerPI(tracking_error, PI_velocity_index_search);
421-
}
421+
422422
// P controller for position control loop
423423
float BLDCMotor::positionP(float ek) {
424424
// calculate the target velocity from the position error
@@ -429,38 +429,153 @@ float BLDCMotor::positionP(float ek) {
429429
}
430430

431431
/**
432-
* Debugger functions
432+
* Monitoring functions
433433
*/
434-
// function implementing the debugger setter
435-
void BLDCMotor::useDebugging(Print &print){
436-
debugger = &print; //operate on the address of print
437-
if(debugger )debugger->println("DEBUG: Serial debugger enabled!");
434+
// function implementing the monitor_port setter
435+
void BLDCMotor::useMonitoring(Print &print){
436+
monitor_port = &print; //operate on the address of print
437+
if(monitor_port ) monitor_port->println("MONITOR: Serial monitor enabled!");
438438
}
439439
// utility function intended to be used with serial plotter to monitor motor variables
440440
// significantly slowing the execution down!!!!
441441
void BLDCMotor::monitor() {
442-
if(!debugger) return;
442+
if(!monitor_port) return;
443443
switch (controller) {
444444
case ControlType::velocity:
445-
debugger->print(voltage_q);
446-
debugger->print("\t");
447-
debugger->print(shaft_velocity_sp);
448-
debugger->print("\t");
449-
debugger->println(shaft_velocity);
445+
monitor_port->print(voltage_q);
446+
monitor_port->print("\t");
447+
monitor_port->print(shaft_velocity_sp);
448+
monitor_port->print("\t");
449+
monitor_port->println(shaft_velocity);
450450
break;
451451
case ControlType::angle:
452-
debugger->print(voltage_q);
453-
debugger->print("\t");
454-
debugger->print(shaft_angle_sp);
455-
debugger->print("\t");
456-
debugger->println(shaft_angle);
452+
monitor_port->print(voltage_q);
453+
monitor_port->print("\t");
454+
monitor_port->print(shaft_angle_sp);
455+
monitor_port->print("\t");
456+
monitor_port->println(shaft_angle);
457457
break;
458458
case ControlType::voltage:
459-
debugger->print(voltage_q);
460-
debugger->print("\t");
461-
debugger->print(shaft_angle);
462-
debugger->print("\t");
463-
debugger->println(shaft_velocity);
459+
monitor_port->print(voltage_q);
460+
monitor_port->print("\t");
461+
monitor_port->print(shaft_angle);
462+
monitor_port->print("\t");
463+
monitor_port->println(shaft_velocity);
464464
break;
465465
}
466-
}
466+
}
467+
468+
int BLDCMotor::command(String user_command) {
469+
// error flag
470+
int errorFlag = 1;
471+
// parse command letter
472+
char cmd = user_command.charAt(0);
473+
// check if get command
474+
char GET = user_command.charAt(1) == '\n';
475+
// parse command values
476+
float value = user_command.substring(1).toFloat();
477+
478+
// apply the the command
479+
switch(cmd){
480+
case 'P': // velocity P gain change
481+
if(monitor_port) monitor_port->print("PI velocity P: ");
482+
if(!GET) PI_velocity.P = value;
483+
if(monitor_port) monitor_port->println(PI_velocity.P);
484+
break;
485+
case 'I': // velocity I gain change
486+
if(monitor_port) monitor_port->print("PI velocity I: ");
487+
if(!GET) PI_velocity.I = value;
488+
if(monitor_port) monitor_port->println(PI_velocity.I);
489+
break;
490+
case 'L': // velocity voltage limit change
491+
if(monitor_port) monitor_port->print("PI velocity voltage limit: ");
492+
if(!GET)PI_velocity.voltage_limit = value;
493+
if(monitor_port) monitor_port->println(PI_velocity.voltage_limit);
494+
break;
495+
case 'R': // velocity voltage ramp change
496+
if(monitor_port) monitor_port->print("PI velocity voltage ramp: ");
497+
if(!GET) PI_velocity.voltage_ramp = value;
498+
if(monitor_port) monitor_port->println(PI_velocity.voltage_ramp);
499+
break;
500+
case 'F': // velocity Tf low pass filter change
501+
if(monitor_port) monitor_port->print("LPF velocity time constant: ");
502+
if(!GET) LPF_velocity.Tf = value;
503+
if(monitor_port) monitor_port->println(LPF_velocity.Tf);
504+
break;
505+
case 'K': // angle loop gain P change
506+
if(monitor_port) monitor_port->print("P angle P value: ");
507+
if(!GET) P_angle.P = value;
508+
if(monitor_port) monitor_port->println(P_angle.P);
509+
break;
510+
case 'N': // angle loop gain velocity_limit change
511+
if(monitor_port) monitor_port->print("P angle velocity limit: ");
512+
if(!GET) P_angle.velocity_limit = value;
513+
if(monitor_port) monitor_port->println(P_angle.velocity_limit);
514+
break;
515+
case 'C':
516+
// change control type
517+
if(monitor_port) monitor_port->print("Contoller type: ");
518+
519+
if(GET){ // if get commang
520+
switch(controller){
521+
case ControlType::voltage:
522+
if(monitor_port) monitor_port->println("voltage");
523+
break;
524+
case ControlType::velocity:
525+
if(monitor_port) monitor_port->println("velocity");
526+
break;
527+
case ControlType::angle:
528+
if(monitor_port) monitor_port->println("angle");
529+
break;
530+
}
531+
}else{ // if set command
532+
switch((int)value){
533+
case 0:
534+
if(monitor_port) monitor_port->println("voltage");
535+
controller = ControlType::voltage;
536+
break;
537+
case 1:
538+
if(monitor_port) monitor_port->println("velocity");
539+
controller = ControlType::velocity;
540+
break;
541+
case 2:
542+
if(monitor_port) monitor_port->println("angle");
543+
controller = ControlType::angle;
544+
break;
545+
default: // not valid command
546+
errorFlag = 0;
547+
}
548+
}
549+
break;
550+
case 'V': // get current values of the state variables
551+
switch((int)value){
552+
case 0: // get voltage
553+
if(monitor_port) monitor_port->print("Uq: ");
554+
if(monitor_port) monitor_port->println(voltage_q);
555+
break;
556+
case 1: // get velocity
557+
if(monitor_port) monitor_port->print("Velocity: ");
558+
if(monitor_port) monitor_port->println(shaft_velocity);
559+
break;
560+
case 2: // get angle
561+
if(monitor_port) monitor_port->print("Angle: ");
562+
if(monitor_port) monitor_port->println(shaft_angle);
563+
break;
564+
case 3: // get angle
565+
if(monitor_port) monitor_port->print("Target: ");
566+
if(monitor_port) monitor_port->println(target);
567+
break;
568+
default: // not valid command
569+
errorFlag = 0;
570+
}
571+
break;
572+
default: // target change
573+
if(monitor_port) monitor_port->print("Target : ");
574+
target = user_command.toFloat();
575+
if(monitor_port) monitor_port->println(target);
576+
}
577+
// return 0 if error and 1 if ok
578+
return errorFlag;
579+
}
580+
581+

0 commit comments

Comments
 (0)