mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Add Current and SOC reading
This commit is contained in:
parent
7cf3c687a9
commit
8be8c5bc3b
1 changed files with 20 additions and 27 deletions
|
@ -4,26 +4,17 @@
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CMFA-EV-BATTERY.h"
|
#include "CMFA-EV-BATTERY.h"
|
||||||
|
|
||||||
/*
|
/* TODO:
|
||||||
TODO:
|
Before this integration can be considered stable, we need to:
|
||||||
- Find the following data points in the transmitted CAN data:
|
- Find the following data points in the transmitted CAN data:
|
||||||
- SOC%
|
- Pack voltage (Current implementation might be wrong)
|
||||||
- SOH% (optional)
|
|
||||||
- Current
|
|
||||||
- Pack voltage
|
|
||||||
- Max discharge power
|
|
||||||
- Max charge power
|
|
||||||
- Temperature min
|
|
||||||
- Temperature max
|
|
||||||
- Cellvoltage min
|
- Cellvoltage min
|
||||||
- Cellvoltage max
|
- Cellvoltage max
|
||||||
- Alternatively all these values can be taken from OBD2 PID polling
|
- Alternatively all these values can be taken from OBD2 PID polling
|
||||||
- Figure out which messages need to be sent towards the battery to keep it satisfied and staying alive
|
|
||||||
- TODO: Test that the current amount of messages sent is enough to keep it alive
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
|
||||||
|
|
||||||
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
CAN_frame CMFA_1EA = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x1EA, .data = {0x00}};
|
CAN_frame CMFA_1EA = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x1EA, .data = {0x00}};
|
||||||
CAN_frame CMFA_125 = {.FD = false,
|
CAN_frame CMFA_125 = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
|
@ -53,8 +44,9 @@ static unsigned long previousMillis10ms = 0;
|
||||||
|
|
||||||
static uint8_t heartbeat = 0; //Alternates between 0x55 and 0xAA every 5th frame
|
static uint8_t heartbeat = 0; //Alternates between 0x55 and 0xAA every 5th frame
|
||||||
static uint8_t heartbeat2 = 0; //Alternates between 0x55 and 0xAA every 5th frame
|
static uint8_t heartbeat2 = 0; //Alternates between 0x55 and 0xAA every 5th frame
|
||||||
static uint16_t SOC = 0;
|
static uint32_t SOC = 0;
|
||||||
static uint16_t SOH = 99;
|
static uint16_t SOH = 99;
|
||||||
|
static int16_t current = 0;
|
||||||
static uint16_t pack_voltage = 2700;
|
static uint16_t pack_voltage = 2700;
|
||||||
static int16_t highest_cell_temperature = 0;
|
static int16_t highest_cell_temperature = 0;
|
||||||
static uint16_t lowest_cell_temperature = 0;
|
static uint16_t lowest_cell_temperature = 0;
|
||||||
|
@ -62,14 +54,16 @@ static uint32_t discharge_power_w = 0;
|
||||||
static uint32_t charge_power_w = 0;
|
static uint32_t charge_power_w = 0;
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
datalayer.battery.status.soh_pptt = SOH * 100;
|
datalayer.battery.status.soh_pptt = (SOH * 100);
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = SOC * 100;
|
datalayer.battery.status.real_soc = (SOC * 0.25);
|
||||||
|
|
||||||
datalayer.battery.status.current_dA;
|
datalayer.battery.status.current_dA = current * 10;
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = pack_voltage;
|
datalayer.battery.status.voltage_dV = pack_voltage;
|
||||||
|
|
||||||
|
datalayer.battery.info.total_capacity_Wh = 27000;
|
||||||
|
|
||||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
||||||
|
@ -89,13 +83,12 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
switch (rx_frame.ID) { //These frames are transmitted by the battery
|
switch (rx_frame.ID) { //These frames are transmitted by the battery
|
||||||
case 0x127: //10ms
|
case 0x127: //10ms , Same structure as old Zoe 0x155 message!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//value1 = ((rx_frame.data.u8[0] << 2 | (rx_frame.data.u8[1] & 0xC0) >> 6));
|
current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
||||||
//value2 = ((rx_frame.data.u8[0] << 2 | (rx_frame.data.u8[1] & 0xC0) >> 6));
|
SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
||||||
SOC = rx_frame.data.u8[7];
|
|
||||||
break;
|
break;
|
||||||
case 0x3D6: // Same structure as old Zoe 0x424 message!
|
case 0x3D6: //100ms, Same structure as old Zoe 0x424 message!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
charge_power_w = rx_frame.data.u8[2] * 500;
|
charge_power_w = rx_frame.data.u8[2] * 500;
|
||||||
discharge_power_w = rx_frame.data.u8[3] * 500;
|
discharge_power_w = rx_frame.data.u8[3] * 500;
|
||||||
|
@ -104,20 +97,20 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
heartbeat = rx_frame.data.u8[6];
|
heartbeat = rx_frame.data.u8[6];
|
||||||
highest_cell_temperature = (rx_frame.data.u8[6] - 40);
|
highest_cell_temperature = (rx_frame.data.u8[6] - 40);
|
||||||
break;
|
break;
|
||||||
case 0x3D7:
|
case 0x3D7: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
pack_voltage = ((rx_frame.data.u8[6] << 4 | (rx_frame.data.u8[5] & 0x0F)));
|
pack_voltage = ((rx_frame.data.u8[6] << 4 | (rx_frame.data.u8[5] & 0x0F)));
|
||||||
break;
|
break;
|
||||||
case 0x3D8:
|
case 0x3D8: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//counter_3D8 = rx_frame.data.u8[3]; //?
|
//counter_3D8 = rx_frame.data.u8[3]; //?
|
||||||
//CRC_3D8 = rx_frame.data.u8[4]; //?
|
//CRC_3D8 = rx_frame.data.u8[4]; //?
|
||||||
break;
|
break;
|
||||||
case 0x43C:
|
case 0x43C: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
heartbeat2 = rx_frame.data.u8[2]; //Alternates between 0x55 and 0xAA every 5th frame
|
heartbeat2 = rx_frame.data.u8[2]; //Alternates between 0x55 and 0xAA every 5th frame
|
||||||
break;
|
break;
|
||||||
case 0x431:
|
case 0x431: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//byte0 9C always
|
//byte0 9C always
|
||||||
//byte1 40 always
|
//byte1 40 always
|
||||||
|
@ -167,7 +160,7 @@ void transmit_can_battery() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
void setup_battery(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "CMFA platform 26.8/27.4kWh", 63);
|
strncpy(datalayer.system.info.battery_protocol, "CMFA platform, 27 kWh battery", 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 72;
|
datalayer.battery.info.number_of_cells = 72;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue