1S-6S Battery Voltage Monitor (ROS)




Introduction: 1S-6S Battery Voltage Monitor (ROS)

About: Firmware Engineer / Hobbiest

The ability to remotely monitor the health of a battery provides the user with the convenience of knowing when it is time to bring their drone back for recharging. Currently, there are devices on the market such as the Hobby King LiPo Alarm or the more common 3DR Power Module used for drones/UAVs. However, neither product allows for real time monitoring of individual cell health over a serial connection. Not to mention that the 3DR PM cannot handle more than a 4S battery. This project will show how to construct a serial enabled power monitoring system that publishes messages over rosserial to a ROS master.

Note: This chip can be expanded to an 18S Cell LiPo battery by using three 8:1 analog multiplexers (MAX4617).

Step 1: Materials Required



  • Volt Meter
  • Soldering Iron
  • Solder
  • Heat Gun
  • Snips
  • Knife

Step 2: Understanding the Circuit

Since the Arduino analog pins operate in the 0-5V range and the voltage of a Lithium Polymer battery is compounding voltage with respect to ground as you advance pins, we need to use a voltage step down circuit using resistors. The equation for this circuit goes as follows:

Vout = (Vin * R2 ) / ( R1 + R2 )


Vin --> Supply Voltage

R1 --> Resistor One

R2 --> Resistor Two

Vout --> Scaled Voltage

By adjusting the ratio between R1 and R2 you can control the output voltage. Knowing that each consecutive pin will provide approximately ~3.7V more than the pin before it, you can design for the required voltage inputs to ensure that the Arduino pins will always get the required 0-5V. A demonstration design chart is HERE.

Step 3: Building & Testing the Circuit

Following the resistor values from the wiring schematic above, plug in the resistors on a bread board so they all share a common ground. Before wiring any of the wires to the Arduino Nano, use the multimeter to check that all the voltages fall within 0-5V. If not, check your circuit and repeat.

Step 4: Programming the Arduino

This tutorial assumes that you already have ROS installed and running on your system. If not, follow these links to get your system up to date:

Install from Source (Recommended)
Navigate to your ROS package directory (usually called your Sandbox) and create a new package for this project.

$ git clone git@github.com:djiglesias/ros-utilities.git
$ cd ros-utilities/

Navigate into the new package and clone the project from GitHub or download it HERE.

$ cd ros_battery_monitor/
$ make

That's it! Now let's upload the code to the Arduino. Open ros-utilities/ros_battery_monitor/src/main/main.ino in your Arduino IDE and select the board type and port. Click the check mark to verify that you have all required dependencies and upload to the board!

Install Manually
This code is an adaptation of the Hello World (publisher) example and this post from RC Groups. For this example, the cell_const[] are drawn from the scaling factors on the chart above.

#include <ros.h>
#include <sensor_msgs/BatteryState.h>

#define K           0.00472199
#define CELLS       6
#define MAX_CELLS   12

double cell_const[MAX_CELLS] = 

ros::NodeHandle nh;
sensor_msgs::BatteryState batt_state;
ros::Publisher batteryState("battery_state", &batt_state);

void setup() 
  // Initialize the ROS node.

  // Populate battery parameters.
  batt_state.design_capacity = 2200;      // mAh
  batt_state.power_supply_status = 2;     // discharging
  batt_state.power_supply_health = 0;     // unknown
  batt_state.power_supply_technology = 3; // LiPo
  batt_state.present = 1;                 // battery present

  batt_state.location = "Crawler";        // unit location
  batt_state.serial_number = "ABC_0001";  // unit serial number
  batt_state.cell_voltage = new float[CELLS];

void loop() 
{<br>  // Battery status.
  double battVoltage = 0.0;
  double prevVoltage = 0.0;
  // Populate battery state message.
  for (int i = 0; i < CELLS; i++)
    // Read raw voltage from analog pin.
    double cellVoltage = analogRead(i) * K;
    // Scale reading to full voltage.
    cellVoltage *= cell_const[i];
    double tmp = cellVoltage;
    // Isolate current cell voltage.
    cellVoltage -= prevVoltage;
    battVoltage += cellVoltage;
    prevVoltage = tmp;

    // Set current cell voltage to message.
    batt_state.cell_voltage[i] = (float)cellVoltage;

    // Check if battery is attached.
    if (batt_state.cell_voltage[i] >= 2.0)
      batt_state.present = 1;
      batt_state.present = 0;

  // Update battery health.
  batt_state.voltage = (float)battVoltage;

  if (batt_state.voltage > CELLS * 4.2)
    batt_state.power_supply_health = 4; // overvoltage
  else if (batt_state.voltage < CELLS * 3.0)
    batt_state.power_supply_health = 3; // dead
    batt_state.power_supply_health = 1; // good

  // Publish data to ROSSERIAL.
  batteryState.publish( &batt_state );

Step 5: Reading From the Arduino

Installed from Source
If you install this project from GitHub, then you can run the following command to launch the battery monitor.

$ roslaunch ros_battery_monitor battery_monitor.launch &
$ rostopic echo /battery/info

Manual Installation

Once the code is uploaded to the Arduino, plug it into your computer (Linux system) without the battery. If not already running, instantiate an instance of ROS master.

$ roscore &

Run the serial_node.py node from the rosserial_python package passing in the appropriate USB port as an argument.

$ rosrun rosserial_python serial_node.py /dev/ttyUSB0 &

If you received errors warning about insufficient permissions, then run the following commands and try again.

$ sudo usermod -a -G dialout client
$ sudo chmod a+rw /dev/ttyUSB0

Now, to view the incoming data from the Arduino you can simply run the echo command to display all new messages being published on /battery_state.

$ rostopic echo /battery/info

At first, the messages should come in stating 0.00V and Present = False for the battery. Once you plug the battery in, these fields will populate accordingly. For more information on the sensor_msgs::BatteryState, please view the documentation.

Note: I have not included diodes, so if you plug the battery in the wrong way there is a chance you will fry your Arduino and entire computer.

Step 6: Assembling the Circuit

Once your circuit is confirmed working, you should mount it to a perforation board to make it a more permanent solution. My project has limited space so I made the board as small as I could without making a PCB board. Notice the common ground rail on the underside of the board, this allowed me to keep the board clean and organized.

Note for Improvement:

  • Use diodes to make the board polarity protected.
  • Use the proper JST socket to prevent short circuiting.

Step 7: Final Touches

To prevent short circuiting, use 3 inch heat shrink tubing to encase the circuit board. Label the polarity of the pinout accordingly, and cut a hole for the USB socket.

Boom! You are done. Plug it into your ROS Robot and enjoy!

Be the First to Share


    • Knitting and Crochet Speed Challenge

      Knitting and Crochet Speed Challenge
    • New Year, New Skill Student Design Challenge

      New Year, New Skill Student Design Challenge
    • One Board Contest

      One Board Contest



    Question 11 months ago

    Firstly, great instructable. Just curious, but why (if cell 1 is 3.7v), do you have a resister R1? If the voltage is less than 5v, can you not take the cell directly to the arduino?


    1 year ago

    I am building this for my self too. can you please guide me how can i change pin mode

    A0-A5 --> D0-D5

    I have some other sensors attached to these A pins. waiting for your reply. Regards....


    Reply 1 year ago

    You can only use pins that start with A (analog), the digital pins (ones that starts with D) are not able to measure analog signal. Maybe you need a analog multiplexer or an arduino with more ananlog pins.


    3 years ago

    Hello, thank you for sharing with as this information. I have a batteri bank from 14s 3,6v. I want to use arduino mega + ethernet shield for monitor (not BMS) my batteri voltage, can you tell me if this is possible using your solution?

    Duncan Iglesias
    Duncan Iglesias

    Reply 3 years ago

    Hello, your question is already answered in the first paragraph. Since you're using a Mega you'll have 16 analog pins, so yes this should theoretically work. Also, the calculations for that are already included in Step 2. Good luck.


    4 years ago

    There's something wrong. If you add all the voltages you'll get arround 80V, with a bridge of 560k/100k this gives more than 14V on the A5 input which won't appreciate !

    Duncan Iglesias
    Duncan Iglesias

    Reply 4 years ago

    Good point, my circuit wasn't quite drawn to spec hence the misinterpretation. Each Lithium Polymer cell is 3.7V and they are compounding. In Step 3 I simply showed the sum of all voltages at each pin with respect to ground rather than show it as 3.7V each time. Therefore, the max circuit voltage is 22.2V for a nominally charged battery. Here is a link that you may find helpful for further understanding lithium polymer batteries.


    Thanks :)


    4 years ago

    great work! any thought of adding a Bluetooth or wifi module?

    Duncan Iglesias
    Duncan Iglesias

    Reply 4 years ago

    This could easily become a stand alone wireless slave device. Add a 7805 voltage regulator to your circuit and simply link up a BlueTooth module or 3DR radio to your RX/TX. Great idea!


    4 years ago

    Great instructable :)