Skip to content

Commit 675e591

Browse files
authored
Merge branch 'dev' into B-G431B-current-sense-fixes
2 parents 370a209 + b300dab commit 675e591

File tree

21 files changed

+926
-246
lines changed

21 files changed

+926
-246
lines changed

.github/workflows/ccpp.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
- adafruit:samd:adafruit_metro_m4 # samd51
1717
- esp32:esp32:esp32doit-devkit-v1 # esp32
1818
- esp32:esp32:esp32s2 # esp32s2
19+
- esp32:esp32:esp32s3 # esp32s3
1920
- STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 # stm32 bluepill
2021
- STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE # stm32 nucleo
2122
- STMicroelectronics:stm32:GenF4:pnum=GENERIC_F405RGTX # stm32f405 - odrive
@@ -26,7 +27,7 @@ jobs:
2627
- arduino-boards-fqbn: arduino:avr:uno # arudino uno - compiling almost all examples
2728
sketch-names: '**.ino'
2829
required-libraries: PciManager
29-
sketches-exclude: bluepill_position_control, esp32_position_control, esp32_i2c_dual_bus_example, stm32_i2c_dual_bus_example, magnetic_sensor_spi_alt_example, osc_esp32_3pwm, osc_esp32_fullcontrol, nano33IoT_velocity_control, smartstepper_control,esp32_current_control_low_side, stm32_spi_alt_example, esp32_spi_alt_example, B_G431B_ESC1, odrive_example_spi, odrive_example_encoder, single_full_control_example, double_full_control_example
30+
sketches-exclude: bluepill_position_control, esp32_position_control, esp32_i2c_dual_bus_example, stm32_i2c_dual_bus_example, magnetic_sensor_spi_alt_example, osc_esp32_3pwm, osc_esp32_fullcontrol, nano33IoT_velocity_control, smartstepper_control,esp32_current_control_low_side, stm32_spi_alt_example, esp32_spi_alt_example, B_G431B_ESC1, odrive_example_spi, odrive_example_encoder, single_full_control_example, double_full_control_example, stm32_current_control_low_side
3031

3132
- arduino-boards-fqbn: arduino:sam:arduino_due_x # arduino due - one full example
3233
sketch-names: single_full_control_example.ino
@@ -51,6 +52,10 @@ jobs:
5152
platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
5253
sketch-names: bldc_driver_3pwm_standalone.ino, stepper_driver_2pwm_standalone.ino, stepper_driver_4pwm_standalone
5354

55+
- arduino-boards-fqbn: esp32:esp32:esp32s3 # esp32s3
56+
platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
57+
sketch-names: esp32_position_control.ino, esp32_i2c_dual_bus_example.ino
58+
5459
- arduino-boards-fqbn: esp32:esp32:esp32doit-devkit-v1 # esp32
5560
platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
5661
sketch-names: esp32_position_control.ino, esp32_i2c_dual_bus_example.ino, esp32_current_control_low_side.ino, esp32_spi_alt_example.ino
@@ -68,11 +73,11 @@ jobs:
6873

6974
- arduino-boards-fqbn: STMicroelectronics:stm32:GenF4:pnum=GENERIC_F405RGTX # stm32f405 - odrive
7075
platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
71-
sketch-names: odrive_example_encoder.ino, odrive_example_spi.ino
76+
sketch-names: odrive_example_encoder.ino, odrive_example_spi.ino, stm32_current_control_low_side.ino
7277

7378
- arduino-boards-fqbn: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE # nucleo one full example
7479
platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
75-
sketch-names: single_full_control_example.ino, stm32_spi_alt_example.ino, sdouble_full_control_example.ino
80+
sketch-names: single_full_control_example.ino, stm32_spi_alt_example.ino, sdouble_full_control_example.ino, stm32_current_control_low_side.ino
7681

7782

7883
# Do not cancel all jobs / architectures if one job fails

README.md

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22
### A Cross-Platform FOC implementation for BLDC and Stepper motors<br> based on the Arduino IDE and PlatformIO
33

44
![Library Compile](https://github.com/simplefoc/Arduino-FOC/workflows/Library%20Compile/badge.svg)
5-
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
![GitHub release (latest by date)](https://img.shields.io/github/v/release/simplefoc/arduino-foc)
6+
![GitHub Release Date](https://img.shields.io/github/release-date/simplefoc/arduino-foc?color=blue)
7+
![GitHub commits since tagged version](https://img.shields.io/github/commits-since/simplefoc/arduino-foc/latest/dev)
8+
![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/simplefoc/arduino-foc/dev)
9+
610
[![arduino-library-badge](https://www.ardu-badge.com/badge/Simple%20FOC.svg?)](https://www.ardu-badge.com/badge/Simple%20FOC.svg)
11+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
712
[![status](https://joss.theoj.org/papers/4382445f249e064e9f0a7f6c1bb06b1d/status.svg)](https://joss.theoj.org/papers/4382445f249e064e9f0a7f6c1bb06b1d)
813

14+
915
We live in very exciting times 😃! BLDC motors are entering the hobby community more and more and many great projects have already emerged leveraging their far superior dynamics and power capabilities. BLDC motors have numerous advantages over regular DC motors but they have one big disadvantage, the complexity of control. Even though it has become relatively easy to design and manufacture PCBs and create our own hardware solutions for driving BLDC motors the proper low-cost solutions are yet to come. One of the reasons for this is the apparent complexity of writing the BLDC driving algorithms, Field oriented control (FOC) being an example of one of the most efficient ones.
1016
The solutions that can be found on-line are almost exclusively very specific for certain hardware configuration and the microcontroller architecture used.
1117
Additionally, most of the efforts at this moment are still channeled towards the high-power applications of the BLDC motors and proper low-cost and low-power FOC supporting boards are very hard to find today and even may not exist. <br>
@@ -25,47 +31,18 @@ Therefore this is an attempt to:
2531
Journal of Open Source Software, 7(74), 4232, https://doi.org/10.21105/joss.04232
2632
</p>
2733

28-
<blockquote class="info">
29-
<p class="heading">NEW RELEASE 📢: <span class="simple">Simple<span class="foc">FOC</span>library</span> v2.2.2 <a href="https://github.com/simplefoc/Arduino-FOC/releases/tag/v2.2.2">see release</a></p>
30-
<ul>
31-
<li>GenericCurrentSense bugfix and testing</li>
32-
<li>bugfix leonardo #170</li>
33-
<li>bugfix - no index search after specifying natural direction</li>
34-
<li>Low level API restructuring
35-
<ul dir="auto">
36-
<li>Driver API</li>
37-
<li>Current sense API</li>
38-
</ul>
39-
</li>
40-
<li>New debugging interface - <a href="https://docs.simplefoc.com/debugging">see in docs</a>
41-
<ul dir="auto">
42-
<li>Static class SimpleFOCDebug</li>
43-
</ul>
44-
</li>
45-
<li>CurrentSense API change - added method <code class="highlighter-rouge">linkDriver()</code> - <a href="https://docs.simplefoc.com/current_sense">see in docs</a></li>
46-
<li>Low-side current sensing - <a href="https://docs.simplefoc.com/low_side_current_sense">see in docs</a>
47-
<ul dir="auto">
48-
<li>ESP32 generic support for multiple motors</li>
49-
<li>Added low-side current sensing support for stm32 - only one motor
50-
<ul dir="auto">
51-
<li>f1 family</li>
52-
<li>f4 family</li>
53-
<li>g4 family</li>
54-
</ul>
55-
</li>
56-
</ul>
57-
</li>
58-
<li>New appraoch for current estimation for torque control using voltage - <a href="https://docs.simplefoc.com/voltage_torque_mode">see in docs </a>
59-
<ul dir="auto">
60-
<li>Support for motor KV rating - back emf estimation</li>
61-
<li>Using motor phase resistance</li>
62-
</ul>
63-
</li>
64-
<li>KV rating and phase resistance used for open-loop current limiting as well - <a href="https://docs.simplefoc.com/open_loop_motion_control">see in docs </a> </li>
65-
</ul>
66-
</blockquote>
67-
68-
## Arduino *SimpleFOClibrary* v2.2
34+
> FUTURE RELEASE : <span class="simple">Simple<span class="foc">FOC</span>library</span> v2.2.3
35+
> - stm32 low-side current sensing
36+
> - g4 supported
37+
> - thoroughly tested f1/f4/g4
38+
> - bugfixing
39+
> - leonardo
40+
> - mega2560
41+
> - inline current sense without driver #188
42+
> - `initFOC` fails if current sense not initialised
43+
> - driver and cs have to be well initialised for `initFOC` to start
44+
> - `cs.init()` and `driver.init()` return `1` if well initialised and `0` if failed
45+
## Arduino *SimpleFOClibrary* v2.2.2
6946

7047
<p align="">
7148
<a href="https://youtu.be/Y5kLeqTc6Zk">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/**
2+
* Comprehensive BLDC motor control example using encoder and the DRV8302 board
3+
*
4+
* Using serial terminal user can send motor commands and configure the motor and FOC in real-time:
5+
* - configure PID controller constants
6+
* - change motion control loops
7+
* - monitor motor variabels
8+
* - set target values
9+
* - check all the configuration values
10+
*
11+
* check the https://docs.simplefoc.com for full list of motor commands
12+
*
13+
*/
14+
#include <SimpleFOC.h>
15+
16+
// DRV8302 pins connections
17+
// don't forget to connect the common ground pin
18+
#define INH_A PA8
19+
#define INH_B PA9
20+
#define INH_C PA10
21+
22+
#define EN_GATE PB7
23+
#define M_PWM PB4
24+
#define M_OC PB3
25+
#define OC_ADJ PB6
26+
#define OC_GAIN PB5
27+
28+
#define IOUTA PA0
29+
#define IOUTB PA1
30+
#define IOUTC PA2
31+
32+
// Motor instance
33+
BLDCMotor motor = BLDCMotor(7);
34+
BLDCDriver3PWM driver = BLDCDriver3PWM(INH_A, INH_B, INH_C, EN_GATE);
35+
36+
// DRV8302 board has 0.005Ohm shunt resistors and the gain of 12.22 V/V
37+
LowsideCurrentSense cs = LowsideCurrentSense(0.005f, 12.22f, IOUTA, IOUTB, IOUTC);
38+
39+
// encoder instance
40+
Encoder encoder = Encoder(PB14, PB15, 2048);
41+
42+
// Interrupt routine intialisation
43+
// channel A and B callbacks
44+
void doA(){encoder.handleA();}
45+
void doB(){encoder.handleB();}
46+
47+
48+
// commander interface
49+
Commander command = Commander(Serial);
50+
void onMotor(char* cmd){ command.motor(&motor, cmd); }
51+
52+
void setup() {
53+
54+
// initialize encoder sensor hardware
55+
encoder.init();
56+
encoder.enableInterrupts(doA, doB);
57+
// link the motor to the sensor
58+
motor.linkSensor(&encoder);
59+
60+
// DRV8302 specific code
61+
// M_OC - enable overcurrent protection
62+
pinMode(M_OC,OUTPUT);
63+
digitalWrite(M_OC,LOW);
64+
// M_PWM - enable 3pwm mode
65+
pinMode(M_PWM,OUTPUT);
66+
digitalWrite(M_PWM,HIGH);
67+
// OD_ADJ - set the maximum overcurrent limit possible
68+
// Better option would be to use voltage divisor to set exact value
69+
pinMode(OC_ADJ,OUTPUT);
70+
digitalWrite(OC_ADJ,HIGH);
71+
pinMode(OC_GAIN,OUTPUT);
72+
digitalWrite(OC_GAIN,LOW);
73+
74+
75+
// driver config
76+
// power supply voltage [V]
77+
driver.voltage_power_supply = 19;
78+
driver.pwm_frequency = 15000; // suggested under 18khz
79+
driver.init();
80+
// link the motor and the driver
81+
motor.linkDriver(&driver);
82+
// link current sense and the driver
83+
cs.linkDriver(&driver);
84+
85+
// align voltage
86+
motor.voltage_sensor_align = 0.5;
87+
88+
// control loop type and torque mode
89+
motor.torque_controller = TorqueControlType::voltage;
90+
motor.controller = MotionControlType::torque;
91+
motor.motion_downsample = 0.0;
92+
93+
// velocity loop PID
94+
motor.PID_velocity.P = 0.2;
95+
motor.PID_velocity.I = 5.0;
96+
// Low pass filtering time constant
97+
motor.LPF_velocity.Tf = 0.02;
98+
// angle loop PID
99+
motor.P_angle.P = 20.0;
100+
// Low pass filtering time constant
101+
motor.LPF_angle.Tf = 0.0;
102+
// current q loop PID
103+
motor.PID_current_q.P = 3.0;
104+
motor.PID_current_q.I = 100.0;
105+
// Low pass filtering time constant
106+
motor.LPF_current_q.Tf = 0.02;
107+
// current d loop PID
108+
motor.PID_current_d.P = 3.0;
109+
motor.PID_current_d.I = 100.0;
110+
// Low pass filtering time constant
111+
motor.LPF_current_d.Tf = 0.02;
112+
113+
// Limits
114+
motor.velocity_limit = 100.0; // 100 rad/s velocity limit
115+
motor.voltage_limit = 12.0; // 12 Volt limit
116+
motor.current_limit = 2.0; // 2 Amp current limit
117+
118+
119+
// use monitoring with serial for motor init
120+
// monitoring port
121+
Serial.begin(115200);
122+
// comment out if not needed
123+
motor.useMonitoring(Serial);
124+
motor.monitor_variables = _MON_CURR_Q | _MON_CURR_D; // monitor the two currents d and q
125+
motor.monitor_downsample = 0;
126+
127+
// initialise motor
128+
motor.init();
129+
130+
cs.init();
131+
// driver 8302 has inverted gains on all channels
132+
cs.gain_a *=-1;
133+
cs.gain_b *=-1;
134+
cs.gain_c *=-1;
135+
motor.linkCurrentSense(&cs);
136+
137+
// align encoder and start FOC
138+
motor.initFOC();
139+
140+
// set the inital target value
141+
motor.target = 0;
142+
143+
// define the motor id
144+
command.add('M', onMotor, "motor");
145+
146+
Serial.println(F("Full control example: "));
147+
Serial.println(F("Run user commands to configure and the motor (find the full command list in docs.simplefoc.com) \n "));
148+
Serial.println(F("Initial motion control loop is voltage loop."));
149+
Serial.println(F("Initial target voltage 2V."));
150+
151+
_delay(1000);
152+
}
153+
154+
155+
void loop() {
156+
// iterative setting FOC phase voltage
157+
motor.loopFOC();
158+
159+
// iterative function setting the outter loop target
160+
motor.move();
161+
162+
// monitoring the state variables
163+
motor.monitor();
164+
165+
// user communication
166+
command.run();
167+
}

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Simple FOC
2-
version=2.2.2
2+
version=2.2.3
33
author=Simplefoc <[email protected]>
44
maintainer=Simplefoc <[email protected]>
55
sentence=A library demistifying FOC for BLDC motors

src/BLDCMotor.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,15 @@ int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction
121121
// and checks the direction of measuremnt.
122122
_delay(500);
123123
if(exit_flag){
124-
if(current_sense) exit_flag *= alignCurrentSense();
124+
if(current_sense){
125+
if (!current_sense->initialized) {
126+
motor_status = FOCMotorStatus::motor_calib_failed;
127+
SIMPLEFOC_DEBUG("MOT: Init FOC error, current sense not initialized");
128+
exit_flag = 0;
129+
}else{
130+
exit_flag *= alignCurrentSense();
131+
}
132+
}
125133
else SIMPLEFOC_DEBUG("MOT: No current sense.");
126134
}
127135

src/common/base_classes/CurrentSense.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class CurrentSense{
2828
// variables
2929
bool skip_align = false; //!< variable signaling that the phase current direction should be verified during initFOC()
3030

31-
BLDCDriver* driver; //!< driver link
31+
BLDCDriver* driver = nullptr; //!< driver link
32+
bool initialized = false; // true if current sense was successfully initialized
3233
void* params = 0; //!< pointer to hardware specific parameters of current sensing
3334

3435
/**

src/current_sense/GenericCurrentSense.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ int GenericCurrentSense::init(){
1313
if(initCallback != nullptr) initCallback();
1414
// calibrate zero offsets
1515
calibrateOffsets();
16+
// set the initialized flag
17+
initialized = (params!=SIMPLEFOC_CURRENT_SENSE_INIT_FAILED);
1618
// return success
1719
return 1;
1820
}

src/current_sense/InlineCurrentSense.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@ InlineCurrentSense::InlineCurrentSense(float _shunt_resistor, float _gain, int _
2121

2222
// Inline sensor init function
2323
int InlineCurrentSense::init(){
24+
// if no linked driver its fine in this case
25+
// at least for init()
26+
void* drv_params = driver ? driver->params : nullptr;
2427
// configure ADC variables
25-
params = _configureADCInline(driver->params,pinA,pinB,pinC);
28+
params = _configureADCInline(drv_params,pinA,pinB,pinC);
2629
// if init failed return fail
2730
if (params == SIMPLEFOC_CURRENT_SENSE_INIT_FAILED) return 0;
2831
// calibrate zero offsets
2932
calibrateOffsets();
33+
// set the initialized flag
34+
initialized = (params!=SIMPLEFOC_CURRENT_SENSE_INIT_FAILED);
3035
// return success
3136
return 1;
3237
}

src/current_sense/LowsideCurrentSense.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ int LowsideCurrentSense::init(){
2929
_driverSyncLowSide(driver->params, params);
3030
// calibrate zero offsets
3131
calibrateOffsets();
32+
// set the initialized flag
33+
initialized = (params!=SIMPLEFOC_CURRENT_SENSE_INIT_FAILED);
3234
// return success
3335
return 1;
3436
}

src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_mcu.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ int _adcToIndex(ADC_HandleTypeDef *AdcHandle){
3333
void* _configureADCLowSide(const void* driver_params, const int pinA, const int pinB, const int pinC){
3434

3535
Stm32CurrentSenseParams* cs_params= new Stm32CurrentSenseParams {
36-
.pins={0},
36+
.pins={(int)NOT_SET,(int)NOT_SET,(int)NOT_SET},
3737
.adc_voltage_conv = (_ADC_VOLTAGE_F1) / (_ADC_RESOLUTION_F1)
3838
};
3939
_adc_gpio_init(cs_params, pinA,pinB,pinC);

0 commit comments

Comments
 (0)