Add safety file, move out safety checks

This commit is contained in:
Daniel 2024-05-13 19:45:56 +03:00
parent 8777a99f7a
commit f6f12652d6
31 changed files with 139 additions and 272 deletions

View file

@ -226,6 +226,7 @@ void core_loop(void* task_time_us) {
if (millis() - previousMillisUpdateVal >= intervalUpdateValues) // Every 5s normally if (millis() - previousMillisUpdateVal >= intervalUpdateValues) // Every 5s normally
{ {
previousMillisUpdateVal = millis(); previousMillisUpdateVal = millis();
update_machineryprotection();
update_SOC(); // Check if real or calculated SOC% value should be sent update_SOC(); // Check if real or calculated SOC% value should be sent
update_values(); // Update values heading towards inverter. Prepare for sending on CAN, or write directly to Modbus. update_values(); // Update values heading towards inverter. Prepare for sending on CAN, or write directly to Modbus.
if (DUMMY_EVENT_ENABLED) { if (DUMMY_EVENT_ENABLED) {
@ -459,36 +460,6 @@ void init_battery() {
// Functions // Functions
#ifdef DEBUG_CANFD_DATA #ifdef DEBUG_CANFD_DATA
void print_canfd_frame(CANFDMessage rx_frame) { void print_canfd_frame(CANFDMessage rx_frame) {
// Frame ID-s that battery transmits. For debugging and development.
// switch (frame.id)
// {
// case 0x7EC:
// case 0x360:
// case 0x3BA:
// case 0x325:
// case 0x330:
// case 0x215:
// case 0x235:
// case 0x2FA:
// case 0x21A:
// case 0x275:
// case 0x150:
// case 0x1F5:
// case 0x335:
// case 0x25A:
// case 0x365:
// case 0x055:
// case 0x245:
// case 0x3F5:
// // case 0x:
// // case 0x:
// // case 0x:
// // Dont print known frames
// return;
// default:
// break;
// }
int i = 0; int i = 0;
Serial.print(rx_frame.id, HEX); Serial.print(rx_frame.id, HEX);
Serial.print(" "); Serial.print(" ");
@ -499,7 +470,6 @@ void print_canfd_frame(CANFDMessage rx_frame) {
} }
Serial.println(" "); Serial.println(" ");
} }
#endif #endif
void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming
CANFDMessage frame; CANFDMessage frame;

View file

@ -15,8 +15,6 @@ static unsigned long previousMillis640 = 0; // will store last time a 600ms C
static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was send static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was send
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 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
enum BatterySize { BATTERY_60AH, BATTERY_94AH, BATTERY_120AH }; enum BatterySize { BATTERY_60AH, BATTERY_94AH, BATTERY_120AH };
@ -357,7 +355,6 @@ static uint16_t battery_soc = 0;
static uint16_t battery_soc_hvmax = 0; static uint16_t battery_soc_hvmax = 0;
static uint16_t battery_soc_hvmin = 0; static uint16_t battery_soc_hvmin = 0;
static uint16_t battery_capacity_cah = 0; static uint16_t battery_capacity_cah = 0;
static uint16_t battery_cell_deviation_mV = 0;
static int16_t battery_temperature_HV = 0; static int16_t battery_temperature_HV = 0;
static int16_t battery_temperature_heat_exchanger = 0; static int16_t battery_temperature_heat_exchanger = 0;
static int16_t battery_temperature_max = 0; static int16_t battery_temperature_max = 0;
@ -454,27 +451,10 @@ void update_values_battery() { //This function maps all the values fetched via
if (datalayer.battery.status.cell_voltages_mV[0] > 0 && datalayer.battery.status.cell_voltages_mV[2] > 0) { if (datalayer.battery.status.cell_voltages_mV[0] > 0 && datalayer.battery.status.cell_voltages_mV[2] > 0) {
datalayer.battery.status.cell_min_voltage_mV = datalayer.battery.status.cell_voltages_mV[0]; datalayer.battery.status.cell_min_voltage_mV = datalayer.battery.status.cell_voltages_mV[0];
datalayer.battery.status.cell_max_voltage_mV = datalayer.battery.status.cell_voltages_mV[2]; datalayer.battery.status.cell_max_voltage_mV = datalayer.battery.status.cell_voltages_mV[2];
battery_cell_deviation_mV =
(datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
} else {
battery_cell_deviation_mV = 0;
} }
if (battery_info_available) { if (battery_info_available) {
// Start checking safeties. First up, cellvoltages! // Start checking safeties. First up, cellvoltages!
if (battery_cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
uint8_t report_value = 0;
if (battery_cell_deviation_mV <= 20 * 254) {
report_value = battery_cell_deviation_mV / 20;
} else {
report_value = 255;
}
set_event(EVENT_CELL_DEVIATION_HIGH, report_value);
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
if (detectedBattery == BATTERY_60AH) { if (detectedBattery == BATTERY_60AH) {
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
@ -505,18 +485,6 @@ void update_values_battery() { //This function maps all the values fetched via
} }
} }
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
// Check if we have encountered any malformed CAN messages
if (CANerror > MAX_CAN_FAILURES) {
set_event(EVENT_CAN_RX_WARNING, 0);
}
// Perform other safety checks // Perform other safety checks
if (battery_status_error_locking == 2) { // HVIL seated? if (battery_status_error_locking == 2) { // HVIL seated?
set_event(EVENT_HVIL_FAILURE, 0); set_event(EVENT_HVIL_FAILURE, 0);
@ -559,7 +527,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2 case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2
battery_awake = true; battery_awake = true;
CANstillAlive = 12; //This message is only sent if 30C (Wakeup pin on battery) is energized with 12V datalayer.battery.status.CAN_battery_still_alive =
12; //This message is only sent if 30C (Wakeup pin on battery) is energized with 12V
battery_current = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) - 8192; //deciAmps (-819.2 to 819.0A) battery_current = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) - 8192; //deciAmps (-819.2 to 819.0A)
battery_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V battery_volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V
battery_HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8 | rx_frame.data.u8[4]); battery_HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 8 | rx_frame.data.u8[4]);
@ -596,7 +565,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
battery_awake = true; battery_awake = true;
if (calculateCRC(rx_frame, rx_frame.FIR.B.DLC, 0x15) != rx_frame.data.u8[0]) { if (calculateCRC(rx_frame, rx_frame.FIR.B.DLC, 0x15) != rx_frame.data.u8[0]) {
//If calculated CRC does not match transmitted CRC, increase CANerror counter //If calculated CRC does not match transmitted CRC, increase CANerror counter
CANerror++; datalayer.battery.status.CAN_error_counter++;
break; break;
} }
battery_status_diagnostics_HV = (rx_frame.data.u8[2] & 0x0F); battery_status_diagnostics_HV = (rx_frame.data.u8[2] & 0x0F);

View file

@ -8,7 +8,6 @@
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
CAN_frame_t CHADEMO_108 = {.FIR = {.B = CAN_frame_t CHADEMO_108 = {.FIR = {.B =
{ {
@ -105,14 +104,6 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>( datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); (static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
/* Check if the Vehicle is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.print("SOC 0x100: "); Serial.print("SOC 0x100: ");
Serial.println(ConstantOfChargingRateIndication); Serial.println(ConstantOfChargingRateIndication);
@ -120,7 +111,8 @@ void update_values_battery() { //This function maps all the values fetched via
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive == 12; //We are getting CAN messages from the vehicle, inform the watchdog datalayer.battery.status.CAN_battery_still_alive ==
12; //We are getting CAN messages from the vehicle, inform the watchdog
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x100: case 0x100:

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION 9999
void setup_battery(void); void setup_battery(void);

View file

@ -10,7 +10,6 @@
//Figure out if CAN messages need to be sent to keep the system happy? //Figure out if CAN messages need to be sent to keep the system happy?
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
static uint8_t BMU_Detected = 0; static uint8_t BMU_Detected = 0;
static uint8_t CMU_Detected = 0; static uint8_t CMU_Detected = 0;
@ -108,14 +107,6 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.temperature_min_dC = (int16_t)(max_temp_cel * 10); datalayer.battery.status.temperature_min_dC = (int16_t)(max_temp_cel * 10);
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (!BMU_Detected) { if (!BMU_Detected) {
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.println("BMU not detected, check wiring!"); Serial.println("BMU not detected, check wiring!");
@ -144,7 +135,7 @@ void update_values_battery() { //This function maps all the values fetched via
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive = datalayer.battery.status.CAN_battery_still_alive =
12; //TODO: move this inside a known message ID to prevent CAN inverter from keeping battery alive detection going 12; //TODO: move this inside a known message ID to prevent CAN inverter from keeping battery alive detection going
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x374: //BMU message, 10ms - SOC case 0x374: //BMU message, 10ms - SOC

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 500
void setup_battery(void); void setup_battery(void);

View file

@ -9,11 +9,9 @@
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis500ms = 0; // will store last time a 500ms CAN Message was send static unsigned long previousMillis500ms = 0; // will store last time a 500ms CAN Message was send
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value #define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value #define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value
#define MAX_CELL_DEVIATION 150 //LED turns yellow on the board if mv delta exceeds this value
static uint16_t inverterVoltageFrameHigh = 0; static uint16_t inverterVoltageFrameHigh = 0;
static uint16_t inverterVoltage = 0; static uint16_t inverterVoltage = 0;
@ -23,7 +21,6 @@ static uint16_t SOC_Display = 0;
static uint16_t batterySOH = 1000; static uint16_t batterySOH = 1000;
static uint16_t CellVoltMax_mV = 3700; static uint16_t CellVoltMax_mV = 3700;
static uint16_t CellVoltMin_mV = 3700; static uint16_t CellVoltMin_mV = 3700;
static uint16_t cell_deviation_mV = 0;
static uint16_t batteryVoltage = 0; static uint16_t batteryVoltage = 0;
static int16_t leadAcidBatteryVoltage = 120; static int16_t leadAcidBatteryVoltage = 120;
static int16_t batteryAmps = 0; static int16_t batteryAmps = 0;
@ -97,10 +94,10 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV; datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) { if (!datalayer.battery.status.CAN_battery_still_alive) {
set_event(EVENT_CANFD_RX_FAILURE, 0); set_event(EVENT_CANFD_RX_FAILURE, 0);
} else { } else {
CANstillAlive--; datalayer.battery.status.CAN_battery_still_alive--;
clear_event(EVENT_CANFD_RX_FAILURE); clear_event(EVENT_CANFD_RX_FAILURE);
} }
@ -113,19 +110,12 @@ void update_values_battery() { //This function maps all the values fetched via
} }
// Check if cell voltages are within allowed range // Check if cell voltages are within allowed range
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) { if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, 0); set_event(EVENT_CELL_OVER_VOLTAGE, 0);
} }
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) { if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
set_event(EVENT_CELL_UNDER_VOLTAGE, 0); set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
} }
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
if (datalayer.battery.status.bms_status == if (datalayer.battery.status.bms_status ==
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
@ -208,7 +198,7 @@ void send_canfd_frame(CANFDMessage frame) {
} }
void receive_canfd_battery(CANFDMessage frame) { void receive_canfd_battery(CANFDMessage frame) {
CANstillAlive = 12; datalayer.battery.status.CAN_battery_still_alive = 12;
switch (frame.id) { switch (frame.id) {
case 0x7EC: case 0x7EC:
// print_canfd_frame(frame); // print_canfd_frame(frame);

View file

@ -8,7 +8,7 @@
extern ACAN2517FD canfd; extern ACAN2517FD canfd;
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 150
#define MAXCHARGEPOWERALLOWED 10000 #define MAXCHARGEPOWERALLOWED 10000
#define MAXDISCHARGEPOWERALLOWED 10000 #define MAXDISCHARGEPOWERALLOWED 10000

View file

@ -9,11 +9,9 @@
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send static unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value #define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value #define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value
#define MAX_CELL_DEVIATION 150 //LED turns yellow on the board if mv delta exceeds this value
static uint16_t soc_calculated = 0; static uint16_t soc_calculated = 0;
static uint16_t SOC_BMS = 0; static uint16_t SOC_BMS = 0;
@ -21,7 +19,6 @@ static uint16_t SOC_Display = 0;
static uint16_t batterySOH = 1000; static uint16_t batterySOH = 1000;
static uint16_t CellVoltMax_mV = 3700; static uint16_t CellVoltMax_mV = 3700;
static uint16_t CellVoltMin_mV = 3700; static uint16_t CellVoltMin_mV = 3700;
static uint16_t cell_deviation_mV = 0;
static uint16_t allowedDischargePower = 0; static uint16_t allowedDischargePower = 0;
static uint16_t allowedChargePower = 0; static uint16_t allowedChargePower = 0;
static uint16_t batteryVoltage = 0; static uint16_t batteryVoltage = 0;
@ -182,14 +179,6 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV; datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (waterleakageSensor == 0) { if (waterleakageSensor == 0) {
set_event(EVENT_WATER_INGRESS, 0); set_event(EVENT_WATER_INGRESS, 0);
} }
@ -216,19 +205,12 @@ void update_values_battery() { //This function maps all the values fetched via
} }
// Check if cell voltages are within allowed range // Check if cell voltages are within allowed range
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) { if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, 0); set_event(EVENT_CELL_OVER_VOLTAGE, 0);
} }
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) { if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
set_event(EVENT_CELL_UNDER_VOLTAGE, 0); set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
} }
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
if (datalayer.battery.status.bms_status == if (datalayer.battery.status.bms_status ==
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
@ -305,7 +287,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
break; break;
case 0x542: //BMS SOC case 0x542: //BMS SOC
startedUp = true; startedUp = true;
CANstillAlive = 12; //We use this message to verify that BMS is still alive datalayer.battery.status.CAN_battery_still_alive = 12; //We use this message to verify that BMS is still alive
SOC_Display = rx_frame.data.u8[0] * 5; //100% = 200 ( 200 * 5 = 1000 ) SOC_Display = rx_frame.data.u8[0] * 5; //100% = 200 ( 200 * 5 = 1000 )
break; break;
case 0x594: case 0x594:

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 150
void setup_battery(void); void setup_battery(void);

View file

@ -13,8 +13,6 @@
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send static unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send
static uint16_t CANerror = 0; //counter on how many CAN errors encountered
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
static uint8_t mprun10r = 0; //counter 0-20 for 0x1F2 message static uint8_t mprun10r = 0; //counter 0-20 for 0x1F2 message
static uint8_t mprun10 = 0; //counter 0-3 static uint8_t mprun10 = 0; //counter 0-3
static uint8_t mprun100 = 0; //counter 0-3 static uint8_t mprun100 = 0; //counter 0-3
@ -91,7 +89,6 @@ static uint8_t crctable[256] = {
static uint8_t LEAF_Battery_Type = ZE0_BATTERY; static uint8_t LEAF_Battery_Type = ZE0_BATTERY;
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value #define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value #define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value
#define MAX_CELL_DEVIATION 500 //LED turns yellow on the board if mv delta exceeds this value
#define WH_PER_GID 77 //One GID is this amount of Watt hours #define WH_PER_GID 77 //One GID is this amount of Watt hours
static uint16_t LB_Discharge_Power_Limit = 0; //Limit in kW static uint16_t LB_Discharge_Power_Limit = 0; //Limit in kW
static uint16_t LB_Charge_Power_Limit = 0; //Limit in kW static uint16_t LB_Charge_Power_Limit = 0; //Limit in kW
@ -137,7 +134,6 @@ static uint8_t hold_off_with_polling_10seconds = 10;
static uint16_t cell_voltages[97]; //array with all the cellvoltages static uint16_t cell_voltages[97]; //array with all the cellvoltages
static uint8_t cellcounter = 0; static uint8_t cellcounter = 0;
static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV
static uint16_t cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
static uint16_t HX = 0; //Internal resistance static uint16_t HX = 0; //Internal resistance
static uint16_t insulation = 0; //Insulation resistance static uint16_t insulation = 0; //Insulation resistance
static uint16_t temp_raw_1 = 0; static uint16_t temp_raw_1 = 0;
@ -308,14 +304,6 @@ void update_values_battery() { /* This function maps all the values fetched via
clear_event(EVENT_BATTERY_CHG_DISCHG_STOP_REQ); clear_event(EVENT_BATTERY_CHG_DISCHG_STOP_REQ);
} }
if (LB_StateOfHealth < 25) { //Battery is extremely degraded, not fit for secondlifestorage. Zero it all out.
if (LB_StateOfHealth != 0) { //Extra check to see that we actually have a SOH Value available
set_event(EVENT_LOW_SOH, LB_StateOfHealth);
} else {
clear_event(EVENT_LOW_SOH);
}
}
#ifdef INTERLOCK_REQUIRED #ifdef INTERLOCK_REQUIRED
if (!LB_Interlock) { if (!LB_Interlock) {
set_event(EVENT_HVIL_FAILURE, 0); set_event(EVENT_HVIL_FAILURE, 0);
@ -324,19 +312,6 @@ void update_values_battery() { /* This function maps all the values fetched via
} }
#endif #endif
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (CANerror >
MAX_CAN_FAILURES) //Also check if we have recieved too many malformed CAN messages. If so, signal via LED
{
set_event(EVENT_CAN_RX_WARNING, 0);
}
if (LB_HeatExist) { if (LB_HeatExist) {
if (LB_Heating_Stop) { if (LB_Heating_Stop) {
set_event(EVENT_BATTERY_WARMED_UP, 0); set_event(EVENT_BATTERY_WARMED_UP, 0);
@ -361,7 +336,6 @@ void update_values_battery() { /* This function maps all the values fetched via
print_with_units(", Has heater: ", LB_HeatExist, " "); print_with_units(", Has heater: ", LB_HeatExist, " ");
print_with_units(", Max cell voltage: ", min_max_voltage[1], "mV "); print_with_units(", Max cell voltage: ", min_max_voltage[1], "mV ");
print_with_units(", Min cell voltage: ", min_max_voltage[0], "mV "); print_with_units(", Min cell voltage: ", min_max_voltage[0], "mV ");
print_with_units(", Cell deviation: ", cell_deviation_mV, "mV ");
#endif #endif
} }
@ -369,7 +343,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x1DB: case 0x1DB:
if (is_message_corrupt(rx_frame)) { if (is_message_corrupt(rx_frame)) {
CANerror++; datalayer.battery.status.CAN_error_counter++;
break; //Message content malformed, abort reading data from it break; //Message content malformed, abort reading data from it
} }
LB_Current2 = (rx_frame.data.u8[0] << 3) | (rx_frame.data.u8[1] & 0xe0) >> 5; LB_Current2 = (rx_frame.data.u8[0] << 3) | (rx_frame.data.u8[1] & 0xe0) >> 5;
@ -394,7 +368,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
break; break;
case 0x1DC: case 0x1DC:
if (is_message_corrupt(rx_frame)) { if (is_message_corrupt(rx_frame)) {
CANerror++; datalayer.battery.status.CAN_error_counter++;
break; //Message content malformed, abort reading data from it break; //Message content malformed, abort reading data from it
} }
LB_Discharge_Power_Limit = ((rx_frame.data.u8[0] << 2 | rx_frame.data.u8[1] >> 6) / 4.0); LB_Discharge_Power_Limit = ((rx_frame.data.u8[0] << 2 | rx_frame.data.u8[1] >> 6) / 4.0);
@ -403,7 +377,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
break; break;
case 0x55B: case 0x55B:
if (is_message_corrupt(rx_frame)) { if (is_message_corrupt(rx_frame)) {
CANerror++; datalayer.battery.status.CAN_error_counter++;
break; //Message content malformed, abort reading data from it break; //Message content malformed, abort reading data from it
} }
LB_TEMP = (rx_frame.data.u8[0] << 2 | rx_frame.data.u8[1] >> 6); LB_TEMP = (rx_frame.data.u8[0] << 2 | rx_frame.data.u8[1] >> 6);
@ -413,7 +387,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
LB_Capacity_Empty = (bool)((rx_frame.data.u8[6] & 0x80) >> 7); LB_Capacity_Empty = (bool)((rx_frame.data.u8[6] & 0x80) >> 7);
break; break;
case 0x5BC: case 0x5BC:
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
LB_MAX = ((rx_frame.data.u8[5] & 0x10) >> 4); LB_MAX = ((rx_frame.data.u8[5] & 0x10) >> 4);
if (LB_MAX) { if (LB_MAX) {
@ -521,15 +496,9 @@ void receive_can_battery(CAN_frame_t rx_frame) {
min_max_voltage[1] = cell_voltages[cellcounter]; min_max_voltage[1] = cell_voltages[cellcounter];
} }
cell_deviation_mV = (min_max_voltage[1] - min_max_voltage[0]);
datalayer.battery.status.cell_max_voltage_mV = min_max_voltage[1]; datalayer.battery.status.cell_max_voltage_mV = min_max_voltage[1];
datalayer.battery.status.cell_min_voltage_mV = min_max_voltage[0]; datalayer.battery.status.cell_min_voltage_mV = min_max_voltage[0];
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
}
if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) { if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, 0); set_event(EVENT_CELL_OVER_VOLTAGE, 0);
} }

View file

@ -6,6 +6,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 500
uint16_t Temp_fromRAW_to_F(uint16_t temperature); uint16_t Temp_fromRAW_to_F(uint16_t temperature);
bool is_message_corrupt(CAN_frame_t rx_frame); bool is_message_corrupt(CAN_frame_t rx_frame);

View file

@ -15,7 +15,6 @@
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
//Actual content messages //Actual content messages
CAN_frame_t PYLON_3010 = {.FIR = {.B = CAN_frame_t PYLON_3010 = {.FIR = {.B =
@ -96,18 +95,10 @@ void update_values_battery() {
datalayer.battery.info.max_design_voltage_dV = charge_cutoff_voltage; datalayer.battery.info.max_design_voltage_dV = charge_cutoff_voltage;
datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage; datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage;
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive = 12; datalayer.battery.status.CAN_battery_still_alive = 12;
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x7310: case 0x7310:
case 0x7311: case 0x7311:

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION 9999
void setup_battery(void); void setup_battery(void);

View file

@ -34,9 +34,7 @@ static uint16_t LB_Charge_Power_Limit = 0;
static uint16_t LB_kWh_Remaining = 0; static uint16_t LB_kWh_Remaining = 0;
static uint16_t LB_Cell_Max_Voltage = 3700; static uint16_t LB_Cell_Max_Voltage = 3700;
static uint16_t LB_Cell_Min_Voltage = 3700; static uint16_t LB_Cell_Min_Voltage = 3700;
static uint16_t cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
static uint16_t LB_MaxChargeAllowed_W = 0; static uint16_t LB_MaxChargeAllowed_W = 0;
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
static uint8_t LB_Discharge_Power_Limit_Byte1 = 0; static uint8_t LB_Discharge_Power_Limit_Byte1 = 0;
static uint8_t GVI_Pollcounter = 0; static uint8_t GVI_Pollcounter = 0;
static uint8_t LB_EOCR = 0; static uint8_t LB_EOCR = 0;
@ -130,27 +128,12 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage; datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage;
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) { if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, (LB_Cell_Max_Voltage / 20)); set_event(EVENT_CELL_OVER_VOLTAGE, (LB_Cell_Max_Voltage / 20));
} }
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) { if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
set_event(EVENT_CELL_UNDER_VOLTAGE, (LB_Cell_Min_Voltage / 20)); set_event(EVENT_CELL_UNDER_VOLTAGE, (LB_Cell_Min_Voltage / 20));
} }
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20));
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.println("Values going to inverter:"); Serial.println("Values going to inverter:");
@ -190,13 +173,15 @@ void receive_can_battery(CAN_frame_t rx_frame) {
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x155: //BMS1 case 0x155: //BMS1
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
LB_MaxChargeAllowed_W = (rx_frame.data.u8[0] * 300); LB_MaxChargeAllowed_W = (rx_frame.data.u8[0] * 300);
LB_Current = word((rx_frame.data.u8[1] & 0xF), rx_frame.data.u8[2]) * 0.25 - 500; //OK! LB_Current = word((rx_frame.data.u8[1] & 0xF), rx_frame.data.u8[2]) * 0.25 - 500; //OK!
LB_SOC = ((rx_frame.data.u8[4] << 8) | (rx_frame.data.u8[5])) * 0.0025; //OK! LB_SOC = ((rx_frame.data.u8[4] << 8) | (rx_frame.data.u8[5])) * 0.0025; //OK!
break; break;
case 0x424: //BMS2 case 0x424: //BMS2
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
LB_EOCR = (rx_frame.data.u8[0] & 0x03); LB_EOCR = (rx_frame.data.u8[0] & 0x03);
LB_HVBUV = (rx_frame.data.u8[0] & 0x0C) >> 2; LB_HVBUV = (rx_frame.data.u8[0] & 0x0C) >> 2;
LB_HVBIR = (rx_frame.data.u8[0] & 0x30) >> 4; LB_HVBIR = (rx_frame.data.u8[0] & 0x30) >> 4;
@ -212,11 +197,13 @@ void receive_can_battery(CAN_frame_t rx_frame) {
LB_MAX_TEMPERATURE = ((rx_frame.data.u8[7]) - 40); //OK! LB_MAX_TEMPERATURE = ((rx_frame.data.u8[7]) - 40); //OK!
break; break;
case 0x425: case 0x425:
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
LB_kWh_Remaining = word((rx_frame.data.u8[0] & 0x1), rx_frame.data.u8[1]) / 10; //OK! LB_kWh_Remaining = word((rx_frame.data.u8[0] & 0x1), rx_frame.data.u8[1]) / 10; //OK!
break; break;
case 0x445: case 0x445:
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
LB_Cell_Max_Voltage = 1000 + word((rx_frame.data.u8[3] & 0x1), rx_frame.data.u8[4]) * 10; //OK! LB_Cell_Max_Voltage = 1000 + word((rx_frame.data.u8[3] & 0x1), rx_frame.data.u8[4]) * 10; //OK!
LB_Cell_Min_Voltage = 1000 + (word(rx_frame.data.u8[5], rx_frame.data.u8[6]) >> 7) * 10; //OK! LB_Cell_Min_Voltage = 1000 + (word(rx_frame.data.u8[5], rx_frame.data.u8[6]) >> 7) * 10; //OK!
@ -227,7 +214,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
} }
break; break;
case 0x7BB: case 0x7BB:
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS datalayer.battery.status.CAN_battery_still_alive =
12; //Indicate that we are still getting CAN messages from the BMS
if (rx_frame.data.u8[0] == 0x10) { //1st response Bytes 0-7 if (rx_frame.data.u8[0] == 0x10) { //1st response Bytes 0-7
GVB_79B_Continue = true; GVB_79B_Continue = true;

View file

@ -7,7 +7,6 @@
#include "RENAULT-ZOE-BATTERY.h" #include "RENAULT-ZOE-BATTERY.h"
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
static uint16_t LB_SOC = 50; static uint16_t LB_SOC = 50;
static uint16_t LB_SOH = 99; static uint16_t LB_SOH = 99;
@ -21,7 +20,6 @@ static int32_t LB_Current = 0;
static uint16_t LB_kWh_Remaining = 0; static uint16_t LB_kWh_Remaining = 0;
static uint16_t LB_Cell_Max_Voltage = 3700; static uint16_t LB_Cell_Max_Voltage = 3700;
static uint16_t LB_Cell_Min_Voltage = 3700; static uint16_t LB_Cell_Min_Voltage = 3700;
static uint16_t cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
static uint32_t LB_Battery_Voltage = 3700; static uint32_t LB_Battery_Voltage = 3700;
static uint8_t LB_Discharge_Power_Limit_Byte1 = 0; static uint8_t LB_Discharge_Power_Limit_Byte1 = 0;
@ -65,27 +63,12 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.cell_max_voltage_mV; datalayer.battery.status.cell_max_voltage_mV;
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) { if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, 0); set_event(EVENT_CELL_OVER_VOLTAGE, 0);
} }
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) { if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
set_event(EVENT_CELL_UNDER_VOLTAGE, 0); set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
} }
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.println("Values going to inverter:"); Serial.println("Values going to inverter:");
@ -122,7 +105,7 @@ void update_values_battery() { //This function maps all the values fetched via
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
datalayer.battery.status.CAN_battery_still_alive = 12;
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x42E: //HV SOC & Battery Temp & Charging Power case 0x42E: //HV SOC & Battery Temp & Charging Power
break; break;

View file

@ -5,11 +5,9 @@
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define ABSOLUTE_CELL_MAX_VOLTAGE \ #define ABSOLUTE_CELL_MAX_VOLTAGE 4100
4100 // Max Cell Voltage mV! if voltage goes over this, charging is not possible (goes into forced discharge) #define ABSOLUTE_CELL_MIN_VOLTAGE 3000
#define ABSOLUTE_CELL_MIN_VOLTAGE \ #define MAX_CELL_DEVIATION_MV 500
3000 // Min Cell Voltage mV! if voltage goes under this, discharging further is disabled
#define MAX_CELL_DEVIATION_MV 500 //LED turns yellow on the board if mv delta exceeds this value
void setup_battery(void); void setup_battery(void);

View file

@ -18,7 +18,6 @@ TODO: Map all values from battery CAN messages
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
static int SOC_1 = 0; static int SOC_1 = 0;
static int SOC_2 = 0; static int SOC_2 = 0;
@ -77,21 +76,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.temperature_max_dC; datalayer.battery.status.temperature_max_dC;
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
#endif #endif
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive = 12; datalayer.battery.status.CAN_battery_still_alive = 12;
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x200: case 0x200:
break; break;

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION 250
uint8_t CalculateCRC8(CAN_frame_t rx_frame); uint8_t CalculateCRC8(CAN_frame_t rx_frame);
void setup_battery(void); void setup_battery(void);

View file

@ -10,7 +10,6 @@
/* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send
static uint8_t stillAliveCAN = 6; //counter for checking if CAN is still alive
CAN_frame_t TESLA_221_1 = { CAN_frame_t TESLA_221_1 = {
.FIR = {.B = .FIR = {.B =
@ -232,14 +231,6 @@ void update_values_battery() { //This function maps all the values fetched via
/* Value mapping is completed. Start to check all safeties */ /* Value mapping is completed. Start to check all safeties */
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!stillAliveCAN) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
stillAliveCAN--;
clear_event(EVENT_CAN_RX_FAILURE);
}
if (hvil_status == 3) { //INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use if (hvil_status == 3) { //INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use
set_event(EVENT_INTERNAL_OPEN_FAULT, 0); set_event(EVENT_INTERNAL_OPEN_FAULT, 0);
} else { } else {
@ -513,7 +504,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
output_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) / 100; output_current = (((rx_frame.data.u8[4] & 0x0F) << 8) | rx_frame.data.u8[3]) / 100;
break; break;
case 0x292: case 0x292:
stillAliveCAN = 12; //We are getting CAN messages from the BMS, set the CAN detect counter datalayer.battery.status.CAN_battery_still_alive = 12; //We are getting CAN messages from the BMS
bat_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]); bat_beginning_of_life = (((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[5]);
soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]); soc_min = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]);
soc_vi = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2)); soc_vi = (((rx_frame.data.u8[2] & 0x0F) << 6) | ((rx_frame.data.u8[1] & 0xFC) >> 2));

View file

@ -8,6 +8,7 @@
//#define LFP_CHEMISTRY // Enable this line to startup in LFP mode //#define LFP_CHEMISTRY // Enable this line to startup in LFP mode
#define RAMPDOWN_SOC 900 // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00% #define RAMPDOWN_SOC 900 // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00%
#define MAX_CELL_DEVIATION 9999 // Handled inside the Tesla.cpp file, just for compilation
#define FLOAT_MAX_POWER_W 200 // W, what power to allow for top balancing battery #define FLOAT_MAX_POWER_W 200 // W, what power to allow for top balancing battery
#define FLOAT_START_MV 20 // mV, how many mV under overvoltage to start float charging #define FLOAT_START_MV 20 // mV, how many mV under overvoltage to start float charging
#define MAXCHARGEPOWERALLOWED 15000 // 15000W we use a define since the value supplied by Tesla is always 0 #define MAXCHARGEPOWERALLOWED 15000 // 15000W we use a define since the value supplied by Tesla is always 0

View file

@ -3,6 +3,7 @@
#include "../include.h" #include "../include.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION 9999
void setup_battery(void); void setup_battery(void);

View file

@ -9,11 +9,9 @@
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
#define MAX_CELL_VOLTAGE 4210 //Battery is put into emergency stop if one cell goes over this value #define MAX_CELL_VOLTAGE 4210 //Battery is put into emergency stop if one cell goes over this value
#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value #define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value
#define MAX_CELL_DEVIATION 500 //LED turns yellow on the board if mv delta exceeds this value
static float BATT_U = 0; //0x3A static float BATT_U = 0; //0x3A
static float MAX_U = 0; //0x3A static float MAX_U = 0; //0x3A
@ -30,12 +28,10 @@ static uint16_t CELL_U_MAX = 0; //0x37D
static uint16_t CELL_U_MIN = 0; //0x37D static uint16_t CELL_U_MIN = 0; //0x37D
static uint8_t CELL_ID_U_MAX = 0; //0x37D static uint8_t CELL_ID_U_MAX = 0; //0x37D
static uint16_t HvBattPwrLimDchaSoft = 0; //0x369 static uint16_t HvBattPwrLimDchaSoft = 0; //0x369
static uint8_t batteryModuleNumber = 0x10; // First battery module static uint8_t batteryModuleNumber = 0x10; // First battery module
static uint8_t battery_request_idx = 0; static uint8_t battery_request_idx = 0;
static uint8_t rxConsecutiveFrames = 0; static uint8_t rxConsecutiveFrames = 0;
static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV
static uint16_t cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
static uint8_t cellcounter = 0; static uint8_t cellcounter = 0;
static uint32_t remaining_capacity = 0; static uint32_t remaining_capacity = 0;
static uint16_t cell_voltages[108]; //array with all the cellvoltages static uint16_t cell_voltages[108]; //array with all the cellvoltages
@ -114,14 +110,6 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i]; datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i];
} }
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
#ifdef DEBUG_VIA_USB #ifdef DEBUG_VIA_USB
Serial.print("BMS reported SOC%: "); Serial.print("BMS reported SOC%: ");
Serial.println(SOC_BMS); Serial.println(SOC_BMS);
@ -159,8 +147,6 @@ void update_values_battery() { //This function maps all the values fetched via
Serial.println(min_max_voltage[1]); Serial.println(min_max_voltage[1]);
Serial.print("Lowest cell voltage: "); Serial.print("Lowest cell voltage: ");
Serial.println(min_max_voltage[0]); Serial.println(min_max_voltage[0]);
Serial.print("Cell deviation voltage: ");
Serial.println(cell_deviation_mV);
Serial.print("Cell voltage,"); Serial.print("Cell voltage,");
while (cnt < 108) { while (cnt < 108) {
Serial.print(cell_voltages[cnt++]); Serial.print(cell_voltages[cnt++]);
@ -171,7 +157,7 @@ void update_values_battery() { //This function maps all the values fetched via
} }
void receive_can_battery(CAN_frame_t rx_frame) { void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive = 12; datalayer.battery.status.CAN_battery_still_alive = 12;
switch (rx_frame.MsgID) { switch (rx_frame.MsgID) {
case 0x3A: case 0x3A:
if ((rx_frame.data.u8[6] & 0x80) == 0x80) if ((rx_frame.data.u8[6] & 0x80) == 0x80)
@ -314,12 +300,6 @@ void receive_can_battery(CAN_frame_t rx_frame) {
min_max_voltage[1] = cell_voltages[cellcounter]; min_max_voltage[1] = cell_voltages[cellcounter];
} }
cell_deviation_mV = (min_max_voltage[1] - min_max_voltage[0]);
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
}
if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) { if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
set_event(EVENT_CELL_OVER_VOLTAGE, 0); set_event(EVENT_CELL_OVER_VOLTAGE, 0);
} }

View file

@ -5,6 +5,7 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED #define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 250
void setup_battery(void); void setup_battery(void);

View file

@ -68,6 +68,11 @@ typedef struct {
* battery.settings.soc_scaling_active * battery.settings.soc_scaling_active
*/ */
uint16_t reported_soc; uint16_t reported_soc;
/** A counter that increases incase a CAN CRC read error occurs */
uint16_t CAN_error_counter;
/** uint8_t */
/** A counter set each time a new message comes from battery.*/
uint8_t CAN_battery_still_alive = 12;
/** Other */ /** Other */
/** The current BMS status */ /** The current BMS status */

View file

@ -0,0 +1,52 @@
#include "../../datalayer/datalayer.h"
#include "../utils/events.h"
static uint16_t cell_deviation_mV = 0;
void update_machineryprotection() {
// Start checking that the battery is within reason. Incase we see any funny business, raise an event!
// Battery is overheated!
if (datalayer.battery.status.temperature_max_dC > 500) {
set_event(EVENT_BATTERY_OVERHEAT, datalayer.battery.status.temperature_max_dC);
} else {
clear_event(EVENT_BATTERY_OVERHEAT);
}
// Battery is frozen!
if (datalayer.battery.status.temperature_min_dC < -250) {
set_event(EVENT_BATTERY_FROZEN, datalayer.battery.status.temperature_min_dC);
} else {
clear_event(EVENT_BATTERY_FROZEN);
}
// 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);
} else {
clear_event(EVENT_LOW_SOH);
}
// Check diff between highest and lowest cell
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20));
} else {
clear_event(EVENT_CELL_DEVIATION_HIGH);
}
// Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error
if (!datalayer.battery.status.CAN_battery_still_alive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
datalayer.battery.status.CAN_battery_still_alive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
// Also check if we have recieved too many malformed CAN messages
if (datalayer.battery.status.CAN_error_counter > MAX_CAN_FAILURES) {
set_event(EVENT_CAN_RX_WARNING, 0);
} else {
clear_event(EVENT_CAN_RX_WARNING);
}
}

View file

@ -0,0 +1,9 @@
#ifndef SAFETY_H
#define SAFETY_H
#include <Arduino.h>
#define MAX_CAN_FAILURES 50
void update_machineryprotection();
#endif

View file

@ -144,10 +144,12 @@ void init_events(void) {
events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].level = EVENT_LEVEL_INFO; events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_EMPTY].level = EVENT_LEVEL_INFO; events.entries[EVENT_BATTERY_EMPTY].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_FULL].level = EVENT_LEVEL_INFO; events.entries[EVENT_BATTERY_FULL].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_FROZEN].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_CAUTION].level = EVENT_LEVEL_INFO; events.entries[EVENT_BATTERY_CAUTION].level = EVENT_LEVEL_INFO;
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_BATTERY_OVERHEAT].level = EVENT_LEVEL_ERROR;
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_PRECHARGE_FAILURE].level = EVENT_LEVEL_INFO; events.entries[EVENT_PRECHARGE_FAILURE].level = EVENT_LEVEL_INFO;
@ -220,6 +222,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Info: Battery is completely discharged"; return "Info: Battery is completely discharged";
case EVENT_BATTERY_FULL: case EVENT_BATTERY_FULL:
return "Info: Battery is fully charged"; return "Info: Battery is fully charged";
case EVENT_BATTERY_FROZEN:
return "Info: Battery is too cold to operate optimally. Consider warming it up!";
case EVENT_BATTERY_CAUTION: case EVENT_BATTERY_CAUTION:
return "Info: Battery has raised a general caution flag. Might want to inspect it closely."; return "Info: Battery has raised a general caution flag. Might want to inspect it closely.";
case EVENT_BATTERY_CHG_STOP_REQ: case EVENT_BATTERY_CHG_STOP_REQ:
@ -232,6 +236,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_BATTERY_OVERHEAT:
return "ERROR: Battery overheated. Shutting down to prevent thermal runaway!";
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

@ -6,7 +6,7 @@
// #define INCLUDE_EVENTS_TEST // Enable to run an event test loop, see events_test_on_target.cpp // #define INCLUDE_EVENTS_TEST // Enable to run an event test loop, see events_test_on_target.cpp
#define EE_MAGIC_HEADER_VALUE 0x0004 // 0x0000 to 0xFFFF #define EE_MAGIC_HEADER_VALUE 0x0005 // 0x0000 to 0xFFFF
#define GENERATE_ENUM(ENUM) ENUM, #define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING, #define GENERATE_STRING(STRING) #STRING,
@ -38,10 +38,12 @@
XX(EVENT_KWH_PLAUSIBILITY_ERROR) \ XX(EVENT_KWH_PLAUSIBILITY_ERROR) \
XX(EVENT_BATTERY_EMPTY) \ XX(EVENT_BATTERY_EMPTY) \
XX(EVENT_BATTERY_FULL) \ XX(EVENT_BATTERY_FULL) \
XX(EVENT_BATTERY_FROZEN) \
XX(EVENT_BATTERY_CAUTION) \ XX(EVENT_BATTERY_CAUTION) \
XX(EVENT_BATTERY_CHG_STOP_REQ) \ XX(EVENT_BATTERY_CHG_STOP_REQ) \
XX(EVENT_BATTERY_DISCHG_STOP_REQ) \ XX(EVENT_BATTERY_DISCHG_STOP_REQ) \
XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \
XX(EVENT_BATTERY_OVERHEAT) \
XX(EVENT_BATTERY_REQUESTS_HEAT) \ XX(EVENT_BATTERY_REQUESTS_HEAT) \
XX(EVENT_BATTERY_WARMED_UP) \ XX(EVENT_BATTERY_WARMED_UP) \
XX(EVENT_LOW_SOH) \ XX(EVENT_LOW_SOH) \

View file

@ -28,6 +28,4 @@ enum led_color { GREEN, YELLOW, RED, BLUE, RGB };
#define INTERVAL_100_MS_DELAYED 120 #define INTERVAL_100_MS_DELAYED 120
#define INTERVAL_500_MS_DELAYED 550 #define INTERVAL_500_MS_DELAYED 550
#define MAX_CAN_FAILURES 500 // Amount of malformed CAN messages to allow before raising a warning
#endif #endif

View file

@ -8,6 +8,7 @@
#include "system_settings.h" #include "system_settings.h"
#include "devboard/hal/hal.h" #include "devboard/hal/hal.h"
#include "devboard/safety/safety.h"
#include "devboard/utils/time_meas.h" #include "devboard/utils/time_meas.h"
#include "devboard/utils/types.h" #include "devboard/utils/types.h"