Skip to content

Commit bc2b355

Browse files
committed
FEAT current limiting in voltage mode and support for adding the KV rating of the motor
1 parent 9fbbf46 commit bc2b355

File tree

8 files changed

+56
-36
lines changed

8 files changed

+56
-36
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ Therefore this is an attempt to:
2626
> - Current sense API
2727
> - Low-side current sensing
2828
> - ESP32 generic support for multiple motors
29+
> - New handlign of current limit using voltage
30+
> - Support for motor KV rating - back emf estimation
31+
> - Using motor phase resistance
2932
3033

3134

keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ _PI_3 LITERAL1
235235
_SQRT3 LITERAL1
236236
_PI LITERAL1
237237
_HIGH_Z LITERAL1
238+
_NC LITERAL1
238239

239240
_MON_TARGET LITERAL1
240241
_MON_VOLT_Q LITERAL1

src/BLDCMotor.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
// BLDCMotor( int pp , float R)
44
// - pp - pole pair number
55
// - R - motor phase resistance
6-
BLDCMotor::BLDCMotor(int pp, float _R)
6+
// - KV - motor kv rating
7+
BLDCMotor::BLDCMotor(int pp, float _R, float _KV)
78
: FOCMotor()
89
{
910
// save pole pairs number
1011
pole_pairs = pp;
1112
// save phase resistance number
1213
phase_resistance = _R;
14+
// save back emf constant KV = 1/KV
15+
K_bemf = 1.0/_KV;
16+
1317
// torque control type is voltage by default
1418
torque_controller = TorqueControlType::voltage;
1519
}
@@ -31,12 +35,6 @@ void BLDCMotor::init() {
3135
motor_status = FOCMotorStatus::motor_initializing;
3236
if(monitor_port) monitor_port->println(F("MOT: Init"));
3337

34-
// if no current sensing and the user has set the phase resistance of the motor use current limit to calculate the voltage limit
35-
if( !current_sense && _isset(phase_resistance)) {
36-
float new_voltage_limit = current_limit * (phase_resistance); // v_lim = current_lim / (3/2 phase resistance) - worst case
37-
// use it if it is less then voltage_limit set by the user
38-
voltage_limit = new_voltage_limit < voltage_limit ? new_voltage_limit : voltage_limit;
39-
}
4038
// sanity check for the voltage limit configuration
4139
if(voltage_limit > driver->voltage_limit) voltage_limit = driver->voltage_limit;
4240
// constrain voltage for sensor alignment
@@ -344,11 +342,18 @@ void BLDCMotor::move(float new_target) {
344342
// set internal target variable
345343
if(_isset(new_target)) target = new_target;
346344

345+
// calculate the back-emf voltage if K_bemf available
346+
if (_isset(K_bemf)) voltage_bemf = K_bemf*shaft_velocity;
347+
// estimate the motor current if phase reistance available and current_sense not available
348+
if(!current_sense && _isset(phase_resistance)) current.q = (voltage.q - voltage_bemf)/phase_resistance;
349+
350+
// upgrade the current based voltage limit
347351
switch (controller) {
348352
case MotionControlType::torque:
349353
if(torque_controller == TorqueControlType::voltage){ // if voltage torque control
350354
if(!_isset(phase_resistance)) voltage.q = target;
351-
else voltage.q = target*phase_resistance;
355+
else voltage.q = target*phase_resistance + voltage_bemf;
356+
voltage.q = _constrain(voltage.q, -voltage_limit, voltage_limit);
352357
voltage.d = 0;
353358
}else{
354359
current_sp = target; // if current/foc_current torque control
@@ -368,7 +373,7 @@ void BLDCMotor::move(float new_target) {
368373
if(torque_controller == TorqueControlType::voltage){
369374
// use voltage if phase-resistance not provided
370375
if(!_isset(phase_resistance)) voltage.q = current_sp;
371-
else voltage.q = current_sp*phase_resistance;
376+
else voltage.q = _constrain( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
372377
voltage.d = 0;
373378
}
374379
break;
@@ -381,7 +386,7 @@ void BLDCMotor::move(float new_target) {
381386
if(torque_controller == TorqueControlType::voltage){
382387
// use voltage if phase-resistance not provided
383388
if(!_isset(phase_resistance)) voltage.q = current_sp;
384-
else voltage.q = current_sp*phase_resistance;
389+
else voltage.q = _constrain( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
385390
voltage.d = 0;
386391
}
387392
break;
@@ -620,7 +625,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
620625

621626
// use voltage limit or current limit
622627
float Uq = voltage_limit;
623-
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
628+
if(_isset(phase_resistance))
629+
Uq = _constrain(current_limit*phase_resistance + voltage_bemf,-voltage_limit, voltage_limit);
624630

625631
// set the maximal allowed voltage (voltage_limit) with the necessary angle
626632
setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs));
@@ -655,10 +661,10 @@ float BLDCMotor::angleOpenloop(float target_angle){
655661
shaft_velocity = 0;
656662
}
657663

658-
659664
// use voltage limit or current limit
660665
float Uq = voltage_limit;
661-
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
666+
if(_isset(phase_resistance))
667+
Uq = _constrain(current_limit*phase_resistance + voltage_bemf,-voltage_limit, voltage_limit);
662668
// set the maximal allowed voltage (voltage_limit) with the necessary angle
663669
// sensor precision: this calculation is OK due to the normalisation
664670
setPhaseVoltage(Uq, 0, _electricalAngle(_normalizeAngle(shaft_angle), pole_pairs));

src/BLDCMotor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ class BLDCMotor: public FOCMotor
1919
BLDCMotor class constructor
2020
@param pp pole pairs number
2121
@param R motor phase resistance
22+
@param KV motor KV rating (1/K_bemf)
2223
*/
23-
BLDCMotor(int pp, float R = NOT_SET);
24+
BLDCMotor(int pp, float R = NOT_SET, float KV = NOT_SET);
2425

2526
/**
2627
* Function linking a motor and a foc driver

src/StepperMotor.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
// StepperMotor(int pp)
44
// - pp - pole pair number
55
// - R - motor phase resistance
6-
StepperMotor::StepperMotor(int pp, float _R)
6+
// - KV - motor kv rating
7+
StepperMotor::StepperMotor(int pp, float _R, float _KV)
78
: FOCMotor()
89
{
910
// number od pole pairs
1011
pole_pairs = pp;
1112
// save phase resistance number
1213
phase_resistance = _R;
14+
// save back emf constant KV = 1/KV
15+
K_bemf = 1.0/_KV;
1316

1417
// torque control type is voltage by default
1518
// current and foc_current not supported yet
@@ -32,12 +35,6 @@ void StepperMotor::init() {
3235
motor_status = FOCMotorStatus::motor_initializing;
3336
if(monitor_port) monitor_port->println(F("MOT: Init"));
3437

35-
// if set the phase resistance of the motor use current limit to calculate the voltage limit
36-
if(_isset(phase_resistance)) {
37-
float new_voltage_limit = current_limit * (phase_resistance); // v_lim = current_lim / (3/2 phase resistance) - worst case
38-
// use it if it is less then voltage_limit set by the user
39-
voltage_limit = new_voltage_limit < voltage_limit ? new_voltage_limit : voltage_limit;
40-
}
4138
// sanity check for the voltage limit configuration
4239
if(voltage_limit > driver->voltage_limit) voltage_limit = driver->voltage_limit;
4340
// constrain voltage for sensor alignment
@@ -283,11 +280,18 @@ void StepperMotor::move(float new_target) {
283280

284281
// set internal target variable
285282
if(_isset(new_target) ) target = new_target;
283+
284+
// calculate the back-emf voltage if K_bemf available
285+
if (_isset(K_bemf)) voltage_bemf = K_bemf*shaft_velocity;
286+
// estimate the motor current if phase reistance available and current_sense not available
287+
if(!current_sense && _isset(phase_resistance)) current.q = (voltage.q - voltage_bemf)/phase_resistance;
288+
286289
// choose control loop
287290
switch (controller) {
288291
case MotionControlType::torque:
289292
if(!_isset(phase_resistance)) voltage.q = target; // if voltage torque control
290-
else voltage.q = target*phase_resistance;
293+
else voltage.q = target*phase_resistance + voltage_bemf;
294+
voltage.q = _constrain(voltage.q, -voltage_limit, voltage_limit);
291295
voltage.d = 0;
292296
break;
293297
case MotionControlType::angle:
@@ -300,8 +304,8 @@ void StepperMotor::move(float new_target) {
300304
// if torque controlled through voltage
301305
// use voltage if phase-resistance not provided
302306
if(!_isset(phase_resistance)) voltage.q = current_sp;
303-
else voltage.q = current_sp*phase_resistance;
304-
voltage.d = 0;
307+
else voltage.q = _constrain( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
308+
voltage.d = 0;
305309
break;
306310
case MotionControlType::velocity:
307311
// velocity set point
@@ -311,7 +315,7 @@ void StepperMotor::move(float new_target) {
311315
// if torque controlled through voltage control
312316
// use voltage if phase-resistance not provided
313317
if(!_isset(phase_resistance)) voltage.q = current_sp;
314-
else voltage.q = current_sp*phase_resistance;
318+
else voltage.q = _constrain( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
315319
voltage.d = 0;
316320
break;
317321
case MotionControlType::velocity_openloop:
@@ -372,7 +376,8 @@ float StepperMotor::velocityOpenloop(float target_velocity){
372376

373377
// use voltage limit or current limit
374378
float Uq = voltage_limit;
375-
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
379+
if(_isset(phase_resistance))
380+
Uq = _constrain(current_limit*phase_resistance + voltage_bemf,-voltage_limit, voltage_limit);
376381

377382
// set the maximal allowed voltage (voltage_limit) with the necessary angle
378383
setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs));
@@ -406,7 +411,8 @@ float StepperMotor::angleOpenloop(float target_angle){
406411

407412
// use voltage limit or current limit
408413
float Uq = voltage_limit;
409-
if(_isset(phase_resistance)) Uq = current_limit*phase_resistance;
414+
if(_isset(phase_resistance))
415+
Uq = _constrain(current_limit*phase_resistance + voltage_bemf,-voltage_limit, voltage_limit);
410416
// set the maximal allowed voltage (voltage_limit) with the necessary angle
411417
setPhaseVoltage(Uq, 0, _electricalAngle((shaft_angle), pole_pairs));
412418

src/StepperMotor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ class StepperMotor: public FOCMotor
2424
StepperMotor class constructor
2525
@param pp pole pair number
2626
@param R motor phase resistance
27+
@param KV motor KV rating (1/K_bemf)
2728
*/
28-
StepperMotor(int pp, float R = NOT_SET);
29+
StepperMotor(int pp, float R = NOT_SET, float KV = NOT_SET);
2930

3031
/**
3132
* Function linking a motor and a foc driver

src/common/base_classes/FOCMotor.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ FOCMotor::FOCMotor()
2828
current_sp = 0;
2929
current.q = 0;
3030
current.d = 0;
31+
32+
// voltage bemf
33+
voltage_bemf = 0;
3134

3235
//monitor_port
3336
monitor_port = nullptr;
@@ -105,14 +108,11 @@ void FOCMotor::monitor() {
105108
}
106109
// read currents if possible - even in voltage mode (if current_sense available)
107110
if(monitor_variables & _MON_CURR_Q || monitor_variables & _MON_CURR_D) {
108-
DQCurrent_s c{0,0};
109-
if(current_sense){
110-
if(torque_controller == TorqueControlType::foc_current) c = current;
111-
else{
112-
c = current_sense->getFOCCurrents(electrical_angle);
113-
c.q = LPF_current_q(c.q);
114-
c.d = LPF_current_d(c.d);
115-
}
111+
DQCurrent_s c = current;
112+
if( current_sense && torque_controller != TorqueControlType::foc_current ){
113+
c = current_sense->getFOCCurrents(electrical_angle);
114+
c.q = LPF_current_q(c.q);
115+
c.d = LPF_current_d(c.d);
116116
}
117117
if(monitor_variables & _MON_CURR_Q) {
118118
monitor_port->print(c.q*1000, 2); // mAmps

src/common/base_classes/FOCMotor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ class FOCMotor
152152
float shaft_angle_sp;//!< current target angle
153153
DQVoltage_s voltage;//!< current d and q voltage set to the motor
154154
DQCurrent_s current;//!< current d and q current measured
155+
float voltage_bemf; //!< estimated backemf voltage (if provided KV constant)
155156

156157
// motor configuration parameters
157158
float voltage_sensor_align;//!< sensor and motor align voltage parameter
@@ -160,6 +161,7 @@ class FOCMotor
160161
// motor physical parameters
161162
float phase_resistance; //!< motor phase resistance
162163
int pole_pairs;//!< motor pole pairs number
164+
float K_bemf; //!< motor back emf constant (1/KV)
163165

164166
// limiting variables
165167
float voltage_limit; //!< Voltage limitting variable - global limit

0 commit comments

Comments
 (0)