From b43c8b98a8cf6ad69e25b32562bca8f051565caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6w?= Date: Mon, 14 Oct 2024 15:58:31 +0200 Subject: [PATCH 1/4] :sparkles: add new battery implementation "Renault Twizy" (first LV battery :rocket:) --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + Software/src/battery/RENAULT-TWIZY.cpp | 142 +++++++++++++++++++++++++ Software/src/battery/RENAULT-TWIZY.h | 12 +++ 4 files changed, 159 insertions(+) create mode 100644 Software/src/battery/RENAULT-TWIZY.cpp create mode 100644 Software/src/battery/RENAULT-TWIZY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 236bbc21..29959d48 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -22,6 +22,7 @@ //#define PYLON_BATTERY //#define RJXZS_BMS //#define RENAULT_KANGOO_BATTERY +#define RENAULT_TWIZY_BATTERY //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SANTA_FE_PHEV_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 4cb112c1..8539c551 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -54,6 +54,10 @@ #include "RENAULT-KANGOO-BATTERY.h" #endif +#ifdef RENAULT_TWIZY_BATTERY +#include "RENAULT-TWIZY.h" +#endif + #ifdef RENAULT_ZOE_GEN1_BATTERY #include "RENAULT-ZOE-GEN1-BATTERY.h" #endif diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp new file mode 100644 index 00000000..e87230aa --- /dev/null +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -0,0 +1,142 @@ +#include "../include.h" +#include +#ifdef RENAULT_TWIZY_BATTERY +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +#include "TWIZY-BATTERY.h" + +/* Do not change code below unless you are sure what you are doing */ + +static int16_t cell_temperatures_dC[8] = { 0 }; +static int16_t current_dA = 0; +static uint16_t voltage_dV = 0; +static int16_t cellvoltages_mV[14] = { 0 }; +static int16_t max_discharge_power = 0; +static int16_t max_recup_power = 0; +static int16_t max_charge_power = 0; +static uint8_t SOC = 0; +static uint8_t SOH = 0; + +// TODO can we use std::max_element for this? Or some other function in Arduino / in this project? +int16_t max_value(int16_t *entries, size_t len) { + int result = INT16_MIN; + for(int i = 0; i < len; i++) { + if(entries[i] > result) + result = entries[i]; + } + + return result; +} +int16_t min_value(int16_t *entries, size_t len) { + int result = INT16_MAX; + for(int i = 0; i < len; i++) { + if(entries[i] < result) + result = entries[i]; + } + + return result; +} + +void update_values_battery() { + + datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 + + datalayer.battery.status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00% + + datalayer.battery.status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0) + + datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign + + datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt + ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); + + // TODO: the twizy provides two values: one for the maximum charge provided by the on-board charger + // and one for the maximum charge during recuperation. + // For now we use the lower of the two (usually the charger one) + datalayer.battery.status.max_charge_power_W = max_charge_power < max_recup_power ? max_charge_power : max_recup_power; + + datalayer.battery.status.max_discharge_power_W = max_discharge_power; + + datalayer.battery.status.cell_min_voltage_mV = min_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); + datalayer.battery.status.cell_max_voltage_mV = max_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); + + datalayer.battery.status.temperature_min_dC = min_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); + datalayer.battery.status.temperature_max_dC = max_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); +} + +void receive_can_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x155: + // current is encoded as a 12 bit integer with Amps = value / 4 - 500 + current_dA = (((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]) & 0xfff) * 10 / 4 - 5000; + + // SOC is encoded as 16 bit integer with SOC% = value / 400 + SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 4; + break; + case 0x424: + max_recup_power = rx_frame.data.u8[2] * 500; + max_discharge_power = rx_frame.data.u8[3] * 500; + SOH = rx_frame.data.u8[5]; + break; + case 0x425: + // rx_frame.data.u8[1] / 10 contains the current stored energy in kWh + // TODO: can we store this kWh value somewhere in datalayer? + break; + case 0x554: + for(int i = 0; i < 8; i++) + cell_temperatures_dC[i] = (int16_t)rx_frame.data.u8[i] * 10 - 400; + break; + case 0x556: + // cell voltages are 12 bit with V = value / 200 + cellvoltages_mV[0] = (((int16_t)rx_frame.data.u8[0] << 4) | ((int16_t)rx_frame.data.u8[1] >> 4)) * 10 / 2; + cellvoltages_mV[1] = (((int16_t)(rx_frame.data.u8[1] & 0xf) << 8) | (int16_t)rx_frame.data.u8[2]) * 10 / 2; + cellvoltages_mV[2] = (((int16_t)rx_frame.data.u8[3] << 4) | ((int16_t)rx_frame.data.u8[4] >> 4)) * 10 / 2; + cellvoltages_mV[3] = (((int16_t)(rx_frame.data.u8[4] & 0xf) << 8) | (int16_t)rx_frame.data.u8[5]) * 10 / 2; + cellvoltages_mV[4] = (((int16_t)rx_frame.data.u8[6] << 4) | ((int16_t)rx_frame.data.u8[7] >> 4)) * 10 / 2; + break; + case 0x557: + // cell voltages are 12 bit with V = value / 200 + cellvoltages_mV[5] = (((int16_t)rx_frame.data.u8[0] << 4) | ((int16_t)rx_frame.data.u8[1] >> 4)) * 10 / 2; + cellvoltages_mV[6] = (((int16_t)(rx_frame.data.u8[1] & 0xf) << 8) | (int16_t)rx_frame.data.u8[2]) * 10 / 2; + cellvoltages_mV[7] = (((int16_t)rx_frame.data.u8[3] << 4) | ((int16_t)rx_frame.data.u8[4] >> 4)) * 10 / 2; + cellvoltages_mV[8] = (((int16_t)(rx_frame.data.u8[4] & 0xf) << 8) | (int16_t)rx_frame.data.u8[5]) * 10 / 2; + cellvoltages_mV[9] = (((int16_t)rx_frame.data.u8[6] << 4) | ((int16_t)rx_frame.data.u8[7] >> 4)) * 10 / 2; + break; + case 0x55E: + // cell voltages are 12 bit with V = value / 200 + cellvoltages_mV[10] = (((int16_t)rx_frame.data.u8[0] << 4) | ((int16_t)rx_frame.data.u8[1] >> 4)) * 10 / 2; + cellvoltages_mV[11] = (((int16_t)(rx_frame.data.u8[1] & 0xf) << 8) | (int16_t)rx_frame.data.u8[2]) * 10 / 2; + cellvoltages_mV[12] = (((int16_t)rx_frame.data.u8[3] << 4) | ((int16_t)rx_frame.data.u8[4] >> 4)) * 10 / 2; + cellvoltages_mV[13] = (((int16_t)(rx_frame.data.u8[4] & 0xf) << 8) | (int16_t)rx_frame.data.u8[5]) * 10 / 2; + // battery odometer in bytes 6 and 7 + break; + case 0x55F: + // TODO: twizy has two pack voltages, assumingly the minimum and maximum measured. + // They usually only differ by 0.1V. We use the lower one here + // The other one is in the last 12 bit of the CAN packet + + // pack voltage is encoded as 16 bit integer in dV + voltage_dV = (((int16_t)rx_frame.data.u8[5] << 4) | ((int16_t)rx_frame.data.u8[6] >> 4)); + break; + default: + break; + } +} + +void send_can_battery() { + // we do not need to send anything to the battery for now +} + +void setup_battery(void) { // Performs one time setup at startup +#ifdef DEBUG_VIA_USB + Serial.println("Renault Twizy battery selected"); +#endif + + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; +} + +#endif diff --git a/Software/src/battery/RENAULT-TWIZY.h b/Software/src/battery/RENAULT-TWIZY.h new file mode 100644 index 00000000..8f282cea --- /dev/null +++ b/Software/src/battery/RENAULT-TWIZY.h @@ -0,0 +1,12 @@ +#ifndef RENAULT_TWIZY_BATTERY_H +#define RENAULT_TWIZY_BATTERY_H +#include "../include.h" + +#define BATTERY_SELECTED +#define MAX_PACK_VOLTAGE_DV 579 // 57.9V at 100% SOC (with 70% SOH, new one might be higher) +#define MIN_PACK_VOLTAGE_DV 480 // 48.4V at 13.76% SOC +#define MAX_CELL_DEVIATION_MV 500 +#define MAX_CELL_VOLTAGE_MV 4200 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 3400 //Battery is put into emergency stop if one cell goes below this value + +#endif \ No newline at end of file From 54f29f1599839f85e2c9d381e3d87d4586a69f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6w?= Date: Tue, 15 Oct 2024 08:59:09 +0200 Subject: [PATCH 2/4] :art: add missing datalayer updates to Twizy battery implementation according to review --- Software/src/battery/RENAULT-TWIZY.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index e87230aa..45bab100 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -3,7 +3,7 @@ #ifdef RENAULT_TWIZY_BATTERY #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" -#include "TWIZY-BATTERY.h" +#include "RENAULT-TWIZY.h" /* Do not change code below unless you are sure what you are doing */ @@ -17,7 +17,6 @@ static int16_t max_charge_power = 0; static uint8_t SOC = 0; static uint8_t SOH = 0; -// TODO can we use std::max_element for this? Or some other function in Arduino / in this project? int16_t max_value(int16_t *entries, size_t len) { int result = INT16_MIN; for(int i = 0; i < len; i++) { @@ -27,6 +26,7 @@ int16_t max_value(int16_t *entries, size_t len) { return result; } + int16_t min_value(int16_t *entries, size_t len) { int result = INT16_MAX; for(int i = 0; i < len; i++) { @@ -50,13 +50,14 @@ void update_values_battery() { datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); - // TODO: the twizy provides two values: one for the maximum charge provided by the on-board charger + // The twizy provides two values: one for the maximum charge provided by the on-board charger // and one for the maximum charge during recuperation. // For now we use the lower of the two (usually the charger one) datalayer.battery.status.max_charge_power_W = max_charge_power < max_recup_power ? max_charge_power : max_recup_power; datalayer.battery.status.max_discharge_power_W = max_discharge_power; + memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mV, sizeof(cellvoltages_mV)); datalayer.battery.status.cell_min_voltage_mV = min_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); datalayer.battery.status.cell_max_voltage_mV = max_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); @@ -115,7 +116,7 @@ void receive_can_battery(CAN_frame rx_frame) { // TODO: twizy has two pack voltages, assumingly the minimum and maximum measured. // They usually only differ by 0.1V. We use the lower one here // The other one is in the last 12 bit of the CAN packet - + // pack voltage is encoded as 16 bit integer in dV voltage_dV = (((int16_t)rx_frame.data.u8[5] << 4) | ((int16_t)rx_frame.data.u8[6] >> 4)); break; @@ -133,6 +134,7 @@ void setup_battery(void) { // Performs one time setup at startup Serial.println("Renault Twizy battery selected"); #endif + datalayer.battery.info.number_of_cells = 14; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; From b95e8fe04bea610d6cce3decc738a1a266b6af11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6w?= Date: Tue, 15 Oct 2024 09:50:41 +0200 Subject: [PATCH 3/4] :art: run clang-format on renault-twizy implementation using pre-commit --- Software/src/battery/RENAULT-TWIZY.cpp | 32 +++++++++++++++----------- Software/src/battery/RENAULT-TWIZY.h | 10 ++++---- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 45bab100..7b57ddd7 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -1,5 +1,5 @@ -#include "../include.h" #include +#include "../include.h" #ifdef RENAULT_TWIZY_BATTERY #include "../datalayer/datalayer.h" #include "../devboard/utils/events.h" @@ -7,30 +7,30 @@ /* Do not change code below unless you are sure what you are doing */ -static int16_t cell_temperatures_dC[8] = { 0 }; +static int16_t cell_temperatures_dC[8] = {0}; static int16_t current_dA = 0; static uint16_t voltage_dV = 0; -static int16_t cellvoltages_mV[14] = { 0 }; +static int16_t cellvoltages_mV[14] = {0}; static int16_t max_discharge_power = 0; static int16_t max_recup_power = 0; static int16_t max_charge_power = 0; static uint8_t SOC = 0; static uint8_t SOH = 0; -int16_t max_value(int16_t *entries, size_t len) { +int16_t max_value(int16_t* entries, size_t len) { int result = INT16_MIN; - for(int i = 0; i < len; i++) { - if(entries[i] > result) + for (int i = 0; i < len; i++) { + if (entries[i] > result) result = entries[i]; } return result; } -int16_t min_value(int16_t *entries, size_t len) { +int16_t min_value(int16_t* entries, size_t len) { int result = INT16_MAX; - for(int i = 0; i < len; i++) { - if(entries[i] < result) + for (int i = 0; i < len; i++) { + if (entries[i] < result) result = entries[i]; } @@ -58,11 +58,15 @@ void update_values_battery() { datalayer.battery.status.max_discharge_power_W = max_discharge_power; memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mV, sizeof(cellvoltages_mV)); - datalayer.battery.status.cell_min_voltage_mV = min_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); - datalayer.battery.status.cell_max_voltage_mV = max_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); + datalayer.battery.status.cell_min_voltage_mV = + min_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); + datalayer.battery.status.cell_max_voltage_mV = + max_value(cellvoltages_mV, sizeof(cellvoltages_mV) / sizeof(*cellvoltages_mV)); - datalayer.battery.status.temperature_min_dC = min_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); - datalayer.battery.status.temperature_max_dC = max_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); + datalayer.battery.status.temperature_min_dC = + min_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); + datalayer.battery.status.temperature_max_dC = + max_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); } void receive_can_battery(CAN_frame rx_frame) { @@ -85,7 +89,7 @@ void receive_can_battery(CAN_frame rx_frame) { // TODO: can we store this kWh value somewhere in datalayer? break; case 0x554: - for(int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) cell_temperatures_dC[i] = (int16_t)rx_frame.data.u8[i] * 10 - 400; break; case 0x556: diff --git a/Software/src/battery/RENAULT-TWIZY.h b/Software/src/battery/RENAULT-TWIZY.h index 8f282cea..8454d35b 100644 --- a/Software/src/battery/RENAULT-TWIZY.h +++ b/Software/src/battery/RENAULT-TWIZY.h @@ -3,10 +3,10 @@ #include "../include.h" #define BATTERY_SELECTED -#define MAX_PACK_VOLTAGE_DV 579 // 57.9V at 100% SOC (with 70% SOH, new one might be higher) -#define MIN_PACK_VOLTAGE_DV 480 // 48.4V at 13.76% SOC +#define MAX_PACK_VOLTAGE_DV 579 // 57.9V at 100% SOC (with 70% SOH, new one might be higher) +#define MIN_PACK_VOLTAGE_DV 480 // 48.4V at 13.76% SOC #define MAX_CELL_DEVIATION_MV 500 -#define MAX_CELL_VOLTAGE_MV 4200 //Battery is put into emergency stop if one cell goes over this value -#define MIN_CELL_VOLTAGE_MV 3400 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CELL_VOLTAGE_MV 4200 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 3400 //Battery is put into emergency stop if one cell goes below this value -#endif \ No newline at end of file +#endif From 9bfead931fc2783938ff4ee78fb7060431345c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6w?= Date: Tue, 15 Oct 2024 15:42:47 +0200 Subject: [PATCH 4/4] :bug: fix bugs and add missing values to renault twizy battery protocol found during testing with a real battery --- Software/USER_SETTINGS.h | 2 +- Software/src/battery/RENAULT-TWIZY.cpp | 30 ++++++++++--------- Software/src/devboard/safety/safety.cpp | 2 +- Software/src/devboard/webserver/webserver.cpp | 3 ++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 29959d48..6776a9e9 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -22,7 +22,7 @@ //#define PYLON_BATTERY //#define RJXZS_BMS //#define RENAULT_KANGOO_BATTERY -#define RENAULT_TWIZY_BATTERY +//#define RENAULT_TWIZY_BATTERY //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SANTA_FE_PHEV_BATTERY diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 7b57ddd7..98f27a83 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -7,15 +7,16 @@ /* Do not change code below unless you are sure what you are doing */ -static int16_t cell_temperatures_dC[8] = {0}; +static int16_t cell_temperatures_dC[7] = {0}; static int16_t current_dA = 0; static uint16_t voltage_dV = 0; static int16_t cellvoltages_mV[14] = {0}; static int16_t max_discharge_power = 0; static int16_t max_recup_power = 0; static int16_t max_charge_power = 0; -static uint8_t SOC = 0; -static uint8_t SOH = 0; +static uint16_t SOC = 0; +static uint16_t SOH = 0; +static uint16_t remaining_capacity_Wh = 0; int16_t max_value(int16_t* entries, size_t len) { int result = INT16_MIN; @@ -39,13 +40,11 @@ int16_t min_value(int16_t* entries, size_t len) { void update_values_battery() { - datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 - - datalayer.battery.status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00% - + datalayer.battery.status.real_soc = SOC; + datalayer.battery.status.soh_pptt = SOH; datalayer.battery.status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0) - - datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign + datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) + datalayer.battery.status.remaining_capacity_Wh = remaining_capacity_Wh; datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); @@ -73,23 +72,25 @@ void receive_can_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x155: + // max charge power is in steps of 300W from 0 to 7 + max_charge_power = (uint16_t)rx_frame.data.u8[0] * 300; + // current is encoded as a 12 bit integer with Amps = value / 4 - 500 current_dA = (((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]) & 0xfff) * 10 / 4 - 5000; // SOC is encoded as 16 bit integer with SOC% = value / 400 - SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 4; + SOC = (((uint16_t)rx_frame.data.u8[4] << 8) | (uint16_t)rx_frame.data.u8[5]) / 4; break; case 0x424: max_recup_power = rx_frame.data.u8[2] * 500; max_discharge_power = rx_frame.data.u8[3] * 500; - SOH = rx_frame.data.u8[5]; + SOH = (uint16_t)rx_frame.data.u8[5] * 100; break; case 0x425: - // rx_frame.data.u8[1] / 10 contains the current stored energy in kWh - // TODO: can we store this kWh value somewhere in datalayer? + remaining_capacity_Wh = (uint16_t)rx_frame.data.u8[1] * 100; break; case 0x554: - for (int i = 0; i < 8; i++) + for (int i = 0; i < 7; i++) cell_temperatures_dC[i] = (int16_t)rx_frame.data.u8[i] * 10 - 400; break; case 0x556: @@ -143,6 +144,7 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.total_capacity_Wh = 6600; } #endif diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index a94702d3..4825444e 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -97,7 +97,7 @@ void update_machineryprotection() { clear_event(EVENT_SOH_LOW); } -#ifndef PYLON_BATTERY +#if !defined(PYLON_BATTERY) && !defined(RENAULT_TWIZY_BATTERY) // Check if SOC% is plausible if (datalayer.battery.status.voltage_dV > (datalayer.battery.info.max_design_voltage_dV - diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 8e60ccb3..e01fbe22 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -549,6 +549,9 @@ String processor(const String& var) { #ifdef RENAULT_KANGOO_BATTERY content += "Renault Kangoo"; #endif // RENAULT_KANGOO_BATTERY +#ifdef RENAULT_TWIZY_BATTERY + content += "Renault Twizy"; +#endif // RENAULT_TWIZY_BATTERY #ifdef RENAULT_ZOE_GEN1_BATTERY content += "Renault Zoe Gen1 22/40"; #endif // RENAULT_ZOE_GEN1_BATTERY