Clarify contactor control variables and usage

This commit is contained in:
Jaakko Haakana 2025-05-17 08:53:58 +03:00
parent 4cf08894f7
commit 2c2f05f186
11 changed files with 46 additions and 30 deletions

View file

@ -334,9 +334,9 @@ void check_interconnect_available() {
clear_event(EVENT_VOLTAGE_DIFFERENCE); clear_event(EVENT_VOLTAGE_DIFFERENCE);
if (datalayer.battery.status.bms_status == FAULT) { if (datalayer.battery.status.bms_status == FAULT) {
// If main battery is in fault state, disengage the second battery // If main battery is in fault state, disengage the second battery
datalayer.system.status.battery2_allows_contactor_closing = false; datalayer.system.status.battery2_allowed_contactor_closing = false;
} else { // If main battery is OK, allow second battery to join } else { // If main battery is OK, allow second battery to join
datalayer.system.status.battery2_allows_contactor_closing = true; datalayer.system.status.battery2_allowed_contactor_closing = true;
} }
} else { //Voltage between the two packs is too large } else { //Voltage between the two packs is too large
set_event(EVENT_VOLTAGE_DIFFERENCE, (uint8_t)(voltage_diff / 10)); set_event(EVENT_VOLTAGE_DIFFERENCE, (uint8_t)(voltage_diff / 10));

View file

@ -30,9 +30,7 @@ void setup_battery() {
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allows_contactor_closing, new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allows_contactor_closing,
can_config.battery_double, WUP_PIN2); can_config.battery_double, WUP_PIN2);
#else #else
battery2 = battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, nullptr, can_config.battery_double);
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allows_contactor_closing,
nullptr, can_config.battery_double);
#endif #endif
} }
battery2->setup(); battery2->setup();

View file

@ -1,10 +1,10 @@
#include "../include.h"
#ifdef BMW_I3_BATTERY #ifdef BMW_I3_BATTERY
#include "BMW-I3-BATTERY.h"
#include "../communication/can/comm_can.h" #include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" #include "../datalayer/datalayer_extended.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "BMW-I3-BATTERY.h" #include "../include.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 */
@ -329,11 +329,15 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
BMW_13E.data.u8[4] = BMW_13E_counter; BMW_13E.data.u8[4] = BMW_13E_counter;
if (datalayer_battery->status.bms_status == FAULT) { if (datalayer_battery->status.bms_status == FAULT) {
} //If battery is not in Fault mode, allow contactor to close by sending 10B } else if (allows_contactor_closing) {
else if (*allows_contactor_closing == true) { //If battery is not in Fault mode, and we are allowed to control contactors, we allow contactor to close by sending 10B
*allows_contactor_closing = true;
transmit_can_frame(&BMW_10B, can_interface);
} else if (contactor_closing_allowed && *contactor_closing_allowed) {
transmit_can_frame(&BMW_10B, can_interface); transmit_can_frame(&BMW_10B, can_interface);
} }
} }
// Send 100ms CAN Message // Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis; previousMillis100 = currentMillis;
@ -512,7 +516,10 @@ void BmwI3Battery::setup(void) { // Performs one time setup at startup
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;
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
datalayer.system.status.battery_allows_contactor_closing = true;
if (allows_contactor_closing) {
*allows_contactor_closing = true;
}
datalayer_battery->info.number_of_cells = NUMBER_OF_CELLS; datalayer_battery->info.number_of_cells = NUMBER_OF_CELLS;
pinMode(wakeup_pin, OUTPUT); pinMode(wakeup_pin, OUTPUT);

View file

@ -12,9 +12,10 @@
class BmwI3Battery : public CanBattery { class BmwI3Battery : public CanBattery {
public: public:
// Use this constructor for the second battery. // Use this constructor for the second battery.
BmwI3Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr, int targetCan, int wakeup) { BmwI3Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* contactor_closing_allowed_ptr, int targetCan, int wakeup) {
datalayer_battery = datalayer_ptr; datalayer_battery = datalayer_ptr;
allows_contactor_closing = allows_contactor_closing_ptr; contactor_closing_allowed = contactor_closing_allowed_ptr;
allows_contactor_closing = nullptr;
can_interface = targetCan; can_interface = targetCan;
wakeup_pin = wakeup; wakeup_pin = wakeup;
*allows_contactor_closing = true; *allows_contactor_closing = true;
@ -27,6 +28,7 @@ class BmwI3Battery : public CanBattery {
BmwI3Battery() { BmwI3Battery() {
datalayer_battery = &datalayer.battery; datalayer_battery = &datalayer.battery;
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing; allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
contactor_closing_allowed = nullptr;
can_interface = can_config.battery; can_interface = can_config.battery;
wakeup_pin = WUP_PIN1; wakeup_pin = WUP_PIN1;
} }
@ -53,9 +55,14 @@ class BmwI3Battery : public CanBattery {
const int NUMBER_OF_CELLS = 96; const int NUMBER_OF_CELLS = 96;
DATALAYER_BATTERY_TYPE* datalayer_battery; DATALAYER_BATTERY_TYPE* datalayer_battery;
bool* allows_contactor_closing;
int wakeup_pin;
// If not null, this battery decides when the contactor can be closed and writes the value here.
bool* allows_contactor_closing;
// If not null, this battery listens to this boolean to determine whether contactor closing is allowed
bool* contactor_closing_allowed;
int wakeup_pin;
int can_interface; int can_interface;
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send

View file

@ -485,10 +485,12 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
previousMillis50 = currentMillis; previousMillis50 = currentMillis;
// Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO) // Set close contactors to allowed (Useful for crashed packs, started via contactor control thru GPIO)
if (datalayer_battery->status.bms_status == ACTIVE) { if (allows_contactor_closing) {
datalayer.system.status.battery_allows_contactor_closing = true; if (datalayer_battery->status.bms_status == ACTIVE) {
} else { // Fault state, open contactors! *allows_contactor_closing = true;
datalayer.system.status.battery_allows_contactor_closing = false; } else { // Fault state, open contactors!
*allows_contactor_closing = false;
}
} }
counter_50ms++; counter_50ms++;

View file

@ -33,11 +33,10 @@
class BydAttoBattery : public CanBattery { class BydAttoBattery : public CanBattery {
public: public:
// Use this constructor for the second battery. // Use this constructor for the second battery.
BydAttoBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr, BydAttoBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_BYDATTO3* extended, int targetCan) {
DATALAYER_INFO_BYDATTO3* extended, int targetCan) {
datalayer_battery = datalayer_ptr; datalayer_battery = datalayer_ptr;
datalayer_bydatto = extended; datalayer_bydatto = extended;
allows_contactor_closing = allows_contactor_closing_ptr; allows_contactor_closing = nullptr;
can_interface = targetCan; can_interface = targetCan;
} }

View file

@ -74,7 +74,7 @@ void NissanLeafBattery::
datalayer_battery->status.max_charge_power_W = (battery_Charge_Power_Limit * 1000); //kW to W datalayer_battery->status.max_charge_power_W = (battery_Charge_Power_Limit * 1000); //kW to W
//Allow contactors to close //Allow contactors to close
if (battery_can_alive) { if (battery_can_alive && allows_contactor_closing) {
*allows_contactor_closing = true; *allows_contactor_closing = true;
} }

View file

@ -19,10 +19,9 @@
class NissanLeafBattery : public CanBattery { class NissanLeafBattery : public CanBattery {
public: public:
// Use this constructor for the second battery. // Use this constructor for the second battery.
NissanLeafBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* allows_contactor_closing_ptr, NissanLeafBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_NISSAN_LEAF* extended, int targetCan) {
DATALAYER_INFO_NISSAN_LEAF* extended, int targetCan) {
datalayer_battery = datalayer_ptr; datalayer_battery = datalayer_ptr;
allows_contactor_closing = allows_contactor_closing_ptr; allows_contactor_closing = nullptr;
datalayer_nissan = extended; datalayer_nissan = extended;
can_interface = targetCan; can_interface = targetCan;
@ -48,6 +47,8 @@ class NissanLeafBattery : public CanBattery {
DATALAYER_BATTERY_TYPE* datalayer_battery; DATALAYER_BATTERY_TYPE* datalayer_battery;
DATALAYER_INFO_NISSAN_LEAF* datalayer_nissan; DATALAYER_INFO_NISSAN_LEAF* datalayer_nissan;
// If not null, this battery decides when the contactor can be closed and writes the value here.
bool* allows_contactor_closing; bool* allows_contactor_closing;
int can_interface; int can_interface;

View file

@ -225,7 +225,7 @@ void handle_contactors() {
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
void handle_contactors_battery2() { void handle_contactors_battery2() {
if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allows_contactor_closing) { if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allowed_contactor_closing) {
set(SECOND_NEGATIVE_CONTACTOR_PIN, ON); set(SECOND_NEGATIVE_CONTACTOR_PIN, ON);
set(SECOND_POSITIVE_CONTACTOR_PIN, ON); set(SECOND_POSITIVE_CONTACTOR_PIN, ON);
datalayer.system.status.contactors_battery2_engaged = true; datalayer.system.status.contactors_battery2_engaged = true;

View file

@ -297,10 +297,12 @@ typedef struct {
* we report the inverter as missing entirely on the CAN bus. * we report the inverter as missing entirely on the CAN bus.
*/ */
uint8_t CAN_inverter_still_alive = CAN_STILL_ALIVE; uint8_t CAN_inverter_still_alive = CAN_STILL_ALIVE;
/** True if the battery allows for the contactors to close */ /** True if the primary battery allows for the contactors to close */
bool battery_allows_contactor_closing = false; bool battery_allows_contactor_closing = false;
/** True if the second battery allows for the contactors to close */
bool battery2_allows_contactor_closing = false; /** True if the second battery is allowed to close the contactors */
bool battery2_allowed_contactor_closing = false;
/** True if the inverter allows for the contactors to close */ /** True if the inverter allows for the contactors to close */
bool inverter_allows_contactor_closing = true; bool inverter_allows_contactor_closing = true;
#ifdef CONTACTOR_CONTROL #ifdef CONTACTOR_CONTROL

View file

@ -1379,7 +1379,7 @@ String processor(const String& var) {
content += "<h4>Automatic contactor closing allowed:</h4>"; content += "<h4>Automatic contactor closing allowed:</h4>";
content += "<h4>Battery: "; content += "<h4>Battery: ";
if (datalayer.system.status.battery2_allows_contactor_closing == true) { if (datalayer.system.status.battery2_allowed_contactor_closing == true) {
content += "<span>&#10003;</span>"; content += "<span>&#10003;</span>";
} else { } else {
content += "<span style='color: red;'>&#10005;</span>"; content += "<span style='color: red;'>&#10005;</span>";