diff --git a/confgenerator.c b/confgenerator.c index 5ed3e7eab..48b2b6e2a 100644 --- a/confgenerator.c +++ b/confgenerator.c @@ -135,6 +135,7 @@ int32_t confgenerator_serialize_mcconf(uint8_t *buffer, const mc_configuration * buffer_append_float16(buffer, conf->foc_fw_ramp_time, 1000, &ind); buffer_append_float16(buffer, conf->foc_fw_q_current_factor, 10000, &ind); buffer[ind++] = conf->foc_speed_soure; + buffer[ind++] = conf->foc_commutation_type; buffer_append_int16(buffer, conf->gpd_buffer_notify_left, &ind); buffer_append_int16(buffer, conf->gpd_buffer_interpol, &ind); buffer_append_float16(buffer, conf->gpd_current_filter_const, 10000, &ind); @@ -532,6 +533,7 @@ bool confgenerator_deserialize_mcconf(const uint8_t *buffer, mc_configuration *c conf->foc_fw_ramp_time = buffer_get_float16(buffer, 1000, &ind); conf->foc_fw_q_current_factor = buffer_get_float16(buffer, 10000, &ind); conf->foc_speed_soure = buffer[ind++]; + conf->foc_commutation_type = buffer[ind++]; conf->gpd_buffer_notify_left = buffer_get_int16(buffer, &ind); conf->gpd_buffer_interpol = buffer_get_int16(buffer, &ind); conf->gpd_current_filter_const = buffer_get_float16(buffer, 10000, &ind); @@ -925,6 +927,7 @@ void confgenerator_set_defaults_mcconf(mc_configuration *conf) { conf->foc_fw_ramp_time = MCCONF_FOC_FW_RAMP_TIME; conf->foc_fw_q_current_factor = MCCONF_FOC_FW_Q_CURRENT_FACTOR; conf->foc_speed_soure = MCCONF_FOC_SPEED_SOURCE; + conf->foc_commutation_type = MCCONF_FOC_COMMUTATION_TYPE; conf->gpd_buffer_notify_left = MCCONF_GPD_BUFFER_NOTIFY_LEFT; conf->gpd_buffer_interpol = MCCONF_GPD_BUFFER_INTERPOL; conf->gpd_current_filter_const = MCCONF_GPD_CURRENT_FILTER_CONST; diff --git a/confgenerator.h b/confgenerator.h index 680c3d873..ecac92fd9 100644 --- a/confgenerator.h +++ b/confgenerator.h @@ -8,7 +8,7 @@ #include // Constants -#define MCCONF_SIGNATURE 776184161 +#define MCCONF_SIGNATURE 608083588 #define APPCONF_SIGNATURE 486554156 // Functions diff --git a/datatypes.h b/datatypes.h index 5fec09244..4fc377415 100644 --- a/datatypes.h +++ b/datatypes.h @@ -25,6 +25,14 @@ #include "ch.h" // Data types +typedef enum { + ALT_REV_SEQ = 0, // alternating reversing sequence (previous implementation) + NULL_V0, // flat bottom + NULL_V7, // flat top + V7_ODD_V0_EVEN, // v7 in [1,3,5] v0 in [2,4,6] + V0_ODD_V7_EVEN, // v0 in [1,3,5] v7 in [2,4,6] +} commutation_technique_t; + typedef enum { HW_TYPE_VESC = 0, HW_TYPE_VESC_BMS, @@ -458,6 +466,7 @@ typedef struct { bool foc_phase_filter_disable_fault; float foc_phase_filter_max_erpm; MTPA_MODE foc_mtpa_mode; + commutation_technique_t foc_commutation_type; // Field Weakening float foc_fw_current_max; float foc_fw_duty_start; diff --git a/motor/foc_math.c b/motor/foc_math.c index 7367ac179..5aaf94a7b 100644 --- a/motor/foc_math.c +++ b/motor/foc_math.c @@ -21,6 +21,10 @@ #include "utils_math.h" #include + +const uint8_t sector_LUT[6] = {6u, 2u, 1u, 4u, 5u, 3u}; + + // See http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf void foc_observer_update(float v_alpha, float v_beta, float i_alpha, float i_beta, float dt, observer_state *state, float *phase, motor_all_state_t *motor) { @@ -196,137 +200,214 @@ void foc_pll_run(float phase, float dt, float *phase_var, /** * @brief svm Space vector modulation. Magnitude must not be larger than sqrt(3)/2, or 0.866 to avoid overmodulation. * See https://github.com/vedderb/bldc/pull/372#issuecomment-962499623 for a full description. + * See the follwoing links for a full description: + * https://youtu.be/5eQyoVMz1dY + * https://link.gale.com/apps/doc/A18320578/AONE * @param alpha voltage * @param beta Park transformed and normalized voltage * @param PWMFullDutyCycle is the peak value of the PWM counter. * @param tAout PWM duty cycle phase A (0 = off all of the time, PWMFullDutyCycle = on all of the time) - * @param tBout PWM duty cycle phase B - * @param tCout PWM duty cycle phase C + * @param tBout PWM duty cycle phase B (0 = off all of the time, PWMFullDutyCycle = on all of the time) + * @param tCout PWM duty cycle phase C (0 = off all of the time, PWMFullDutyCycle = on all of the time) */ void foc_svm(float alpha, float beta, uint32_t PWMFullDutyCycle, - uint32_t* tAout, uint32_t* tBout, uint32_t* tCout, uint32_t *svm_sector) { - uint32_t sector; - - if (beta >= 0.0f) { - if (alpha >= 0.0f) { - //quadrant I - if (ONE_BY_SQRT3 * beta > alpha) { - sector = 2; - } else { - sector = 1; - } - } else { - //quadrant II - if (-ONE_BY_SQRT3 * beta > alpha) { - sector = 3; - } else { - sector = 2; - } - } - } else { - if (alpha >= 0.0f) { - //quadrant IV5 - if (-ONE_BY_SQRT3 * beta > alpha) { - sector = 5; - } else { - sector = 6; - } - } else { - //quadrant III - if (ONE_BY_SQRT3 * beta > alpha) { - sector = 4; - } else { - sector = 5; - } - } - } + uint32_t* tAout, uint32_t* tBout, uint32_t* tCout, + uint32_t *svm_sector, commutation_technique_t comm_tech) { - // PWM timings - uint32_t tA, tB, tC; + uint32_t tA = 0u, tB = 0u, tC = 0u, N = 0u, sector = 0u; + float T0 = 0.0f, T1 = 0.0f, T2 = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, temp = 0.0f; - switch (sector) { + a = SQRT3_BY_2*alpha - 0.5f*beta; + b = beta; - // sector 1-2 - case 1: { - // Vector on-times - uint32_t t1 = (alpha - ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t2 = (TWO_BY_SQRT3 * beta) * PWMFullDutyCycle; + temp = (float)PWMFullDutyCycle/SQRT3_BY_2; - // PWM timings - tA = (PWMFullDutyCycle + t1 + t2) / 2; - tB = tA - t1; - tC = tB - t2; + a *= temp; + b *= temp; + c = -1.0f*(a+b); // kirchhoff current law (current in = current out) + N = (((int32_t)a) >= 0) + 2u*(((int32_t)b) >= 0) + 4u*(((int32_t)c) >= 0); + N = (N > 6u || N == 0u) ? 2u : N-1; // if a, b, c are all zero (happens when alpha & beta are zero) or negative set it to index 2 (sector 1) + sector = sector_LUT[N]; + + switch(sector) { + case 1: { + T1 = a; + T2 = b; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(T1+T2+0.5f*T0); + tB = (uint32_t)(T2+0.5f*T0); + tC = (uint32_t)(0.5f*T0); + break; + + case V0_ODD_V7_EVEN: + case NULL_V0: + tA = (uint32_t)(T1+T2); + tB = (uint32_t)(T2); + tC = (uint32_t)(0); + break; + + case V7_ODD_V0_EVEN: + case NULL_V7: + tA = (uint32_t)(PWMFullDutyCycle); + tB = (uint32_t)(T0+T2); + tC = (uint32_t)(T0); + break; + } break; } - // sector 2-3 case 2: { - // Vector on-times - uint32_t t2 = (alpha + ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t3 = (-alpha + ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - - // PWM timings - tB = (PWMFullDutyCycle + t2 + t3) / 2; - tA = tB - t3; - tC = tA - t2; - + T1 = -c; + T2 = -a; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(T1+0.5f*T0); + tB = (uint32_t)(T1+T2+0.5f*T0); + tC = (uint32_t)(0.5f*T0); + break; + + case V7_ODD_V0_EVEN: + case NULL_V0: + tA = (uint32_t)(T1); + tB = (uint32_t)(T1+T2); + tC = (uint32_t)(0); + break; + + case V0_ODD_V7_EVEN: + case NULL_V7: + tA = (uint32_t)(T0+T1); + tB = (uint32_t)(PWMFullDutyCycle); + tC = (uint32_t)(T0); + break; + } break; } - // sector 3-4 case 3: { - // Vector on-times - uint32_t t3 = (TWO_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t4 = (-alpha - ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - - // PWM timings - tB = (PWMFullDutyCycle + t3 + t4) / 2; - tC = tB - t3; - tA = tC - t4; - + T1 = b; + T2 = c; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(0.5f*T0); + tB = (uint32_t)(T1+T2+0.5f*T0); + tC = (uint32_t)(T2+0.5f*T0); + break; + + case V0_ODD_V7_EVEN: + case NULL_V0: + tA = (uint32_t)(0); + tB = (uint32_t)(T1+T2); + tC = (uint32_t)(T2); + break; + + case V7_ODD_V0_EVEN: + case NULL_V7: + tA = (uint32_t)(T0); + tB = (uint32_t)(PWMFullDutyCycle); + tC = (uint32_t)(T0+T2); + break; + } break; } - // sector 4-5 case 4: { - // Vector on-times - uint32_t t4 = (-alpha + ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t5 = (-TWO_BY_SQRT3 * beta) * PWMFullDutyCycle; - - // PWM timings - tC = (PWMFullDutyCycle + t4 + t5) / 2; - tB = tC - t5; - tA = tB - t4; - + T1 = -a; + T2 = -b; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(0.5f*T0); + tB = (uint32_t)(T1+0.5f*T0); + tC = (uint32_t)(T1+T2+0.5f*T0); + break; + + case V7_ODD_V0_EVEN: + case NULL_V0: + tA = (uint32_t)(0); + tB = (uint32_t)(T1); + tC = (uint32_t)(T1+T2); + break; + + case V0_ODD_V7_EVEN: + case NULL_V7: + tA = (uint32_t)(T0); + tB = (uint32_t)(T0+T1); + tC = (uint32_t)(PWMFullDutyCycle); + break; + } break; } - // sector 5-6 case 5: { - // Vector on-times - uint32_t t5 = (-alpha - ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t6 = (alpha - ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - - // PWM timings - tC = (PWMFullDutyCycle + t5 + t6) / 2; - tA = tC - t5; - tB = tA - t6; - + T1 = c; + T2 = a; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(T2+0.5f*T0); + tB = (uint32_t)(0.5f*T0); + tC = (uint32_t)(T1+T2+0.5f*T0); + break; + + case V0_ODD_V7_EVEN: + case NULL_V0: + tA = (uint32_t)(T2); + tB = (uint32_t)(0); + tC = (uint32_t)(T1+T2); + break; + + case V7_ODD_V0_EVEN: + case NULL_V7: + tA = (uint32_t)(T0+T2); + tB = (uint32_t)(T0); + tC = (uint32_t)(PWMFullDutyCycle); + break; + } break; } - // sector 6-1 case 6: { - // Vector on-times - uint32_t t6 = (-TWO_BY_SQRT3 * beta) * PWMFullDutyCycle; - uint32_t t1 = (alpha + ONE_BY_SQRT3 * beta) * PWMFullDutyCycle; - - // PWM timings - tA = (PWMFullDutyCycle + t6 + t1) / 2; - tC = tA - t1; - tB = tC - t6; - + T1 = -b; + T2 = -c; + T0 = (float)PWMFullDutyCycle - T1 - T2; + + switch (comm_tech) { + case ALT_REV_SEQ: + default: + tA = (uint32_t)(T1+T2+0.5f*T0); + tB = (uint32_t)(0.5f*T0); + tC = (uint32_t)(T1+0.5f*T0); + break; + + case V7_ODD_V0_EVEN: + case NULL_V0: + tA = (uint32_t)(T1+T2); + tB = (uint32_t)(0); + tC = (uint32_t)(T1); + break; + + case V0_ODD_V7_EVEN: + case NULL_V7: + tA = (uint32_t)(PWMFullDutyCycle); + tB = (uint32_t)(T0); + tC = (uint32_t)(T0+T1); + break; + } break; } } diff --git a/motor/foc_math.h b/motor/foc_math.h index a2210829a..c0eb2321a 100644 --- a/motor/foc_math.h +++ b/motor/foc_math.h @@ -210,7 +210,8 @@ void foc_observer_update(float v_alpha, float v_beta, float i_alpha, float i_bet void foc_pll_run(float phase, float dt, float *phase_var, float *speed_var, mc_configuration *conf); void foc_svm(float alpha, float beta, uint32_t PWMFullDutyCycle, - uint32_t* tAout, uint32_t* tBout, uint32_t* tCout, uint32_t *svm_sector); + uint32_t* tAout, uint32_t* tBout, uint32_t* tCout, + uint32_t *svm_sector, commutation_technique_t comm_tech); void foc_run_pid_control_pos(bool index_found, float dt, motor_all_state_t *motor); void foc_run_pid_control_speed(float dt, motor_all_state_t *motor); float foc_correct_encoder(float obs_angle, float enc_angle, float speed, float sl_erpm, motor_all_state_t *motor); diff --git a/motor/mcconf_default.h b/motor/mcconf_default.h index 8da59c572..5327e9ef9 100644 --- a/motor/mcconf_default.h +++ b/motor/mcconf_default.h @@ -472,6 +472,9 @@ #ifndef MCCONF_FOC_SPEED_SOURCE #define MCCONF_FOC_SPEED_SOURCE SPEED_SRC_OBSERVER // Position source for speed trackers #endif +#ifndef MCCONF_FOC_COMMUTATION_TYPE +#define MCCONF_FOC_COMMUTATION_TYPE ALT_REV_SEQ // Commutation method during FOC +#endif // GPD #ifndef MCCONF_GPD_BUFFER_NOTIFY_LEFT diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index 120e3303a..7e49751af 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -4236,7 +4236,8 @@ static void control_current(motor_all_state_t *motor, float dt) { (uint32_t*)&motor->m_duty1_next, (uint32_t*)&motor->m_duty2_next, (uint32_t*)&motor->m_duty3_next, - (uint32_t*)&state_m->svm_sector); + (uint32_t*)&state_m->svm_sector, + motor->m_conf->foc_commutation_type); motor->m_duty_next_set = true; } } else { @@ -4262,7 +4263,7 @@ static void control_current(motor_all_state_t *motor, float dt) { // Calculate the duty cycles for all the phases. This also injects a zero modulation signal to // be able to fully utilize the bus voltage. See https://microchipdeveloper.com/mct5001:start - foc_svm(state_m->mod_alpha_raw, state_m->mod_beta_raw, top, &duty1, &duty2, &duty3, (uint32_t*)&state_m->svm_sector); + foc_svm(state_m->mod_alpha_raw, state_m->mod_beta_raw, top, &duty1, &duty2, &duty3, (uint32_t*)&state_m->svm_sector, motor->m_conf->foc_commutation_type); if (motor == &m_motor_1) { TIMER_UPDATE_DUTY_M1(duty1, duty2, duty3);