Skip to content

Commit 717480b

Browse files
Merge pull request #315 from simplefoc/dev
Release v2.3.1
2 parents 05954cb + 192ab76 commit 717480b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1039
-222
lines changed

README.md

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,20 @@ Therefore this is an attempt to:
2424
- *Medium-power* BLDC driver (<30Amps): [Arduino <span class="simple">Simple<b>FOC</b>PowerShield</span> ](https://github.com/simplefoc/Arduino-SimpleFOC-PowerShield).
2525
- See also [@byDagor](https://github.com/byDagor)'s *fully-integrated* ESP32 based board: [Dagor Brushless Controller](https://github.com/byDagor/Dagor-Brushless-Controller)
2626

27-
> NEW RELEASE 📢 : <span class="simple">Simple<span class="foc">FOC</span>library</span> v2.3.0
28-
> - Arduino Mega 6pwm more timers supported
29-
> - Arduino boards - frequency change support either 32kHz or 4kHz
30-
> - Arduino Uno - synched timers in 3pwm and 6pwm mode [#71](https://github.com/simplefoc/Arduino-FOC/issues/71)
31-
> - Teensy 3.x initial support for 6pwm
32-
> - Teensy 4.x initial support for 6pwm
33-
> - Example for v3.1 SimpleFOCShield
34-
> - RP2040 compatibility for earlehillpower core [#234](https://github.com/simplefoc/Arduino-FOC/pull/234) [#236](https://github.com/simplefoc/Arduino-FOC/pull/236)
35-
> - More flexible monitoring API
36-
> - start, end and separator characters
37-
> - decimal places (settable through commander)
38-
> - Added machine readable verbose mode in `Commander` [#233](https://github.com/simplefoc/Arduino-FOC/pull/233)
39-
> - *Simple**FOC**WebController* - Web based user interface for SimpleFOC by [@geekuillaume](https://github.com/geekuillaume) - [webcontroller.simplefoc.com](webcontroller.simplefoc.com)
40-
> - bugfix - `MagneticSensorPWM` multiple occasions - [#258](https://github.com/simplefoc/Arduino-FOC/pull/258)
41-
> - bugfix - current sense align - added offset exchange when exchanging pins
42-
> - bugfix - trapezoid 150 fixed
43-
> - bugfix - 4pwm on ESP8266 [#224](https://github.com/simplefoc/Arduino-FOC/pull/224)
44-
> - Additional `InlineCurrentSense` and `LowsideCurrentSense` constructor using milliVolts per Amp [#253](https://github.com/simplefoc/Arduino-FOC/pull/253)
45-
> - STM32L4xx current sense support by [@Triple6](https://github.com/Triple6) (discord) [#257](https://github.com/simplefoc/Arduino-FOC/pull/257)
46-
> - phase disable in 6pwm mode
47-
> - stm32 - software and hardware 6pwm
48-
> - atmega328
49-
> - atmega2560
50-
> - Lag compensation using motor inductance [#246](https://github.com/simplefoc/Arduino-FOC/issues/246)
51-
> - current control through voltage torque mode enhancement
52-
> - extended `BLDCMotor` and `StepperMotor` constructors to receive the inductance paramerer
53-
> - can also be set using `motor.phase_inductance` or through `Commander`
54-
## Arduino *SimpleFOClibrary* v2.3
27+
> NEW RELEASE 📢 : <span class="simple">Simple<span class="foc">FOC</span>library</span> v2.3.1
28+
> - Support for Arduino UNO R4 Minima (Renesas R7FA4M1 MCU - note UNO R4 WiFi is not yet supported)
29+
> - Support setting PWM polarity on ESP32 (thanks to [@mcells](https://github.com/mcells))
30+
> - Expose I2C errors in MagneticSensorI2C (thanks to [@padok](https://github.com/padok))
31+
> - Improved default trig functions (sine, cosine) - faster, smaller
32+
> - Overridable trig functions - plug in your own optimized versions
33+
> - Bugfix: microseconds overflow in velocity mode [#287](https://github.com/simplefoc/Arduino-FOC/issues/287)
34+
> - Bugfix: KV initialization ([5fc3128](https://github.com/simplefoc/Arduino-FOC/commit/5fc3128d282b65c141ca486327c6235089999627))
35+
> - And more bugfixes - see the [complete list of 2.3.1 fixes here](https://github.com/simplefoc/Arduino-FOC/issues?q=is%3Aissue+milestone%3A2.3.1_Release)
36+
> - Change: simplify initFOC() API ([d57d32d](https://github.com/simplefoc/Arduino-FOC/commit/d57d32dd8715dbed4e476469bc3de0c052f1d531). [5231e5e](https://github.com/simplefoc/Arduino-FOC/commit/5231e5e1d044b0cc33ede67664b6ef2f9d0a8cdf), [10c5b87](https://github.com/simplefoc/Arduino-FOC/commit/10c5b872672cab72df16ddd738bbf09bcce95d28))
37+
> - Change: check for linked driver in currentsense and exit gracefully ([5ef4d9d](https://github.com/simplefoc/Arduino-FOC/commit/5ef4d9d5a92e03da0dd5af7f624243ab30f1b688))
38+
> - Compatibility with newest versions of Arduino framework for STM32, Renesas, ESP32, Atmel SAM, Atmel AVR, nRF52 and RP2040
39+
40+
## Arduino *SimpleFOClibrary* v2.3.1
5541

5642
<p align="">
5743
<a href="https://youtu.be/Y5kLeqTc6Zk">
@@ -78,7 +64,7 @@ This video demonstrates the *Simple**FOC**library* basic usage, electronic conne
7864
- **Cross-platform**:
7965
- Seamless code transfer from one microcontroller family to another
8066
- Supports multiple [MCU architectures](https://docs.simplefoc.com/microcontrollers):
81-
- Arduino: UNO, MEGA, DUE, Leonardo ....
67+
- Arduino: UNO R4, UNO, MEGA, DUE, Leonardo, Nano, Nano33 ....
8268
- STM32
8369
- ESP32
8470
- Teensy
@@ -132,7 +118,9 @@ Please do not hesitate to leave an issue if you have problems/advices/suggestion
132118

133119
Pull requests are welcome, but let's first discuss them in [community forum](https://community.simplefoc.com)!
134120

135-
If you'd like to contribute to this porject but you are not very familiar with github, don't worry, let us know either by posting at the community forum , by posting a github issue or at our discord server.
121+
If you'd like to contribute to this project but you are not very familiar with github, don't worry, let us know either by posting at the community forum , by posting a github issue or at our discord server.
122+
123+
If you are familiar, we accept pull requests to the dev branch!
136124

137125
## Arduino code example
138126
This is a simple Arduino code example implementing the velocity control program of a BLDC motor with encoder.

examples/motion_control/open_loop_motor_control/open_loop_position_example/open_loop_position_example.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ void setup() {
6262
void loop() {
6363
// open loop angle movements
6464
// using motor.voltage_limit and motor.velocity_limit
65+
// angles can be positive or negative, negative angles correspond to opposite motor direction
6566
motor.move(target_position);
6667

6768
// user communication

examples/motion_control/open_loop_motor_control/open_loop_velocity_example/open_loop_velocity_example.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ void loop() {
6060

6161
// open loop velocity movement
6262
// using motor.voltage_limit and motor.velocity_limit
63+
// to turn the motor "backwards", just set a negative target_velocity
6364
motor.move(target_velocity);
6465

6566
// user communication

examples/utils/calibration/find_sensor_offset_and_direction/find_sensor_offset_and_direction.ino

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* Simple example intended to help users find the zero offset and natural direction of the sensor.
33
*
44
* These values can further be used to avoid motor and sensor alignment procedure.
5-
*
6-
* motor.initFOC(zero_offset, sensor_direction);
5+
* To use these values add them to the code:");
6+
* motor.sensor_direction=Direction::CW; // or Direction::CCW
7+
* motor.zero_electric_angle=1.2345; // use the real value!
78
*
89
* This will only work for abosolute value sensors - magnetic sensors.
910
* Bypassing the alignment procedure is not possible for the encoders and for the current implementation of the Hall sensors.
@@ -44,6 +45,9 @@ void setup() {
4445
// set motion control loop to be used
4546
motor.controller = MotionControlType::torque;
4647

48+
// force direction search - because default is CW
49+
motor.sensor_direction = Direction::UNKNOWN;
50+
4751
// initialize motor
4852
motor.init();
4953
// align sensor and start FOC
@@ -54,9 +58,16 @@ void setup() {
5458
Serial.println("Sensor zero offset is:");
5559
Serial.println(motor.zero_electric_angle, 4);
5660
Serial.println("Sensor natural direction is: ");
57-
Serial.println(motor.sensor_direction == 1 ? "Direction::CW" : "Direction::CCW");
61+
Serial.println(motor.sensor_direction == Direction::CW ? "Direction::CW" : "Direction::CCW");
62+
63+
Serial.println("To use these values add them to the code:");
64+
Serial.print(" motor.sensor_direction=");
65+
Serial.print(motor.sensor_direction == Direction::CW ? "Direction::CW" : "Direction::CCW");
66+
Serial.println(";");
67+
Serial.print(" motor.zero_electric_angle=");
68+
Serial.print(motor.zero_electric_angle, 4);
69+
Serial.println(";");
5870

59-
Serial.println("To use these values provide them to the: motor.initFOC(offset, direction)");
6071
_delay(1000);
6172
Serial.println("If motor is not moving the alignment procedure was not successfull!!");
6273
}

src/BLDCMotor.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ BLDCMotor::BLDCMotor(int pp, float _R, float _KV, float _inductance)
4444
phase_resistance = _R;
4545
// save back emf constant KV = 1/KV
4646
// 1/sqrt(2) - rms value
47-
KV_rating = _KV*_SQRT2;
47+
KV_rating = NOT_SET;
48+
if (_isset(_KV))
49+
KV_rating = _KV*_SQRT2;
4850
// save phase inductance
4951
phase_inductance = _inductance;
5052

@@ -90,6 +92,13 @@ void BLDCMotor::init() {
9092
}
9193
P_angle.limit = velocity_limit;
9294

95+
// if using open loop control, set a CW as the default direction if not already set
96+
if ((controller==MotionControlType::angle_openloop
97+
||controller==MotionControlType::velocity_openloop)
98+
&& (sensor_direction == Direction::UNKNOWN)) {
99+
sensor_direction = Direction::CW;
100+
}
101+
93102
_delay(500);
94103
// enable motor
95104
SIMPLEFOC_DEBUG("MOT: Enable driver.");
@@ -124,20 +133,13 @@ void BLDCMotor::enable()
124133
FOC functions
125134
*/
126135
// FOC initialization function
127-
int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction) {
136+
int BLDCMotor::initFOC() {
128137
int exit_flag = 1;
129138

130139
motor_status = FOCMotorStatus::motor_calibrating;
131140

132141
// align motor if necessary
133142
// alignment necessary for encoders!
134-
if(_isset(zero_electric_offset)){
135-
// abosolute zero offset provided - no need to align
136-
zero_electric_angle = zero_electric_offset;
137-
// set the sensor direction - default CW
138-
sensor_direction = _sensor_direction;
139-
}
140-
141143
// sensor and motor alignment - can be skipped
142144
// by setting motor.sensor_direction and motor.zero_electric_angle
143145
_delay(500);
@@ -165,7 +167,7 @@ int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction
165167
exit_flag *= alignCurrentSense();
166168
}
167169
}
168-
else SIMPLEFOC_DEBUG("MOT: No current sense.");
170+
else { SIMPLEFOC_DEBUG("MOT: No current sense."); }
169171
}
170172

171173
if(exit_flag){
@@ -211,7 +213,7 @@ int BLDCMotor::alignSensor() {
211213
if(!exit_flag) return exit_flag;
212214

213215
// if unknown natural direction
214-
if(!_isset(sensor_direction)){
216+
if(sensor_direction==Direction::UNKNOWN){
215217

216218
// find natural direction
217219
// move one electrical revolution forward
@@ -250,10 +252,11 @@ int BLDCMotor::alignSensor() {
250252
// check pole pair number
251253
if( fabs(moved*pole_pairs - _2PI) > 0.5f ) { // 0.5f is arbitrary number it can be lower or higher!
252254
SIMPLEFOC_DEBUG("MOT: PP check: fail - estimated pp: ", _2PI/moved);
253-
} else
255+
} else {
254256
SIMPLEFOC_DEBUG("MOT: PP check: OK!");
257+
}
255258

256-
} else SIMPLEFOC_DEBUG("MOT: Skip dir calib.");
259+
} else { SIMPLEFOC_DEBUG("MOT: Skip dir calib."); }
257260

258261
// zero electric angle not known
259262
if(!_isset(zero_electric_angle)){
@@ -274,7 +277,7 @@ int BLDCMotor::alignSensor() {
274277
// stop everything
275278
setPhaseVoltage(0, 0, 0);
276279
_delay(200);
277-
}else SIMPLEFOC_DEBUG("MOT: Skip offset calib.");
280+
} else { SIMPLEFOC_DEBUG("MOT: Skip offset calib."); }
278281
return exit_flag;
279282
}
280283

@@ -303,8 +306,8 @@ int BLDCMotor::absoluteZeroSearch() {
303306
voltage_limit = limit_volt;
304307
// check if the zero found
305308
if(monitor_port){
306-
if(sensor->needsSearch()) SIMPLEFOC_DEBUG("MOT: Error: Not found!");
307-
else SIMPLEFOC_DEBUG("MOT: Success!");
309+
if(sensor->needsSearch()) { SIMPLEFOC_DEBUG("MOT: Error: Not found!"); }
310+
else { SIMPLEFOC_DEBUG("MOT: Success!"); }
308311
}
309312
return !sensor->needsSearch();
310313
}
@@ -418,7 +421,8 @@ void BLDCMotor::move(float new_target) {
418421
// angle set point
419422
shaft_angle_sp = target;
420423
// calculate velocity set point
421-
shaft_velocity_sp = P_angle( shaft_angle_sp - shaft_angle );
424+
shaft_velocity_sp = feed_forward_velocity + P_angle( shaft_angle_sp - shaft_angle );
425+
shaft_angle_sp = _constrain(shaft_angle_sp,-velocity_limit, velocity_limit);
422426
// calculate the torque command - sensor precision: this calculation is ok, but based on bad value from previous calculation
423427
current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if voltage torque control
424428
// if torque controlled through voltage
@@ -543,12 +547,8 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
543547
case FOCModulationType::SinePWM :
544548
// Sinusoidal PWM modulation
545549
// Inverse Park + Clarke transformation
550+
_sincos(angle_el, &_sa, &_ca);
546551

547-
// angle normalization in between 0 and 2pi
548-
// only necessary if using _sin and _cos - approximation functions
549-
angle_el = _normalizeAngle(angle_el);
550-
_ca = _cos(angle_el);
551-
_sa = _sin(angle_el);
552552
// Inverse park transform
553553
Ualpha = _ca * Ud - _sa * Uq; // -sin(angle) * Uq;
554554
Ubeta = _sa * Ud + _ca * Uq; // cos(angle) * Uq;

src/BLDCMotor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class BLDCMotor: public FOCMotor
4949
* Function initializing FOC algorithm
5050
* and aligning sensor's and motors' zero position
5151
*/
52-
int initFOC( float zero_electric_offset = NOT_SET , Direction sensor_direction = Direction::CW) override;
52+
int initFOC() override;
5353
/**
5454
* Function running FOC algorithm in real-time
5555
* it calculates the gets motor angle and sets the appropriate voltages

src/StepperMotor.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ void StepperMotor::init() {
5656
}
5757
P_angle.limit = velocity_limit;
5858

59+
// if using open loop control, set a CW as the default direction if not already set
60+
if ((controller==MotionControlType::angle_openloop
61+
||controller==MotionControlType::velocity_openloop)
62+
&& (sensor_direction == Direction::UNKNOWN)) {
63+
sensor_direction = Direction::CW;
64+
}
65+
5966
_delay(500);
6067
// enable motor
6168
SIMPLEFOC_DEBUG("MOT: Enable driver.");
@@ -92,20 +99,13 @@ void StepperMotor::enable()
9299
FOC functions
93100
*/
94101
// FOC initialization function
95-
int StepperMotor::initFOC( float zero_electric_offset, Direction _sensor_direction ) {
102+
int StepperMotor::initFOC() {
96103
int exit_flag = 1;
97104

98105
motor_status = FOCMotorStatus::motor_calibrating;
99106

100107
// align motor if necessary
101108
// alignment necessary for encoders!
102-
if(_isset(zero_electric_offset)){
103-
// abosolute zero offset provided - no need to align
104-
zero_electric_angle = zero_electric_offset;
105-
// set the sensor direction - default CW
106-
sensor_direction = _sensor_direction;
107-
}
108-
109109
// sensor and motor alignment - can be skipped
110110
// by setting motor.sensor_direction and motor.zero_electric_angle
111111
_delay(500);
@@ -114,7 +114,7 @@ int StepperMotor::initFOC( float zero_electric_offset, Direction _sensor_direct
114114
// added the shaft_angle update
115115
sensor->update();
116116
shaft_angle = sensor->getAngle();
117-
}else SIMPLEFOC_DEBUG("MOT: No sensor.");
117+
} else { SIMPLEFOC_DEBUG("MOT: No sensor."); }
118118

119119
if(exit_flag){
120120
SIMPLEFOC_DEBUG("MOT: Ready.");
@@ -177,10 +177,13 @@ int StepperMotor::alignSensor() {
177177
float moved = fabs(mid_angle - end_angle);
178178
if( fabs(moved*pole_pairs - _2PI) > 0.5f ) { // 0.5f is arbitrary number it can be lower or higher!
179179
SIMPLEFOC_DEBUG("MOT: PP check: fail - estimated pp: ", _2PI/moved);
180-
} else
180+
} else {
181181
SIMPLEFOC_DEBUG("MOT: PP check: OK!");
182+
}
182183

183-
}else SIMPLEFOC_DEBUG("MOT: Skip dir calib.");
184+
} else {
185+
SIMPLEFOC_DEBUG("MOT: Skip dir calib.");
186+
}
184187

185188
// zero electric angle not known
186189
if(!_isset(zero_electric_angle)){
@@ -200,7 +203,7 @@ int StepperMotor::alignSensor() {
200203
// stop everything
201204
setPhaseVoltage(0, 0, 0);
202205
_delay(200);
203-
}else SIMPLEFOC_DEBUG("MOT: Skip offset calib.");
206+
} else { SIMPLEFOC_DEBUG("MOT: Skip offset calib."); }
204207
return exit_flag;
205208
}
206209

@@ -229,7 +232,7 @@ int StepperMotor::absoluteZeroSearch() {
229232
// check if the zero found
230233
if(monitor_port){
231234
if(sensor->needsSearch()) SIMPLEFOC_DEBUG("MOT: Error: Not found!");
232-
else SIMPLEFOC_DEBUG("MOT: Success!");
235+
else { SIMPLEFOC_DEBUG("MOT: Success!"); }
233236
}
234237
return !sensor->needsSearch();
235238
}
@@ -307,7 +310,8 @@ void StepperMotor::move(float new_target) {
307310
// angle set point
308311
shaft_angle_sp = target;
309312
// calculate velocity set point
310-
shaft_velocity_sp = P_angle( shaft_angle_sp - shaft_angle );
313+
shaft_velocity_sp = feed_forward_velocity + P_angle( shaft_angle_sp - shaft_angle );
314+
shaft_angle_sp = _constrain(shaft_angle_sp, -velocity_limit, velocity_limit);
311315
// calculate the torque command
312316
current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if voltage torque control
313317
// if torque controlled through voltage
@@ -357,12 +361,9 @@ void StepperMotor::move(float new_target) {
357361
void StepperMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
358362
// Sinusoidal PWM modulation
359363
// Inverse Park transformation
364+
float _sa, _ca;
365+
_sincos(angle_el, &_sa, &_ca);
360366

361-
// angle normalization in between 0 and 2pi
362-
// only necessary if using _sin and _cos - approximation functions
363-
angle_el = _normalizeAngle(angle_el);
364-
float _ca = _cos(angle_el);
365-
float _sa = _sin(angle_el);
366367
// Inverse park transform
367368
Ualpha = _ca * Ud - _sa * Uq; // -sin(angle) * Uq;
368369
Ubeta = _sa * Ud + _ca * Uq; // cos(angle) * Uq;

src/StepperMotor.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,8 @@ class StepperMotor: public FOCMotor
5454
* and aligning sensor's and motors' zero position
5555
*
5656
* - If zero_electric_offset parameter is set the alignment procedure is skipped
57-
*
58-
* @param zero_electric_offset value of the sensors absolute position electrical offset in respect to motor's electrical 0 position.
59-
* @param sensor_direction sensor natural direction - default is CW
60-
*
6157
*/
62-
int initFOC( float zero_electric_offset = NOT_SET , Direction sensor_direction = Direction::CW) override;
58+
int initFOC() override;
6359
/**
6460
* Function running FOC algorithm in real-time
6561
* it calculates the gets motor angle and sets the appropriate voltages

0 commit comments

Comments
 (0)