Skip to content

Commit 0d83541

Browse files
committed
FEAT open loop control with the same interface as close loop
1 parent cb99187 commit 0d83541

File tree

5 files changed

+130
-84
lines changed

5 files changed

+130
-84
lines changed

examples/motion_control/open_loop_motor_control/open_loop_position_example/open_loop_position_example.ino

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,27 @@ void setup() {
1010
// default 12V
1111
motor.voltage_power_supply = 12;
1212

13+
// limiting motor movements
14+
motor.voltage_limit = 3; // rad/s
15+
motor.velocity_limit = 20; // rad/s
16+
// open loop control config
17+
motor.controller = ControlType::angle_openloop;
18+
1319
// init motor hardware
1420
motor.init();
21+
1522

1623
Serial.begin(115200);
1724
Serial.println("Motor ready!");
1825
_delay(1000);
1926
}
2027

2128
float target_position = 0; // rad/s
22-
float target_velocity= 10; // rad/s
23-
float target_voltage = 3; // V
2429

2530
void loop() {
26-
// set angle in open loop
27-
// - angle - rad
28-
// - velocity - rad/s
29-
// - voltage - V
30-
motor.angleOpenloop(target_position, target_velocity, target_voltage);
31-
32-
// a bit of delay
33-
_delay(1);
31+
// open loop angle movements
32+
// using motor.voltage_limit and motor.velocity_limit
33+
motor.move(target_position);
3434

3535
// receive the used commands from serial
3636
serialReceiveUserCommand();

examples/motion_control/open_loop_motor_control/open_loop_velocity_example/open_loop_velocity_example.ino

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,28 @@ void setup() {
1010
// default 12V
1111
motor.voltage_power_supply = 12;
1212

13+
// limiting motor movements
14+
motor.voltage_limit = 3; // rad/s
15+
motor.velocity_limit = 20; // rad/s
16+
17+
// open loop control config
18+
motor.controller = ControlType::velocity_openloop;
19+
1320
// init motor hardware
1421
motor.init();
22+
1523

1624
Serial.begin(115200);
1725
Serial.println("Motor ready!");
1826
_delay(1000);
1927
}
2028

21-
float target_velocity= 2; // rad/s
22-
float target_voltage = 3; // V
23-
void loop() {
24-
// set velocity in open loop
25-
// - velocity - rad/s
26-
// - voltage - V
27-
motor.velocityOpenloop(target_velocity, target_voltage);
29+
float target_velocity = 0; // rad/s
2830

29-
// a bit of delay
30-
_delay(1);
31+
void loop() {
32+
// open loop velocity movement
33+
// using motor.voltage_limit and motor.velocity_limit
34+
motor.move(target_velocity);
3135

3236
// receive the used commands from serial
3337
serialReceiveUserCommand();
@@ -50,7 +54,7 @@ void serialReceiveUserCommand() {
5054

5155
// change the motor target
5256
target_velocity = received_chars.toFloat();
53-
Serial.print("Target velocity: ");
57+
Serial.print("Target velocity ");
5458
Serial.println(target_velocity);
5559

5660
// reset the command buffer

keywords.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ target KEYWORD2
6464

6565
voltage KEYWORD2
6666
velocity KEYWORD2
67-
velocity_ultra_slow KEYWORD2
67+
velocity_openloop KEYWORD2
6868
angle KEYWORD2
69+
angle_openloop KEYWORD2
6970

7071

7172
ON KEYWORD2

src/BLDCMotor.cpp

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ 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;
2827
PI_velocity.voltage_ramp = DEF_PI_VEL_U_RAMP;
2928
PI_velocity.voltage_prev = 0;
3029
PI_velocity.tracking_error_prev = 0;
@@ -37,8 +36,11 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
3736
// position loop config
3837
// P controller constant
3938
P_angle.P = DEF_P_ANGLE_P;
39+
4040
// maximum angular velocity to be used for positioning
41-
P_angle.velocity_limit = DEF_P_ANGLE_VEL_LIM;
41+
velocity_limit = DEF_P_ANGLE_VEL_LIM;
42+
// maximum voltage to be set to the motor
43+
voltage_limit = voltage_power_supply;
4244

4345
// index search velocity
4446
velocity_index_search = DEF_INDEX_SEARCH_TARGET_VELOCITY;
@@ -56,6 +58,8 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
5658

5759
//monitor_port
5860
monitor_port = nullptr;
61+
//sensor
62+
sensor = nullptr;
5963
}
6064

6165
// init hardware pins
@@ -73,7 +77,7 @@ void BLDCMotor::init() {
7377
_setPwmFrequency(pwmA, pwmB, pwmC);
7478

7579
// sanity check for the voltage limit configuration
76-
if(PI_velocity.voltage_limit > voltage_power_supply) PI_velocity.voltage_limit = voltage_power_supply;
80+
if(voltage_limit > voltage_power_supply) voltage_limit = voltage_power_supply;
7781

7882
_delay(500);
7983
// enable motor
@@ -187,10 +191,14 @@ int BLDCMotor::absoluteZeroAlign() {
187191
*/
188192
// shaft angle calculation
189193
float BLDCMotor::shaftAngle() {
194+
// if no sensor linked return 0
195+
//if(!sensor) return 0;
190196
return sensor->getAngle();
191197
}
192198
// shaft velocity calculation
193199
float BLDCMotor::shaftVelocity() {
200+
// if no sensor linked return 0
201+
//if(!sensor) return 0;
194202
float Ts = (_micros() - LPF_velocity.timestamp) * 1e-6;
195203
// quick fix for strange cases (micros overflow)
196204
if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
@@ -269,6 +277,18 @@ void BLDCMotor::move(float new_target) {
269277
shaft_velocity_sp = target;
270278
voltage_q = velocityPI(shaft_velocity_sp - shaft_velocity);
271279
break;
280+
case ControlType::velocity_openloop:
281+
// velocity control in open loop
282+
// loopFOC should not be called
283+
shaft_velocity_sp = target;
284+
velocityOpenloop(shaft_velocity_sp);
285+
break;
286+
case ControlType::angle_openloop:
287+
// angle control in open loop
288+
// loopFOC should not be called
289+
shaft_angle_sp = target;
290+
angleOpenloop(shaft_angle_sp);
291+
break;
272292
}
273293
}
274294

@@ -364,9 +384,9 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
364384
}
365385

366386
// calculate the phase voltages and center
367-
Ua = Ta*voltage_power_supply;// + (voltage_power_supply - Uq) / 2;
368-
Ub = Tb*voltage_power_supply;// + (voltage_power_supply - Uq) / 2;
369-
Uc = Tc*voltage_power_supply;// + (voltage_power_supply - Uq) / 2;
387+
Ua = Ta*voltage_power_supply;
388+
Ub = Tb*voltage_power_supply;
389+
Uc = Tc*voltage_power_supply;
370390
break;
371391
}
372392

@@ -376,14 +396,13 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
376396

377397

378398

379-
380399
// Set voltage to the pwm pin
381400
void BLDCMotor::setPwm(float Ua, float Ub, float Uc) {
382401
// calculate duty cycle
383402
// limited in [0,1]
384-
float dc_a = (Ua < 0) ? 0 : (Ua >= voltage_power_supply) ? 1 : Ua / voltage_power_supply;
385-
float dc_b = (Ub < 0) ? 0 : (Ub >= voltage_power_supply) ? 1 : Ub / voltage_power_supply;
386-
float dc_c = (Uc < 0) ? 0 : (Uc >= voltage_power_supply) ? 1 : Uc / voltage_power_supply;
403+
float dc_a = constrain(Ua / voltage_power_supply, 0 , 1 );
404+
float dc_b = constrain(Ub / voltage_power_supply, 0 , 1 );
405+
float dc_c = constrain(Uc / voltage_power_supply, 0 , 1 );
387406
// hardware specific writing
388407
_writeDutyCycle(dc_a, dc_b, dc_c, pwmA, pwmB, pwmC );
389408
}
@@ -419,7 +438,7 @@ float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
419438
float voltage = cont.voltage_prev + (tmp + cont.P) * tracking_error + (tmp - cont.P) * cont.tracking_error_prev;
420439

421440
// antiwindup - limit the output voltage_q
422-
if (abs(voltage) > cont.voltage_limit) voltage = voltage > 0 ? cont.voltage_limit : -cont.voltage_limit;
441+
voltage = constrain(voltage, -voltage_limit, voltage_limit);
423442
// limit the acceleration by ramping the the voltage
424443
float d_voltage = voltage - cont.voltage_prev;
425444
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;
@@ -440,10 +459,51 @@ float BLDCMotor::positionP(float ek) {
440459
// calculate the target velocity from the position error
441460
float velocity_target = P_angle.P * ek;
442461
// constrain velocity target value
443-
if (abs(velocity_target) > P_angle.velocity_limit) velocity_target = velocity_target > 0 ? P_angle.velocity_limit : -P_angle.velocity_limit;
462+
velocity_target = constrain(velocity_target, -velocity_limit, velocity_limit);
444463
return velocity_target;
445464
}
446465

466+
// Function (iterative) generating open loop movement for target velocity
467+
// - target_velocity - rad/s
468+
// it uses voltage_limit variable
469+
void BLDCMotor::velocityOpenloop(float target_velocity){
470+
// get current timestamp
471+
long now_us = _micros();
472+
// calculate the sample time from last call
473+
float Ts = (now_us - open_loop_timestamp) * 1e-6;
474+
475+
// calculate the necessary angle to achieve target velocity
476+
shaft_angle += target_velocity*Ts;
477+
// set the maximal allowed voltage (voltage_limit) with the necessary angle
478+
setPhaseVoltage(voltage_limit, electricAngle(shaft_angle));
479+
480+
// save timestamp for next call
481+
open_loop_timestamp = now_us;
482+
}
483+
484+
// Function (iterative) generating open loop movement towards the target angle
485+
// - target_angle - rad
486+
// it uses voltage_limit and velocity_limit variables
487+
void BLDCMotor::angleOpenloop(float target_angle){
488+
// get current timestamp
489+
long now_us = _micros();
490+
// calculate the sample time from last call
491+
float Ts = (now_us - open_loop_timestamp) * 1e-6;
492+
493+
// calculate the necessary angle to move from current position towards target angle
494+
// with maximal velocity (velocity_limit)
495+
if(abs( target_angle - shaft_angle ) > abs(velocity_limit*Ts))
496+
shaft_angle += _sign(target_angle - shaft_angle) * abs( velocity_limit )*Ts;
497+
else
498+
shaft_angle = target_angle;
499+
500+
// set the maximal allowed voltage (voltage_limit) with the necessary angle
501+
setPhaseVoltage(voltage_limit, electricAngle(shaft_angle));
502+
503+
// save timestamp for next call
504+
open_loop_timestamp = now_us;
505+
}
506+
447507
/**
448508
* Monitoring functions
449509
*/
@@ -498,17 +558,20 @@ int BLDCMotor::command(String user_command) {
498558
switch(cmd){
499559
case 'P': // velocity P gain change
500560
case 'I': // velocity I gain change
501-
case 'L': // velocity voltage limit change
502561
case 'R': // velocity voltage ramp change
503562
if(monitor_port) monitor_port->print(" PI velocity| ");
504563
break;
505564
case 'F': // velocity Tf low pass filter change
506565
if(monitor_port) monitor_port->print(" LPF velocity| ");
507566
break;
508567
case 'K': // angle loop gain P change
509-
case 'N': // angle loop gain velocity_limit change
510568
if(monitor_port) monitor_port->print(" P angle| ");
511569
break;
570+
case 'L': // velocity voltage limit change
571+
case 'N': // angle loop gain velocity_limit change
572+
if(monitor_port) monitor_port->print(" Limits| ");
573+
break;
574+
512575
}
513576

514577
// apply the the command
@@ -525,8 +588,8 @@ int BLDCMotor::command(String user_command) {
525588
break;
526589
case 'L': // velocity voltage limit change
527590
if(monitor_port) monitor_port->print("volt_limit: ");
528-
if(!GET)PI_velocity.voltage_limit = value;
529-
if(monitor_port) monitor_port->println(PI_velocity.voltage_limit);
591+
if(!GET)voltage_limit = value;
592+
if(monitor_port) monitor_port->println(voltage_limit);
530593
break;
531594
case 'R': // velocity voltage ramp change
532595
if(monitor_port) monitor_port->print("volt_ramp: ");
@@ -545,8 +608,8 @@ int BLDCMotor::command(String user_command) {
545608
break;
546609
case 'N': // angle loop gain velocity_limit change
547610
if(monitor_port) monitor_port->print("vel_limit: ");
548-
if(!GET) P_angle.velocity_limit = value;
549-
if(monitor_port) monitor_port->println(P_angle.velocity_limit);
611+
if(!GET) velocity_limit = value;
612+
if(monitor_port) monitor_port->println(velocity_limit);
550613
break;
551614
case 'C':
552615
// change control type
@@ -612,36 +675,4 @@ int BLDCMotor::command(String user_command) {
612675
}
613676
// return 0 if error and 1 if ok
614677
return errorFlag;
615-
}
616-
617-
618-
// set velocity in open loop
619-
// - velocity - rad/s
620-
// - voltage - V
621-
void BLDCMotor::velocityOpenloop(float vel, float voltage){
622-
float Ts = (_micros() - open_loop_timestamp) * 1e-6;
623-
624-
shaft_angle += vel*Ts;
625-
626-
setPhaseVoltage(voltage, electricAngle(shaft_angle));
627-
628-
open_loop_timestamp = _micros();
629-
}
630-
631-
// set angle in open loop
632-
// - angle - rad
633-
// - velocity - rad/s
634-
// - voltage - V
635-
void BLDCMotor::angleOpenloop(float angle, float vel, float voltage){
636-
float Ts = (_micros() - open_loop_timestamp) * 1e-6;
637-
638-
if(abs(angle- shaft_angle) > abs(vel*Ts)){
639-
shaft_angle += _sign(angle - shaft_angle) * abs(vel)*Ts;
640-
}else{
641-
shaft_angle = angle;
642-
}
643-
644-
setPhaseVoltage(voltage, electricAngle(shaft_angle));
645-
646-
open_loop_timestamp = _micros();
647678
}

0 commit comments

Comments
 (0)