mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 09:49:32 +02:00
Add Rivian battery support
This commit is contained in:
parent
edb69472c3
commit
fc109cd954
5 changed files with 243 additions and 4 deletions
|
@ -116,6 +116,8 @@ const char* name_for_battery_type(BatteryType type) {
|
|||
return RenaultZoeGen1Battery::Name;
|
||||
case BatteryType::RenaultZoe2:
|
||||
return RenaultZoeGen2Battery::Name;
|
||||
case BatteryType::RivianBattery:
|
||||
return RivianBattery::Name;
|
||||
case BatteryType::SamsungSdiLv:
|
||||
return SamsungSdiLVBattery::Name;
|
||||
case BatteryType::SantaFePhev:
|
||||
|
@ -137,11 +139,7 @@ const char* name_for_battery_type(BatteryType type) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LFP_CHEMISTRY
|
||||
const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::LFP;
|
||||
#else
|
||||
const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::NMC;
|
||||
#endif
|
||||
|
||||
battery_chemistry_enum user_selected_battery_chemistry = battery_chemistry_default;
|
||||
|
||||
|
@ -216,6 +214,8 @@ Battery* create_battery(BatteryType type) {
|
|||
return new RenaultZoeGen1Battery();
|
||||
case BatteryType::RenaultZoe2:
|
||||
return new RenaultZoeGen2Battery();
|
||||
case BatteryType::RivianBattery:
|
||||
return new RivianBattery();
|
||||
case BatteryType::SamsungSdiLv:
|
||||
return new SamsungSdiLVBattery();
|
||||
case BatteryType::SantaFePhev:
|
||||
|
|
|
@ -44,6 +44,7 @@ void setup_can_shunt();
|
|||
#include "RENAULT-TWIZY.h"
|
||||
#include "RENAULT-ZOE-GEN1-BATTERY.h"
|
||||
#include "RENAULT-ZOE-GEN2-BATTERY.h"
|
||||
#include "RIVIAN-BATTERY.h"
|
||||
#include "RJXZS-BMS.h"
|
||||
#include "SAMSUNG-SDI-LV-BATTERY.h"
|
||||
#include "SANTA-FE-PHEV-BATTERY.h"
|
||||
|
|
|
@ -47,6 +47,7 @@ enum class BatteryType {
|
|||
HyundaiIoniq28 = 39,
|
||||
Kia64FD = 40,
|
||||
RelionBattery = 41,
|
||||
RivianBattery = 42,
|
||||
Highest
|
||||
};
|
||||
|
||||
|
|
177
Software/src/battery/RIVIAN-BATTERY.cpp
Normal file
177
Software/src/battery/RIVIAN-BATTERY.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
#include "RIVIAN-BATTERY.h"
|
||||
|
||||
#include "../battery/BATTERIES.h"
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
|
||||
/*
|
||||
Initial support for Rivian BIG battery (135kWh)
|
||||
The battery has 3x CAN channels
|
||||
- Failover CAN (CAN-FD) lots of content, not required for operation
|
||||
- Platform CAN (500kbps) with all the control messages needed to control the battery <- This is the one we want
|
||||
- Battery CAN (500kbps) lots of content, not required for operation
|
||||
*/
|
||||
|
||||
void RivianBattery::update_values() {
|
||||
|
||||
datalayer.battery.status.real_soc = battery_SOC;
|
||||
|
||||
datalayer.battery.status.soh_pptt;
|
||||
|
||||
datalayer.battery.status.voltage_dV = battery_voltage;
|
||||
datalayer.battery.status.current_dA = ((int16_t)battery_current / 10.0 - 3200) * 10;
|
||||
|
||||
datalayer.battery.info.total_capacity_Wh = kWh_available_total * 5;
|
||||
datalayer.battery.status.remaining_capacity_Wh = kWh_available_max * 5;
|
||||
|
||||
//static lower limits for testing
|
||||
// datalayer.battery.info.total_capacity_Wh = 10000;
|
||||
// datalayer.battery.status.remaining_capacity_Wh = 9800;
|
||||
|
||||
datalayer.battery.status.max_charge_power_W = ((battery_voltage / 10) * ((battery_charge_limit_amp / 20)));
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
(abs((battery_voltage / 10) * ((battery_discharge_limit_amp / 20) - 3276.75)));
|
||||
|
||||
//static lower limits for testing
|
||||
// datalayer.battery.status.max_charge_power_W = 2000;
|
||||
// datalayer.battery.status.max_discharge_power_W = 3000;
|
||||
|
||||
datalayer.battery.status.cell_min_voltage_mV = 3700 - BMS_state;
|
||||
datalayer.battery.status.cell_max_voltage_mV = 3700;
|
||||
|
||||
datalayer.battery.status.temperature_min_dC = battery_min_temperature * 10;
|
||||
datalayer.battery.status.temperature_max_dC = battery_max_temperature * 10;
|
||||
}
|
||||
|
||||
void RivianBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x160: //Current [Platform CAN]+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_current = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
|
||||
break;
|
||||
case 0x151: //Celltemps (requires other CAN channel)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x120: //Voltages [Platform CAN]+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_voltage = (((rx_frame.data.u8[7] & 0x1F) << 8) | rx_frame.data.u8[6]);
|
||||
break;
|
||||
case 0x25A: //SOC and kWh [Platform CAN]+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
//battery_SOC = (((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[0]);
|
||||
kWh_available_max = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) |
|
||||
(rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) &
|
||||
0b11111111111111110000000000) >>
|
||||
10;
|
||||
kWh_available_total = ((uint32_t)((rx_frame.data.u8[6] << 24) | (rx_frame.data.u8[5] << 16) |
|
||||
(rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) &
|
||||
0b111111111111111100) >>
|
||||
2;
|
||||
;
|
||||
break;
|
||||
case 0x405: //State [Platform CAN]+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
BMS_state = (rx_frame.data.u8[0] & 0x03);
|
||||
break;
|
||||
case 0x100: //Discharge/Charge speed (Not visible on Platform-CAN?)
|
||||
battery_charge_limit_amp = ((uint32_t)((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) |
|
||||
(rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) &
|
||||
0b1111111111111111000000000000) >>
|
||||
12;
|
||||
battery_discharge_limit_amp =
|
||||
((uint32_t)((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]) &
|
||||
0b11111111111111110000) >>
|
||||
4;
|
||||
break;
|
||||
case 0x153: //Temperatures (Not visible on Platform-CAN?)+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_max_temperature = (rx_frame.data.u8[5] / 2) - 40;
|
||||
battery_min_temperature = (rx_frame.data.u8[6] / 2) - 40;
|
||||
break;
|
||||
case 0x55B: //Temperatures (Not visible on Platform-CAN?)+
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_SOC = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RivianBattery::transmit_can(unsigned long currentMillis) {
|
||||
// Send 500ms CAN Message, too fast and the pack can't change states (pre-charge is built in, seems we can't change state during pre-charge)
|
||||
// 100ms seems to draw too much current for a 5A supply during contactor pull in
|
||||
if (currentMillis - previousMillis10 >= (INTERVAL_200_MS)) {
|
||||
previousMillis10 = currentMillis;
|
||||
|
||||
//If we want to close contactors, and preconditions are met
|
||||
if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) {
|
||||
//Standby -> Ready Mode
|
||||
if (BMS_state == STANDBY || BMS_state == SLEEP) {
|
||||
RIVIAN_150.data.u8[0] = 0x03;
|
||||
RIVIAN_150.data.u8[2] = 0x01;
|
||||
RIVIAN_420.data.u8[0] = 0x02;
|
||||
RIVIAN_200.data.u8[0] = 0x08;
|
||||
|
||||
transmit_can_frame(&RIVIAN_150);
|
||||
transmit_can_frame(&RIVIAN_420);
|
||||
transmit_can_frame(&RIVIAN_41F);
|
||||
transmit_can_frame(&RIVIAN_207);
|
||||
transmit_can_frame(&RIVIAN_200);
|
||||
}
|
||||
//Ready mode -> Go Mode
|
||||
|
||||
if (BMS_state == READY) {
|
||||
RIVIAN_150.data.u8[0] = 0x3E;
|
||||
RIVIAN_150.data.u8[2] = 0x03;
|
||||
RIVIAN_420.data.u8[0] = 0x03;
|
||||
|
||||
transmit_can_frame(&RIVIAN_150);
|
||||
transmit_can_frame(&RIVIAN_420);
|
||||
}
|
||||
|
||||
} else { //If we want to open contactors, transition the other way
|
||||
//Go mode -> Ready Mode
|
||||
|
||||
if (BMS_state == GO) {
|
||||
RIVIAN_150.data.u8[0] = 0x03;
|
||||
RIVIAN_150.data.u8[2] = 0x01;
|
||||
|
||||
transmit_can_frame(&RIVIAN_150);
|
||||
}
|
||||
|
||||
if (BMS_state == READY) {
|
||||
RIVIAN_150.data.u8[0] = 0x03;
|
||||
RIVIAN_150.data.u8[2] = 0x01;
|
||||
RIVIAN_420.data.u8[0] = 0x01;
|
||||
RIVIAN_200.data.u8[0] = 0x10;
|
||||
|
||||
transmit_can_frame(&RIVIAN_245);
|
||||
transmit_can_frame(&RIVIAN_150);
|
||||
transmit_can_frame(&RIVIAN_420);
|
||||
transmit_can_frame(&RIVIAN_41F);
|
||||
transmit_can_frame(&RIVIAN_200);
|
||||
}
|
||||
}
|
||||
//disabled this because the battery didn't like it so fast (slowed to 100ms) and because the battery couldn't change states fast enough
|
||||
//as much as I don't like the "free-running" aspect of it, checking the BMS_state and acting on it should fix issues caused by that.
|
||||
//transmit_can_frame(&RIVIAN_150);
|
||||
//transmit_can_frame(&RIVIAN_420);
|
||||
//transmit_can_frame(&RIVIAN_41F);
|
||||
//transmit_can_frame(&RIVIAN_207);
|
||||
//transmit_can_frame(&RIVIAN_200);
|
||||
}
|
||||
}
|
||||
|
||||
void RivianBattery::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.number_of_cells = 108;
|
||||
datalayer.battery.info.total_capacity_Wh = 135000;
|
||||
datalayer.battery.info.chemistry = NMC;
|
||||
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;
|
||||
}
|
60
Software/src/battery/RIVIAN-BATTERY.h
Normal file
60
Software/src/battery/RIVIAN-BATTERY.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#ifndef RIVIAN_BATTERY_H
|
||||
#define RIVIAN_BATTERY_H
|
||||
#include "CanBattery.h"
|
||||
|
||||
class RivianBattery : public CanBattery {
|
||||
public:
|
||||
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 = "Rivian R1T large 135kWh battery";
|
||||
|
||||
private:
|
||||
static const int MAX_PACK_VOLTAGE_DV = 4480;
|
||||
static const int MIN_PACK_VOLTAGE_DV = 2920;
|
||||
static const int MAX_CELL_DEVIATION_MV = 150;
|
||||
static const int MAX_CELL_VOLTAGE_MV = 4200; //Battery is put into emergency stop if one cell goes over this value
|
||||
static const int MIN_CELL_VOLTAGE_MV = 3300; //Battery is put into emergency stop if one cell goes below this value
|
||||
|
||||
uint8_t BMS_state = 0;
|
||||
uint16_t battery_voltage = 3700;
|
||||
uint16_t battery_SOC = 5000;
|
||||
int32_t battery_current = 0;
|
||||
uint16_t kWh_available_total = 135;
|
||||
uint16_t kWh_available_max = 135;
|
||||
int16_t battery_min_temperature = 0;
|
||||
int16_t battery_max_temperature = 0;
|
||||
uint16_t battery_discharge_limit_amp = 0;
|
||||
uint16_t battery_charge_limit_amp = 0;
|
||||
static const uint8_t SLEEP = 0;
|
||||
static const uint8_t STANDBY = 1;
|
||||
static const uint8_t READY = 2;
|
||||
static const uint8_t GO = 3;
|
||||
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
|
||||
|
||||
CAN_frame RIVIAN_150 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 6,
|
||||
.ID = 0x150,
|
||||
.data = {0x03, 0x00, 0x01, 0x00, 0x01, 0x00}};
|
||||
CAN_frame RIVIAN_420 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x420,
|
||||
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame RIVIAN_41F = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x41F, .data = {0x62, 0x10, 0x00}};
|
||||
CAN_frame RIVIAN_245 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 6,
|
||||
.ID = 0x245,
|
||||
.data = {0x10, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame RIVIAN_200 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x200, .data = {0x08}};
|
||||
CAN_frame RIVIAN_207 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 1,
|
||||
.ID = 0x207,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}};
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue