Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions include/CONSTANTS.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ namespace constants {
constexpr uint32_t kModuleScanIntervalMs = 2000;

constexpr uint32_t kCanBitRate = 250000;
constexpr uint32_t kCanStatusIntervalMs = 500;
constexpr uint32_t kCanStatusMessageId = 0x070;
constexpr uint32_t kCanStatusIntervalMs = 500; // Rate at which data CAN status information is sent
constexpr uint32_t kCanChargerIntervalMs = 1000; // Rate to check if the charger sent a CAN message to toggle on charging mode
constexpr uint32_t kCanChargerTimeOutMs = 2000; // If the charger stops sending CAN messages then toggle off charging mode
constexpr uint32_t kCanChargerControlIntervalMs = 500; // Rate at which the charger needs a CAN control message
constexpr uint32_t kChargerStatusUpdateIntervalMs = 250;
constexpr uint8_t kCanStatusPayloadLength = 8;

constexpr uint8_t kConnectDebounce = 2;
Expand All @@ -50,4 +53,12 @@ namespace constants {

constexpr std::size_t kLedCount = 13;
constexpr uint8_t kLedBrightness = 32;
} // namespace constants

// TODO constants for charging
constexpr float kSocChargingLimit = 1.0f; // SOC percentage charge limit
constexpr float kVoltageChargerMaxPackV = 445.0f; // Charger will shutoff if limit is over-reached and BMS or wiring fails; this parameter is sent to the charger via CAN in charger mode
constexpr uint16_t kStartBalancingMv = 3900; // when any cell reaches this value then balancing will start
constexpr float kMaxChargerPowerOutputW = 6550.0f; // ELCON charger specification
constexpr float kStartChargeA = 18.0f; // 1.0C begining charging amperage

} // namespace constants
38 changes: 38 additions & 0 deletions include/SOCLookUpTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <cstddef>
#include <cstdint>

namespace soclookuptable {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move the lookup function here? It would be easier to follow. Also, be sure to mention that the two tables are interlinked, where you're mapping from the first table to the second table.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, at the top of the namespace would be a good place to define what the SOC acronym means.

constexpr uint8_t kNumLookUpPoints = 100;

constexpr float kVoltageTable[kNumLookUpPoints] = {
3150.0f, 3159.6f, 3169.2f, 3178.8f, 3188.4f, 3198.0f, 3207.6f, 3217.2f,
3226.8f, 3236.4f, 3246.0f, 3255.6f, 3265.2f, 3274.7f, 3284.3f, 3293.9f,
3303.5f, 3313.1f, 3322.7f, 3332.3f, 3341.9f, 3351.5f, 3361.1f, 3370.7f,
3380.3f, 3389.9f, 3399.5f, 3409.1f, 3418.7f, 3428.3f, 3437.9f, 3447.5f,
3457.1f, 3466.7f, 3476.3f, 3485.9f, 3495.5f, 3505.1f, 3514.6f, 3524.2f,
3533.8f, 3543.4f, 3553.0f, 3562.6f, 3572.2f, 3581.8f, 3591.4f, 3601.0f,
3610.6f, 3620.2f, 3629.8f, 3639.4f, 3649.0f, 3658.6f, 3668.2f, 3677.8f,
3687.4f, 3697.0f, 3706.6f, 3716.2f, 3725.8f, 3735.4f, 3744.9f, 3754.5f,
3764.1f, 3773.7f, 3783.3f, 3792.9f, 3802.5f, 3812.1f, 3821.7f, 3831.3f,
3840.9f, 3850.5f, 3860.1f, 3869.7f, 3879.3f, 3888.9f, 3898.5f, 3908.1f,
3917.7f, 3927.3f, 3936.9f, 3946.5f, 3956.1f, 3965.7f, 3975.3f, 3984.8f,
3994.4f, 4004.0f, 4013.6f, 4023.2f, 4032.8f, 4042.4f, 4052.0f, 4061.6f,
4071.2f, 4080.8f, 4090.4f, 4100.0f
};

constexpr float kSocTable[kNumLookUpPoints] = {
0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.8f, 0.9f, 1.1f,
1.3f, 1.5f, 1.7f, 1.9f, 2.1f, 2.4f, 2.7f, 2.9f, 3.3f, 3.6f,
4.0f, 4.4f, 4.8f, 5.3f, 5.8f, 6.3f, 6.8f, 7.5f, 8.1f, 8.8f,
9.5f, 10.3f, 11.2f, 12.0f, 13.0f, 14.0f, 15.0f, 16.2f, 17.3f, 18.6f,
19.9f, 21.3f, 22.7f, 24.2f, 25.8f, 27.4f, 29.1f, 30.8f, 32.6f, 34.5f,
36.4f, 38.3f, 40.3f, 42.3f, 44.4f, 46.4f, 48.5f, 50.6f, 52.7f, 54.8f,
56.9f, 58.9f, 61.0f, 63.0f, 64.9f, 66.9f, 68.7f, 70.6f, 72.4f, 74.1f,
75.8f, 77.4f, 78.9f, 80.4f, 81.8f, 83.1f, 84.4f, 85.6f, 86.8f, 87.9f,
88.9f, 89.9f, 90.8f, 91.7f, 92.5f, 93.3f, 94.0f, 94.7f, 95.3f, 95.9f,
96.5f, 97.0f, 97.5f, 97.9f, 98.3f, 98.7f, 99.1f, 99.4f, 99.7f, 100.0f,
};

} // State of charge lookup table
8 changes: 0 additions & 8 deletions include/SystemStatus.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,7 @@ inline StatusMode evaluateVoltageStatus(const ModuleReadings& module) {
if (cellMv == adbms6830::BMSInterface::kInvalidCellValue) {
return StatusMode::BAD_DATA;
}
#if defined(DANGEROUS_MODE)
if (cellMv >= constants::kBalanceMaxCellMv) {
continue;
}
if (cellMv < constants::kCellVoltageErrorMinMv ||
(cellMv > constants::kCellVoltageErrorMaxMv && cellMv < constants::kBalanceMaxCellMv)) {
#else
if (cellMv < constants::kCellVoltageErrorMinMv || cellMv > constants::kCellVoltageErrorMaxMv) {
#endif
return StatusMode::ERROR;
}
if (cellMv < constants::kCellVoltageExhaustedMinMv || cellMv > constants::kCellVoltageWarningMaxMv) {
Expand Down
13 changes: 7 additions & 6 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
monitor_speed = 115200
upload_protocol = picotool
build_flags =
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
fastled/FastLED@^3.10.3
pierremolinaro/acan2517
pierremolinaro/acan2517FD
build_flags =
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
fastled/FastLED@^3.10.3
pierremolinaro/acan2517
pierremolinaro/acan2517FD
throwtheswitch/Unity@^2.6.1
72 changes: 72 additions & 0 deletions src/BMSControl.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "BMSControl.h"
#include "SOCLookUpTable.h"

const SPISettings ReadBMS::kBmsSpiSettings(1000000, MSBFIRST, SPI_MODE0);

Expand Down Expand Up @@ -691,3 +692,74 @@ void ReadBMS::copyModuleReadings(ModuleReadings& destination,
destination.cellVoltages = source.cellVoltages;
destination.thermistorTempsC = source.thermistorTempsC;
}

// CHARGING
float ReadBMS::lookUpSOC(uint16_t cellMv) {
// check if value is out of range
if (cellMv <= soclookuptable::kVoltageTable[0]) {
return soclookuptable::kSocTable[0];
}

if (cellMv >= soclookuptable::kVoltageTable[soclookuptable::kNumLookUpPoints - 1]) {
return soclookuptable::kSocTable[soclookuptable::kNumLookUpPoints - 1];
}

for (size_t i=0; i < soclookuptable::kNumLookUpPoints - 1; i++) {
if (cellMv >= soclookuptable::kVoltageTable[i] && cellMv <= soclookuptable::kVoltageTable[i+1]) {
// linear interpolation
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be clearer to say "linear interpolation to map between the two tables."

float v1 = soclookuptable::kVoltageTable[i];
float v2 = soclookuptable::kVoltageTable[i + 1];
float soc1 = soclookuptable::kSocTable[i];
float soc2 = soclookuptable::kSocTable[i + 1];

return static_cast<float>((soc1 * (v1 - cellMv) + soc2 * (cellMv - v2)) / (v1 - v2));
}
}

// fallback
return 0.0;
}

ReadBMS::StateOfCharge ReadBMS::pollSOC() {
uint16_t lowestCellMv = UINT16_MAX;
uint16_t highestCellMv = 0;
float minStateOfCharge = 0.0f;
float maxStateOfCharge = 0.0f;
uint32_t totalCellMv = 0;

// get lastest module readings
updatePollData();

for (const ReadBMS::ModuleReadings &module : pollData_.modules)
{
if (!module.connected || !module.cellDataValid) {
continue;
}
Comment on lines +735 to +737
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional to ignore bad cells? Might want to add a comment explaining why it's okay to ignore.


for (uint16_t cellMv : module.cellVoltages) {
if (cellMv == adbms6830::BMSInterface::kInvalidCellValue) {
continue;
}

if (cellMv < lowestCellMv) {
lowestCellMv = cellMv;
}

if (cellMv > highestCellMv) {
highestCellMv = cellMv;
}

totalCellMv += cellMv;
}
}

minStateOfCharge = lookUpSOC(lowestCellMv);
maxStateOfCharge = lookUpSOC(highestCellMv);

StateOfCharge soc{};
soc.minSOC = minStateOfCharge;
soc.maxSOC = maxStateOfCharge;
soc.minCellMv = lowestCellMv;
soc.maxCellMv = highestCellMv;
return soc;
}
11 changes: 11 additions & 0 deletions src/BMSControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,21 @@ class ReadBMS {
std::array<adbms6830::BMSInterface::SiliconIdReadback, constants::kModuleCount> moduleSiliconIds{};
};

// To be used for charging logic and CAN msg sent to the dashboard
struct StateOfCharge {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you document what this structure is used for?

float minSOC = 0.0f;
float maxSOC = 0.0f;
uint16_t minCellMv = 0;
uint16_t maxCellMv = 0;
};

ReadBMS();

void begin();
void pollBMS();
void updateBalancing(bool enabled);
const PollData& data() const;
StateOfCharge pollSOC(); // to pull SOC data for charging
LogSnapshot captureLogSnapshot() const;
static void logBalancingState(const LogSnapshot& snapshot, Stream& stream);
static void logConnectedModules(const LogSnapshot& snapshot, Stream& stream);
Expand Down Expand Up @@ -115,6 +124,8 @@ class ReadBMS {
const adbms6830::BMSInterface::ModuleData& source,
bool connected) const;

float lookUpSOC(uint16_t cellMv);

static const SPISettings kBmsSpiSettings;

adbms6830::ADBMS6830Driver mainBmsDriver_;
Expand Down
20 changes: 20 additions & 0 deletions src/MCP2517Can.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ class MCP2517Can {
Osc40MHzDiv2,
};

enum CanMsgId : uint32_t {
MotorControlCommand = 0x0C0, // Motor control command, BMS will switch to drive ready mode when this msg is recieved

BmsStatus = 0x070, // BMS status message
StateOfCharge = 0x072, // BMS state of charge

ChargerControl = 0x1806E5F4, // ELCON CAN 3865 charger control message id
ChargerStatus = 0x18FF50E5, // ELCON CAN 3865 charger status broadcast message
};

enum ChargerControl : bool {
ChargerStart = 0,
ChargerClose = 1,
};

enum ChargingMode : bool {
ChargingMode = 0,
HeatingMode = 1,
};

struct Message {
uint32_t id = 0;
bool extended = false;
Expand Down
Loading