How to Create a Battery State Publisher in ROS 2

cover_battery_state

In this tutorial, I will show you how to create a simulated battery state publisher in ROS 2. My goal is to publish a sensor_msgs/BatteryState message to a topic named /battery_status

Real-World Application

The application that we will develop in this tutorial can be used as a template for a number of real-world robotic applications…the most important being:

  • Autonomous docking at a charging station once the battery level gets below a certain threshold.

Prerequisites

You can find the files for this post here on my Google Drive

In this implementation, I want the float32 percentage variable of the sensor_msgs/BatteryState message to start off as 1.0 and gradually decrease. 1.0 indicates a full battery at 100% charge. 

In a real-life application, we could have a condition plugin that listens to the /battery_status topic and returns SUCCESS when the battery percentage is lower than a specified value, and FAILURE otherwise.

Create the Battery State Publisher Node

Open a terminal window, and move to your package.

cd ~/dev_ws/src/two_wheeled_robot/scripts

Create a folder for battery state.

mkdir battery_state
cd battery_state

Open a new Python program called battery_state_pub.py.

gedit battery_state_pub.py

Add this code.

#!/usr/bin/env python3 

"""
Description:
Publish the battery state at a specific time interval
-------
Publishing Topics:
/battery_status – sensor_msgs/BatteryState
-------
Subscription Topics:
None
-------
Author: Addison Sears-Collins
Website: AutomaticAddison.com
Date: November 10, 2021
"""
 
import rclpy # Import the ROS client library for Python
from rclpy.node import Node # Enables the use of rclpy's Node class
from sensor_msgs.msg import BatteryState # Enable use of the sensor_msgs/BatteryState message type
 
class BatteryStatePublisher(Node):
  """
  Create a BatteryStatePublisher class, which is a subclass of the Node class.
  The class publishes the battery state of an object at a specific time interval.
  """
  
  def __init__(self):
    """
    Class constructor to set up the node
    """
   
    # Initiate the Node class's constructor and give it a name
    super().__init__('battery_state_pub')
     
    # Create publisher(s)  
     
    # This node publishes the state of the battery.
    # Maximum queue size of 10. 
    self.publisher_battery_state = self.create_publisher(BatteryState, '/battery_status', 10)
     
    # Time interval in seconds
    timer_period = 5.0 
    self.timer = self.create_timer(timer_period, self.get_battery_state)
    
    # Initialize battery level
    self.battery_voltage = 9.0 # Initialize the battery voltage level
    self.percent_charge_level = 1.0  # Initialize the percentage charge level
    self.decrement_factor = 0.99 # Used to reduce battery level each cycle
     
  def get_battery_state(self):
    """
    Callback function.
    This function gets called at the specific time interval.
    We decrement the battery charge level to simulate a real-world battery.
    """
    msg = BatteryState() # Create a message of this type 
    msg.voltage = self.battery_voltage 
    msg.percentage = self.percent_charge_level
    self.publisher_battery_state.publish(msg) # Publish BatteryState message 
     
    # Decrement the battery state 
    self.battery_voltage = self.battery_voltage * self.decrement_factor
    self.percent_charge_level = self.percent_charge_level * self.decrement_factor
   
def main(args=None):
 
  # Initialize the rclpy library
  rclpy.init(args=args)
 
  # Create the node
  battery_state_pub = BatteryStatePublisher()
 
  # Spin the node so the callback function is called.
  # Publish any pending messages to the topics.
  rclpy.spin(battery_state_pub)
 
  # Destroy the node explicitly
  # (optional - otherwise it will be done automatically
  # when the garbage collector destroys the node object)
  battery_state_pub.destroy_node()
 
  # Shutdown the ROS client library for Python
  rclpy.shutdown()
 
if __name__ == '__main__':
  main()

Save the code, and close the file.

Change the access permissions on the file.

chmod +x battery_state_pub.py

Open CMakeLists.txt.

cd ~/dev_ws/src/two_wheeled_robot
gedit CMakeLists.txt

Add the Python executables.

scripts/battery_state/battery_state_pub.py

Build the Package

Now we build the package.

cd ~/dev_ws/
colcon build

Run the Node

Open a new terminal,  and run the node:

ros2 run two_wheeled_robot battery_state_pub.py

Check out the current ROS topics.

ros2 topic list

Check the output on the /battery_status topic by opening a new terminal window and typing:

ros2 topic echo /battery_status

Here is the output:

1-battery-state-publisher

That’s it! Keep building!