If Battery Voltages is Less than the Threshold Values then Circuit should stop

Hello Everyone ...,

I want to create a logic in my code such as If my Battery Voltages is Less than the Threshold Values (11.6 volts) then Circuit should stop working; I have already created the voltage divider circuit and it works like a charm; I don't want to use any relays.

Code Below is as an example; I only want to create a logic in my code like that

If (load connected) {
  if(voltage < 11.6) {
    disconnect load;
  }
} else {
  if (voltage > 11.6 ) {
  connect load;
  }
}

Below is the code that I'm currently working on and i want to add If my 12 volts Battery Voltages is Less than the Threshold Values then Circuit should stop working.
I'm using two motors and On a serial monitor screen, i'm controlling its speed like that when I enter "<A+010>" means motorA runs at slow speed or "<A+100>" full speed or <A+000>" stop, similar goes to motor B as well <B+000> motor B stop <B+010> slow speed <B+100> full speed.,
to run both motors like this <C+000> <C+010> <C+100>. on a serial monitor and it shows voltages on a serial monitor screen as well.

#include <Servo.h>
const int m_1 = 5;
const int m_2 = 6;
const int LED = 13;
const int Battery = A0;
float Voltage = 0.0; //input battery voltage
float Voltage1 = 0.0; //output voltage for analog pin A0
float R1 = 1590; // R1 =1.590
float R2 = 1000; // R2 =1000
int readValue = 0;
String strID = "";
int BaudRate = 4800;
Servo ESC_1; // create servo object to control the ESC 1
Servo ESC_2; // create servo object to control the ESC 2
#define FWD 0
#define BWD 1

unsigned int FORWARD = 2000;
unsigned int NEUTRAL = 1500;
unsigned int REVERSE = 1000;

unsigned int APwm = NEUTRAL;
unsigned int BPwm = NEUTRAL;

boolean ADirection = FWD;
boolean BDirection = FWD;
unsigned int AVelocity = 0; // CURRENT VELOCITY OF M1 in 0-100%
unsigned int BVelocity = 0; // CURRENT VELOCITY OF M2 in 0-100%

String inputString = "";
int TaskNumber = 0;


unsigned int GetValue(void)// fetch three digit number value from received string and convert to INTEGER
{
  unsigned int Val = 0;
  Val = (inputString[3] - 48) * 100;
  Val = Val + (inputString[4] - 48) * 10;
  Val = Val + (inputString[5] - 48);
  return (Val);
}



void setup()
{
  Serial.begin(BaudRate); //RX0 for Radiolink
  ESC_1.attach(m_1);// (pin, min pulse width, max pulse width in microseconds)
  ESC_2.attach(m_2);// (pin, min pulse width, max pulse width in microseconds)
  pinMode(LED, OUTPUT);
  pinMode(Battery, INPUT);
  Serial.println("System Started");
  ESC_1.writeMicroseconds(APwm);
  ESC_2.writeMicroseconds(BPwm);
  
  
}

boolean AFwdFlag = 0; //makes sure that the serial only prints once the state
boolean BFwdFlag = 0; //makes sure that the serial only prints once the state



void loop()
{
readValue = analogRead(Battery);
Voltage1 = (readValue * 5.0) / 1023;
Serial.print("$ , Voltages at Analog Pin A0 = ");
Serial.print(Voltage1);
Serial.print(" Volts");
Voltage = Voltage1 / (R2/(R1+R2));
Serial.print("\n,Battery Voltages = \r");
Serial.print(Voltage); 
Serial.print("\r Volts");

if (Voltage > 11.60) //
  {
   Serial.print(", GOOD BATTERY,\n");
  }

else if (Voltage < 10.00)
  {
    Serial.print(", LOW BATTERY,\n");
    
  }

  
//serialEvent(); 

if(TaskNumber){
  if(TaskNumber==1) Serial.println("OK");
  if(TaskNumber==2 || TaskNumber==4) {ESC_1.writeMicroseconds(NEUTRAL); }
  if(TaskNumber==3 || TaskNumber==4) {ESC_2.writeMicroseconds(NEUTRAL);}
  if(TaskNumber==5 || TaskNumber==7) {
                      if(ADirection==FWD) { APwm= NEUTRAL + (((FORWARD-NEUTRAL)/100)*AVelocity); ESC_1.writeMicroseconds(APwm); AFwdFlag=1; }
                      else {
                              if(AFwdFlag==1)
                               {
                                ESC_1.writeMicroseconds(NEUTRAL);delay(100);
                                ESC_1.writeMicroseconds(REVERSE);delay(100); 
                                ESC_1.writeMicroseconds(NEUTRAL);delay(100);
                                AFwdFlag=0;
                               } 
                              APwm= NEUTRAL - (((NEUTRAL-REVERSE)/100)*AVelocity); ESC_1.writeMicroseconds(APwm);  
                           }
                     } 


  if(TaskNumber==6 || TaskNumber==7) {
                      if(BDirection==FWD) { BPwm= NEUTRAL + (((FORWARD-NEUTRAL)/100)*BVelocity); ESC_2.writeMicroseconds(BPwm); BFwdFlag=1; }
                      else {
                              if(AFwdFlag==1)
                               {
                                ESC_2.writeMicroseconds(NEUTRAL);delay(100);
                                ESC_2.writeMicroseconds(REVERSE);delay(100); 
                                ESC_2.writeMicroseconds(NEUTRAL);delay(100);
                                BFwdFlag=0;
                               } 
                              BPwm= NEUTRAL - (((NEUTRAL-REVERSE)/100)*BVelocity); ESC_2.writeMicroseconds(BPwm);  
                           }
                     } 

 
  TaskNumber=0;
  
}


// <AN> <A+xxx> <A-xxx>
// <BN> <B+xxx> <B-xxx>
// <CN> <C+xxx> <C-xxx>

  while (Serial.available()) {
      
    char inChar = (char)Serial.read();
    inputString += inChar;

    if (inChar == '\r' || inChar == 10)
    {
      
      if(inputString[0]=='<') 
      {

        if(inputString[1]=='A' && inputString[2]=='T' && inputString[3]=='>' ) TaskNumber=1; // AT

        if(inputString[2]=='N' && inputString[3]=='>' )
        {
          if ( inputString[1] == 'A') TaskNumber = 2; // Set Motor A to Neutral
          if ( inputString[1] == 'B') TaskNumber = 3; // Set Motor B to Neutral
          if ( inputString[1] == 'C') TaskNumber = 4; // Set Both Motors to Neutral
        }
    
        if(inputString[6]=='>' )
        {
          
          if ( inputString[1] == 'A') { 
            if(inputString[2]=='+') ADirection=FWD; else ADirection=BWD; 
            AVelocity=GetValue(); 
            TaskNumber=5;
          }  
          
          if ( inputString[1] == 'B') { 
            if(inputString[2]=='+') BDirection=FWD; else BDirection=BWD; 
            BVelocity=GetValue(); 
            TaskNumber=6;
          }  
                    
          if ( inputString[1] == 'C'){ 
            if(inputString[2]=='+') { ADirection=FWD; BDirection=FWD;} 
            else {ADirection=BWD; BDirection=BWD;} 
            AVelocity=GetValue();
            BVelocity=GetValue(); 
            TaskNumber=7;
          }  
          
        }
  
      }
      inputString = "";
    }
  }
}

I also tested the LED code such as if voltages >11.6 volts LED on and if voltages<11.6 volts then LED off ... please don't give me an example like that.

Please help me ...

Which microcontroller are you using?

Arduino FAQ - How to stop an Arduino sketch

1 Like

I'm using arduino UNO

If you took a look at the ink from post#2 you'd find, if you are NOT going to use a relay, then you can put the Uno to sleep. It's not ideal but its something.

Do you just want the motors to shut down, or do you want everything to shut down including the Uno? It would help if we had some idea of how your power supplies are set up for the motors and the Uno.

1 Like

Thank you for your response; I want everything to shutdown.

I'm wirelessly controlling the motors and I'm using two arduino's. One as a transmitter and the other one as a receiver. I want to shut down everything when my battery would be less than 11.6 volts at the receiving section.

So you want the functionality to implement "disconnect load" and "connect load"?

For that we need full circuit please. And which Arduino?

BTW you need to implement hysteresis with the battery voltage test, otherwise it will oscillate off on off on off on off on - when load is removed battery voltage recovers a bit, causing immediate reconnect, then voltage drops under load, causing it to disconnect immediately - this repeats until the battery has drained till the no-load voltage is below the single threshold.

So the logic needs to be like:

#define BATT_THRESHOLD 11.6
#define HYSTERESIS  0.3    // a total guess, experimentally determined
If (load_connected())
{
  if (voltage < BATT_THRESHOLD)
    disconnect_load() ;
}
else
{ 
  if (voltage > BATT_THRESHOLD+HYSTERESIS)
    connect_load();
}

How to find hysteresis of the battery ?

I am not using any comparator circuit. I'm just using a step down dc-dc converter XM1584 Voltage Regulator IC which directly connects with the 12 volts Battery at the input and at the output with the Arduino 5 volts. The motors are directly connected with the Battery (both positive and negative) and its both signal pins are connected to the Arduino pin 5 and 6 digital PWM pins. Also I'm using MAX232 IC for interfacing my external radiolink to the arduino for wireless communication ...

Yes you are right because I'm monitoring my battery voltages and its varies gives different values means that 11.61, 11.54, 11.58, 11.62 and soo on ...
Can you please help me to calculate hysteresis of the battery ?

The variance in voltage readings from moment to moment is a normal thing that many people use some sort of filtering to smooth out.

A moving average filter works fairly well, GitHub - sebnil/Moving-Avarage-Filter--Arduino-Library-: A moving average, also called rolling average, rolling mean or running average, is a type of finite impulse response filter (FIR) used to analyze a set of datum points by creating a series of averages of different subsets of the full data set.

Me, I use a SimpleKalman Filter to do the job like so, GitHub - denyssene/SimpleKalmanFilter: A basic implementation of Kalman Filter for single variable models.

void fReadBattery( void * parameter )
{
  float adcValue = 0.0f;
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  float Vbatt = 0.0f;
  int printCount = 0;
  float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 1000; //delay for mS
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    /*
      printCount++;
      if ( printCount == 3 )
      {
      log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    */
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}
////
1 Like

Yes I calculated the Voltage Hysteresis which is 0.22 when the motor is running at full speed and 0.11 when the motors running at low speed

Now I want to include hysteresis in this code of Battery voltage

/BATTERY READINGS VARIABLES
const int Battery = A0;
float Voltage = 0.0; //input battery voltage
float Voltage1 = 0.0; //output voltage for analog pin A0
float R1 = 1590; // R1 =1.590
float R2 = 1000; // R2 =1000
int readValue = 0;
long previousMillis_battery = 0;
byte Bat_start_timer = 0;
int battery_wait;
unsigned long currentMillis = 0;


//BATTERY FUNCTION
void battery(long * previousMillis_battery)
{
 readValue = analogRead(Battery);
Voltage1 = (readValue * 5.0) / 1023;
Voltage = Voltage1 / (R2/(R1+R2));
if(Bat_start_timer == 0) battery_wait = 1000;
  if(currentMillis - *previousMillis_battery > battery_wait) {
     Serial.println(Voltage); Serial.print(",V,");  Serial.print(",Volts,");
  *previousMillis_battery = currentMillis;
    battery_wait = 1000; Bat_start_timer = 1; }
} // battery FUNCTION END

void setup()
{
  Serial.begin(9600);
  pinMode(Battery, INPUT);
  }

void loop()
{
     currentMillis = millis();
    battery(&previousMillis_battery);
}

Can anyone help me to add hysteresis which is 0.22 in this code and define voltages greater than 11. 6 volts and less than 11.6 volts ?

low end (11.6-.22)
high end (11.6+.22)

You have the 12V supply which directly drives the motors and drives the Arduino through a buck converter. So if you want to shut everything down, you would be switching off the 12V supply, and there would be no battery measurements by the Arduino after that even if the voltage rebounds because it would be off. Is that what you want to do?

If that isn't what you want, maybe you could describe more carefully exactly what you want to happen.

Yes ,I want this ..

Pick one.

The circuit shown below could be used to permit the Arduino to turn off all power. But then you would have to push the button to turn it on again.

Also, the voltage divider used to measure voltage would have to be placed downstream from the mosfet so that it will not source any current into the analog pin after the mosfet is turned off.

You really need to post your circuit. Without that, we're all just guessing.

Measure it? If you know the internal resistance of the battery (datasheet) and the load current it will be their product. But you can just monitor the change in voltage at the battery terminals as the load is connected and removed.