From 37f9d3e8f8c5b6bff6788c200e9a0ac123f06cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Wed, 20 Aug 2025 12:58:45 +0300 Subject: [PATCH] Add Relion battery protocol --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.cpp | 4 ++ Software/src/battery/BATTERIES.h | 1 + Software/src/battery/Battery.h | 1 + Software/src/battery/RELION-LV-BATTERY.cpp | 83 ++++++++++++++++++++++ Software/src/battery/RELION-LV-BATTERY.h | 43 +++++++++++ 6 files changed, 133 insertions(+) create mode 100644 Software/src/battery/RELION-LV-BATTERY.cpp create mode 100644 Software/src/battery/RELION-LV-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index a1d246fa..2dccf642 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -35,6 +35,7 @@ //#define DALY_BMS //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY +//#define RELION_BATTERY //#define RENAULT_KANGOO_BATTERY //#define RENAULT_TWIZY_BATTERY //#define RENAULT_ZOE_GEN1_BATTERY diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 1aa07bc6..9b81a479 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -108,6 +108,8 @@ const char* name_for_battery_type(BatteryType type) { return RjxzsBms::Name; case BatteryType::RangeRoverPhev: return RangeRoverPhevBattery::Name; + case BatteryType::RelionBattery: + return RelionBattery::Name; case BatteryType::RenaultKangoo: return RenaultKangooBattery::Name; case BatteryType::RenaultTwizy: @@ -209,6 +211,8 @@ Battery* create_battery(BatteryType type) { return new RjxzsBms(); case BatteryType::RangeRoverPhev: return new RangeRoverPhevBattery(); + case BatteryType::RelionBattery: + return new RelionBattery(); case BatteryType::RenaultKangoo: return new RenaultKangooBattery(); case BatteryType::RenaultTwizy: diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 3e89149c..2c649a47 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -39,6 +39,7 @@ void setup_can_shunt(); #include "ORION-BMS.h" #include "PYLON-BATTERY.h" #include "RANGE-ROVER-PHEV-BATTERY.h" +#include "RELION-LV-BATTERY.h" #include "RENAULT-KANGOO-BATTERY.h" #include "RENAULT-TWIZY.h" #include "RENAULT-ZOE-GEN1-BATTERY.h" diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index 2b163a95..da98a513 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -45,6 +45,7 @@ enum class BatteryType { MgHsPhev = 37, SamsungSdiLv = 38, HyundaiIoniq28 = 39, + RelionBattery = 40, Highest }; diff --git a/Software/src/battery/RELION-LV-BATTERY.cpp b/Software/src/battery/RELION-LV-BATTERY.cpp new file mode 100644 index 00000000..693a5f8f --- /dev/null +++ b/Software/src/battery/RELION-LV-BATTERY.cpp @@ -0,0 +1,83 @@ +#include "RELION-LV-BATTERY.h" +#include "../battery/BATTERIES.h" +#include "../communication/can/comm_can.h" +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +/*CAN Type:CAN2.0(Extended) +BPS:250kbps +Data Length: 8 +Data Encoded Format:Motorola*/ + +void RelionBattery::update_values() { + + datalayer.battery.status.real_soc = battery_soc * 100; + + datalayer.battery.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); + + datalayer.battery.status.soh_pptt = battery_soh * 100; + + datalayer.battery.status.voltage_dV = battery_total_voltage; + + datalayer.battery.status.current_dA = battery_total_current; //Charging negative, discharge positive + + datalayer.battery.status.max_charge_power_W = + ((battery_total_voltage / 10) * charge_current_A); //90A recommended charge current + + datalayer.battery.status.max_discharge_power_W = + ((battery_total_voltage / 10) * discharge_current_A); //150A max continous discharge current + + datalayer.battery.status.temperature_min_dC = max_cell_temperature * 10; + + datalayer.battery.status.temperature_max_dC = max_cell_temperature * 10; + + datalayer.battery.status.cell_max_voltage_mV = max_cell_voltage; + + datalayer.battery.status.cell_min_voltage_mV = min_cell_voltage; +} + +void RelionBattery::handle_incoming_can_frame(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x02018100: //ID1 + battery_total_voltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + break; + case 0x02028100: //ID2 + battery_total_current = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]); + system_state = rx_frame.data.u8[2]; + battery_soc = rx_frame.data.u8[3]; + battery_soh = rx_frame.data.u8[4]; + most_serious_fault = rx_frame.data.u8[5]; + break; + case 0x02038100: //ID3 + max_cell_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]); + min_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case 0x02628100: //Temperatures + max_cell_temperature = rx_frame.data.u8[0] - 50; + min_cell_temperature = rx_frame.data.u8[2] - 50; + break; + case 0x02648100: //Charging limitis + charge_current_A = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]) - 800; + regen_charge_current_A = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]) - 800; + discharge_current_A = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]) - 800; + break; + default: + break; + } +} + +void RelionBattery::transmit_can(unsigned long currentMillis) { + // No periodic sending for this protocol +} + +void RelionBattery::setup(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, Name, 63); + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.battery.info.chemistry = LFP; + datalayer.battery.info.number_of_cells = 16; + 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; + datalayer.system.status.battery_allows_contactor_closing = true; +} diff --git a/Software/src/battery/RELION-LV-BATTERY.h b/Software/src/battery/RELION-LV-BATTERY.h new file mode 100644 index 00000000..53c59431 --- /dev/null +++ b/Software/src/battery/RELION-LV-BATTERY.h @@ -0,0 +1,43 @@ +#ifndef RELION_BATTERY_H +#define RELION_BATTERY_H + +#include "../system_settings.h" +#include "CanBattery.h" + +#ifdef RELION_BATTERY +#define SELECTED_BATTERY_CLASS RelionBattery +#endif + +class RelionBattery : public CanBattery { + public: + RelionBattery() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {} + + virtual void setup(void); + virtual void handle_incoming_can_frame(CAN_frame rx_frame); + virtual void update_values(); + virtual void transmit_can(unsigned long currentMillis); + static constexpr const char* Name = "Relion LV protocol via 250kbps CAN"; + + private: + static const int MAX_PACK_VOLTAGE_DV = 584; //58.4V recommended charge voltage. BMS protection steps in at 60.8V + static const int MIN_PACK_VOLTAGE_DV = 440; //44.0V Recommended LV disconnect. BMS protection steps in at 40.0V + static const int MAX_CELL_DEVIATION_MV = 300; + static const int MAX_CELL_VOLTAGE_MV = 3800; //Battery is put into emergency stop if one cell goes over this value + static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value + + uint16_t battery_total_voltage = 500; + int16_t battery_total_current = 0; + uint8_t system_state = 0; + uint8_t battery_soc = 50; + uint8_t battery_soh = 99; + uint8_t most_serious_fault = 0; + uint16_t max_cell_voltage = 3300; + uint16_t min_cell_voltage = 3300; + int16_t max_cell_temperature = 0; + int16_t min_cell_temperature = 0; + int16_t charge_current_A = 0; + int16_t regen_charge_current_A = 0; + int16_t discharge_current_A = 0; +}; + +#endif