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
- ROS 2 Foxy Fitzroy installed on Ubuntu Linux 20.04 or newer. I am using ROS 2 Galactic, which is the latest version of ROS 2 as of the date of this post.
- You have already created a ROS 2 workspace. The name of our workspace is “dev_ws”, which stands for “development workspace.”
- You have Python 3.7 or higher.
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
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:
That’s it! Keep building!