mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Separate Zoe and Kangoo
This commit is contained in:
parent
10a5d5e81c
commit
958ddde672
10 changed files with 370 additions and 131 deletions
1
.github/workflows/compile-all-batteries.yml
vendored
1
.github/workflows/compile-all-batteries.yml
vendored
|
@ -38,6 +38,7 @@ jobs:
|
||||||
- IMIEV_CZERO_ION_BATTERY
|
- IMIEV_CZERO_ION_BATTERY
|
||||||
- KIA_HYUNDAI_64_BATTERY
|
- KIA_HYUNDAI_64_BATTERY
|
||||||
- NISSAN_LEAF_BATTERY
|
- NISSAN_LEAF_BATTERY
|
||||||
|
- RENAULT_KANGOO_BATTERY
|
||||||
- RENAULT_ZOE_BATTERY
|
- RENAULT_ZOE_BATTERY
|
||||||
- TESLA_MODEL_3_BATTERY
|
- TESLA_MODEL_3_BATTERY
|
||||||
- TEST_FAKE_BATTERY
|
- TEST_FAKE_BATTERY
|
||||||
|
|
|
@ -41,6 +41,7 @@ jobs:
|
||||||
- IMIEV_CZERO_ION_BATTERY
|
- IMIEV_CZERO_ION_BATTERY
|
||||||
- KIA_HYUNDAI_64_BATTERY
|
- KIA_HYUNDAI_64_BATTERY
|
||||||
- NISSAN_LEAF_BATTERY
|
- NISSAN_LEAF_BATTERY
|
||||||
|
- RENAULT_KANGOO_BATTERY
|
||||||
- RENAULT_ZOE_BATTERY
|
- RENAULT_ZOE_BATTERY
|
||||||
- TESLA_MODEL_3_BATTERY
|
- TESLA_MODEL_3_BATTERY
|
||||||
- TEST_FAKE_BATTERY
|
- TEST_FAKE_BATTERY
|
||||||
|
|
|
@ -304,8 +304,11 @@ void inform_user_on_battery() {
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
Serial.println("Nissan LEAF battery selected");
|
Serial.println("Nissan LEAF battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
Serial.println("Renault Kangoo battery selected");
|
||||||
|
#endif
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
Serial.println("Renault Zoe / Kangoo battery selected");
|
Serial.println("Renault Zoe battery selected");
|
||||||
#endif
|
#endif
|
||||||
#ifdef TESLA_MODEL_3_BATTERY
|
#ifdef TESLA_MODEL_3_BATTERY
|
||||||
Serial.println("Tesla Model 3 battery selected");
|
Serial.println("Tesla Model 3 battery selected");
|
||||||
|
@ -344,6 +347,9 @@ void receive_can() { // This section checks if we have a complete CAN message i
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
receive_can_leaf_battery(rx_frame);
|
receive_can_leaf_battery(rx_frame);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
receive_can_kangoo_battery(rx_frame);
|
||||||
|
#endif
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
receive_can_zoe_battery(rx_frame);
|
receive_can_zoe_battery(rx_frame);
|
||||||
#endif
|
#endif
|
||||||
|
@ -403,6 +409,9 @@ void send_can() {
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
send_can_leaf_battery();
|
send_can_leaf_battery();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
send_can_kangoo_battery();
|
||||||
|
#endif
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
send_can_zoe_battery();
|
send_can_zoe_battery();
|
||||||
#endif
|
#endif
|
||||||
|
@ -600,6 +609,9 @@ void update_values() {
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
update_values_leaf_battery(); // Map the values to the correct registers
|
update_values_leaf_battery(); // Map the values to the correct registers
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
update_values_kangoo_battery(); // Map the values to the correct registers
|
||||||
|
#endif
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
update_values_zoe_battery(); // Map the values to the correct registers
|
update_values_zoe_battery(); // Map the values to the correct registers
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//#define IMIEV_CZERO_ION_BATTERY
|
//#define IMIEV_CZERO_ION_BATTERY
|
||||||
//#define KIA_HYUNDAI_64_BATTERY
|
//#define KIA_HYUNDAI_64_BATTERY
|
||||||
//#define NISSAN_LEAF_BATTERY
|
//#define NISSAN_LEAF_BATTERY
|
||||||
|
//#define RENAULT_KANGOO_BATTERY
|
||||||
//#define RENAULT_ZOE_BATTERY
|
//#define RENAULT_ZOE_BATTERY
|
||||||
//#define TESLA_MODEL_3_BATTERY
|
//#define TESLA_MODEL_3_BATTERY
|
||||||
//#define TEST_FAKE_BATTERY
|
//#define TEST_FAKE_BATTERY
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
#include "NISSAN-LEAF-BATTERY.h" //See this file for more LEAF battery settings
|
#include "NISSAN-LEAF-BATTERY.h" //See this file for more LEAF battery settings
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
#include "RENAULT-KANGOO-BATTERY.h" //See this file for more Kangoo battery settings
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
#include "RENAULT-ZOE-BATTERY.h" //See this file for more Zoe battery settings
|
#include "RENAULT-ZOE-BATTERY.h" //See this file for more Zoe battery settings
|
||||||
#endif
|
#endif
|
||||||
|
|
273
Software/src/battery/RENAULT-KANGOO-BATTERY.cpp
Normal file
273
Software/src/battery/RENAULT-KANGOO-BATTERY.cpp
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#include "RENAULT-KANGOO-BATTERY.h"
|
||||||
|
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t LB_Battery_Voltage = 3700;
|
||||||
|
static uint32_t LB_Charge_Power_Limit_Watts = 0;
|
||||||
|
static uint32_t LB_Discharge_Power_Limit_Watts = 0;
|
||||||
|
static int32_t LB_Current = 0;
|
||||||
|
static int16_t LB_MAX_TEMPERATURE = 0;
|
||||||
|
static int16_t LB_MIN_TEMPERATURE = 0;
|
||||||
|
static uint16_t soc_calculated = 0;
|
||||||
|
static uint16_t LB_SOC = 0;
|
||||||
|
static uint16_t LB_SOH = 0;
|
||||||
|
static uint16_t LB_Discharge_Power_Limit = 0;
|
||||||
|
static uint16_t LB_Charge_Power_Limit = 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 uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
||||||
|
static uint8_t LB_Discharge_Power_Limit_Byte1 = 0;
|
||||||
|
static uint8_t GVI_Pollcounter = 0;
|
||||||
|
static bool GVB_79B_Continue = false;
|
||||||
|
|
||||||
|
|
||||||
|
CAN_frame_t KANGOO_423 = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x423,
|
||||||
|
.data = {0x33, 0x00, 0xFF, 0xFF, 0x00, 0xE0, 0x00, 0x00}};
|
||||||
|
CAN_frame_t KANGOO_79B = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x79B,
|
||||||
|
.data = {0x02, 0x21, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00}};
|
||||||
|
CAN_frame_t KANGOO_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 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_kangoo_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
|
||||||
|
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 (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 = (soc_calculated * 10); //increase LB_SOC range from 0-100.0 -> 100.00
|
||||||
|
|
||||||
|
battery_voltage = LB_Battery_Voltage;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
if (LB_Discharge_Power_Limit_Watts > 30000) //if >30kW can be pulled from battery
|
||||||
|
{
|
||||||
|
max_target_discharge_power = 30000; //cap value so we don't go over the Fronius limits
|
||||||
|
} else {
|
||||||
|
max_target_discharge_power = LB_Discharge_Power_Limit_Watts;
|
||||||
|
}
|
||||||
|
if (SOC == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further
|
||||||
|
{
|
||||||
|
max_target_discharge_power = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LB_Charge_Power_Limit_Watts = (LB_Charge_Power_Limit * 500); //Convert value fetched from battery to watts
|
||||||
|
/* Define power able to be put into the battery */
|
||||||
|
if (LB_Charge_Power_Limit_Watts > 30000) //if >30kW can be put into the battery
|
||||||
|
{
|
||||||
|
max_target_charge_power = 30000; //cap value so we don't go over the Fronius limits
|
||||||
|
}
|
||||||
|
if (LB_Charge_Power_Limit_Watts < 0) {
|
||||||
|
max_target_charge_power = 0; //cap calue so we dont do under the Fronius limits
|
||||||
|
} else {
|
||||||
|
max_target_charge_power = LB_Charge_Power_Limit_Watts;
|
||||||
|
}
|
||||||
|
if (SOC == 10000) //Scaled SOC% value is 100.00%
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
Serial.println("No CAN communication detected for 60s. Shutting down battery control.");
|
||||||
|
} else {
|
||||||
|
CANstillAlive--;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.println("Values going to inverter:");
|
||||||
|
Serial.print("SOH%: ");
|
||||||
|
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_kangoo_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_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
|
||||||
|
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]) - 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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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_kangoo_battery() {
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
// Send 100ms CAN Message (for 2.4s, then pause 10s)
|
||||||
|
if ((currentMillis - previousMillis100) >= (interval100 + GVL_pause)) {
|
||||||
|
previousMillis100 = currentMillis;
|
||||||
|
ESP32Can.CANWriteFrame(&KANGOO_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(&KANGOO_79B_Continue);
|
||||||
|
} else {
|
||||||
|
ESP32Can.CANWriteFrame(&KANGOO_79B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t convert2uint16(int16_t signed_value) {
|
||||||
|
if (signed_value < 0) {
|
||||||
|
return (65535 + signed_value);
|
||||||
|
} else {
|
||||||
|
return (uint16_t)signed_value;
|
||||||
|
}
|
||||||
|
}
|
51
Software/src/battery/RENAULT-KANGOO-BATTERY.h
Normal file
51
Software/src/battery/RENAULT-KANGOO-BATTERY.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef RENAULT_KANGOO_BATTERY_H
|
||||||
|
#define RENAULT_KANGOO_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; //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 uint16_t CANerror;
|
||||||
|
extern uint8_t LEDcolor; //Enum, 0-10
|
||||||
|
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||||
|
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||||
|
|
||||||
|
// Definitions for BMS status
|
||||||
|
#define STANDBY 0
|
||||||
|
#define INACTIVE 1
|
||||||
|
#define DARKSTART 2
|
||||||
|
#define ACTIVE 3
|
||||||
|
#define FAULT 4
|
||||||
|
#define UPDATING 5
|
||||||
|
|
||||||
|
void update_values_kangoo_battery();
|
||||||
|
void receive_can_kangoo_battery(CAN_frame_t rx_frame);
|
||||||
|
void send_can_kangoo_battery();
|
||||||
|
uint16_t convert2uint16(int16_t signed_value);
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
|
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 uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
|
||||||
static uint16_t LB_SOC = 0;
|
static uint16_t LB_SOC = 50;
|
||||||
static uint16_t soc_calculated = 0;
|
static uint16_t soc_calculated = 0;
|
||||||
static uint16_t LB_SOH = 0;
|
static uint16_t LB_SOH = 99;
|
||||||
static int16_t LB_MIN_TEMPERATURE = 0;
|
static int16_t LB_MIN_TEMPERATURE = 0;
|
||||||
static int16_t LB_MAX_TEMPERATURE = 0;
|
static int16_t LB_MAX_TEMPERATURE = 0;
|
||||||
static uint16_t LB_Discharge_Power_Limit = 0;
|
static uint16_t LB_Discharge_Power_Limit = 0;
|
||||||
|
@ -24,8 +24,6 @@ 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 uint16_t cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
|
||||||
static uint32_t LB_Battery_Voltage = 3700;
|
static uint32_t LB_Battery_Voltage = 3700;
|
||||||
static uint8_t LB_Discharge_Power_Limit_Byte1 = 0;
|
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 =
|
CAN_frame_t ZOE_423 = {.FIR = {.B =
|
||||||
{
|
{
|
||||||
|
@ -34,20 +32,6 @@ CAN_frame_t ZOE_423 = {.FIR = {.B =
|
||||||
}},
|
}},
|
||||||
.MsgID = 0x423,
|
.MsgID = 0x423,
|
||||||
.data = {0x33, 0x00, 0xFF, 0xFF, 0x00, 0xE0, 0x00, 0x00}};
|
.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 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 previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||||
|
@ -78,48 +62,24 @@ void update_values_zoe_battery() { //This function maps all the values fetched
|
||||||
|
|
||||||
battery_current = LB_Current;
|
battery_current = LB_Current;
|
||||||
|
|
||||||
capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value
|
capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows
|
||||||
|
|
||||||
remaining_capacity_Wh = (uint16_t)((SOC / 10000) * capacity_Wh);
|
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||||
|
remaining_capacity_Wh = static_cast<int>((static_cast<double>(SOC) / 10000) * BATTERY_WH_MAX);
|
||||||
|
|
||||||
LB_Discharge_Power_Limit_Watts = (LB_Discharge_Power_Limit * 500); //Convert value fetched from battery to watts
|
max_target_discharge_power;
|
||||||
/* Define power able to be discharged from battery */
|
|
||||||
if (LB_Discharge_Power_Limit_Watts > 30000) //if >30kW can be pulled from battery
|
|
||||||
{
|
|
||||||
max_target_discharge_power = 30000; //cap value so we don't go over the Fronius limits
|
|
||||||
} else {
|
|
||||||
max_target_discharge_power = LB_Discharge_Power_Limit_Watts;
|
|
||||||
}
|
|
||||||
if (SOC == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further
|
|
||||||
{
|
|
||||||
max_target_discharge_power = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LB_Charge_Power_Limit_Watts = (LB_Charge_Power_Limit * 500); //Convert value fetched from battery to watts
|
max_target_charge_power;
|
||||||
/* Define power able to be put into the battery */
|
|
||||||
if (LB_Charge_Power_Limit_Watts > 30000) //if >30kW can be put into the battery
|
|
||||||
{
|
|
||||||
max_target_charge_power = 30000; //cap value so we don't go over the Fronius limits
|
|
||||||
}
|
|
||||||
if (LB_Charge_Power_Limit_Watts < 0) {
|
|
||||||
max_target_charge_power = 0; //cap calue so we dont do under the Fronius limits
|
|
||||||
} else {
|
|
||||||
max_target_charge_power = LB_Charge_Power_Limit_Watts;
|
|
||||||
}
|
|
||||||
if (SOC == 10000) //Scaled SOC% value is 100.00%
|
|
||||||
{
|
|
||||||
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
|
stat_batt_power;
|
||||||
|
|
||||||
temperature_min = convert2uint16(LB_MIN_TEMPERATURE * 10);
|
temperature_min;
|
||||||
|
|
||||||
temperature_max = convert2uint16(LB_MAX_TEMPERATURE * 10);
|
temperature_max;
|
||||||
|
|
||||||
cell_min_voltage = LB_Cell_Min_Voltage;
|
cell_min_voltage;
|
||||||
|
|
||||||
cell_max_voltage = LB_Cell_Max_Voltage;
|
cell_max_voltage;
|
||||||
|
|
||||||
cell_deviation_mV = (cell_max_voltage - cell_min_voltage);
|
cell_deviation_mV = (cell_max_voltage - cell_min_voltage);
|
||||||
|
|
||||||
|
@ -178,64 +138,15 @@ void update_values_zoe_battery() { //This function maps all the values fetched
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void receive_can_zoe_battery(CAN_frame_t rx_frame) //GKOE reworked
|
void receive_can_zoe_battery(CAN_frame_t rx_frame)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (rx_frame.MsgID) {
|
switch (rx_frame.MsgID) {
|
||||||
case 0x155: //BMS1
|
case 0x42E: //HV SOC & Battery Temp & Charging Power
|
||||||
CANstillAlive = 12; //Indicate that we are still getting CAN messages from the BMS
|
|
||||||
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;
|
break;
|
||||||
|
case 0x430: //HVBatteryCoolingState & HVBatteryEvapTemp & HVBatteryEvapSetpoint
|
||||||
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]) - 40); //OK!
|
|
||||||
LB_MAX_TEMPERATURE = ((rx_frame.data.u8[7]) - 40); //OK!
|
|
||||||
break;
|
break;
|
||||||
|
case 0x432: //BatVEShutDownAlert & HVBatCondPriorityLevel & HVBatteryLevelAlert & HVBatCondPriorityLevel & HVBatteryConditioningMode
|
||||||
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 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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -244,31 +155,14 @@ void receive_can_zoe_battery(CAN_frame_t rx_frame) //GKOE reworked
|
||||||
|
|
||||||
void send_can_zoe_battery() {
|
void send_can_zoe_battery() {
|
||||||
unsigned long currentMillis = millis();
|
unsigned long currentMillis = millis();
|
||||||
// Send 100ms CAN Message (for 2.4s, then pause 10s)
|
// Send 100ms CAN Message
|
||||||
if ((currentMillis - previousMillis100) >= (interval100 + GVL_pause)) {
|
if (currentMillis - previousMillis100 >= interval100){
|
||||||
previousMillis100 = currentMillis;
|
previousMillis100 = currentMillis;
|
||||||
ESP32Can.CANWriteFrame(&ZOE_423);
|
//ESP32Can.CANWriteFrame(&ZOE_423);
|
||||||
GVI_Pollcounter++;
|
|
||||||
GVL_pause = 0;
|
|
||||||
if (GVI_Pollcounter >= 24) {
|
|
||||||
GVI_Pollcounter = 0;
|
|
||||||
GVL_pause = 10000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 1000ms CAN handling
|
// 1000ms CAN handling
|
||||||
if (currentMillis - previousMillis1000 >= interval1000){
|
if (currentMillis - previousMillis1000 >= interval1000){
|
||||||
previousMillis1000 = currentMillis;
|
previousMillis1000 = currentMillis;
|
||||||
if (GVB_79B_Continue)
|
//ESP32Can.CANWriteFrame(&ZOE_423);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,6 +46,5 @@ extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||||
void update_values_zoe_battery();
|
void update_values_zoe_battery();
|
||||||
void receive_can_zoe_battery(CAN_frame_t rx_frame);
|
void receive_can_zoe_battery(CAN_frame_t rx_frame);
|
||||||
void send_can_zoe_battery();
|
void send_can_zoe_battery();
|
||||||
uint16_t convert2uint16(int16_t signed_value);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -207,8 +207,11 @@ String processor(const String& var) {
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
content += "Nissan LEAF";
|
content += "Nissan LEAF";
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
|
content += "Renault Kangoo";
|
||||||
|
#endif
|
||||||
#ifdef RENAULT_ZOE_BATTERY
|
#ifdef RENAULT_ZOE_BATTERY
|
||||||
content += "Renault Zoe / Kangoo";
|
content += "Renault Zoe";
|
||||||
#endif
|
#endif
|
||||||
#ifdef TESLA_MODEL_3_BATTERY
|
#ifdef TESLA_MODEL_3_BATTERY
|
||||||
content += "Tesla Model S/3/X/Y";
|
content += "Tesla Model S/3/X/Y";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue