mirror of
https://github.com/dexterbg/KlausBMS.git
synced 2024-11-18 12:43:59 +00:00
Initial commit
This commit is contained in:
commit
7a136c9d2b
8 changed files with 2034 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
assets
|
||||||
|
*.html
|
1393
KlausBMS.ino
Normal file
1393
KlausBMS.ino
Normal file
File diff suppressed because it is too large
Load diff
201
KlausBMS_config.h
Normal file
201
KlausBMS_config.h
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/**
|
||||||
|
* ==========================================================================
|
||||||
|
* Klaus' Twizy LiFEPO4 (LFP) BMS: Configuration
|
||||||
|
* ==========================================================================
|
||||||
|
*/
|
||||||
|
#ifndef _KlausBMS_config_h
|
||||||
|
#define _KlausBMS_config_h
|
||||||
|
|
||||||
|
// Personalization:
|
||||||
|
#define KLAUS_BMS_NAME "KlausBMS"
|
||||||
|
|
||||||
|
// Serial baud rate:
|
||||||
|
// (Arduino supports up to 2 Mbit, but cannot send faster than 1 Mbit)
|
||||||
|
#define SERIAL_BAUD 1000000
|
||||||
|
|
||||||
|
// Bluetooth baud rate:
|
||||||
|
// (i.e. 57600 / 38400 / 19200 / 9600, Default of HC-05/06 is 9600)
|
||||||
|
#define BT_BAUD 57600
|
||||||
|
|
||||||
|
// Input calibration mode (inhibits normal operation):
|
||||||
|
#define CALIBRATION_MODE 1
|
||||||
|
// Note: calibration mode will still allow VirtualBMS state transitions.
|
||||||
|
// You can drive & charge in calibration mode, but no sensor data
|
||||||
|
// will be used to update the Twizy SOC & power status. So if you charge
|
||||||
|
// or drive in calibration mode, you need to monitor your voltages!
|
||||||
|
|
||||||
|
// Optional / development features:
|
||||||
|
#define FEATURE_CMD_ES 0
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// PORTS
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Analog input port assignment:
|
||||||
|
#define PORT_VOLT A0 // cell voltage MUX
|
||||||
|
#define PORT_TEMP_F A1 // temperature sensor front
|
||||||
|
#define PORT_TEMP_R A2 // temperature sensor rear
|
||||||
|
#define PORT_CURR A3 // pack current (comment out to disable)
|
||||||
|
|
||||||
|
// MUX address pins:
|
||||||
|
#define PORT_MUX_S0 4
|
||||||
|
#define PORT_MUX_S1 5
|
||||||
|
#define PORT_MUX_S2 6
|
||||||
|
#define PORT_MUX_S3 7
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// OPERATION
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Maximum charge current to use [A] (5…35):
|
||||||
|
#define MAX_CHARGE_CURRENT 35
|
||||||
|
// Charge current → power drawn from socket:
|
||||||
|
// 35 A = 2,2 kW
|
||||||
|
// 30 A = 2,1 kW
|
||||||
|
// 25 A = 1,7 kW
|
||||||
|
// 20 A = 1,4 kW
|
||||||
|
// 15 A = 1,0 kW
|
||||||
|
// 10 A = 0,7 kW
|
||||||
|
// 5 A = 0,4 kW
|
||||||
|
|
||||||
|
// Maximum driving & recuperation power limits to use [W] (500…30000):
|
||||||
|
#define MAX_DRIVE_POWER 25000
|
||||||
|
#define MAX_RECUP_POWER 12500
|
||||||
|
|
||||||
|
|
||||||
|
// Drive power cutback [%]:
|
||||||
|
// (100% at FULL → 100% at <SOC1>% → <LVL2>% at <SOC2>% → 0% at EMPTY)
|
||||||
|
#define DRV_CUTBACK_SOC1 50
|
||||||
|
#define DRV_CUTBACK_SOC2 25
|
||||||
|
#define DRV_CUTBACK_LVL2 70
|
||||||
|
|
||||||
|
// Charge power cutback by SOC [%]:
|
||||||
|
// (100% at EMPTY → 100% at <SOC>% → 0% at FULL)
|
||||||
|
#define CHG_CUTBACK_SOC 90
|
||||||
|
|
||||||
|
// Charge power cutback by charger temperature [°C]:
|
||||||
|
#define CHG_CUTBACK_TEMP 50
|
||||||
|
#define CHG_CUTBACK_TEMPMAX 65
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// VOLTAGE
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Number of cells (max 16):
|
||||||
|
#define CELL_COUNT 16
|
||||||
|
|
||||||
|
// Voltage range for discharging [V]:
|
||||||
|
#define VMIN_DRV 2.90
|
||||||
|
#define VMAX_DRV 3.35
|
||||||
|
|
||||||
|
// Voltage range for charging [V]:
|
||||||
|
#define VMIN_CHG 2.90
|
||||||
|
#define VMAX_CHG 3.65
|
||||||
|
|
||||||
|
// Voltage smoothing [100ms samples] (min 1 = no smoothing):
|
||||||
|
#define SMOOTH_VOLT 20
|
||||||
|
|
||||||
|
// Port scaling utils:
|
||||||
|
#define VPORT 5.0 / 1024.0
|
||||||
|
#define VDIV(R1,R2) (R1+R2) / R2
|
||||||
|
|
||||||
|
// Voltage divider analog input scaling:
|
||||||
|
// - scale = R_sum / R_probe * calibration
|
||||||
|
// - first cell is connected directly
|
||||||
|
const float SCALE_VOLT[CELL_COUNT] = {
|
||||||
|
VPORT * 1.00000 // 3.2 V
|
||||||
|
, VPORT * VDIV( 27, 47) * 1.00000 // 6.4 V
|
||||||
|
, VPORT * VDIV( 68, 47) * 1.00000 // 9.6 V
|
||||||
|
, VPORT * VDIV(100, 47) * 1.00000 // 12.8 V
|
||||||
|
, VPORT * VDIV(150, 47) * 1.00000 // 16.0 V
|
||||||
|
, VPORT * VDIV(180, 47) * 1.00000 // 19.2 V
|
||||||
|
, VPORT * VDIV(220, 47) * 1.00000 // 22.4 V
|
||||||
|
, VPORT * VDIV(270, 47) * 1.00000 // 25.6 V
|
||||||
|
, VPORT * VDIV(330, 47) * 1.00000 // 28.8 V
|
||||||
|
, VPORT * VDIV(330, 47) * 1.00000 // 32.0 V
|
||||||
|
, VPORT * VDIV(390, 47) * 1.00000 // 35.2 V
|
||||||
|
, VPORT * VDIV(390, 47) * 1.00000 // 38.4 V
|
||||||
|
, VPORT * VDIV(470, 47) * 1.00000 // 41.6 V
|
||||||
|
, VPORT * VDIV(470, 47) * 1.00000 // 44.8 V
|
||||||
|
, VPORT * VDIV(560, 47) * 1.00000 // 48.0 V
|
||||||
|
, VPORT * VDIV(560, 47) * 1.00000 // 51.2 V
|
||||||
|
};
|
||||||
|
|
||||||
|
// Voltage warning/error thresholds [V]:
|
||||||
|
// (Note: resolution of cell #16 is ~ 80 mV)
|
||||||
|
#define VOLT_DIFF_WARN 0.3
|
||||||
|
#define VOLT_DIFF_ERROR 0.6
|
||||||
|
#define VOLT_DIFF_SHUTDOWN 1.0
|
||||||
|
|
||||||
|
// SOC smoothing [1s samples] (min 1 = no smoothing):
|
||||||
|
#define SMOOTH_SOC_DOWN 60 // adaption to lower voltage
|
||||||
|
#define SMOOTH_SOC_UP_DRV 30 // adaption to higher voltage while driving
|
||||||
|
#define SMOOTH_SOC_UP_CHG 10 // adaption to higher voltage while charging
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// CURRENT & CAPACITY
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Current analog input scaling:
|
||||||
|
|
||||||
|
// LEM HAC-600-S: -600 … +600 A → 0.072 … 4.002 V
|
||||||
|
//#define SCALE_CURR (1200.0 / (4.002 - 0.072))
|
||||||
|
//#define BASE_CURR (-600.0 - 0.072 * SCALE_CURR)
|
||||||
|
|
||||||
|
// Tamura L06P400S05: -400 … +400 A → 1.0 … 4.0 V
|
||||||
|
#define SCALE_CURR (800.0 / (4.0 - 1.0))
|
||||||
|
#define BASE_CURR (-400.0 - 1.0 * SCALE_CURR)
|
||||||
|
|
||||||
|
// If you need to reverse polarity, change to -1:
|
||||||
|
#define CURR_POLARITY_DRV 1
|
||||||
|
#define CURR_POLARITY_CHG 1
|
||||||
|
|
||||||
|
// Battery capacity:
|
||||||
|
#define CAP_NOMINAL_AH 120
|
||||||
|
|
||||||
|
// Capacity adjustment smoothing (min 100 = fastest adaption):
|
||||||
|
#define SMOOTH_CAP 200
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// HYBRID SOC
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Prioritize voltage based SOC [%]:
|
||||||
|
#define SOC_VOLT_PRIO_ABOVE 90
|
||||||
|
#define SOC_VOLT_PRIO_BELOW 20
|
||||||
|
|
||||||
|
// Degrade coulomb based SOC [%]:
|
||||||
|
#define SOC_COUL_DEGR_ABOVE 90
|
||||||
|
#define SOC_COUL_DEGR_BELOW 20
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// TEMPERATURE
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Temperature analog input scaling:
|
||||||
|
// LM35D: +2 .. +100°, 10 mV / °C => 100 °C = 1.0 V
|
||||||
|
#define SCALE_TEMP (100.0 / 1.0)
|
||||||
|
#define BASE_TEMP (+2.0)
|
||||||
|
|
||||||
|
// Temperature smoothing [samples]:
|
||||||
|
#define SMOOTH_TEMP 30
|
||||||
|
|
||||||
|
// Temperature warning/error thresholds [°C]:
|
||||||
|
#define TEMP_WARN 40
|
||||||
|
#define TEMP_ERROR 45
|
||||||
|
#define TEMP_SHUTDOWN 50
|
||||||
|
|
||||||
|
// Temperature front/rear difference warning/error thresholds [°C]:
|
||||||
|
#define TEMP_DIFF_WARN 3
|
||||||
|
#define TEMP_DIFF_ERROR 5
|
||||||
|
#define TEMP_DIFF_SHUTDOWN 10
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _KlausBMS_config_h
|
||||||
|
|
157
LICENSE.md
Normal file
157
LICENSE.md
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
### GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||||
|
<http://fsf.org/>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates the
|
||||||
|
terms and conditions of version 3 of the GNU General Public License,
|
||||||
|
supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
#### 0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the
|
||||||
|
GNU General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License, other
|
||||||
|
than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
#### 1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
#### 2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
- a) under this License, provided that you make a good faith effort
|
||||||
|
to ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
- b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
#### 3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from a
|
||||||
|
header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
- a) Give prominent notice with each copy of the object code that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
- b) Accompany the object code with a copy of the GNU GPL and this
|
||||||
|
license document.
|
||||||
|
|
||||||
|
#### 4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that, taken
|
||||||
|
together, effectively do not restrict modification of the portions of
|
||||||
|
the Library contained in the Combined Work and reverse engineering for
|
||||||
|
debugging such modifications, if you also do each of the following:
|
||||||
|
|
||||||
|
- a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
- b) Accompany the Combined Work with a copy of the GNU GPL and this
|
||||||
|
license document.
|
||||||
|
- c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
- d) Do one of the following:
|
||||||
|
- 0) Convey the Minimal Corresponding Source under the terms of
|
||||||
|
this License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
- 1) Use a suitable shared library mechanism for linking with
|
||||||
|
the Library. A suitable mechanism is one that (a) uses at run
|
||||||
|
time a copy of the Library already present on the user's
|
||||||
|
computer system, and (b) will operate properly with a modified
|
||||||
|
version of the Library that is interface-compatible with the
|
||||||
|
Linked Version.
|
||||||
|
- e) Provide Installation Information, but only if you would
|
||||||
|
otherwise be required to provide such information under section 6
|
||||||
|
of the GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the Application
|
||||||
|
with a modified version of the Linked Version. (If you use option
|
||||||
|
4d0, the Installation Information must accompany the Minimal
|
||||||
|
Corresponding Source and Corresponding Application Code. If you
|
||||||
|
use option 4d1, you must provide the Installation Information in
|
||||||
|
the manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.)
|
||||||
|
|
||||||
|
#### 5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the Library
|
||||||
|
side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
- a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities, conveyed under the terms of this License.
|
||||||
|
- b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
#### 6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
as you received it specifies that a certain numbered version of the
|
||||||
|
GNU Lesser General Public License "or any later version" applies to
|
||||||
|
it, you have the option of following the terms and conditions either
|
||||||
|
of that published version or of any later version published by the
|
||||||
|
Free Software Foundation. If the Library as you received it does not
|
||||||
|
specify a version number of the GNU Lesser General Public License, you
|
||||||
|
may choose any version of the GNU Lesser General Public License ever
|
||||||
|
published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
190
README.md
Normal file
190
README.md
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
# KlausBMS
|
||||||
|
|
||||||
|
This is a battery monitoring system for Renault Twizy based on [TwizyVirtualBMS](https://github.com/dexterbg/Twizy-Virtual-BMS/) supporting Lithium packs with 14 (LiPo) or 16 (LiFe) cells.
|
||||||
|
|
||||||
|
This is not a fully featured BMS yet (in terms of M=*management*), it currently relies on an additional standard BMS for cell protection and balancing. The BMS can be a very simple one without any communication though, as KlausBMS does the monitoring itself.
|
||||||
|
|
||||||
|
KlausBMS is capable of monitoring up to 16 cell voltages, two temperature sensors and a current sensor.
|
||||||
|
|
||||||
|
The hardware setup is following the [VirtualBMS example](https://github.com/dexterbg/Twizy-Virtual-BMS/blob/master/extras/Twizy-Battery-Part-List.md#example-arduino-wiring-scheme). See [Voltage-Dividers.ods](extras/Voltage-Dividers.ods) for the default voltage probe resistor values. Both LEM HAC-600-S and Tamura L06P400S05 current sensors have been used successfully, others may work as well (see configuration).
|
||||||
|
|
||||||
|
The BMS will raise warnings and errors based on voltage and temperature anomalies detected. Drive and recuperation power levels as well as charging current can be controlled following the battery state and condition.
|
||||||
|
|
||||||
|
Using the (optional but recommended) current sensor it provides SOC and SOH/capacity measurements based on a (simple) hybrid calculation combining coulomb counting and voltage readings.
|
||||||
|
|
||||||
|
Log output can be monitored in parallel at the USB serial port and via Bluetooth (if BT module is used). Both log channels also support controlling and configuring the BMS by sending text commands.
|
||||||
|
|
||||||
|
KlausBMS is currently used in Twizy battery projects by:
|
||||||
|
- Błażej Błaszczyk (LiPo) <blazej.blaszczyk@pascal-engineering.com>
|
||||||
|
- Klaus Zinser (LiFePO4) <klauszinser@posteo.eu>
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To download, click the DOWNLOADS button in the top right corner, download the ZIP file. Extract to your Arduino sketchbook folder, start the Arduino IDE and open the sketch.
|
||||||
|
|
||||||
|
You will also need these libraries:
|
||||||
|
- [Twizy-Virtual-BMS](https://github.com/dexterbg/Twizy-Virtual-BMS)
|
||||||
|
- [MCP_CAN_lib by Cory Fowler](https://github.com/coryjfowler/MCP_CAN_lib)
|
||||||
|
- …and one of…
|
||||||
|
- [TimerOne by Paul Stoffregen](https://github.com/PaulStoffregen/TimerOne)
|
||||||
|
- [FlexiTimer2 by Paul Stoffregen](https://github.com/PaulStoffregen/FlexiTimer2)
|
||||||
|
- [TimerThree by Paul Stoffregen](https://github.com/PaulStoffregen/TimerThree)
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration & calibration
|
||||||
|
|
||||||
|
All configuration directives are located in the files "TwizyVirtualBMS_config.h" and "KlausBMS_config.h", read these files first to get an overview of the configuration features. When installing a KlausBMS update later on, you should be able to mostly keep your configuration files and just replace the "KlausBMS.ino" file, but take care to check for configuration changes.
|
||||||
|
|
||||||
|
Most operational configuration values are just initial defaults used when the Arduino EEPROM is empty/invalid. You can also restore the system to these values any time by issuing the "init" command (see "Runtime commands" below).
|
||||||
|
|
||||||
|
Configure your hardware characteristics and sensor setup first and enable the calibration mode (is enabled on a fresh copy). Update the voltage sensor scaling if you use other divider resistors.
|
||||||
|
|
||||||
|
In calibration mode, the KlausBMS will just output all sensor readings every 10 seconds. Upload the sketch and check for necessary input scaling adjustments. Adjust scaling factors and check again, until the Arduino readings match the real values, then disable calibration mode.
|
||||||
|
|
||||||
|
Hint: to do a dry run now, set `TWIZY_CAN_SEND` to 0. The KlausBMS will then enter the VirtualBMS "Init" and "Ready" state on startup even if the Twizy is not switched on (or not even connected).
|
||||||
|
|
||||||
|
|
||||||
|
## Operation
|
||||||
|
|
||||||
|
During operation, KlausBMS logs the battery state every three seconds on both communication channels like this:
|
||||||
|
|
||||||
|
| 33.8 %SOC | 52.6 V | 9598 Wd | 35 Ac | Driving
|
||||||
|
| 55.1 %Sv | -1.2 A | 3240 Wr | 29 Cc |
|
||||||
|
| 33.8 %Sc | 40.6 Ah | 19 Cf |< 48 %V | 0.06 V
|
||||||
|
| 100.0 %SOH | 120.0 Ah | 18 Cr |> 61 %V |
|
||||||
|
| 3.29 | 3.28 | 3.30 | 3.28 | 3.29 | 3.31 | 3.27 | 3.29 |
|
||||||
|
|>3.31 |<3.26 | 3.29 | 3.29 | 3.29 | 3.29 | 3.29 | 3.28 |
|
||||||
|
|
||||||
|
The layout needs a fixed spacing font, so make sure your (bluetooth) terminal is configured appropriately.
|
||||||
|
|
||||||
|
The upper four lines show the battery pack state followed by two lines of up to 16 cell voltages.
|
||||||
|
|
||||||
|
The `<` and `>` mark the cells with lowest and highest voltages. Their respective voltage based SOC is shown as `%V` above, along with the voltage difference between them (`0.06 V` in this example).
|
||||||
|
|
||||||
|
Pack state:
|
||||||
|
|
||||||
|
- `%SOC`: combined (effective) SOC of battery pack
|
||||||
|
- `%Sv`, `%Sc`: voltage and coulomb based SOC of battery pack
|
||||||
|
- `%SOH`: state of health (SOH) of battery pack (equivalent to relative capacity)
|
||||||
|
- `V`, `A`: momentary pack voltage and current
|
||||||
|
- `Ah`: upper/first value = available charge, lower value = absolute pack capacity in amp hours
|
||||||
|
- `Wd`, `Wr`: available drive and recuperation power levels (W)
|
||||||
|
- `Cf`, `Cr`: temperatures of front and rear sensors (°C)
|
||||||
|
- `Ac`: available/configured charge current (A)
|
||||||
|
- `Cc`: charger temperature (read from CAN) (°C)
|
||||||
|
- `Driving`: the current VirtualBMS state, error codes will be displayed below this field
|
||||||
|
|
||||||
|
|
||||||
|
## Log analysis
|
||||||
|
|
||||||
|
Capture the output to a file. Be aware the standard Arduino will do a reset on a new USB connection, so make sure your laptop will stay awake, or apply one of the hardware patches to disable this behaviour. Of course the bluetooth channel can be used as well, take care the terminal app is capable of receiving large logs (some will eat up your memory and become unusable).
|
||||||
|
|
||||||
|
The bash script [`logconv.sh`](extras/logconv.sh) can be used to convert the captured output into CSV and ODS format. You'll need some standard linux setup and the OpenOffice or LibreOffice "headless" package.
|
||||||
|
|
||||||
|
Alternatively, you can use the [logconv web service](https://dexters-web.de/logconv) on my site.
|
||||||
|
|
||||||
|
The resulting table will contain all of the log values in separate numerical columns, so can be used directly for analysis and to generate charts.
|
||||||
|
|
||||||
|
|
||||||
|
## Runtime commands
|
||||||
|
|
||||||
|
Set your serial monitor or terminal program to send CR, LF or both.
|
||||||
|
|
||||||
|
After sending any command, the KlausBMS will respond with the current configuration state and inhibit standard log output for 10 seconds. To return to standard log output immediately, send an empty command. Any unknown / misspelled command will output a command overview.
|
||||||
|
|
||||||
|
| Command | Function |
|
||||||
|
| --- | --- |
|
||||||
|
| `soh <prc>` | set SOH% |
|
||||||
|
| `soc <prc>` | set SOC% |
|
||||||
|
| `mcc <cur>` | set max charge current |
|
||||||
|
| `sc [<prc>]` | stop charge / set charge stop SOC |
|
||||||
|
| `mpw <drv> <rec>` | set max power |
|
||||||
|
| `dcb <soc1> <soc2> <lvl2>` | set drive cutback |
|
||||||
|
| `vrd <min> <max>` | set voltage range discharging |
|
||||||
|
| `vrc <min> <max>` | set voltage range charging |
|
||||||
|
| `svp <top> <bot>` | set SOC voltage prioritize |
|
||||||
|
| `scd <top> <bot>` | set SOC coulomb degrade |
|
||||||
|
| `init` | reset to default config |
|
||||||
|
| `load` | load state from EEPROM |
|
||||||
|
| `save` | save state to EEPROM |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
- All parameters are validated and constrained to their respective ranges.
|
||||||
|
- The max current and power levels define the upper limits, the system will use lower values as necessary / configured.
|
||||||
|
- To stop a running charge, simply issue `sc` without a parameter.
|
||||||
|
- Voltage ranges are defined at the cell voltage level.
|
||||||
|
- `save` is done automatically at every drive & charge end.
|
||||||
|
- `load` is done automatically after every Arduino start/reset.
|
||||||
|
- `init` is done automatically if the EEPROM is empty or the checksum is invalid.
|
||||||
|
|
||||||
|
The EEPROM checksum will become invalid when a KlausBMS update introduces new state variables, so it's a good idea to note the last state before installing an update.
|
||||||
|
|
||||||
|
|
||||||
|
## SOC hybrid algorithm parameters
|
||||||
|
|
||||||
|
The effectice pack SOC is calculated from both pack voltage and coulomb (Ah) counting. The pack voltage marks the absolute limits of the battery for "empty" and "full", but is a bad base for the SOC in between. Especially LiFe chemistry has a nearly constant voltage between 20 and 80%. Coulomb counting alone on the other hand would introduce cumulating measurement errors.
|
||||||
|
|
||||||
|
So the algorithm uses coulomb counting most of the time, but prioritizes the voltage measurement over the coulomb counting when approaching 0% or 100% relative voltage and/or degrades the coulomb count when approaching 0% or 100% respectively.
|
||||||
|
|
||||||
|
This process is defined by the voltage ranges and the threshold values:
|
||||||
|
|
||||||
|
- Voltage range discharging / charging (commands `vrd` and `vrc`)
|
||||||
|
- SOC voltage prioritize top / bottom (command `svp`)
|
||||||
|
- SOC coulomb degrade top / bottom (command `scd`)
|
||||||
|
|
||||||
|
The ranges and thresholds apply depending on the state: the "top" thresholds apply on charging/recuperating, the "bottom" ones on discharging.
|
||||||
|
|
||||||
|
The voltage thresholds always take precedence over the coulomb degradation, as voltage is a hard measurement.
|
||||||
|
|
||||||
|
The effects of wrong/bad voltage ranges and/or thresholds parameters are nonlinear SOC slopes. If you encounter sudden jumps or fast changes when approaching 0/100%, you need to adjust the SOC parameters.
|
||||||
|
|
||||||
|
Keep in mind you can do manual corrections of the SOC by issuing `soc`.
|
||||||
|
|
||||||
|
|
||||||
|
## SOH measurement
|
||||||
|
|
||||||
|
The SOH is the percentage of the measured usable capacity in relation to the nominal capacity as configured (`CAP_NOMINAL_AH`).
|
||||||
|
|
||||||
|
The usable capacity measurement is again based on the coulomb counting, so a properly calibrated current sensor is crucial.
|
||||||
|
|
||||||
|
The system adjusts the usable capacity at every charge stop after charging at least 50% SOC difference. The adjustment is calculated based on the difference between the charge amount reflecting the SOC change and the actual measured charge amount. The difference is applied smoothed by `SMOOTH_CAP` and weighted by the SOC difference charged: the more you charge, the more weight is put on the new measurement.
|
||||||
|
|
||||||
|
The results are written to the serial ports like this:
|
||||||
|
|
||||||
|
bms.enterState: capacity/SOH adjustment:
|
||||||
|
- SOC charged = 72%
|
||||||
|
- expected Ah = 86.4
|
||||||
|
- charged Ah = 84.7
|
||||||
|
- old cap Ah = 120.0
|
||||||
|
- new cap Ah = 119.2
|
||||||
|
- new SOH % = 99.3
|
||||||
|
|
||||||
|
Keep in mind you can do manual corrections of the SOH by issuing `soh`.
|
||||||
|
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
KlausBMS has been written and is maintained by Michael Balzer (<dexter@dexters-web.de> / https://dexters-web.de/).
|
||||||
|
|
||||||
|
A lot of ideas and refinements have been contributed by Błażej Błaszczyk, who has been using this software for multiple Twizy battery replacements beginning with the [Build #2 using Nissan Leaf cells](https://github.com/dexterbg/Twizy-Virtual-BMS/blob/master/extras/Blazej2-Leaf-Cells.md), and by Klaus Zinser, who is using the system for his 120 Ah LiFePO4 battery pack and heads for an upgrade to 240 Ah.
|
||||||
|
|
||||||
|
|
||||||
|
## Donations
|
||||||
|
|
||||||
|
**Donations** to support my efforts and further development are very welcome.
|
||||||
|
Please send donations via **Paypal** to: `dexter@dexters-web.de`
|
||||||
|
**Thanks! :-)**
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This is free software; you can redistribute it and/or modify it under the terms of the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl.html) as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110- 1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
**Have fun!**
|
45
TwizyVirtualBMS_config.h
Normal file
45
TwizyVirtualBMS_config.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* ==========================================================================
|
||||||
|
* Twizy Virtual BMS: Configuration
|
||||||
|
* ==========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TwizyVirtualBMS_config_h
|
||||||
|
#define _TwizyVirtualBMS_config_h
|
||||||
|
|
||||||
|
// Serial debug output:
|
||||||
|
// Level 0 = none, only output init message
|
||||||
|
// Level 1 = log state transitions, errors & CAN statistics
|
||||||
|
// Level 2 = log CAN frame dumps (10 second interval)
|
||||||
|
#define TWIZY_DEBUG_LEVEL 0
|
||||||
|
|
||||||
|
// Set to 0 to disable CAN transmissions for testing:
|
||||||
|
#define TWIZY_CAN_SEND 1
|
||||||
|
|
||||||
|
// CAN send timing is normally 10 ms (10.000 us).
|
||||||
|
// You may need to lower this if your Arduino is too slow.
|
||||||
|
#define TWIZY_CAN_CLOCK_US 10000
|
||||||
|
|
||||||
|
// VirtualBMS can use Timer1 (16 bit), Timer2 (8 bit) or Timer3 (16bit)
|
||||||
|
// Select Timer2/3 if you need Timer1 for e.g. AltSoftSerial
|
||||||
|
#define TWIZY_USE_TIMER 2
|
||||||
|
|
||||||
|
// Timer2: precise resolutions depend on CPU type & clock frequency
|
||||||
|
// i.e. Arduino Nano 16 MHz: 1000 = 1 ms / 2000 = 0.5 ms / 5000 = 0.2 ms / 10000 = 0.1 ms
|
||||||
|
// Use lowest resolution possible to minimize side effects on AltSoftSerial
|
||||||
|
#define TWIZY_TIMER2_RESOLUTION 1000
|
||||||
|
|
||||||
|
// Set your MCP clock frequency here:
|
||||||
|
#define TWIZY_CAN_MCP_FREQ MCP_16MHZ
|
||||||
|
|
||||||
|
// Set your SPI CS pin number here:
|
||||||
|
#define TWIZY_CAN_CS_PIN 10
|
||||||
|
|
||||||
|
// If you've connected the CAN module's IRQ pin (0 = polling):
|
||||||
|
#define TWIZY_CAN_IRQ_PIN 2
|
||||||
|
|
||||||
|
// Set your 3MW control pin here:
|
||||||
|
#define TWIZY_3MW_CONTROL_PIN 3
|
||||||
|
|
||||||
|
#endif // _TwizyVirtualBMS_config_h
|
||||||
|
|
BIN
extras/Voltage-Divider.ods
Normal file
BIN
extras/Voltage-Divider.ods
Normal file
Binary file not shown.
46
extras/logconv.sh
Executable file
46
extras/logconv.sh
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
log=$1
|
||||||
|
base=$(basename $log .txt)
|
||||||
|
csv=${2:-$base.csv}
|
||||||
|
ods=$base.ods
|
||||||
|
|
||||||
|
echo "Konvertiere $log ..."
|
||||||
|
|
||||||
|
if [ ! -f $log ] ; then
|
||||||
|
echo "Abbruch: '$log' nicht gefunden!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
conv() {
|
||||||
|
n=1
|
||||||
|
while true ; do
|
||||||
|
line=""
|
||||||
|
for i in {1..6} ; do
|
||||||
|
read col || return
|
||||||
|
line+=$col
|
||||||
|
done
|
||||||
|
echo $n $line
|
||||||
|
n=$((n + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo \
|
||||||
|
'#;soc;-;vpack;-;drvpwr;-;chgcur;-;state;soc_volt;-;curr;-;recpwr;-;temp_chg;-;error;' \
|
||||||
|
'soc_coul;-;avail_ah;-;temp_f;-;cmin_soc;-;cdif;-;' \
|
||||||
|
'soh;-;cap_ah;-;temp_r;-;cmax_soc;-;' \
|
||||||
|
'c0;c1;c2;c3;c4;c5;c6;c7;c8;c9;c10;c11;c12;c13;c14;c15' \
|
||||||
|
> $csv
|
||||||
|
|
||||||
|
cat $log | recode -f /CRLF | grep '^|' | conv \
|
||||||
|
| sed -e 's:Cc ||:Cc |-|:g' -e 's:|[<>]:|:g' -e 's:[| ][| ]*:;:g' -e 's:;$::' \
|
||||||
|
>> $csv
|
||||||
|
|
||||||
|
echo "CSV: $csv"
|
||||||
|
|
||||||
|
#unoconv -d spreadsheet -f ods -i 59,34,UTF8,,,1033 $csv
|
||||||
|
soffice --headless --convert-to ods --infilter=CSV:59,34,UTF8,,,1033 $csv
|
||||||
|
|
||||||
|
echo "ODS: $ods"
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in a new issue