Skip to content

Commit

Permalink
Merge pull request #145 from dalathegreat/feature/LEAF-optimization
Browse files Browse the repository at this point in the history
Bugfix: Tesla / LEAF / BYD CAN
  • Loading branch information
dalathegreat authored Feb 2, 2024
2 parents 3c23bf5 + feb45c3 commit 38524e2
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 75 deletions.
147 changes: 79 additions & 68 deletions Software/src/battery/NISSAN-LEAF-BATTERY.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,6 @@ void print_with_units(char* header, int value, char* units) {
}

void update_values_leaf_battery() { /* This function maps all the values fetched via CAN to the correct parameters used for modbus */
bms_status = ACTIVE; //Startout in active mode

/* Start with mapping all values */

StateOfHealth = (LB_StateOfHealth * 100); //Increase range from 99% -> 99.00%
Expand Down Expand Up @@ -239,6 +237,8 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
max_target_charge_power = 0; //No need to charge further, set max power to 0
}

bms_status = ACTIVE; //Startout in active mode

/*Extra safety functions below*/
if (LB_GIDS < 10) //800Wh left in battery
{ //Battery is running abnormally low, some discharge logic might have failed. Zero it all out.
Expand All @@ -251,16 +251,24 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
(ABSOLUTE_MAX_VOLTAGE - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
if (LB_SOC < 650) {
bms_status = FAULT;
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: SOC% reported by battery not plausible. Restart battery!");
#endif
}
}

if (LB_Full_CHARGE_flag) { //Battery reports that it is fully charged stop all further charging incase it hasn't already
max_target_charge_power = 0;
}

if (LB_Capacity_Empty) { //Battery reports that it is fully discharged. Stop all further discharging incase it hasn't already
max_target_discharge_power = 0;
}

if (LB_Relay_Cut_Request) { //LB_FAIL, BMS requesting shutdown and contactors to be opened
#ifdef DEBUG_VIA_USB
Serial.println("Battery requesting immediate shutdown and contactors to be opened!");
#endif
//Note, this is sometimes triggered during the night while idle, and the BMS recovers after a while. Removed latching from this scenario
errorCode = 1;
max_target_discharge_power = 0;
Expand All @@ -283,27 +291,35 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
//Normal stop request. For stationary storage we don't disconnect contactors, so we ignore this.
break;
case (4):
//Caution Lamp Request
//Caution Lamp Request
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: Battery raised caution indicator. Inspect battery status!");
#endif
break;
case (5):
//Caution Lamp Request & Normal Stop Request
bms_status = FAULT;
errorCode = 2;
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: Battery raised caution indicator AND requested discharge stop. Inspect battery status!");
#endif
break;
case (6):
//Caution Lamp Request & Charging Mode Stop Request
bms_status = FAULT;
errorCode = 3;
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: Battery raised caution indicator AND requested charge stop. Inspect battery status!");
#endif
break;
case (7):
//Caution Lamp Request & Charging Mode Stop Request & Normal Stop Request
bms_status = FAULT;
errorCode = 4;
#ifdef DEBUG_VIA_USB
Serial.println(
"ERROR: Battery raised caution indicator AND requested charge/discharge stop. Inspect battery status!");
#endif
break;
default:
break;
Expand All @@ -312,8 +328,10 @@ void update_values_leaf_battery() { /* This function maps all the values fetched

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
#ifdef DEBUG_VIA_USB
Serial.println(
"ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle battery.");
#endif
bms_status = FAULT;
errorCode = 5;
max_target_discharge_power = 0;
Expand All @@ -323,9 +341,11 @@ void update_values_leaf_battery() { /* This function maps all the values fetched

#ifdef INTERLOCK_REQUIRED
if (!LB_Interlock) {
#ifdef DEBUG_VIA_USB
Serial.println(
"ERROR: Battery interlock loop broken. Check that high voltage connectors are seated. Battery will be "
"disabled!");
#endif
bms_status = FAULT;
errorCode = 6;
SOC = 0;
Expand All @@ -338,7 +358,9 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
if (!CANstillAlive) {
bms_status = FAULT;
errorCode = 7;
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: No CAN communication detected for 60s. Shutting down battery control.");
#endif
} else {
CANstillAlive--;
}
Expand All @@ -347,7 +369,9 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
{
errorCode = 10;
LEDcolor = YELLOW;
#ifdef DEBUG_VIA_USB
Serial.println("ERROR: High amount of corrupted CAN messages detected. Check CAN wire shielding!");
#endif
}

/*Finally print out values to serial if configured to do so*/
Expand Down Expand Up @@ -449,6 +473,7 @@ void receive_can_leaf_battery(CAN_frame_t rx_frame) {
if (LB_TEMP != 0x3ff) { //3FF is unavailable value
LB_SOC = LB_TEMP;
}
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
Expand Down Expand Up @@ -579,18 +604,24 @@ void receive_can_leaf_battery(CAN_frame_t rx_frame) {

if (cell_deviation_mV > MAX_CELL_DEVIATION) {
LEDcolor = YELLOW;
#ifdef DEBUG_VIA_USB
Serial.println("HIGH CELL DEVIATION!!! Inspect battery!");
#endif
}

if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
bms_status = FAULT;
errorCode = 8;
#ifdef DEBUG_VIA_USB
Serial.println("CELL OVERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
#endif
}
if (min_max_voltage[0] <= MIN_CELL_VOLTAGE) {
bms_status = FAULT;
errorCode = 9;
#ifdef DEBUG_VIA_USB
Serial.println("CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
#endif
}
break;
}
Expand Down Expand Up @@ -686,77 +717,75 @@ void send_can_leaf_battery() {
// VCM message, containing info if battery should sleep or stay awake
ESP32Can.CANWriteFrame(&LEAF_50B); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1

mprun100++;
if (mprun100 > 3) {
mprun100 = 0;
}

if (mprun100 == 0) {
LEAF_50C.data.u8[3] = 0x00;
LEAF_50C.data.u8[4] = 0x5D;
LEAF_50C.data.u8[5] = 0xC8;
} else if (mprun100 == 1) {
LEAF_50C.data.u8[3] = 0x01;
LEAF_50C.data.u8[4] = 0xB2;
LEAF_50C.data.u8[5] = 0x31;
} else if (mprun100 == 2) {
LEAF_50C.data.u8[3] = 0x02;
LEAF_50C.data.u8[4] = 0x5D;
LEAF_50C.data.u8[5] = 0x63;
} else if (mprun100 == 3) {
LEAF_50C.data.u8[3] = 0x03;
LEAF_50C.data.u8[4] = 0xB2;
LEAF_50C.data.u8[5] = 0x9A;
switch (mprun100) {
case 0:
LEAF_50C.data.u8[3] = 0x00;
LEAF_50C.data.u8[4] = 0x5D;
LEAF_50C.data.u8[5] = 0xC8;
break;
case 1:
LEAF_50C.data.u8[3] = 0x01;
LEAF_50C.data.u8[4] = 0xB2;
LEAF_50C.data.u8[5] = 0x31;
break;
case 2:
LEAF_50C.data.u8[3] = 0x02;
LEAF_50C.data.u8[4] = 0x5D;
LEAF_50C.data.u8[5] = 0x63;
break;
case 3:
LEAF_50C.data.u8[3] = 0x03;
LEAF_50C.data.u8[4] = 0xB2;
LEAF_50C.data.u8[5] = 0x9A;
break;
}
ESP32Can.CANWriteFrame(&LEAF_50C);

mprun100 = (mprun100 + 1) % 4; // mprun100 cycles between 0-1-2-3-0-1...
}
//Send 10ms message
if (currentMillis - previousMillis10 >= interval10) {
previousMillis10 = currentMillis;

if (mprun10 == 0) {
LEAF_1D4.data.u8[4] = 0x07;
LEAF_1D4.data.u8[7] = 0x12;
} else if (mprun10 == 1) {
LEAF_1D4.data.u8[4] = 0x47;
LEAF_1D4.data.u8[7] = 0xD5;
} else if (mprun10 == 2) {
LEAF_1D4.data.u8[4] = 0x87;
LEAF_1D4.data.u8[7] = 0x19;
} else if (mprun10 == 3) {
LEAF_1D4.data.u8[4] = 0xC7;
LEAF_1D4.data.u8[7] = 0xDE;
switch (mprun10) {
case 0:
LEAF_1D4.data.u8[4] = 0x07;
LEAF_1D4.data.u8[7] = 0x12;
break;
case 1:
LEAF_1D4.data.u8[4] = 0x47;
LEAF_1D4.data.u8[7] = 0xD5;
break;
case 2:
LEAF_1D4.data.u8[4] = 0x87;
LEAF_1D4.data.u8[7] = 0x19;
break;
case 3:
LEAF_1D4.data.u8[4] = 0xC7;
LEAF_1D4.data.u8[7] = 0xDE;
break;
}
ESP32Can.CANWriteFrame(&LEAF_1D4);

mprun10++;
if (mprun10 > 3) {
mprun10 = 0;
}

switch (mprun10r) {
case (0):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x00;
LEAF_1F2.data.u8[7] = 0x8F;
break;
case (1):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x01;
LEAF_1F2.data.u8[7] = 0x80;
break;
case (2):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x02;
LEAF_1F2.data.u8[7] = 0x81;
break;
case (3):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x03;
LEAF_1F2.data.u8[7] = 0x82;
break;
case (4):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x00;
LEAF_1F2.data.u8[7] = 0x8F;
break;
Expand All @@ -766,22 +795,18 @@ void send_can_leaf_battery() {
LEAF_1F2.data.u8[7] = 0x84;
break;
case (6):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x02;
LEAF_1F2.data.u8[7] = 0x85;
break;
case (7):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x03;
LEAF_1F2.data.u8[7] = 0x86;
break;
case (8):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x00;
LEAF_1F2.data.u8[7] = 0x83;
break;
case (9):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x01;
LEAF_1F2.data.u8[7] = 0x84;
break;
Expand All @@ -791,22 +816,18 @@ void send_can_leaf_battery() {
LEAF_1F2.data.u8[7] = 0x81;
break;
case (11):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x03;
LEAF_1F2.data.u8[7] = 0x82;
break;
case (12):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x00;
LEAF_1F2.data.u8[7] = 0x8F;
break;
case (13):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x01;
LEAF_1F2.data.u8[7] = 0x80;
break;
case (14):
LEAF_1F2.data.u8[3] = 0xB0;
LEAF_1F2.data.u8[6] = 0x02;
LEAF_1F2.data.u8[7] = 0x81;
break;
Expand All @@ -816,22 +837,18 @@ void send_can_leaf_battery() {
LEAF_1F2.data.u8[7] = 0x86;
break;
case (16):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x00;
LEAF_1F2.data.u8[7] = 0x83;
break;
case (17):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x01;
LEAF_1F2.data.u8[7] = 0x84;
break;
case (18):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x02;
LEAF_1F2.data.u8[7] = 0x85;
break;
case (19):
LEAF_1F2.data.u8[3] = 0xB4;
LEAF_1F2.data.u8[6] = 0x03;
LEAF_1F2.data.u8[7] = 0x86;
break;
Expand All @@ -841,24 +858,18 @@ void send_can_leaf_battery() {

ESP32Can.CANWriteFrame(&LEAF_1F2); //Contains (CHG_STA_RQ == 1 == Normal Charge)

mprun10r++;
if (mprun10r > 19) { // 0x1F2 patter repeats after 20 messages,
mprun10r = 0;
}
mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0

mprun10 = (mprun10 + 1) % 4; // mprun10 cycles between 0-1-2-3-0-1...
}
//Send 10s CAN messages
if (currentMillis - previousMillis10s >= interval10s) {
previousMillis10s = currentMillis;

//Every 10s, ask diagnostic data from the battery. Don't ask if someone is already polling on the bus (Leafspy?)
if (!stop_battery_query) {
if (group == 1) { // Cycle between group 1, 2, and 4 using bit manipulation
group = 2;
} else if (group == 2) {
group = 4;
} else if (group == 4) {
group = 1;
}
group = (group == 1) ? 2 : (group == 2) ? 4 : 1;
// Cycle between group 1, 2, and 4 using ternary operation
LEAF_GROUP_REQUEST.data.u8[2] = group;
ESP32Can.CANWriteFrame(&LEAF_GROUP_REQUEST);
}
Expand Down
Loading

0 comments on commit 38524e2

Please sign in to comment.