Once you build an Arduino based robot you will soon run into a situation where your robot goes nuts in some way or another. This is often caused when the battery voltage has dropped below a level to support both the arduino and the peripherals you have attached to it. One way to avoid or be made aware of this situation is to include a battery voltage monitor into your project. I have read a lot of naysayers saying this is not good practice, but I have had really good luck with this one and it keeps me aware of my battery status. Especially if your going to be using LiPo batteries.
Safely Read Voltage
Creating a voltage monitor is really a simple concept on the Arduino, but it does take some planning on your part. The Arduino inputs can only safely take 5 volts or less when a signal is supplied to them. So if your using a battery of more than 5 volts you have to reduce this voltage to a usable level. The battery I use on the Woody Bot is only 7 volts, but it is still too much for the Arduino to handle and will cause a failure eventually if not right away. This voltage divider I use here should be safe using 9v or less as your power source. Anything of a higher voltage and we will need to recalculate the resistor values.
So how do we measure our battery safely. For this we must incorporate a Voltage Divider. A voltage divider is a very basic circuit that takes an input voltage and reduces it to a safe output voltage. In our case we are looking for a 2 to 1 voltage divider. Using two 1K ohm resistors and a small perforated circuit board I created a voltage divider that effectively cut my input voltage in half. Reducing it to 3.5 volts at full charge.
Voltage Divider Calculations.
To figure out what your output voltage will be using a voltage divider we will need to do a little math.
In the image to the right you will see:
7v battery (Vin),
R1 - the first resistor,
R2 - the second resistor,
Ground.
In the middle you will see the Output wire to the Arduino (Zout) for our sensor pin.
No matter what your input voltage the Divider formula is the same. remember when you said you would never use Algebra in your real life...Wrong! LOL
The Divider Formula is Vout = Vin x (R1 \ (R1 + R2))
In our case it is:
Vout = 7v x (1000/(1000 + 1000))
Vout = 7v x (1000/2000)
Vout = 7v x 0.5
Vout = 3.5V
Since our Resistors are the same value we create a 50% to 50% Voltage Divider, By raising and lower the numbers of the individual resistors we can get different percentage. if you replaced R2 with a 4K resistor your change to a 75%/25% voltage divider. Which would drop your voltage to 1.75V at Vout. You would then have to adjust your readout calculations to match.
Change R2 to 3K
Vout = 7v x (1000/(1000 + 3000))
Vout = 7v x (1000/4000)
Vout = 7v x 0.25
Vout = 1.75V
You don't have to Create a board like I did but I find it easier to switch it out if I change input voltages. So I used a piece of perforated circuit board and soldered it up with jumper pin sockets on the board. I created a set of boards of diffeent values that I can switch at a moments notice. You could just solder wires the ends of the resistors and connect it up as well.
Voltage Loss
Anytime you connect a device to a battery you are indeed going to lose some voltage over time. Depending on the power draw of the device it could substantially reduce your battery life. This unit connected to your arduino draws a mere 3.5 milliamps so it shouldn't be a large drain on your battery.This should be less than the natural drain down of the battery when it is sitting idle.
Add this line to your void Loop() Section. It will run the function to display the time on an lcd.
Next we have to add a function that will read the sensor, then convert it to a readable number and display it on the lcd screen.
I have included the entire code I use for the Woody Bot with the Motorshield, Ping sensor and the 16x2 lcd. You will notice since I have the code for the start switch that I had to add the printVolts() line ahead of this code so that I can get a voltage reading when I first power the bot up. Adding it to the loop just keeps it updated while running.
//Code for the Woody Bot, with Ping Sensor, and LCD2004 readout
Safely Read Voltage
Creating a voltage monitor is really a simple concept on the Arduino, but it does take some planning on your part. The Arduino inputs can only safely take 5 volts or less when a signal is supplied to them. So if your using a battery of more than 5 volts you have to reduce this voltage to a usable level. The battery I use on the Woody Bot is only 7 volts, but it is still too much for the Arduino to handle and will cause a failure eventually if not right away. This voltage divider I use here should be safe using 9v or less as your power source. Anything of a higher voltage and we will need to recalculate the resistor values.
Voltage Divider Calculations.
To figure out what your output voltage will be using a voltage divider we will need to do a little math.
In the image to the right you will see:
7v battery (Vin),
R1 - the first resistor,
R2 - the second resistor,
Ground.
In the middle you will see the Output wire to the Arduino (Zout) for our sensor pin.
No matter what your input voltage the Divider formula is the same. remember when you said you would never use Algebra in your real life...Wrong! LOL
The Divider Formula is Vout = Vin x (R1 \ (R1 + R2))
In our case it is:
Vout = 7v x (1000/(1000 + 1000))
Vout = 7v x (1000/2000)
Vout = 7v x 0.5
Vout = 3.5V
Since our Resistors are the same value we create a 50% to 50% Voltage Divider, By raising and lower the numbers of the individual resistors we can get different percentage. if you replaced R2 with a 4K resistor your change to a 75%/25% voltage divider. Which would drop your voltage to 1.75V at Vout. You would then have to adjust your readout calculations to match.
Change R2 to 3K
Vout = 7v x (1000/(1000 + 3000))
Vout = 7v x (1000/4000)
Vout = 7v x 0.25
Vout = 1.75V
Perf Board Voltage Divider |
Voltage Loss
Anytime you connect a device to a battery you are indeed going to lose some voltage over time. Depending on the power draw of the device it could substantially reduce your battery life. This unit connected to your arduino draws a mere 3.5 milliamps so it shouldn't be a large drain on your battery.This should be less than the natural drain down of the battery when it is sitting idle.
Add this line to your void Loop() Section. It will run the function to display the time on an lcd.
printVolts();
Next we have to add a function that will read the sensor, then convert it to a readable number and display it on the lcd screen.
void printVolts()
{
int sensorValue = analogRead(A1); //read the A1 pin value
float voltage= sensorValue * (5.0 / 1024.0); //convert the value to a true voltage.
lcd.setCursor(13,1); //set the cursor to the end of line 2
lcd.print(voltage); //print the voltage
lcd.setCursor(13,0); //set the cursor to the end of line 1
lcd.print("VDC"); //print a label for the voltage
delay(100); //this delay makes the display readout more stable and not flash
}
{
int sensorValue = analogRead(A1); //read the A1 pin value
float voltage= sensorValue * (5.0 / 1024.0); //convert the value to a true voltage.
lcd.setCursor(13,1); //set the cursor to the end of line 2
lcd.print(voltage); //print the voltage
lcd.setCursor(13,0); //set the cursor to the end of line 1
lcd.print("VDC"); //print a label for the voltage
delay(100); //this delay makes the display readout more stable and not flash
}
I have included the entire code I use for the Woody Bot with the Motorshield, Ping sensor and the 16x2 lcd. You will notice since I have the code for the start switch that I had to add the printVolts() line ahead of this code so that I can get a voltage reading when I first power the bot up. Adding it to the loop just keeps it updated while running.
//Code for the Woody Bot, with Ping Sensor, and LCD2004 readout
//
//Kevin "Woody" Woodyard
//
//Check out http://woodystime.blogspot.com for more info and build guide.
#include <Ping.h>
#include <AFMotor.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define THRESHOLD 6
LiquidCrystal_I2C lcd(0x3f, 16, 2); // set the LCD address to 0x3f for a 16 chars and 2 line display
Ping ping = Ping(A3);
//Set motors to right frequency to match your servo.
AF_DCMotor motor(1, MOTOR12_64KHZ);
AF_DCMotor motor2(2, MOTOR12_64KHZ);
void setup()
{
Serial.begin(9600);
pinMode(A0, INPUT_PULLUP);
motor.setSpeed(255);
motor2.setSpeed(255);
lcd.init();
lcd.backlight();
sayHello();
}
void loop()
{
printVolts();
if (scan() <= THRESHOLD) // if the Woody Bot gets too close...
turnLeft();
else
goForward();
}
void sayHello()
{
lcd.print("Woody Bot");
lcd.setCursor(0,1);
lcd.print("Version 1.4");
delay(3000);
// Pause until the button is pressed
while (digitalRead(A0) == HIGH)
{
printVolts();
lcd.setCursor(0,1);
lcd.print("Press Start! ");
}
}
double scan()
{
ping.fire();
return ping.inches();
}
void goForward()
{
motor.run(FORWARD);
motor2.run(FORWARD);
lcd.setCursor(0,1);
lcd.print("Forward ");
delay(100);
}
void turnLeft()
{
motor.run(BACKWARD);
motor2.run(FORWARD);
lcd.setCursor(0,1);
lcd.print("Turn Left ");
delay(300);
}
void turnRight()
{
motor.run(FORWARD);
motor2.run(BACKWARD);
lcd.setCursor(0,1);
lcd.print("Turn Right ");
delay(300);
}
void printVolts()
{
int sensorValue = analogRead(A1);
float voltage= sensorValue * ((5.0 / 1024.0) * 2);
lcd.setCursor(13,1);
lcd.print(voltage);
lcd.setCursor(13,0);
lcd.print("VDC");
delay(100); //stability?
}
The next addition to the project is to have the bot go into a pause state when the voltage gets too low.//Kevin "Woody" Woodyard
//
//Check out http://woodystime.blogspot.com for more info and build guide.
#include <Ping.h>
#include <AFMotor.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define THRESHOLD 6
LiquidCrystal_I2C lcd(0x3f, 16, 2); // set the LCD address to 0x3f for a 16 chars and 2 line display
Ping ping = Ping(A3);
//Set motors to right frequency to match your servo.
AF_DCMotor motor(1, MOTOR12_64KHZ);
AF_DCMotor motor2(2, MOTOR12_64KHZ);
void setup()
{
Serial.begin(9600);
pinMode(A0, INPUT_PULLUP);
motor.setSpeed(255);
motor2.setSpeed(255);
lcd.init();
lcd.backlight();
sayHello();
}
void loop()
{
printVolts();
if (scan() <= THRESHOLD) // if the Woody Bot gets too close...
turnLeft();
else
goForward();
}
void sayHello()
{
lcd.print("Woody Bot");
lcd.setCursor(0,1);
lcd.print("Version 1.4");
delay(3000);
// Pause until the button is pressed
while (digitalRead(A0) == HIGH)
{
printVolts();
lcd.setCursor(0,1);
lcd.print("Press Start! ");
}
}
double scan()
{
ping.fire();
return ping.inches();
}
void goForward()
{
motor.run(FORWARD);
motor2.run(FORWARD);
lcd.setCursor(0,1);
lcd.print("Forward ");
delay(100);
}
void turnLeft()
{
motor.run(BACKWARD);
motor2.run(FORWARD);
lcd.setCursor(0,1);
lcd.print("Turn Left ");
delay(300);
}
void turnRight()
{
motor.run(FORWARD);
motor2.run(BACKWARD);
lcd.setCursor(0,1);
lcd.print("Turn Right ");
delay(300);
}
void printVolts()
{
int sensorValue = analogRead(A1);
float voltage= sensorValue * ((5.0 / 1024.0) * 2);
lcd.setCursor(13,1);
lcd.print(voltage);
lcd.setCursor(13,0);
lcd.print("VDC");
delay(100); //stability?
}
Comments