Skip to content

Commit

Permalink
Fixes from GKOE testing
Browse files Browse the repository at this point in the history
  • Loading branch information
dalathegreat committed Nov 19, 2023
1 parent 179b8ee commit 0f687b8
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 79 deletions.
245 changes: 181 additions & 64 deletions Software/src/battery/RENAULT-ZOE-BATTERY.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"

/* Do not change code below unless you are sure what you are doing */
#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Fronius
#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Fronius
const int rx_queue_size = 10; // Receive Queue size
#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Fronius
#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Fronius

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 int16_t LB_SOC = 0;
static int16_t LB_SOH = 0;
static uint16_t LB_SOC = 0;
static uint16_t soc_calculated = 0;
static uint16_t LB_SOH = 0;
static int16_t LB_MIN_TEMPERATURE = 0;
static int16_t LB_MAX_TEMPERATURE = 0;
static uint16_t LB_Discharge_Power_Limit = 0;
static uint32_t LB_Discharge_Power_Limit_Watts = 0;
static uint16_t LB_Charge_Power_Limit = 0;
static uint32_t LB_Charge_Power_Limit_Watts = 0;
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;
static bool GVB_79B_Continue = false;
static uint8_t GVI_Pollcounter = 0;

CAN_frame_t ZOE_423 = {.FIR = {.B =
{
Expand All @@ -24,32 +34,53 @@ CAN_frame_t ZOE_423 = {.FIR = {.B =
}},
.MsgID = 0x423,
.data = {0x33, 0x00, 0xFF, 0xFF, 0x00, 0xE0, 0x00, 0x00}};
CAN_frame_t ZOE_79B = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_std,
}},
.MsgID = 0x79B,
.data = {0x02, 0x21, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00}};
CAN_frame_t ZOE_79B_Continue = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_std,
}},
.MsgID = 0x79B,
.data = {0x030, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};

static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
static const int interval10 = 10; // interval (ms) at which send CAN Messages
static const int interval100 = 100; // interval (ms) at which send CAN Messages
static int BMSPollCounter = 0;
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
static unsigned long GVL_pause = 0;
static const int interval10 = 10; // interval (ms) at which send CAN Messages
static const int interval100 = 100; // interval (ms) at which send CAN Messages
static const int interval1000 = 1000; // interval (ms) at which send CAN Messages

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

StateOfHealth = (LB_SOH * 100); //Increase range from 99% -> 99.00%

//Calculate the SOC% value to send to Fronius
LB_SOC = LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (LB_SOC - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE);
if (LB_SOC < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Fronius as 0%
LB_SOC = 0;
soc_calculated = LB_SOC;
soc_calculated =
LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (soc_calculated - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE);
if (soc_calculated < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Inverter as 0%
soc_calculated = 0;
}
if (LB_SOC > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Fronius as 100%
LB_SOC = 1000;
if (soc_calculated > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Inverter as 100%
soc_calculated = 1000;
}
SOC = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
SOC = (soc_calculated * 10); //increase LB_SOC range from 0-100.0 -> 100.00

battery_voltage = LB_Battery_Voltage;

battery_voltage;
battery_current;
capacity_Wh = BATTERY_WH_MAX;
remaining_capacity_Wh;
battery_current = LB_Current;

capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value

remaining_capacity_Wh = (uint16_t)((SOC / 10000) * capacity_Wh);

LB_Discharge_Power_Limit_Watts = (LB_Discharge_Power_Limit * 500); //Convert value fetched from battery to watts
/* Define power able to be discharged from battery */
Expand Down Expand Up @@ -80,6 +111,18 @@ void update_values_zoe_battery() { //This function maps all the values fetched
max_target_charge_power = 0; //No need to charge further, set max power to 0
}

stat_batt_power = (battery_voltage * LB_Current); //TODO: check if scaling is OK

temperature_min = convert2uint16(LB_MIN_TEMPERATURE * 10);

temperature_max = convert2uint16(LB_MAX_TEMPERATURE * 10);

cell_min_voltage = LB_Cell_Min_Voltage;

cell_max_voltage = LB_Cell_Max_Voltage;

cell_deviation_mV = (cell_max_voltage - cell_min_voltage);

/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
bms_status = FAULT;
Expand All @@ -88,70 +131,144 @@ void update_values_zoe_battery() { //This function maps all the values fetched
CANstillAlive--;
}

stat_batt_power;
temperature_min;
temperature_max;
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
bms_status = FAULT;
Serial.println("ERROR: CELL OVERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
}
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
bms_status = FAULT;
Serial.println("ERROR: CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
}
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
LEDcolor = YELLOW;
Serial.println("ERROR: HIGH CELL mV DEVIATION!!! Inspect battery!");
}

#ifdef DEBUG_VIA_USB
Serial.print("BMS Status (3=OK): ");
Serial.println(bms_status);
Serial.print("Max discharge power: ");
Serial.println(max_target_discharge_power);
Serial.print("Max charge power: ");
Serial.println(max_target_charge_power);
Serial.println("Values going to inverter:");
Serial.print("SOH%: ");
Serial.println(LB_SOH);
Serial.print("SOH% to Fronius: ");
Serial.println(StateOfHealth);
Serial.print("LB_SOC: ");
Serial.println(LB_SOC);
Serial.print("SOC% to Fronius: ");
Serial.println(SOC);
Serial.print("Temperature Min: ");
Serial.println(temperature_min);
Serial.print("Temperature Max: ");
Serial.println(temperature_max);
Serial.print(StateOfHealth);
Serial.print(", SOC% scaled: ");
Serial.print(SOC);
Serial.print(", Voltage: ");
Serial.print(battery_voltage);
Serial.print(", Max discharge power: ");
Serial.print(max_target_discharge_power);
Serial.print(", Max charge power: ");
Serial.print(max_target_charge_power);
Serial.print(", Max temp: ");
Serial.print(temperature_max);
Serial.print(", Min temp: ");
Serial.print(temperature_min);
Serial.print(", BMS Status (3=OK): ");
Serial.print(bms_status);

Serial.println("Battery values: ");
Serial.print("Real SOC: ");
Serial.print(LB_SOC);
Serial.print(", Current: ");
Serial.print(LB_Current);
Serial.print(", kWh remain: ");
Serial.print(LB_kWh_Remaining);
Serial.print(", max mV: ");
Serial.print(LB_Cell_Max_Voltage);
Serial.print(", min mV: ");
Serial.print(LB_Cell_Min_Voltage);

#endif
}

void receive_can_zoe_battery(CAN_frame_t rx_frame) {
void receive_can_zoe_battery(CAN_frame_t rx_frame) //GKOE reworked
{

switch (rx_frame.MsgID) {
case 0x155: //BMS1
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS
//LB_Max_Charge_Amps =
//LB_Current = (((rx_frame.data.u8[1] & 0xF8) << 5) | (rx_frame.data.u8[2]));
LB_SOC = ((rx_frame.data.u8[4] << 8) | (rx_frame.data.u8[5]));
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
LB_Charge_Power_Limit = (rx_frame.data.u8[2]);
LB_Discharge_Power_Limit = (rx_frame.data.u8[3]);

case 0x424: //BMS2
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS
LB_SOH = (rx_frame.data.u8[5]);
LB_MIN_TEMPERATURE = ((rx_frame.data.u8[4] & 0x7F) - 40);
LB_MAX_TEMPERATURE = ((rx_frame.data.u8[7] & 0x7F) - 40);
LB_MIN_TEMPERATURE = ((rx_frame.data.u8[4]) - 40); //OK!
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
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
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!

if ((LB_Cell_Max_Voltage == 6110) or (LB_Cell_Min_Voltage == 6110)) { //Read Error
LB_Cell_Max_Voltage = 3880;
LB_Cell_Min_Voltage = 3880;
break;
}

// LB_Battery_Voltage = (LB_Cell_Max_Voltage * 80 + LB_Cell_Min_Voltage * 20) / 100 * 96; // GKOE just as long as we don't have the real pack voltage... ?
break;
case 0x425: //BMS3 (could also be 445?)
//LB_kWh_Remaining =
//LB_Cell_Max_Voltage =
//LB_Cell_Min_Voltage =
case 0x7BB:
CANstillAlive = 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;
}
if (rx_frame.data.u8[0] == 0x21) { //2nd response Bytes 8-15
GVB_79B_Continue = true;
}
if (rx_frame.data.u8[0] == 0x22) { //3rd response Bytes 16-23
GVB_79B_Continue = true;
}
if (rx_frame.data.u8[0] == 0x23) { //4th response Bytes 16-23
LB_Charge_Power_Limit = word(rx_frame.data.u8[5], rx_frame.data.u8[6]) * 100; //OK!
LB_Discharge_Power_Limit_Byte1 = rx_frame.data.u8[7];
GVB_79B_Continue = true;
}
if (rx_frame.data.u8[0] == 0x24) { //5th response Bytes 24-31
LB_Discharge_Power_Limit = word(LB_Discharge_Power_Limit_Byte1, rx_frame.data.u8[1]) * 100; //OK!
LB_Battery_Voltage = word(rx_frame.data.u8[2], rx_frame.data.u8[3]) * 10; //OK!
GVB_79B_Continue = false;
}
break;
default:
break;
}
}

void send_can_zoe_battery() {
unsigned long currentMillis = millis();
// Send 100ms CAN Message
if (currentMillis - previousMillis100 >= interval100) {
// Send 100ms CAN Message (for 2.4s, then pause 10s)
if ((currentMillis - previousMillis100) >= (interval100 + GVL_pause)) {
previousMillis100 = currentMillis;
BMSPollCounter++; //GKOE

if (BMSPollCounter < 46) //GKOE
{ //The Kangoo batteries (also Zoe?) dont like getting this message continously, so we pause after 4.6s, and resume after 40s
ESP32Can.CANWriteFrame(&ZOE_423); //Send 0x423 to keep BMS happy
}
if (BMSPollCounter > 400) //GKOE
{
BMSPollCounter = 0;
ESP32Can.CANWriteFrame(&ZOE_423);
GVI_Pollcounter++;
GVL_pause = 0;
if (GVI_Pollcounter >= 24) {
GVI_Pollcounter = 0;
GVL_pause = 10000;
}
}
// 1000ms CAN handling
if (currentMillis - previousMillis1000 >= interval1000) {
previousMillis1000 = currentMillis;
if (GVB_79B_Continue)
ESP32Can.CANWriteFrame(&ZOE_79B_Continue);
} else {
ESP32Can.CANWriteFrame(&ZOE_79B);
}
}

uint16_t convert2uint16(int16_t signed_value) {
if (signed_value < 0) {
return (65535 + signed_value);
} else {
return (uint16_t)signed_value;
}
}
39 changes: 24 additions & 15 deletions Software/src/battery/RENAULT-ZOE-BATTERY.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,36 @@
#define RENAULT_ZOE_BATTERY_H
#include <Arduino.h>
#include "../../USER_SETTINGS.h"
#include "../devboard/config.h" // Needed for LED defines
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"

#define ABSOLUTE_MAX_VOLTAGE \
4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge)
#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled
#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

// These parameters need to be mapped for the Gen24
extern uint16_t SOC;
extern uint16_t StateOfHealth;
extern uint16_t battery_voltage;
extern uint16_t battery_current;
extern uint16_t capacity_Wh;
extern uint16_t remaining_capacity_Wh;
extern uint16_t max_target_discharge_power;
extern uint16_t max_target_charge_power;
extern uint16_t bms_status;
extern uint16_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;
extern uint16_t temperature_max;
extern uint16_t CANerror;
extern uint16_t SOC; //SOC%, 0-100.00 (0-10000)
extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000)
extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000)
extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485)
extern uint16_t capacity_Wh; //Wh, 0-60000
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
extern uint16_t max_target_discharge_power; //W, 0-60000
extern uint16_t max_target_charge_power; //W, 0-60000
extern uint16_t bms_status; //Enum, 0-5
extern uint16_t bms_char_dis_status; //Enum, 0-2
extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530)
extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
extern uint16_t cell_max_voltage; //mV, 0-4350
extern uint16_t cell_min_voltage; //mV, 0-4350
extern uint8_t LEDcolor; //Enum, 0-10
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
// Definitions for BMS status
#define STANDBY 0
#define INACTIVE 1
Expand All @@ -34,6 +43,6 @@ extern uint16_t CANerror;
void update_values_zoe_battery();
void receive_can_zoe_battery(CAN_frame_t rx_frame);
void send_can_zoe_battery();
uint16_t convert2unsignedint16(uint16_t signed_value);
uint16_t convert2uint16(int16_t signed_value);

#endif

0 comments on commit 0f687b8

Please sign in to comment.