Safety tweaks for double battery

This commit is contained in:
Daniel Öster 2024-07-11 19:09:21 +03:00
parent 8b952b805c
commit 12ec967e5d
7 changed files with 47 additions and 24 deletions

View file

@ -606,7 +606,7 @@ void handle_CAN_contactors() {
if (abs(datalayer.battery.status.voltage_dV - datalayer.battery2.status.voltage_dV) < 30) { // If we are within 3.0V
clear_event(EVENT_VOLTAGE_DIFFERENCE);
if (datalayer.battery2.status.bms_status != FAULT) { // Only proceed if BMS on battery2 is not faulted
if (datalayer.battery.status.bms_status != FAULT) { // Only proceed if we are not in faulted state
datalayer.system.status.battery2_allows_contactor_closing = true;
}
} else { //We are over 3.0V diff

View file

@ -457,7 +457,7 @@ static uint8_t battery2_status_diagnosis_powertrain_maximum_multiplexer = 0;
static uint8_t battery2_status_diagnosis_powertrain_immediate_multiplexer = 0;
static uint8_t battery2_ID2 = 0;
static uint8_t battery2_cellvoltage_mux = 0;
static uint8_t battery2_soh = 0;
static uint8_t battery2_soh = 99;
static uint8_t message_data[50];
static uint8_t next_data = 0;

View file

@ -811,7 +811,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
battery_TEMP = (rx_frame.data.u8[4] >> 1);
if (battery_TEMP != 0) {
battery_StateOfHealth = battery_TEMP; //Collect state of health from battery
battery_StateOfHealth = (uint8_t)battery_TEMP; //Collect state of health from battery
}
break;
case 0x5C0:

View file

@ -7,6 +7,8 @@ static uint8_t discharge_limit_failures = 0;
static bool battery_full_event_fired = false;
static bool battery_empty_event_fired = false;
#define MAX_SOH_DEVIATION_PPTT 2500
void update_machineryprotection() {
// Start checking that the battery is within reason. Incase we see any funny business, raise an event!
@ -67,9 +69,9 @@ void update_machineryprotection() {
// Battery is extremely degraded, not fit for secondlifestorage!
if (datalayer.battery.status.soh_pptt < 2500) {
set_event(EVENT_LOW_SOH, datalayer.battery.status.soh_pptt);
set_event(EVENT_SOH_LOW, datalayer.battery.status.soh_pptt);
} else {
clear_event(EVENT_LOW_SOH);
clear_event(EVENT_SOH_LOW);
}
// Check if SOC% is plausible
@ -129,25 +131,43 @@ void update_machineryprotection() {
// Too many malformed CAN messages recieved!
if (datalayer.battery.status.CAN_error_counter > MAX_CAN_FAILURES) {
set_event(EVENT_CAN_RX_WARNING, 0);
set_event(EVENT_CAN_RX_WARNING, 1);
} else {
clear_event(EVENT_CAN_RX_WARNING);
}
#ifdef DOUBLE_BATTERY
// Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error
#ifdef DOUBLE_BATTERY // Additional Double-Battery safeties are checked here
// Check if the Battery 2 BMS is still sending CAN messages. If we go 60s without messages we raise an error
if (!datalayer.battery2.status.CAN_battery_still_alive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
set_event(EVENT_CAN2_RX_FAILURE, 0);
} else {
datalayer.battery2.status.CAN_battery_still_alive--;
clear_event(EVENT_CAN_RX_FAILURE);
clear_event(EVENT_CAN2_RX_FAILURE);
}
// Too many malformed CAN messages recieved!
if (datalayer.battery2.status.CAN_error_counter > MAX_CAN_FAILURES) {
set_event(EVENT_CAN_RX_WARNING, 0);
set_event(EVENT_CAN_RX_WARNING, 2);
} else {
clear_event(EVENT_CAN_RX_WARNING);
}
#endif
// Check if SOH% between the packs is too large
if((datalayer.battery.status.soh_pptt != 9900) && (datalayer.battery2.status.soh_pptt != 9900)){
// Both values available, check diff
uint16_t soh_diff_pptt;
if(datalayer.battery.status.soh_pptt > datalayer.battery2.status.soh_pptt) {
soh_diff_pptt = datalayer.battery.status.soh_pptt - datalayer.battery2.status.soh_pptt;
} else {
soh_diff_pptt = datalayer.battery2.status.soh_pptt - datalayer.battery.status.soh_pptt;
}
if(soh_diff_pptt > MAX_SOH_DEVIATION_PPTT){
set_event(EVENT_SOH_DIFFERENCE, MAX_SOH_DEVIATION_PPTT);
} else {
clear_event(EVENT_SOH_DIFFERENCE);
}
}
#endif // DOUBLE_BATTERY
}

View file

@ -157,7 +157,8 @@ void init_events(void) {
events.entries[EVENT_BATTERY_UNDERVOLTAGE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_BATTERY_ISOLATION].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_VOLTAGE_DIFFERENCE].level = EVENT_LEVEL_INFO;
events.entries[EVENT_LOW_SOH].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_SOH_DIFFERENCE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_SOH_LOW].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_HVIL_FAILURE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_PRECHARGE_FAILURE].level = EVENT_LEVEL_INFO;
events.entries[EVENT_INTERNAL_OPEN_FAULT].level = EVENT_LEVEL_ERROR;
@ -276,7 +277,9 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Warning: Battery reports isolation error. High voltage might be leaking to ground. Check battery!";
case EVENT_VOLTAGE_DIFFERENCE:
return "Info: Too large voltage diff between the batteries. Second battery cannot join the DC-link";
case EVENT_LOW_SOH:
case EVENT_SOH_DIFFERENCE:
return "Warning: Large deviation in State of health between packs. Inspect battery.";
case EVENT_SOH_LOW:
return "ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle "
"battery.";
case EVENT_HVIL_FAILURE:

View file

@ -6,7 +6,7 @@
// #define INCLUDE_EVENTS_TEST // Enable to run an event test loop, see events_test_on_target.cpp
#define EE_MAGIC_HEADER_VALUE 0x0009 // 0x0000 to 0xFFFF
#define EE_MAGIC_HEADER_VALUE 0x0010 // 0x0000 to 0xFFFF
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
@ -53,7 +53,8 @@
XX(EVENT_BATTERY_REQUESTS_HEAT) \
XX(EVENT_BATTERY_WARMED_UP) \
XX(EVENT_VOLTAGE_DIFFERENCE) \
XX(EVENT_LOW_SOH) \
XX(EVENT_SOH_DIFFERENCE) \
XX(EVENT_SOH_LOW) \
XX(EVENT_HVIL_FAILURE) \
XX(EVENT_PRECHARGE_FAILURE) \
XX(EVENT_INTERNAL_OPEN_FAULT) \

View file

@ -643,7 +643,7 @@ String processor(const String& var) {
#ifdef DOUBLE_BATTERY
content += "<div style='flex: 1; background-color: ";
switch (datalayer.battery2.status.bms_status) {
switch (datalayer.battery.status.bms_status) {
case ACTIVE:
content += "#2D3F2F;";
break;
@ -660,8 +660,7 @@ String processor(const String& var) {
// Display battery statistics within this block
socRealFloat =
static_cast<float>(datalayer.battery2.status.real_soc) / 100.0; // Convert to float and divide by 100
socScaledFloat =
static_cast<float>(datalayer.battery.status.reported_soc) / 100.0; // Convert to float and divide by 100
//socScaledFloat; // Same value used for bat2
sohFloat = static_cast<float>(datalayer.battery2.status.soh_pptt) / 100.0; // Convert to float and divide by 100
voltageFloat =
static_cast<float>(datalayer.battery2.status.voltage_dV) / 10.0; // Convert to float and divide by 10
@ -685,12 +684,12 @@ String processor(const String& var) {
content += "<h4>Cell min: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV</h4>";
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " C</h4>";
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " C</h4>";
if (datalayer.battery2.status.bms_status == ACTIVE) {
content += "<h4>BMS Status: OK </h4>";
} else if (datalayer.battery2.status.bms_status == UPDATING) {
content += "<h4>BMS Status: UPDATING </h4>";
if (datalayer.battery.status.bms_status == ACTIVE) {
content += "<h4>System status: OK </h4>";
} else if (datalayer.battery.status.bms_status == UPDATING) {
content += "<h4>System status: UPDATING </h4>";
} else {
content += "<h4>BMS Status: FAULT </h4>";
content += "<h4>System status: FAULT </h4>";
}
if (datalayer.battery2.status.current_dA == 0) {
content += "<h4>Battery idle</h4>";