Skip to content

Commit

Permalink
Issue #116
Browse files Browse the repository at this point in the history
* Improve battery percentage calculation to work better for batteries of different voltages.
* Fix LVC limiting to work better for batteries of different voltages.
* Make battery soc value available earlier to display at boot.
  • Loading branch information
danielnilsson9 committed Apr 27, 2023
1 parent 5485de7 commit ae2eb2e
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 45 deletions.
44 changes: 24 additions & 20 deletions src/firmware/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ typedef struct
static uint8_t assist_level;
static uint8_t operation_mode;
static uint16_t global_max_speed_rpm;
static uint16_t lvc_ramp_down_offset_volt_x10;

static uint16_t lvc_voltage_x100;
static uint16_t lvc_ramp_down_start_voltage_x100;

static assist_level_data_t assist_level_data;
static uint16_t speed_limit_ramp_interval_rpm_x10;
Expand Down Expand Up @@ -90,11 +92,16 @@ void app_init()
motor_disable();
lights_disable();

lvc_voltage_x100 = g_config.low_cut_off_v * 100u;

uint16_t voltage_range_x100 =
EXPAND_U16(g_config.max_battery_x100v_u16h, g_config.max_battery_x100v_u16l) - lvc_voltage_x100;
lvc_ramp_down_start_voltage_x100 = (uint16_t)(lvc_voltage_x100 +
((voltage_range_x100 * LVC_RAMP_DOWN_OFFSET_PERCENT) / 100));

global_max_speed_rpm = 0;
lvc_ramp_down_offset_volt_x10 = (uint16_t)((g_config.low_cut_off_v * 10 * LVC_RAMP_DOWN_OFFSET_PERCENT) / 100);
temperature_contr_c = 0;
temperature_motor_c = 0;

ramp_up_target_current = 0;
last_ramp_up_increment_ms = 0;
ramp_up_current_interval_ms = (g_config.max_current_amps * 10u) / g_config.current_ramp_amps_s;
Expand Down Expand Up @@ -674,45 +681,42 @@ void apply_low_voltage_limit(uint8_t* target_current)
if (system_ms() > next_voltage_reading_ms)
{
next_voltage_reading_ms = system_ms() + 125;
int32_t voltage_x100 = motor_get_battery_voltage_x10() * 10ul;
int32_t voltage_reading_x100 = motor_get_battery_voltage_x10() * 10ul;

if (voltage_x100 < flt_min_bat_volt_x100)
if (voltage_reading_x100 < flt_min_bat_volt_x100)
{
flt_min_bat_volt_x100 = EXPONENTIAL_FILTER(flt_min_bat_volt_x100, voltage_x100, 8);
flt_min_bat_volt_x100 = EXPONENTIAL_FILTER(flt_min_bat_volt_x100, voltage_reading_x100, 8);
}

if (eventlog_is_enabled() && system_ms() > next_log_volt_ms)
{
next_log_volt_ms = system_ms() + 10000;
eventlog_write_data(EVT_DATA_VOLTAGE, (uint16_t)voltage_x100);
eventlog_write_data(EVT_DATA_VOLTAGE, (uint16_t)voltage_reading_x100);
}
}

uint16_t voltage_x10 = flt_min_bat_volt_x100 / 10;
uint16_t start_limit_v_x10 = motor_get_battery_lvc_x10() + lvc_ramp_down_offset_volt_x10;
uint16_t voltage_x100 = flt_min_bat_volt_x100;

if (voltage_x10 <= start_limit_v_x10)
if (voltage_x100 <= lvc_ramp_down_start_voltage_x100)
{
uint16_t lvc_x10 = motor_get_battery_lvc_x10();

if (!lvc_limiting)
{
eventlog_write_data(EVT_DATA_LVC_LIMITING, voltage_x10);
eventlog_write_data(EVT_DATA_LVC_LIMITING, voltage_x100);
lvc_limiting = true;
}

if (voltage_x10 < lvc_x10)
if (voltage_x100 < lvc_voltage_x100)
{
voltage_x10 = lvc_x10;
voltage_x100 = lvc_voltage_x100;
}

// ramp down power until 20% when approaching lvc
uint8_t tmp = (uint8_t)MAP32(
voltage_x10, // value
lvc_x10, // in_min
start_limit_v_x10, // in_max
LVC_LOW_CURRENT_PERCENT, // out_min
100 // out_max
voltage_x100, // value
lvc_voltage_x100, // in_min
lvc_ramp_down_start_voltage_x100, // in_max
LVC_LOW_CURRENT_PERCENT, // out_min
100 // out_max
);

if (*target_current > tmp)
Expand Down
77 changes: 58 additions & 19 deletions src/firmware/battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,25 @@ static int16_t battery_full_x100v;

static uint8_t battery_percent;
static uint32_t motor_disabled_at_ms;
static bool first_reading_done;

#define BATTERY_NO_LOAD_DELAY_MS 2000

#define BATTERY_FULL_OFFSET_PERCENT 8
#define BATTERY_EMPTY_OFFSET_PERCENT 8

//
// No attempt is made to have accurate battery state of charge display.
//
// This is only a voltage based approch using configred max and min battery voltages.
// The end values are padded (BATTERY_EMPTY_OFFSET_PERCENT, BATTERY_FULL_OFFSET_PERCENT).
//
// Battery voltage is measured when no motor power has been applied for at least 2 seconds
// (to mitigate measuring voltage sag but is still problematic in cold weather).
//
// Battery SOC percentage is calculated from measured voltage using linear interpolation.
//


static uint8_t compute_battery_percent()
{
Expand All @@ -32,35 +48,58 @@ static uint8_t compute_battery_percent()

void battery_init()
{
battery_percent = 0;
// default to 70% until first reading is available
battery_percent = 70;
motor_disabled_at_ms = 0;
first_reading_done = false;

uint16_t battery_min_voltage_x100v = g_config.low_cut_off_v * 100u;
uint16_t battery_max_voltage_x100v =
EXPAND_U16(g_config.max_battery_x100v_u16h, g_config.max_battery_x100v_u16l);

// Consider battery full if above 98% of configured max voltage
battery_full_x100v = (98l * EXPAND_U16(g_config.max_battery_x100v_u16h, g_config.max_battery_x100v_u16l)) / 100;
uint16_t battery_range_x100v = battery_max_voltage_x100v - battery_min_voltage_x100v;

// Consider battery empty at 5% above configured low voltage cutoff
battery_empty_x100v = 105l * g_config.low_cut_off_v;
// Consider battery full if above 95% (100 - BATTERY_FULL_OFFSET_PERCENT)

This comment has been minimized.

Copy link
@EigenMania

EigenMania Apr 27, 2023

Contributor

92%

// of configured voltage range
battery_full_x100v = battery_max_voltage_x100v -
((BATTERY_FULL_OFFSET_PERCENT * battery_range_x100v) / 100);

// Consider battery empty if below 8% (BATTERY_EMPTY_OFFSET_PERCENT)
// of configured voltage range
battery_empty_x100v = battery_min_voltage_x100v +
((BATTERY_EMPTY_OFFSET_PERCENT * battery_range_x100v) / 100);
}

void battery_process()
{
uint8_t target_current = motor_get_target_current();

if (motor_disabled_at_ms == 0 && target_current == 0)
if (!first_reading_done)
{
motor_disabled_at_ms = system_ms();
if (motor_get_battery_voltage_x10() > 0)
{
battery_percent = compute_battery_percent();
first_reading_done = true;
}
}
else if (target_current > 0)
else
{
motor_disabled_at_ms = 0;
}

if (target_current == 0 && (system_ms() - motor_disabled_at_ms) > BATTERY_NO_LOAD_DELAY_MS)
{
// Compute battery percent using linear interpolation between lvc
// and configured max voltage while under no load.

battery_percent = compute_battery_percent();
uint8_t target_current = motor_get_target_current();

if (motor_disabled_at_ms == 0 && target_current == 0)
{
motor_disabled_at_ms = system_ms();
}
else if (target_current > 0)
{
motor_disabled_at_ms = 0;
}

if (target_current == 0 && (system_ms() - motor_disabled_at_ms) > BATTERY_NO_LOAD_DELAY_MS)
{
// Compute battery percent using linear interpolation between lvc
// and configured max voltage while under no load.

battery_percent = compute_battery_percent();
}
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/firmware/fwconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@
#endif


// Current ramp down starts at LVC + (LVC * LVC_RAMP_DOWN_OFFSET_PERCENT / 100)
// Current ramp down starts at LVC + (VOLTAGE_RANGE * LVC_RAMP_DOWN_OFFSET_PERCENT / 100)
// Example:
// LVC is 42V
// 42 * 0.06 = 2.5V
// Ramp down starts at 42V + 2.5V
#define LVC_RAMP_DOWN_OFFSET_PERCENT 6
// LVC is 42V, max voltage at 58.8
// Range = 58.8 - 42 = 16.8
// Ramp down starts at 42V + Range * 0.09 = 43.5
#define LVC_RAMP_DOWN_OFFSET_PERCENT 9

// Maximum allowed motor current in percent of maximum configured current (A)
// to still apply when LVC has been reached.
Expand Down
2 changes: 1 addition & 1 deletion src/tool/Model/EventLogEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public string Parse()
case EVT_DATA_LVC_LIMITING:
if (_data.Value != 0)
{
return $"Low voltage limiting activated, voltage={(_data / 10.0):0.0}";
return $"Low voltage limiting activated, voltage={(_data / 100f):0.0}";
}
else
{
Expand Down

0 comments on commit ae2eb2e

Please sign in to comment.