I wanted to replicate this BMS I have seen in youtube because I cannot afford the price the owner is asking. I want to explore how to do it. Here's the youtube link
I already have the codes for measuring temperature, voltage and current.
// Floats for ADC voltage & Input voltage
float adc_voltage = 0.0;
float in_voltage = 0.0;
// Floats for resistor values in divider (in ohms)
float R1 = 30000.0;
float R2 = 7500.0;
// Float for Reference Voltage
float ref_voltage = 5.0;
// Integer for ADC value
int adc_value = 0;
// Variables for Measured Voltage and Calculated Current
double Vout = 0;
double Current = 0;
const double scale_factor = 0.066; // 30A
const double vRef = 5.00;
const double resConvert = 1024;
double resADC = vRef/resConvert;
double zeroPoint = vRef/2;
void setup(){
// Setup Serial Monitor
Serial.begin(9600);
Serial.println("BMS");
}
void loop(){
// Read the Analog Input
adc_value = analogRead(A0);
// Determine voltage at ADC input
adc_voltage = (adc_value * ref_voltage) / 1024.0;
// Calculate voltage at divider input
in_voltage = adc_voltage / (R2/(R1+R2));
// Print results to Serial Monitor to 2 decimal places
Serial.print("Input_Voltage = ");
Serial.print(in_voltage, 2);
Serial.print(" V ");
// Vout is read 1000 Times for precision
for(int i = 0; i < 1000; i++) {
Vout = (Vout + (resADC * analogRead(A1)));
delay(1);
}
// Get Vout in mv
Vout = Vout /1000;
// Convert Vout into Current using Scale Factor
Current = (Vout - zeroPoint)/ scale_factor;
// Print Vout and Current to two Current = ");
Serial.print("Input_Current = ");
Serial.print(Current,2);
Serial.print(" A ");
//Multiply voltage and current to get power
float power = in_voltage*Current;
Serial.print("Power= ");
Serial.print(power,2);
Serial.print(" W ");
// Get a reading from the temperature sensor:
int reading = analogRead(A3);
// Convert the reading into voltage:
float voltage = reading * (5000 / 1024.0);
// Convert the voltage into the temperature in degree Celsius:
float temperature = voltage / 10;
// Print the temperature in the Serial Monitor:
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.print(" \xC2\xB0"); // shows degree symbol
Serial.println("C");
delay(1000);
}
I also seen this code for SOC calculation but there's no comments in the code so I cannot fully understand where are the values are comming and the basis for some of the multipliers used
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int mVperAmp = 100;const float chargingdfficiency= 0.7;
int RawValue= 0, ACSoffset = 2500;
double Voltage = 0, Amps = 0;
double g,q;
int m=0,c=0,d;
void resett() {
digitalWrite(8,LOW);
digitalWrite(7,LOW);
}
void setup() {
pinMode(A0, INPUT);pinMode(A1, INPUT);
pinMode(7,OUTPUT);pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
Serial.begin(9600);
delay(10);lcd.begin(20, 4); delay(10);
}
void loop() {
resett();
double vini=analogRead(1);vini = vini*5/1023;
vini=5*vini;Serial.print(vini,3);vini=vini/6;
double soc=((666.6667)*vini)-1300;delay(10);
q=soc*.42;
if(soc<30){
m=1;resett(); digitalWrite(7,HIGH);
} //charging
if(soc>=100){
m=0;resett();digitalWrite(8,HIGH);
} // DISCHARGING
if(m==0){
resett();digitalWrite(8,HIGH);
}
delay(10);
while(1){
RawValue = analogRead(0);
Voltage = (RawValue / 1024.0) * 5000;
Amps = ((Voltage - ACSoffset) / mVperAmp);Amps=-Amps;
if((Amps<.098)&&(Amps>-.098)){
Amps=0;
}
if(Amps>9){
resett();
lcd.clear();
lcd.display();
lcd.setCursor(1,0);
lcd.print("Overload");digitalWrite(9,HIGH);
while(1);
}
if(m==0){
if(Amps<=1.5) {
g=1.183;
}
else if(Amps<=2) {
g=0.042*Amps+1.12;
}
else if(Amps<=4) {
g=0.028*Amps+1.148;
}
else if(Amps<=5) {
g=0.032*Amps+1.132;
}
else if(Amps<=6) {
g=0.03*Amps+1.142;
}
else if(Amps<=7) {
g=0.325*Amps-0.628;
}
else if(Amps<=7.5) {
g=0.066*Amps+1.185;
}
else if(Amps<=8) {
g=0.028*Amps+1.47;
}
else if(Amps<=10){
g=1.694;
}
soc=(q-Amps*g*0.0002778)*2.38095;
q=soc*.42;
if(soc<5) {
m=1;resett();digitalWrite(7,HIGH);
}
}
if(m==1){
soc=(q-Amps*chargingdfficiency*0.0002778)*2.38095;
q=soc*.42;
if(soc>=100) {
m=0;resett();digitalWrite(8,HIGH);
}
}
lcd.clear();
lcd.display();
lcd.setCursor(1,0);
lcd.print("Soc = ");
lcd.setCursor(13,0);
lcd.print(soc,1);
lcd.setCursor(19,0);
lcd.print("%");
lcd.setCursor(1,1);
lcd.print("Amps= ");
lcd.setCursor(13,1);
lcd.print(Amps,1);
if (m==1) {
lcd.setCursor(1,2);lcd.print("Charging");
}
else {
lcd.setCursor(1,2);lcd.print("Discharge");
}
lcd.setCursor(1,3);lcd.print("Normal");
Serial.println((vini),3);
Serial.print("Amps = ");
Serial.println(Amps,9);
Serial.print(" Soc = ");
Serial.println(soc,9);
for(d=0;((Amps==0)&&(d<=1200));d++) {
RawValue = analogRead(0);
Voltage = (RawValue / 1024.0) * 5000;
Amps = ((Voltage - ACSoffset) / mVperAmp);Amps=-Amps;
if(d==1200 ){
vini=analogRead(1);vini = vini*25/(6*1023);
soc=((666.6667)*vini)-1300;d=0;
}
}
delay(1000);
}
}
I also tried to convert the couomb counting method (the integration formula) in tode but no luck it wasn't working well and I cant show it here I've deleted it already :< I really need to estimate the SOC and SOH. I dont need it to be too accurate (compared to SOC estimation methods that includes kalman filter or other that uses matlab or python) I really need it in Arduino only.