mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Add safety file, move out safety checks
This commit is contained in:
parent
8777a99f7a
commit
f6f12652d6
31 changed files with 139 additions and 272 deletions
|
@ -226,6 +226,7 @@ void core_loop(void* task_time_us) {
|
|||
if (millis() - previousMillisUpdateVal >= intervalUpdateValues) // Every 5s normally
|
||||
{
|
||||
previousMillisUpdateVal = millis();
|
||||
update_machineryprotection();
|
||||
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.
|
||||
if (DUMMY_EVENT_ENABLED) {
|
||||
|
@ -459,36 +460,6 @@ void init_battery() {
|
|||
// Functions
|
||||
#ifdef DEBUG_CANFD_DATA
|
||||
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;
|
||||
Serial.print(rx_frame.id, HEX);
|
||||
Serial.print(" ");
|
||||
|
@ -499,7 +470,6 @@ void print_canfd_frame(CANFDMessage rx_frame) {
|
|||
}
|
||||
Serial.println(" ");
|
||||
}
|
||||
|
||||
#endif
|
||||
void receive_canfd() { // This section checks if we have a complete CAN-FD message incoming
|
||||
CANFDMessage frame;
|
||||
|
|
|
@ -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 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 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
|
||||
|
||||
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_hvmin = 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_heat_exchanger = 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) {
|
||||
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];
|
||||
|
||||
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) {
|
||||
// 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) {
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_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
|
||||
if (battery_status_error_locking == 2) { // HVIL seated?
|
||||
set_event(EVENT_HVIL_FAILURE, 0);
|
||||
|
@ -559,7 +527,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
switch (rx_frame.MsgID) {
|
||||
case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2
|
||||
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_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]);
|
||||
|
@ -596,7 +565,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
battery_awake = true;
|
||||
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
|
||||
CANerror++;
|
||||
datalayer.battery.status.CAN_error_counter++;
|
||||
break;
|
||||
}
|
||||
battery_status_diagnostics_HV = (rx_frame.data.u8[2] & 0x0F);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
/* 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 uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
||||
|
||||
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>(
|
||||
(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
|
||||
Serial.print("SOC 0x100: ");
|
||||
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) {
|
||||
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) {
|
||||
case 0x100:
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION 9999
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//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 */
|
||||
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 BMU_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);
|
||||
|
||||
/* 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) {
|
||||
#ifdef DEBUG_VIA_USB
|
||||
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) {
|
||||
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
|
||||
switch (rx_frame.MsgID) {
|
||||
case 0x374: //BMU message, 10ms - SOC
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION_MV 500
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
|
||||
/* 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 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 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 inverterVoltage = 0;
|
||||
|
@ -23,7 +21,6 @@ static uint16_t SOC_Display = 0;
|
|||
static uint16_t batterySOH = 1000;
|
||||
static uint16_t CellVoltMax_mV = 3700;
|
||||
static uint16_t CellVoltMin_mV = 3700;
|
||||
static uint16_t cell_deviation_mV = 0;
|
||||
static uint16_t batteryVoltage = 0;
|
||||
static int16_t leadAcidBatteryVoltage = 120;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
datalayer.battery.status.CAN_battery_still_alive--;
|
||||
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
|
||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||
|
||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
}
|
||||
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
|
||||
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 ==
|
||||
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) {
|
||||
CANstillAlive = 12;
|
||||
datalayer.battery.status.CAN_battery_still_alive = 12;
|
||||
switch (frame.id) {
|
||||
case 0x7EC:
|
||||
// print_canfd_frame(frame);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
extern ACAN2517FD canfd;
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
#define MAX_CELL_DEVIATION_MV 150
|
||||
#define MAXCHARGEPOWERALLOWED 10000
|
||||
#define MAXDISCHARGEPOWERALLOWED 10000
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
/* 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 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 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_BMS = 0;
|
||||
|
@ -21,7 +19,6 @@ static uint16_t SOC_Display = 0;
|
|||
static uint16_t batterySOH = 1000;
|
||||
static uint16_t CellVoltMax_mV = 3700;
|
||||
static uint16_t CellVoltMin_mV = 3700;
|
||||
static uint16_t cell_deviation_mV = 0;
|
||||
static uint16_t allowedDischargePower = 0;
|
||||
static uint16_t allowedChargePower = 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;
|
||||
|
||||
/* 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) {
|
||||
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
|
||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||
|
||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
}
|
||||
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
|
||||
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 ==
|
||||
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;
|
||||
case 0x542: //BMS SOC
|
||||
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 )
|
||||
break;
|
||||
case 0x594:
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION_MV 150
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
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 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 mprun10 = 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;
|
||||
#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 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
|
||||
static uint16_t LB_Discharge_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 uint8_t cellcounter = 0;
|
||||
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 insulation = 0; //Insulation resistance
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
if (!LB_Interlock) {
|
||||
set_event(EVENT_HVIL_FAILURE, 0);
|
||||
|
@ -324,19 +312,6 @@ void update_values_battery() { /* This function maps all the values fetched via
|
|||
}
|
||||
#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_Heating_Stop) {
|
||||
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(", Max cell voltage: ", min_max_voltage[1], "mV ");
|
||||
print_with_units(", Min cell voltage: ", min_max_voltage[0], "mV ");
|
||||
print_with_units(", Cell deviation: ", cell_deviation_mV, "mV ");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -369,7 +343,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
switch (rx_frame.MsgID) {
|
||||
case 0x1DB:
|
||||
if (is_message_corrupt(rx_frame)) {
|
||||
CANerror++;
|
||||
datalayer.battery.status.CAN_error_counter++;
|
||||
break; //Message content malformed, abort reading data from it
|
||||
}
|
||||
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;
|
||||
case 0x1DC:
|
||||
if (is_message_corrupt(rx_frame)) {
|
||||
CANerror++;
|
||||
datalayer.battery.status.CAN_error_counter++;
|
||||
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);
|
||||
|
@ -403,7 +377,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
break;
|
||||
case 0x55B:
|
||||
if (is_message_corrupt(rx_frame)) {
|
||||
CANerror++;
|
||||
datalayer.battery.status.CAN_error_counter++;
|
||||
break; //Message content malformed, abort reading data from it
|
||||
}
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
if (LB_MAX) {
|
||||
|
@ -521,15 +496,9 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
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_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) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION_MV 500
|
||||
|
||||
uint16_t Temp_fromRAW_to_F(uint16_t temperature);
|
||||
bool is_message_corrupt(CAN_frame_t rx_frame);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
/* 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 uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
||||
|
||||
//Actual content messages
|
||||
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.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) {
|
||||
CANstillAlive = 12;
|
||||
datalayer.battery.status.CAN_battery_still_alive = 12;
|
||||
switch (rx_frame.MsgID) {
|
||||
case 0x7310:
|
||||
case 0x7311:
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION 9999
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -34,9 +34,7 @@ static uint16_t LB_Charge_Power_Limit = 0;
|
|||
static uint16_t LB_kWh_Remaining = 0;
|
||||
static uint16_t LB_Cell_Max_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 uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
||||
static uint8_t LB_Discharge_Power_Limit_Byte1 = 0;
|
||||
static uint8_t GVI_Pollcounter = 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;
|
||||
|
||||
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) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, (LB_Cell_Max_Voltage / 20));
|
||||
}
|
||||
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
|
||||
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
|
||||
Serial.println("Values going to inverter:");
|
||||
|
@ -190,13 +173,15 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
|
||||
switch (rx_frame.MsgID) {
|
||||
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_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!
|
||||
break;
|
||||
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_HVBUV = (rx_frame.data.u8[0] & 0x0C) >> 2;
|
||||
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!
|
||||
break;
|
||||
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!
|
||||
break;
|
||||
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_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;
|
||||
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
|
||||
GVB_79B_Continue = true;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "RENAULT-ZOE-BATTERY.h"
|
||||
|
||||
/* 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 uint16_t LB_SOC = 50;
|
||||
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_Cell_Max_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 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;
|
||||
|
||||
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) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
}
|
||||
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
|
||||
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
|
||||
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) {
|
||||
|
||||
datalayer.battery.status.CAN_battery_still_alive = 12;
|
||||
switch (rx_frame.MsgID) {
|
||||
case 0x42E: //HV SOC & Battery Temp & Charging Power
|
||||
break;
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
#define ABSOLUTE_CELL_MAX_VOLTAGE \
|
||||
4100 // Max Cell Voltage mV! if voltage goes over this, charging is not possible (goes into forced discharge)
|
||||
#define ABSOLUTE_CELL_MIN_VOLTAGE \
|
||||
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
|
||||
#define ABSOLUTE_CELL_MAX_VOLTAGE 4100
|
||||
#define ABSOLUTE_CELL_MIN_VOLTAGE 3000
|
||||
#define MAX_CELL_DEVIATION_MV 500
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
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 uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
||||
|
||||
static int SOC_1 = 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;
|
||||
|
||||
/* 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
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void receive_can_battery(CAN_frame_t rx_frame) {
|
||||
CANstillAlive = 12;
|
||||
datalayer.battery.status.CAN_battery_still_alive = 12;
|
||||
switch (rx_frame.MsgID) {
|
||||
case 0x200:
|
||||
break;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION 250
|
||||
|
||||
uint8_t CalculateCRC8(CAN_frame_t rx_frame);
|
||||
void setup_battery(void);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
/* 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 uint8_t stillAliveCAN = 6; //counter for checking if CAN is still alive
|
||||
|
||||
CAN_frame_t TESLA_221_1 = {
|
||||
.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 */
|
||||
|
||||
/* 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
|
||||
set_event(EVENT_INTERNAL_OPEN_FAULT, 0);
|
||||
} 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;
|
||||
break;
|
||||
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]);
|
||||
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));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//#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 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_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
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "../include.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION 9999
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
/* 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 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 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 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 uint8_t CELL_ID_U_MAX = 0; //0x37D
|
||||
static uint16_t HvBattPwrLimDchaSoft = 0; //0x369
|
||||
|
||||
static uint8_t batteryModuleNumber = 0x10; // First battery module
|
||||
static uint8_t battery_request_idx = 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 cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
|
||||
static uint8_t cellcounter = 0;
|
||||
static uint32_t remaining_capacity = 0;
|
||||
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];
|
||||
}
|
||||
|
||||
/* 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
|
||||
Serial.print("BMS reported SOC%: ");
|
||||
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.print("Lowest cell voltage: ");
|
||||
Serial.println(min_max_voltage[0]);
|
||||
Serial.print("Cell deviation voltage: ");
|
||||
Serial.println(cell_deviation_mV);
|
||||
Serial.print("Cell voltage,");
|
||||
while (cnt < 108) {
|
||||
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) {
|
||||
CANstillAlive = 12;
|
||||
datalayer.battery.status.CAN_battery_still_alive = 12;
|
||||
switch (rx_frame.MsgID) {
|
||||
case 0x3A:
|
||||
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];
|
||||
}
|
||||
|
||||
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) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
#define MAX_CELL_DEVIATION_MV 250
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -68,6 +68,11 @@ typedef struct {
|
|||
* battery.settings.soc_scaling_active
|
||||
*/
|
||||
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 */
|
||||
/** The current BMS status */
|
||||
|
|
52
Software/src/devboard/safety/safety.cpp
Normal file
52
Software/src/devboard/safety/safety.cpp
Normal 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);
|
||||
}
|
||||
}
|
9
Software/src/devboard/safety/safety.h
Normal file
9
Software/src/devboard/safety/safety.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef SAFETY_H
|
||||
#define SAFETY_H
|
||||
#include <Arduino.h>
|
||||
|
||||
#define MAX_CAN_FAILURES 50
|
||||
|
||||
void update_machineryprotection();
|
||||
|
||||
#endif
|
|
@ -144,10 +144,12 @@ void init_events(void) {
|
|||
events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].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_FROZEN].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_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_HVIL_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
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";
|
||||
case EVENT_BATTERY_FULL:
|
||||
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:
|
||||
return "Info: Battery has raised a general caution flag. Might want to inspect it closely.";
|
||||
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!";
|
||||
case EVENT_BATTERY_WARMED_UP:
|
||||
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:
|
||||
return "ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle "
|
||||
"battery.";
|
||||
|
|
|
@ -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 0x0004 // 0x0000 to 0xFFFF
|
||||
#define EE_MAGIC_HEADER_VALUE 0x0005 // 0x0000 to 0xFFFF
|
||||
|
||||
#define GENERATE_ENUM(ENUM) ENUM,
|
||||
#define GENERATE_STRING(STRING) #STRING,
|
||||
|
@ -38,10 +38,12 @@
|
|||
XX(EVENT_KWH_PLAUSIBILITY_ERROR) \
|
||||
XX(EVENT_BATTERY_EMPTY) \
|
||||
XX(EVENT_BATTERY_FULL) \
|
||||
XX(EVENT_BATTERY_FROZEN) \
|
||||
XX(EVENT_BATTERY_CAUTION) \
|
||||
XX(EVENT_BATTERY_CHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_DISCHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_OVERHEAT) \
|
||||
XX(EVENT_BATTERY_REQUESTS_HEAT) \
|
||||
XX(EVENT_BATTERY_WARMED_UP) \
|
||||
XX(EVENT_LOW_SOH) \
|
||||
|
|
|
@ -28,6 +28,4 @@ enum led_color { GREEN, YELLOW, RED, BLUE, RGB };
|
|||
#define INTERVAL_100_MS_DELAYED 120
|
||||
#define INTERVAL_500_MS_DELAYED 550
|
||||
|
||||
#define MAX_CAN_FAILURES 500 // Amount of malformed CAN messages to allow before raising a warning
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "system_settings.h"
|
||||
|
||||
#include "devboard/hal/hal.h"
|
||||
#include "devboard/safety/safety.h"
|
||||
#include "devboard/utils/time_meas.h"
|
||||
#include "devboard/utils/types.h"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue