Skip to content

Commit 977003d

Browse files
committed
foc: fix the bias on the sine pwm modulation
and introduce the space vector PWM modulation. Signed-off-by: Felipe Neves <[email protected]>
1 parent 7b49463 commit 977003d

File tree

15 files changed

+254
-68
lines changed

15 files changed

+254
-68
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
idf_build_get_property(target IDF_TARGET)
22

33
set(requires driver esp_adc freertos esp_system esp_timer)
4-
set(srcs "esp_foc.c" "esp_foc_scope.c" "esp_foc_consts.c" "esp_foc_sine_cosine.c")
4+
set(srcs "esp_foc.c" "esp_foc_scope.c" "esp_foc_consts.c" "esp_foc_sine_cosine.c" "esp_foc_sqrtf.c")
55
set(includes "include" "drivers")
66

77
list(APPEND srcs "drivers/inverter_3pwm_ledc.c"

Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ menu "espFoC Settings"
3939
int "Size of scope buffer in frames"
4040
default 1536
4141

42+
config ESP_FOC_USE_SINE_PWM
43+
bool "Use Sinewave modulation for PWM, if not it will use the SVPWM"
44+
default y
45+
46+
config ESP_FOC_COMP_THI
47+
bool "Enable third harmonic injection compensation on SVPWM"
48+
depends on !ESP_FOC_USE_SINE_PWM
49+
default n
4250
endmenu
4351

4452

drivers/inverter_3pwm_ledc.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,20 @@ IRAM_ATTR static void set_voltages(esp_foc_inverter_t *self,
102102
esp_foc_ledc_inverter *obj =
103103
__containerof(self, esp_foc_ledc_inverter, interface);
104104

105-
if(v_u > obj->dc_link_voltage) {
106-
v_u = obj->dc_link_voltage;
105+
if(v_u > 1.0f) {
106+
v_u = 1.0f;
107107
} else if (v_u < 0.0f) {
108108
v_u = 0.0f;
109109
}
110110

111-
if(v_v > obj->dc_link_voltage) {
112-
v_v = obj->dc_link_voltage;
111+
if(v_v > 1.0f) {
112+
v_v = 1.0f;
113113
} else if (v_v < 0.0f) {
114114
v_v = 0.0f;
115115
}
116116

117-
if(v_w > obj->dc_link_voltage) {
118-
v_w = obj->dc_link_voltage;
117+
if(v_w > 1.0f) {
118+
v_w = 1.0f;
119119
} else if (v_w < 0.0f) {
120120
v_w = 0.0f;
121121
}
@@ -266,7 +266,8 @@ esp_foc_inverter_t *inverter_3pwm_ledc_new(ledc_channel_t ch_u,
266266
}
267267

268268
ledc[port].hw = LEDC_LL_GET_HW();
269-
ledc[port].voltage_to_duty_ratio = LEDC_RESOLUTION_STEPS / ledc[port].dc_link_voltage;
269+
270+
ledc[port].voltage_to_duty_ratio = LEDC_RESOLUTION_STEPS;
270271

271272
return &ledc[port].interface;
272273
}

drivers/rotor_sensor_as5600.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
* The above copyright notice and this permission notice shall be included in all
1414
* copies or substantial portions of the Software.
15-
*
15+
*
1616
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1717
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1818
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -21,7 +21,7 @@
2121
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
* SOFTWARE.
2323
*/
24-
24+
2525
#include <math.h>
2626
#include "espFoC/rotor_sensor_as5600.h"
2727
#include "driver/gpio.h"
@@ -33,7 +33,7 @@
3333
#define AS5600_SLAVE_ADDR 0x36
3434
#define AS5600_ANGLE_REGISTER_H 0x0E
3535
#define AS5600_PULSES_PER_REVOLUTION 4096.0f
36-
#define AS5600_READING_MASK 0xFFF
36+
#define AS5600_READING_MASK 0xFFF
3737

3838
static const char *tag = "ROTOR_SENSOR_AS5600";
3939

@@ -50,7 +50,7 @@ static bool i2c_bus_configured = false;
5050
DRAM_ATTR static esp_foc_as5600_t rotor_sensors[CONFIG_NOOF_AXIS];
5151
static const float encoder_wrap_value = AS5600_PULSES_PER_REVOLUTION * 0.95f;
5252

53-
IRAM_ATTR static uint16_t read_angle_sensor(int i2c_port)
53+
IRAM_ATTR static uint16_t read_angle_sensor(int i2c_port)
5454
{
5555
uint8_t write_buffer = AS5600_ANGLE_REGISTER_H;
5656
uint8_t read_buffer[2] = {0,0};
@@ -65,7 +65,7 @@ IRAM_ATTR static uint16_t read_angle_sensor(int i2c_port)
6565
read_buffer,
6666
2,
6767
portMAX_DELAY);
68-
68+
6969
} while (err != ESP_OK);
7070

7171
raw = read_buffer[0];
@@ -114,7 +114,7 @@ IRAM_ATTR static float read_counts(esp_foc_rotor_sensor_t *self)
114114
float delta = (float)raw - obj->previous;
115115

116116
if(fabs(delta) >= encoder_wrap_value) {
117-
obj->accumulated = (delta < 0.0f) ?
117+
obj->accumulated = (delta < 0.0f) ?
118118
obj->accumulated + AS5600_PULSES_PER_REVOLUTION :
119119
obj->accumulated - AS5600_PULSES_PER_REVOLUTION;
120120
}

esp_foc.c

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ static inline void esp_foc_torque_control_loop(esp_foc_axis_t *axis)
115115
esp_foc_low_pass_filter_update(
116116
&axis->current_filters[1], axis->i_d.raw)) +
117117
axis->target_u_d.raw;
118-
119-
if(axis->u_q.raw > (axis->dc_link_voltage * 0.4)) {
120-
axis->u_q.raw = (axis->dc_link_voltage * 0.4);
121-
} else if (axis->u_q.raw < -(axis->dc_link_voltage * 0.4)){
122-
axis->u_q.raw = -(axis->dc_link_voltage * 0.4);
123-
}
124-
125-
if(axis->u_d.raw > (axis->dc_link_voltage * 0.4)) {
126-
axis->u_d.raw = (axis->dc_link_voltage * 0.4);
127-
} else if (axis->u_d.raw < -(axis->dc_link_voltage * 0.4)){
128-
axis->u_d.raw = -(axis->dc_link_voltage * 0.4);
129-
}
130118
}
131119

132120
IRAM_ATTR static void esp_foc_control_loop(void *arg)
@@ -142,7 +130,9 @@ IRAM_ATTR static void esp_foc_control_loop(void *arg)
142130
axis->u_q.raw,
143131
&axis->u_u.raw,
144132
&axis->u_v.raw,
145-
&axis->u_w.raw);
133+
&axis->u_w.raw,
134+
axis->biased_dc_link_voltage,
135+
axis->dc_link_to_normalized);
146136

147137
axis->inverter_driver->set_voltages(axis->inverter_driver,
148138
axis->u_u.raw,
@@ -211,14 +201,30 @@ esp_foc_err_t esp_foc_initialize_axis(esp_foc_axis_t *axis,
211201
return ESP_FOC_ERR_INVALID_ARG;
212202
}
213203

204+
#ifdef CONFIG_ESP_FOC_CUSTOM_MATH
205+
extern void esp_foc_fast_init_sqrt_table(void);
206+
esp_foc_fast_init_sqrt_table();
207+
#endif
208+
214209
axis->inverter_driver = inverter;
215210
axis->rotor_sensor_driver = rotor;
216211
axis->isensor_driver = isensor;
217212

218213
axis->dc_link_voltage =
219214
axis->inverter_driver->get_dc_link_voltage(axis->inverter_driver);
215+
216+
#ifdef CONFIG_ESP_FOC_USE_SINE_PWM
217+
axis->biased_dc_link_voltage = axis->dc_link_voltage / 4.0f;
218+
axis->dc_link_to_normalized = 1.0f / axis->dc_link_voltage;
219+
#else
220+
axis->biased_dc_link_voltage = (axis->dc_link_voltage * ESP_FOC_SQRT3_TWO) / 2.0f;
221+
axis->dc_link_to_normalized = 1.0f / (axis->dc_link_voltage * ESP_FOC_SQRT3_TWO);
222+
#endif
220223
axis->inverter_driver->set_voltages(axis->inverter_driver, 0.0, 0.0, 0.0);
224+
221225
ESP_LOGI(tag,"inverter dc-link voltage: %f[V]", axis->dc_link_voltage);
226+
ESP_LOGI(tag, "FoC max voltage: %f", axis->biased_dc_link_voltage);
227+
ESP_LOGI(tag, "FoC normalizer scale: %f", axis->dc_link_to_normalized);
222228

223229
axis->dt = 0.0;
224230
axis->last_timestamp = 0.0;
@@ -341,10 +347,10 @@ esp_foc_err_t esp_foc_align_axis(esp_foc_axis_t *axis)
341347
0.0f);
342348

343349
axis->inverter_driver->enable(axis->inverter_driver);
344-
esp_foc_sleep_ms(2000);
350+
esp_foc_sleep_ms(100);
345351

346352
axis->inverter_driver->set_voltages(axis->inverter_driver,
347-
0.1 * (axis->dc_link_voltage/2.0f),
353+
0.1,
348354
0.0f,
349355
0.0f);
350356

@@ -379,16 +385,16 @@ IRAM_ATTR esp_foc_err_t esp_foc_set_target_voltage(esp_foc_axis_t *axis,
379385
return ESP_FOC_ERR_AXIS_INVALID_STATE;
380386
}
381387

382-
if(uq.raw > (axis->dc_link_voltage * 0.4)) {
383-
uq.raw = (axis->dc_link_voltage * 0.4);
384-
} else if (uq.raw < -(axis->dc_link_voltage * 0.4)){
385-
uq.raw = -(axis->dc_link_voltage * 0.4);
388+
if(uq.raw > (axis->biased_dc_link_voltage)) {
389+
uq.raw = (axis->biased_dc_link_voltage);
390+
} else if (uq.raw < -(axis->biased_dc_link_voltage)){
391+
uq.raw = -(axis->biased_dc_link_voltage);
386392
}
387393

388-
if(ud.raw > (axis->dc_link_voltage * 0.4)) {
389-
ud.raw = (axis->dc_link_voltage * 0.4);
390-
} else if (ud.raw < -(axis->dc_link_voltage * 0.4)){
391-
ud.raw = -(axis->dc_link_voltage * 0.4);
394+
if(ud.raw > (axis->biased_dc_link_voltage)) {
395+
ud.raw = (axis->biased_dc_link_voltage);
396+
} else if (ud.raw < -(axis->biased_dc_link_voltage)){
397+
ud.raw = -(axis->biased_dc_link_voltage);
392398
}
393399

394400
esp_foc_critical_enter();
@@ -464,6 +470,8 @@ esp_foc_err_t esp_foc_test_motor(esp_foc_inverter_t *inverter,
464470
esp_foc_rotor_sensor_t *rotor,
465471
esp_foc_motor_control_settings_t settings)
466472
{
473+
float norm, bias;
474+
467475
if(inverter == NULL) {
468476
ESP_LOGE(tag, "invalid inverter driver!");
469477
return ESP_FOC_ERR_INVALID_ARG;
@@ -488,6 +496,14 @@ esp_foc_err_t esp_foc_test_motor(esp_foc_inverter_t *inverter,
488496
0.0f);
489497
esp_foc_sleep_ms(250);
490498

499+
#ifdef CONFIG_ESP_FOC_USE_SINE_PWM
500+
bias = inverter->get_dc_link_voltage(inverter) / 2.0f;
501+
norm = 1.0f / inverter->get_dc_link_voltage(inverter);
502+
#else
503+
bias = (inverter->get_dc_link_voltage(inverter) * ESP_FOC_SQRT3_TWO) / 2.0f;
504+
norm = 1.0f / (inverter->get_dc_link_voltage(inverter) * ESP_FOC_SQRT3_TWO);
505+
#endif
506+
491507
/* Turn motor in one direction */
492508
for(float i = 0.0f; i < 2 * M_PI * settings.motor_pole_pairs; i += 0.05) {
493509
esp_foc_u_voltage u;
@@ -503,7 +519,9 @@ esp_foc_err_t esp_foc_test_motor(esp_foc_inverter_t *inverter,
503519
0.2f,
504520
&u.raw,
505521
&v.raw,
506-
&w.raw);
522+
&w.raw,
523+
bias,
524+
norm);
507525

508526
inverter->set_voltages(inverter,
509527
u.raw,
@@ -528,7 +546,9 @@ esp_foc_err_t esp_foc_test_motor(esp_foc_inverter_t *inverter,
528546
0.2f,
529547
&u.raw,
530548
&v.raw,
531-
&w.raw);
549+
&w.raw,
550+
bias,
551+
norm);
532552

533553
inverter->set_voltages(inverter,
534554
u.raw,

esp_foc_consts.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
* The above copyright notice and this permission notice shall be included in all
1414
* copies or substantial portions of the Software.
15-
*
15+
*
1616
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1717
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1818
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -21,7 +21,7 @@
2121
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
* SOFTWARE.
2323
*/
24-
24+
2525
#include <math.h>
2626

2727
#ifdef CONFIG_ESP_FOC_CUSTOM_MATH
@@ -30,10 +30,11 @@ const float ESP_FOC_FAST_2PI = ESP_FOC_FAST_PI * 2.0f;
3030
const float ESP_FOC_SIN_COS_APPROX_B = 4.0f / ESP_FOC_FAST_PI;
3131
const float ESP_FOC_SIN_COS_APPROX_C = -4.0f / (ESP_FOC_FAST_PI * ESP_FOC_FAST_PI);
3232
const float ESP_FOC_SIN_COS_APPROX_P = 0.225f;
33-
const float ESP_FOC_SIN_COS_APPROX_D = ESP_FOC_FAST_PI/2.0f;
33+
const float ESP_FOC_SIN_COS_APPROX_D = ESP_FOC_FAST_PI/2.0f;
3434
#endif
3535

3636
const float ESP_FOC_CLARKE_K1 = 2.0/3.0f;
3737
const float ESP_FOC_CLARKE_K2 = 1.0/3.0f;
3838
const float ESP_FOC_CLARKE_PARK_SQRT3 = 1.73205080757f;
3939
const float ESP_FOC_CLARKE_K3 = 2.0f / ESP_FOC_CLARKE_PARK_SQRT3;
40+
const float ESP_FOC_SQRT3_TWO = ESP_FOC_CLARKE_PARK_SQRT3 / 2.0f;

esp_foc_sine_cosine.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <math.h>
2626
#include <stdint.h>
27+
#include "esp_attr.h"
2728

2829
static const float sine_table[4096] = {
2930
0.000000f, 0.001534f, 0.003068f, 0.004602f, 0.006136f, 0.007670f, 0.009204f, 0.010738f,
@@ -1058,14 +1059,14 @@ static const float cosine_table[4096] = {
10581059
const static float full2pi = M_PI * 2.0f;
10591060
const static float index_scale = (4096.0f / full2pi);
10601061

1061-
float esp_foc_fast_sine(float angle)
1062+
IRAM_ATTR float esp_foc_fast_sine(float angle)
10621063
{
10631064
uint16_t index = (uint16_t)(angle * index_scale);
10641065
index &= (4096 - 1);
10651066
return sine_table[index];
10661067
}
10671068

1068-
float esp_foc_fast_cosine(float angle)
1069+
IRAM_ATTR float esp_foc_fast_cosine(float angle)
10691070
{
10701071
uint16_t index = (uint16_t)(angle * index_scale);
10711072
index &= (4096 - 1);

esp_foc_sqrtf.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2021 Felipe Neves
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
#include <stdint.h>
26+
#include <math.h>
27+
#include "esp_attr.h"
28+
29+
#define SQRT_TABLE_BITS 12
30+
#define SQRT_TABLE_SIZE (1 << SQRT_TABLE_BITS)
31+
32+
static float sqrt_table[SQRT_TABLE_SIZE];
33+
34+
void esp_foc_fast_init_sqrt_table(void)
35+
{
36+
for (int i = 0; i < SQRT_TABLE_SIZE; i++) {
37+
float x = 1.0f + 3.0f * ((float)i / (SQRT_TABLE_SIZE - 1));
38+
sqrt_table[i] = sqrtf(x);
39+
}
40+
}
41+
42+
IRAM_ATTR float esp_foc_fast_sqrt(float x)
43+
{
44+
if (x <= 0.0f) {
45+
return 0.0f;
46+
}
47+
48+
union {
49+
float f;
50+
uint32_t i;
51+
} u = { x };
52+
53+
int e = (u.i >> 23) & 0xff;
54+
int exponent = e - 127;
55+
float m = 1.0f + (u.i & 0x7fffff) / 8388608.0f;
56+
int odd = exponent & 1;
57+
58+
if (odd) {
59+
m *= 2.0f;
60+
}
61+
62+
float t = (m - 1.0f) / 3.0f;
63+
float pos = t * (SQRT_TABLE_SIZE - 1);
64+
int index = (int) pos;
65+
66+
if (index >= SQRT_TABLE_SIZE - 1) {
67+
index = SQRT_TABLE_SIZE - 2;
68+
}
69+
70+
float frac = pos - index;
71+
float sqrt_m = sqrt_table[index] + frac * (sqrt_table[index + 1] - sqrt_table[index]);
72+
73+
if (odd) {
74+
sqrt_m *= 0.707106781186547524f;
75+
}
76+
77+
int new_exp = exponent >> 1;
78+
return ldexpf(sqrt_m, new_exp);
79+
}

0 commit comments

Comments
 (0)