Tweak logic for contactor closing

This commit is contained in:
Daniel 2024-04-20 21:45:41 +03:00
parent f83bbc35eb
commit 997866ef8c
5 changed files with 55 additions and 25 deletions

View file

@ -619,9 +619,19 @@ void send_can2() {
#ifdef DOUBLE_BATTERY #ifdef DOUBLE_BATTERY
void handle_CAN_contactors() { void handle_CAN_contactors() {
if (abs(datalayer.battery.status.voltage_dV - datalayer.battery2.status.voltage_dV) < 50) { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) {
return; // Both voltage values need to be available to start check
}
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
datalayer.system.status.battery2_allows_contactor_closing = true; datalayer.system.status.battery2_allows_contactor_closing = true;
} //TODO: Shall we handle opening incase of fault here? }
} else { //We are over 3.0V diff
set_event(EVENT_VOLTAGE_DIFFERENCE,
(uint8_t)(abs(datalayer.battery.status.voltage_dV - datalayer.battery2.status.voltage_dV) / 10));
}
} }
#endif #endif
@ -744,7 +754,29 @@ void update_SOC() {
datalayer.battery.status.reported_soc = calc_soc; datalayer.battery.status.reported_soc = calc_soc;
} else { // No SOC window wanted. Set scaled to same as real. } else { // No SOC window wanted. Set scaled to same as real.
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc; datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
#ifdef DOUBLE_BATTERY
datalayer.battery.status.reported_soc =
(datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
#endif
} }
#ifdef DOUBLE_BATTERY
datalayer.battery.status.reported_soc = (datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
if (datalayer.battery.status.real_soc < 100) { //If this battery is under 1.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
}
if (datalayer.battery2.status.real_soc < 100) { //If this battery is under 1.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
}
if (datalayer.battery.status.real_soc > 9900) { //If this battery is over 99.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
}
if (datalayer.battery2.status.real_soc > 9900) { //If this battery is over 99.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
}
#endif //TODO: Constrain according to the user settings. Help wanted on algoritm to use.
} }
void summarize_battery_values() { void summarize_battery_values() {

View file

@ -16,14 +16,6 @@ static unsigned long previousMillis1000 = 0; // will store last time a 1000m
static unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send static unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send
static unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send static unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send
static uint8_t CANstillAlive = 12; // counter for checking if CAN is still alive static uint8_t CANstillAlive = 12; // counter for checking if CAN is still alive
static unsigned long previousMillis20_2 = 0; // will store last time a 20ms CAN Message was send
static unsigned long previousMillis100_2 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis200_2 = 0; // will store last time a 200ms CAN Message was send
static unsigned long previousMillis500_2 = 0; // will store last time a 500ms CAN Message was send
static unsigned long previousMillis640_2 = 0; // will store last time a 600ms CAN Message was send
static unsigned long previousMillis1000_2 = 0; // will store last time a 1000ms CAN Message was send
static unsigned long previousMillis5000_2 = 0; // will store last time a 5000ms CAN Message was send
static unsigned long previousMillis10000_2 = 0; // will store last time a 10000ms CAN Message was send
static uint8_t CAN2stillAlive = 12; // counter for checking if CAN2 is still alive static uint8_t CAN2stillAlive = 12; // counter for checking if CAN2 is still alive
static uint16_t CANerror = 0; // counter on how many CAN errors encountered static uint16_t CANerror = 0; // counter on how many CAN errors encountered
#define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14 #define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14
@ -533,6 +525,7 @@ void update_values_battery2() { //This function maps all the values fetched via
if (!CAN2stillAlive) { if (!CAN2stillAlive) {
set_event(EVENT_CAN2_RX_FAILURE, 2); set_event(EVENT_CAN2_RX_FAILURE, 2);
datalayer.battery2.status.bms_status = FAULT; //TODO: Refactor handling of event for battery2 datalayer.battery2.status.bms_status = FAULT; //TODO: Refactor handling of event for battery2
datalayer.system.status.battery2_allows_contactor_closing = false;
} else { } else {
CAN2stillAlive--; CAN2stillAlive--;
clear_event(EVENT_CAN2_RX_FAILURE); clear_event(EVENT_CAN2_RX_FAILURE);
@ -788,7 +781,8 @@ void receive_can_battery2(CAN_frame_t rx_frame) {
CAN2stillAlive = 12; //This message is only sent if 30C (Wakeup pin on battery) is energized with 12V CAN2stillAlive = 12; //This message is only sent if 30C (Wakeup pin on battery) is energized with 12V
battery2_current = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) - 8192; //deciAmps (-819.2 to 819.0A) battery2_current = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) - 8192; //deciAmps (-819.2 to 819.0A)
battery2_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V battery2_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V
datalayer.battery2.status.voltage_dV = battery2_volts; // Update the datalayer as soon as possible with this info datalayer.battery2.status.voltage_dV =
battery2_volts; // Update the datalayer as soon as possible with this info, needed for contactor control
battery2_HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8 | rx_frame.data.u8[4]); battery2_HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8 | rx_frame.data.u8[4]);
battery2_request_open_contactors = (rx_frame.data.u8[5] & 0xC0) >> 6; battery2_request_open_contactors = (rx_frame.data.u8[5] & 0xC0) >> 6;
battery2_request_open_contactors_instantly = (rx_frame.data.u8[6] & 0x03); battery2_request_open_contactors_instantly = (rx_frame.data.u8[6] & 0x03);

View file

@ -143,6 +143,7 @@ void init_events(void) {
events.entries[EVENT_BATTERY_CHG_STOP_REQ].level = EVENT_LEVEL_ERROR; events.entries[EVENT_BATTERY_CHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_BATTERY_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR; events.entries[EVENT_BATTERY_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_BATTERY_CHG_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR; events.entries[EVENT_BATTERY_CHG_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_VOLTAGE_DIFFERENCE].level = EVENT_LEVEL_INFO;
events.entries[EVENT_LOW_SOH].level = EVENT_LEVEL_ERROR; events.entries[EVENT_LOW_SOH].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_HVIL_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_HVIL_FAILURE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_INTERNAL_OPEN_FAULT].level = EVENT_LEVEL_ERROR; events.entries[EVENT_INTERNAL_OPEN_FAULT].level = EVENT_LEVEL_ERROR;
@ -227,6 +228,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Info: COLD BATTERY! Battery requesting heating pads to activate!"; return "Info: COLD BATTERY! Battery requesting heating pads to activate!";
case EVENT_BATTERY_WARMED_UP: case EVENT_BATTERY_WARMED_UP:
return "Info: Battery requesting heating pads to stop. The battery is now warm enough."; return "Info: Battery requesting heating pads to stop. The battery is now warm enough.";
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_LOW_SOH:
return "ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle " return "ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle "
"battery."; "battery.";

View file

@ -45,6 +45,7 @@
XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \
XX(EVENT_BATTERY_REQUESTS_HEAT) \ XX(EVENT_BATTERY_REQUESTS_HEAT) \
XX(EVENT_BATTERY_WARMED_UP) \ XX(EVENT_BATTERY_WARMED_UP) \
XX(EVENT_VOLTAGE_DIFFERENCE) \
XX(EVENT_LOW_SOH) \ XX(EVENT_LOW_SOH) \
XX(EVENT_HVIL_FAILURE) \ XX(EVENT_HVIL_FAILURE) \
XX(EVENT_INTERNAL_OPEN_FAULT) \ XX(EVENT_INTERNAL_OPEN_FAULT) \

View file

@ -599,7 +599,7 @@ String processor(const String& var) {
socRealFloat = socRealFloat =
static_cast<float>(datalayer.battery2.status.real_soc) / 100.0; // Convert to float and divide by 100 static_cast<float>(datalayer.battery2.status.real_soc) / 100.0; // Convert to float and divide by 100
socScaledFloat = socScaledFloat =
static_cast<float>(datalayer.battery2.status.reported_soc) / 100.0; // Convert to float and divide by 100 static_cast<float>(datalayer.battery.status.reported_soc) / 100.0; // Convert to float and divide by 100
sohFloat = static_cast<float>(datalayer.battery2.status.soh_pptt) / 100.0; // Convert to float and divide by 100 sohFloat = static_cast<float>(datalayer.battery2.status.soh_pptt) / 100.0; // Convert to float and divide by 100
voltageFloat = voltageFloat =
static_cast<float>(datalayer.battery2.status.voltage_dV) / 10.0; // Convert to float and divide by 10 static_cast<float>(datalayer.battery2.status.voltage_dV) / 10.0; // Convert to float and divide by 10