diff --git a/Software/BMW-I3-BATTERY.cpp b/Software/BMW-I3-BATTERY.cpp index 59b1a809..311c52fd 100644 --- a/Software/BMW-I3-BATTERY.cpp +++ b/Software/BMW-I3-BATTERY.cpp @@ -2,6 +2,10 @@ #include "ESP32CAN.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 */ 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 @@ -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 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 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 uint8_t BMW_10B_counter = 0; - -static int BMS_SOC = 0; +static int16_t Battery_Current = 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() { //This function maps all the values fetched via CAN to the correct parameters used for modbus 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; - 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*/ if(!CANstillAlive) { - bms_status = FAULT; - Serial.println("No CAN communication detected for 60s. Shutting down battery control."); + bms_status = FAULT; + Serial.println("No CAN communication detected for 60s. Shutting down battery control."); } else { - CANstillAlive--; + CANstillAlive--; } if(printValues) { //values heading towards the inverter - Serial.print("SOC%: "); - Serial.println(BMS_SOC); + Serial.print("SOC% battery: "); + 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; 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; - 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; default: break; diff --git a/Software/Software.ino b/Software/Software.ino index cc47e3d4..7b0d61da 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,8 +1,8 @@ /* 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 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 KIA_HYUNDAI_64_BATTERY // See KIA-HYUNDAI-64-BATTERY.h for more battery settings //#define CHADEMO // See CHADEMO.h for more Chademo related settings