Skip to content

Commit

Permalink
Added Field Weakening
Browse files Browse the repository at this point in the history
  • Loading branch information
casainho committed Apr 25, 2020
1 parent 3eb91a7 commit 8f4cf96
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 38 deletions.
6 changes: 5 additions & 1 deletion src/config.h
Expand Up @@ -36,9 +36,13 @@
// Choose PWM ramp up/down step (higher value will make the motor acceleration slower)
//
// For a 24V battery, 25 for ramp up seems ok. For an higher voltage battery, this values should be higher
#define PWM_DUTY_CYCLE_RAMP_UP_INVERSE_STEP 25
#define PWM_DUTY_CYCLE_RAMP_UP_INVERSE_STEP 40
#define PWM_DUTY_CYCLE_RAMP_DOWN_INVERSE_STEP 30

// The following value were tested by Casainho on 2020.04.23
#define FIELD_WEAKENING_RAMP_UP_INVERSE_STEP 600
#define FIELD_WEAKENING_RAMP_DOWN_INVERSE_STEP 600

// *************************************************************************** //
// MOTOR

Expand Down
26 changes: 19 additions & 7 deletions src/ebike_app.c
Expand Up @@ -585,7 +585,15 @@ static void communications_process_packages(uint8_t ui8_frame_type)
ui8_tx_buffer[14] = ui8_pas_cadence_rpm;

// PWM duty_cycle
ui8_tx_buffer[15] = ui8_g_duty_cycle;
// convert duty-cycle to 0 - 100 %
// add field_weakening_angle
ui16_temp = (uint16_t) ui8_g_duty_cycle;
ui16_temp = (ui16_temp * 100) / PWM_DUTY_CYCLE_MAX;
if (ui8_g_field_weakening_enable_state)
{
ui16_temp += (((uint16_t) ui8_g_field_weakening_angle) * 14) / 10;
}
ui8_tx_buffer[15] = (uint8_t) ui16_temp;

// motor speed in ERPS
ui16_temp = ui16_motor_get_motor_speed_erps();
Expand Down Expand Up @@ -718,8 +726,11 @@ static void communications_process_packages(uint8_t ui8_frame_type)
// battery current min ADC
m_config_vars.ui8_battery_current_min_adc = ui8_rx_buffer[79];

ui8_g_pedal_cadence_fast_stop = ui8_rx_buffer[80];
ui8_temp = ui8_rx_buffer[80];
ui8_g_pedal_cadence_fast_stop = ui8_temp & 1;
ui8_g_field_weakening_enable = (ui8_temp & 2) >> 1;

// coast brake threshold
ui8_temp = ui8_rx_buffer[81];
if ((ui8_temp + 5) > ui16_g_adc_torque_sensor_min_value)
{
Expand All @@ -730,15 +741,14 @@ static void communications_process_packages(uint8_t ui8_frame_type)
ui8_temp = 5;
}
ui8_g_adc_coast_brake_torque_threshold = ui8_temp;

break;

// firmware version
case COMM_FRAME_TYPE_FIRMWARE_VERSION:
ui8_tx_buffer[3] = ui8_m_system_state;
ui8_tx_buffer[4] = 0;
ui8_tx_buffer[5] = 58;
ui8_tx_buffer[6] = 0;
ui8_tx_buffer[5] = 0;
ui8_tx_buffer[6] = 1;
ui8_len += 4;
break;

Expand Down Expand Up @@ -786,6 +796,7 @@ static void ebike_app_set_target_adc_battery_max_current(uint16_t ui16_value)
}

ui16_g_adc_target_battery_max_current = ui16_g_adc_current_offset + ui16_value;
ui16_g_adc_target_battery_max_current_fw = ui16_g_adc_target_battery_max_current + (ui16_g_adc_target_battery_max_current >> 2);
}

static void ebike_app_set_target_adc_motor_max_current(uint16_t ui16_value)
Expand All @@ -797,6 +808,7 @@ static void ebike_app_set_target_adc_motor_max_current(uint16_t ui16_value)
}

ui16_g_adc_target_motor_max_current = ui16_g_adc_current_offset + ui16_value;
ui16_g_adc_target_motor_max_current_fw = ui16_g_adc_target_motor_max_current + (ui16_g_adc_target_motor_max_current >> 2);
}

// in amps
Expand Down Expand Up @@ -1292,8 +1304,8 @@ static void read_pas_cadence(void)
}
else
{
// cadence in RPM = 60 / (ui16_pas_timer2_ticks * PAS_NUMBER_MAGNETS * 0.000064)
ui8_pas_cadence_rpm = (uint8_t) (60 / (((float) ui16_pas_pwm_cycles_ticks) * ((float) PAS_NUMBER_MAGNETS) * 0.000053));
// cadence in RPM = 60 / (ui16_pas_pwm_cycles_ticks * PAS_NUMBER_MAGNETS * 0.000053)
ui8_pas_cadence_rpm = (uint8_t) (((uint16_t) 56604) / ui16_pas_pwm_cycles_ticks);
}

if (m_config_vars.ui8_torque_sensor_calibration_pedal_ground)
Expand Down
4 changes: 3 additions & 1 deletion src/main.h
Expand Up @@ -18,6 +18,7 @@
#define PWM_DUTY_CYCLE_MAX 254
#define PWM_DUTY_CYCLE_MIN 20
#define MIDDLE_PWM_DUTY_CYCLE_MAX (PWM_DUTY_CYCLE_MAX/2)
#define FIELD_WEAKENING_ANGLE_MAX 8 // 8 * 1.4 = 11 | tested by Casainho on 2020.04.23 and gives up to 125% more motor speed

#define MOTOR_ROTOR_ANGLE_90 (63 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_150 (106 + MOTOR_ROTOR_OFFSET_ANGLE)
Expand All @@ -27,7 +28,8 @@
#define MOTOR_ROTOR_ANGLE_30 (20 + MOTOR_ROTOR_OFFSET_ANGLE)

// motor maximum rotation
#define MOTOR_OVER_SPEED_ERPS 700 // motor max speed, protection max value | 27 points for the sinewave at max speed
#define MOTOR_OVER_SPEED_ERPS 700 // 675 is equal to 120 cadence, as TSDZ2 has a reduciton ratio of 41.8
#define MOTOR_SPEED_FIELD_WEAKEANING_MIN 250

// throttle
#define THROTTLE_FILTER_COEFFICIENT 1 // see note below
Expand Down
145 changes: 116 additions & 29 deletions src/motor.c
Expand Up @@ -382,6 +382,12 @@ uint16_t ui16_duty_cycle_ramp_down_inverse_step;
uint16_t ui16_counter_duty_cycle_ramp_up = 0;
uint16_t ui16_counter_duty_cycle_ramp_down = 0;

volatile uint8_t ui8_g_field_weakening_angle = 0;
volatile uint8_t ui8_g_field_weakening_enable = 0;
volatile uint8_t ui8_g_field_weakening_enable_state = 0;
uint16_t ui16_counter_field_weakening_ramp_up = 0;
uint16_t ui16_counter_field_weakening_ramp_down = 0;

uint8_t ui8_phase_a_voltage;
uint8_t ui8_phase_b_voltage;
uint8_t ui8_phase_c_voltage;
Expand All @@ -406,11 +412,14 @@ volatile uint16_t ui16_g_adc_motor_current_filtered;
volatile uint16_t ui16_g_adc_battery_current;
volatile uint16_t ui16_g_adc_motor_current;
uint8_t ui8_current_controller_counter = 0;
uint16_t ui16_motor_speed_controller_counter = 0;

volatile uint16_t ui16_g_adc_target_battery_max_current;
volatile uint16_t ui16_g_adc_target_battery_max_current_fw;
volatile uint16_t ui16_g_adc_current_offset;

volatile uint16_t ui16_g_adc_target_motor_max_current;
volatile uint16_t ui16_g_adc_target_motor_max_current_fw;

static uint8_t ui8_m_pas_state;
static uint8_t ui8_m_pas_state_old;
Expand Down Expand Up @@ -454,6 +463,7 @@ void motor_controller(void)
void TIM1_CAP_COM_IRQHandler(void) __interrupt(TIM1_CAP_COM_IRQHANDLER)
{
uint8_t ui8_temp;
uint16_t ui16_adc_target_motor_max_current;

/****************************************************************************/
// read battery current ADC value | should happen at middle of the PWM duty_cycle
Expand Down Expand Up @@ -607,14 +617,19 @@ void TIM1_CAP_COM_IRQHandler(void) __interrupt(TIM1_CAP_COM_IRQHANDLER)
// TODO: verifiy if (ui16_PWM_cycles_counter_6 << 8) do not overflow
ui8_interpolation_angle = (ui16_PWM_cycles_counter_6 << 8) / ui16_PWM_cycles_counter_total; // this operations take 4.4us
ui8_motor_rotor_angle = ui8_motor_rotor_absolute_angle + ui8_interpolation_angle;
ui8_svm_table_index = ui8_motor_rotor_angle + ui8_g_foc_angle;
ui8_svm_table_index = ui8_motor_rotor_angle;
}
else
#endif
{
ui8_svm_table_index = ui8_motor_rotor_absolute_angle + ui8_g_foc_angle;
ui8_svm_table_index = ui8_motor_rotor_absolute_angle;
}

ui8_svm_table_index += ui8_g_foc_angle;

// we need to put phase voltage 90 degrees ahead of rotor position, to get current 90 degrees ahead and have max torque per amp
ui8_svm_table_index -= 63;

/****************************************************************************/
// check brakes state

Expand All @@ -629,10 +644,6 @@ void TIM1_CAP_COM_IRQHandler(void) __interrupt(TIM1_CAP_COM_IRQHANDLER)
ui8_g_brakes_state = ((BRAKE__PORT->IDR & (uint8_t)BRAKE__PIN) == 0);
}
/****************************************************************************/


// we need to put phase voltage 90 degrees ahead of rotor position, to get current 90 degrees ahead and have max torque per amp
ui8_svm_table_index -= 63;

/****************************************************************************/
// PWM duty_cycle controller:
Expand All @@ -644,46 +655,117 @@ void TIM1_CAP_COM_IRQHandler(void) __interrupt(TIM1_CAP_COM_IRQHANDLER)
// - limit motor max ERPS
// - ramp up/down PWM duty_cycle value

// check to enable field weakening state
if (ui8_g_field_weakening_enable &&
(ui16_motor_speed_erps > MOTOR_SPEED_FIELD_WEAKEANING_MIN)) // do not enable at low motor speed / low cadence
ui8_g_field_weakening_enable_state = 1;

++ui8_current_controller_counter;
++ui16_motor_speed_controller_counter;

if (ui8_g_brakes_state ||
(ui8_m_pas_min_cadence_flag && (ui8_g_throttle == 0)) ||
(UI8_ADC_BATTERY_VOLTAGE < ui8_adc_battery_voltage_cut_off))
{
if (ui8_g_duty_cycle > 0)
if (ui8_g_field_weakening_angle)
{
--ui8_g_field_weakening_angle;
}
else if (ui8_g_duty_cycle)
{
--ui8_g_duty_cycle;
}
}
// do not control current at every PWM cycle, that will measure and control too fast. Use counter to limit
else if (++ui8_current_controller_counter > 14)
else if ((ui8_current_controller_counter > 14) &&
((ui16_g_adc_battery_current > ui16_g_adc_target_battery_max_current) ||
(ui16_g_adc_motor_current > ui16_controller_adc_max_current)))
{
ui8_current_controller_counter = 0;

if((ui16_g_adc_battery_current > ui16_g_adc_target_battery_max_current) ||
(ui16_g_adc_motor_current > ui16_controller_adc_max_current) ||
if (ui8_g_field_weakening_angle)
{
--ui8_g_field_weakening_angle;
}
else if (ui8_g_duty_cycle)
{
--ui8_g_duty_cycle;
}
}
else if ((ui16_motor_speed_controller_counter > 2000) && // test about every 100ms
(ui16_motor_speed_erps > ui16_max_motor_speed_erps))
{
if (ui8_g_field_weakening_angle)
{
if (ui8_g_duty_cycle > 0)
--ui8_g_duty_cycle;
--ui8_g_field_weakening_angle;
}
else if (ui8_g_duty_cycle)
{
--ui8_g_duty_cycle;
}
}
else // nothing to limit, so adjust duty_cycle to duty_cycle_target, including ramping
// or adjust field weakening
{
if (ui8_m_duty_cycle_target > ui8_g_duty_cycle)
if ((ui8_g_duty_cycle >= PWM_DUTY_CYCLE_MAX) && // max voltage already applied to motor windings, enter or keep in field weakening state
ui8_g_field_weakening_enable_state)
{
if (ui16_counter_duty_cycle_ramp_up++ >= ui16_duty_cycle_ramp_up_inverse_step)
if (ui16_g_adc_motor_current < ui16_controller_adc_max_current)
{
ui16_counter_duty_cycle_ramp_up = 0;
++ui8_g_duty_cycle;
if (ui16_counter_field_weakening_ramp_up++ >= FIELD_WEAKENING_RAMP_UP_INVERSE_STEP)
{
ui16_counter_field_weakening_ramp_up = 0;

if (ui8_g_field_weakening_angle < FIELD_WEAKENING_ANGLE_MAX)
++ui8_g_field_weakening_angle;
}
}
else if (ui16_g_adc_motor_current > ui16_controller_adc_max_current)
{
if (ui16_counter_field_weakening_ramp_down++ >= FIELD_WEAKENING_RAMP_DOWN_INVERSE_STEP)
{
ui16_counter_field_weakening_ramp_down = 0;

if (ui8_g_field_weakening_angle)
{
--ui8_g_field_weakening_angle;
}
else
{
--ui8_g_duty_cycle; // exit from field weakening state
}
}
}
}
else if (ui8_m_duty_cycle_target < ui8_g_duty_cycle)
else
{
if (ui16_counter_duty_cycle_ramp_down++ >= ui16_duty_cycle_ramp_down_inverse_step)
if (ui8_m_duty_cycle_target > ui8_g_duty_cycle)
{
ui16_counter_duty_cycle_ramp_down = 0;
--ui8_g_duty_cycle;
if (ui16_counter_duty_cycle_ramp_up++ >= ui16_duty_cycle_ramp_up_inverse_step)
{
ui16_counter_duty_cycle_ramp_up = 0;
++ui8_g_duty_cycle;
}
}
else if (ui8_m_duty_cycle_target < ui8_g_duty_cycle)
{
if (ui16_counter_duty_cycle_ramp_down++ >= ui16_duty_cycle_ramp_down_inverse_step)
{
ui16_counter_duty_cycle_ramp_down = 0;
--ui8_g_duty_cycle;
}
}
}
}

ui8_svm_table_index += ui8_g_field_weakening_angle;

// disable field weakening only after leaving the field weakening state
if (ui8_g_field_weakening_enable == 0 &&
ui8_g_duty_cycle < PWM_DUTY_CYCLE_MAX)
ui8_g_field_weakening_enable_state = 0;

if (ui8_current_controller_counter > 14)
ui8_current_controller_counter = 0;

/****************************************************************************/
// calculate final PWM duty_cycle values to be applied to TIMER1
// scale and apply PWM duty_cycle for the 3 phases
Expand Down Expand Up @@ -745,18 +827,23 @@ void TIM1_CAP_COM_IRQHandler(void) __interrupt(TIM1_CAP_COM_IRQHANDLER)

/****************************************************************************/
// ramp up ADC battery current
if (ui16_g_adc_target_motor_max_current > ui16_controller_adc_max_current)

// field weakening has a higher current value to provide the same torque
if (ui8_g_field_weakening_enable_state)
ui16_adc_target_motor_max_current = ui16_g_adc_target_motor_max_current_fw;
else
ui16_adc_target_motor_max_current = ui16_g_adc_target_motor_max_current;

// now ramp up
if (ui16_adc_target_motor_max_current > ui16_controller_adc_max_current)
{
if (ui16_counter_adc_current_ramp_up++ >= ui16_g_current_ramp_up_inverse_step)
{
// reset counter
ui16_counter_adc_current_ramp_up = 0;

// increment current
ui16_controller_adc_max_current++;
}
}
else if (ui16_g_adc_target_motor_max_current < ui16_controller_adc_max_current)
else if (ui16_adc_target_motor_max_current < ui16_controller_adc_max_current)
{
// we are not doing a ramp down here, just directly setting to the target value
ui16_controller_adc_max_current = ui16_g_adc_target_motor_max_current;
Expand Down Expand Up @@ -984,12 +1071,12 @@ void motor_set_pwm_duty_cycle_target(uint8_t ui8_value)
ui8_m_duty_cycle_target = ui8_value;
}

void motor_set_pwm_duty_cycle_ramp_up_inverse_step (uint16_t ui16_value)
void motor_set_pwm_duty_cycle_ramp_up_inverse_step(uint16_t ui16_value)
{
ui16_duty_cycle_ramp_up_inverse_step = ui16_value;
}

void motor_set_pwm_duty_cycle_ramp_down_inverse_step (uint16_t ui16_value)
void motor_set_pwm_duty_cycle_ramp_down_inverse_step(uint16_t ui16_value)
{
ui16_duty_cycle_ramp_down_inverse_step = ui16_value;
}
Expand Down
5 changes: 5 additions & 0 deletions src/motor.h
Expand Up @@ -24,10 +24,15 @@ extern volatile uint8_t ui8_g_pas_pedal_right;
extern volatile uint8_t ui8_g_hall_sensors_state;
extern volatile uint16_t ui16_main_loop_wdt_cnt_1;
extern volatile uint16_t ui16_g_adc_target_battery_max_current;
extern volatile uint16_t ui16_g_adc_target_battery_max_current_fw;
extern volatile uint16_t ui16_g_adc_current_offset;
extern volatile uint16_t ui16_g_adc_target_motor_max_current;
extern volatile uint16_t ui16_g_adc_target_motor_max_current_fw;
extern volatile uint16_t ui16_g_adc_battery_current_filtered;
extern volatile uint16_t ui16_g_adc_motor_current_filtered;
extern volatile uint8_t ui8_g_field_weakening_angle;
extern volatile uint8_t ui8_g_field_weakening_enable;
extern volatile uint8_t ui8_g_field_weakening_enable_state;

/***************************************************************************************/
// Motor interface
Expand Down

0 comments on commit 8f4cf96

Please sign in to comment.