Add BMW i3 CAN mappings from DBC

This commit is contained in:
Daniel 2023-08-02 22:21:06 +03:00
parent 5bbc1669cb
commit b373a15ea1
2 changed files with 108 additions and 21 deletions

View file

@ -2,6 +2,10 @@
#include "ESP32CAN.h" #include "ESP32CAN.h"
#include "CAN_config.h" #include "CAN_config.h"
//TODO before using
// Map the final values in update_values_i3_battery, set some to static values if not available (current, discharge max , charge max)
// Check if I3 battery stays alive with only 10B and 512. If not, add 12F. If that doesn't help, add more from CAN log (ask Dala)
/* 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 previousMillis20 = 0; // will store last time a 20ms CAN Message was send static unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send
static unsigned long previousMillis600 = 0; // will store last time a 600ms CAN Message was send static unsigned long previousMillis600 = 0; // will store last time a 600ms CAN Message was send
@ -13,55 +17,103 @@ static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Inverter #define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Inverter
CAN_frame_t BMW_10B = {.FIR = {.B = {.DLC = 3,.FF = CAN_frame_std,}},.MsgID = 0x10B,.data = {0xCD, 0x01, 0xFC}}; CAN_frame_t BMW_10B = {.FIR = {.B = {.DLC = 3,.FF = CAN_frame_std,}},.MsgID = 0x10B,.data = {0xCD, 0x01, 0xFC}};
CAN_frame_t BMW_512 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x512,.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12}}; CAN_frame_t BMW_512 = {.FIR = {.B = {.DLC = 8,.FF = CAN_frame_std,}},.MsgID = 0x512,.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12}}; //0x512 Network management edme VCU
//CAN_frame_t BMW_12F //Might be needed, Wake up ,VCU 100ms
//These CAN messages need to be sent towards the battery to keep it alive //These CAN messages need to be sent towards the battery to keep it alive
static const uint8_t BMW_10B_0[15] = {0xCD,0x19,0x94,0x6D,0xE0,0x34,0x78,0xDB,0x97,0x43,0x0F,0xF6,0xBA,0x6E,0x81}; static const uint8_t BMW_10B_0[15] = {0xCD,0x19,0x94,0x6D,0xE0,0x34,0x78,0xDB,0x97,0x43,0x0F,0xF6,0xBA,0x6E,0x81};
static const uint8_t BMW_10B_1[15] = {0x01,0x02,0x33,0x34,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x00}; static const uint8_t BMW_10B_1[15] = {0x01,0x02,0x33,0x34,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x00};
static uint8_t BMW_10B_counter = 0; static uint8_t BMW_10B_counter = 0;
static int16_t Battery_Current = 0;
static int BMS_SOC = 0; static uint16_t Battery_Capacity_kWh = 0;
static uint16_t Voltage_Setpoint = 0;
static uint16_t Low_SOC = 0;
static uint16_t High_SOC = 0;
static uint16_t Display_SOC = 0;
static uint16_t Calculated_SOC = 0;
static uint16_t Battery_Volts = 0;
static uint16_t HVBatt_SOC = 0;
static uint16_t Battery_Status = 0;
static uint16_t DC_link = 0;
static int16_t Battery_Power = 0;
void update_values_i3_battery() void update_values_i3_battery()
{ //This function maps all the values fetched via CAN to the correct parameters used for modbus { //This function maps all the values fetched via CAN to the correct parameters used for modbus
bms_status = ACTIVE; //Startout in active mode bms_status = ACTIVE; //Startout in active mode
SOC; //Calculate the SOC% value to send to inverter
Calculated_SOC = (Display_SOC * 10); //Increase decimal amount
Calculated_SOC = LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (Calculated_SOC - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE);
if (Calculated_SOC < 0)
{ //We are in the real SOC% range of 0-20%, always set SOC sent to inverter as 0%
Calculated_SOC = 0;
}
if (Calculated_SOC > 1000)
{ //We are in the real SOC% range of 80-100%, always set SOC sent to inverter as 100%
Calculated_SOC = 1000;
}
SOC = (Calculated_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
battery_voltage; battery_voltage = Battery_Volts; //Unit V+1 (5000 = 500.0V)
battery_current; battery_current = Battery_Current;
capacity_Wh = BATTERY_WH_MAX; capacity_Wh = BATTERY_WH_MAX;
remaining_capacity_Wh; remaining_capacity_Wh = (Battery_Capacity_kWh * 1000);
max_target_discharge_power; if(SOC > 9900) //If Soc is over 99%, stop charging
{
max_target_charge_power = 0;
}
else
{
max_target_charge_power = 5000; //Hardcoded value for testing. TODO, read real value from battery when discovered
}
max_target_charge_power; if(SOC < 500) //If Soc is under 5%, stop dicharging
{
max_target_discharge_power = 0;
}
else
{
max_target_discharge_power = 5000; //Hardcoded value for testing. TODO, read real value from battery when discovered
}
stat_batt_power; Battery_Power = (Battery_Current * (Battery_Volts/10));
temperature_min; stat_batt_power = Battery_Power; //TODO, is mapping OK?
temperature_min; //hardcoded to 5*C in startup, TODO, find from battery CAN later
temperature_max; temperature_max; //hardcoded to 6*C in startup, TODO, find from battery CAN later
/* 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(!CANstillAlive)
{ {
bms_status = FAULT; bms_status = FAULT;
Serial.println("No CAN communication detected for 60s. Shutting down battery control."); Serial.println("No CAN communication detected for 60s. Shutting down battery control.");
} }
else else
{ {
CANstillAlive--; CANstillAlive--;
} }
if(printValues) if(printValues)
{ //values heading towards the inverter { //values heading towards the inverter
Serial.print("SOC%: "); Serial.print("SOC% battery: ");
Serial.println(BMS_SOC); Serial.print(Display_SOC);
Serial.print(" SOC% sent to inverter: ");
Serial.print(SOC);
Serial.print(" Battery voltage: ");
Serial.print(battery_voltage);
Serial.print(" Remaining Wh: ");
Serial.print(remaining_capacity_Wh);
Serial.print(" Max charge power: ");
Serial.print(max_target_charge_power);
Serial.print(" Max discharge power: ");
Serial.print(max_target_discharge_power);
} }
} }
@ -70,9 +122,44 @@ void receive_can_i3_battery(CAN_frame_t rx_frame)
CANstillAlive = 12; CANstillAlive = 12;
switch (rx_frame.MsgID) switch (rx_frame.MsgID)
{ {
case 0x431: //Battery capacity case 0x431: //Battery capacity [200ms]
Battery_Capacity_kWh = (((rx_frame.data.u8[1] & 0x0F) << 8 | rx_frame.data.u8[5])) / 50;
break; break;
case 0x432: //SOC% charged case 0x432: //SOC% charged [200ms]
Voltage_Setpoint = ((rx_frame.data.u8[1] << 4 | rx_frame.data.u8[0] >> 4)) / 10;
Low_SOC = (rx_frame.data.u8[2] / 2);
High_SOC = (rx_frame.data.u8[3] / 2);
Display_SOC = (rx_frame.data.u8[4] / 2);
break;
case 0x112: //BMS status [10ms]
CANstillAlive = 12;
Battery_Current = ((rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]) / 10) - 819; //Amps
Battery_Volts = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); //500.0 V
HVBatt_SOC = ((rx_frame.data.u8[5] & 0x0F) << 4 | rx_frame.data.u8[4]) / 10;
Battery_Status = (rx_frame.data.u8[6] & 0x0F);
DC_link = rx_frame.data.u8[7];
break;
case 0x430:
break;
case 0x1FA:
break;
case 0x40D:
break;
case 0x2FF:
break;
case 0x239:
break;
case 0x2BD:
break;
case 0x2F5:
break;
case 0x3EB:
break;
case 0x363:
break;
case 0x507:
break;
case 0x41C:
break; break;
default: default:
break; break;

View file

@ -1,8 +1,8 @@
/* Select battery used */ /* Select battery used */
//#define BATTERY_TYPE_LEAF // See NISSAN-LEAF-BATTERY.h for more LEAF battery settings #define BATTERY_TYPE_LEAF // See NISSAN-LEAF-BATTERY.h for more LEAF battery settings
//#define TESLA_MODEL_3_BATTERY // See TESLA-MODEL-3-BATTERY.h for more Tesla battery settings //#define TESLA_MODEL_3_BATTERY // See TESLA-MODEL-3-BATTERY.h for more Tesla battery settings
//#define RENAULT_ZOE_BATTERY // See RENAULT-ZOE-BATTERY.h for more Zoe battery settings //#define RENAULT_ZOE_BATTERY // See RENAULT-ZOE-BATTERY.h for more Zoe battery settings
#define BMW_I3_BATTERY // See BMW-I3-BATTERY.h for more i3 battery settings //#define BMW_I3_BATTERY // See BMW-I3-BATTERY.h for more i3 battery settings
//#define IMIEV_ION_CZERO_BATTERY // See IMIEV-CZERO-ION-BATTERY.h for more triplet battery settings //#define IMIEV_ION_CZERO_BATTERY // See IMIEV-CZERO-ION-BATTERY.h for more triplet battery settings
//#define KIA_HYUNDAI_64_BATTERY // See KIA-HYUNDAI-64-BATTERY.h for more battery settings //#define KIA_HYUNDAI_64_BATTERY // See KIA-HYUNDAI-64-BATTERY.h for more battery settings
//#define CHADEMO // See CHADEMO.h for more Chademo related settings //#define CHADEMO // See CHADEMO.h for more Chademo related settings