Python for Robotics: ROS2

In the world of robotics, there’s a constant need for adaptable and efficient software that can effectively communicate with the hardware. As a result, the Robot Operating System (ROS) was created to simplify the task of designing and building robust robotic applications. In this article, we will explore ROS2, the latest version of ROS and how it can be used with Python to create powerful robotic systems.
Introduction to ROS2
ROS2, or Robot Operating System 2, is the second generation of the popular open-source robotics middleware. It is designed to provide a common framework for developing, maintaining and deploying robotic applications on different platforms. ROS2 has been built with a focus on improving the limitations of ROS, such as scalability, reliability and real-time capabilities. It also adopts modern software engineering practices, making it easier for developers to create more robust and maintainable systems.
Why Use Python for Robotics?
Python is a versatile and widely-used programming language that has found its way into various domains, including robotics. Its readability, ease of use and a vast ecosystem of libraries make it a popular choice among robotics developers. Python’s key advantages for robotics include:
- Readability: Python’s syntax is clean and easy to understand, making it perfect for quickly grasping complex algorithms and logic.
- Ecosystem: Python has an extensive library ecosystem that caters to a wide range of applications, including robotics. This enables developers to build upon existing tools and libraries to accelerate development.
- Productivity: Python’s high-level nature allows developers to write less code, making it faster to prototype and implement new ideas.
- Cross-platform: Python can run on various platforms, including Windows, macOS and Linux, allowing for seamless integration with other systems.
Setting Up Your Environment
Before diving into ROS2 with Python, you need to set up your development environment. This involves installing ROS2 and configuring your workspace.
- Install ROS2: Follow the [official ROS2 installation guide](https://index.ros.org/doc/ros2/Installation/) for your operating system. Make sure to install the latest distribution.
- Set Up Your Workspace: To create a new ROS2 workspace, follow these steps:
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
After building the workspace, source the setup file:
source install/setup.bash
Now that your environment is set up, let’s get started with the basics of ROS2.
ROS2 Basics: Nodes, Topics and Services
ROS2 applications are built around three core concepts: nodes, topics and services.
- Nodes: A node is an executable that performs a specific task. In a robotic system, nodes can represent various components like sensors, actuators, or algorithms that need to communicate with each other.
- Topics: Topics are named channels through which nodes can send and receive messages. Nodes can publish messages to a topic or subscribe to it to receive updates. Topics enable many-to-many communication between nodes.
- Services: Services are another way for nodes to communicate. They allow for request-response communication between nodes, where one node sends a request message and the other node replies with a response message.
Creating a Python Package in ROS2
To create a Python package in ROS2, follow these steps:
- Navigate to your workspace’s
src
directory:
cd ~/ros2_ws/src
- Use the
ros2 pkg create
command to generate a new Python package:
ros2 pkg create --build-type ament_python my_robot_python_pkg
Writing a Simple Python Publisher and Subscriber
In this section, we will create a simple Python publisher and subscriber using ROS2.
- Create a Python Publisher: Inside your package’s
my_robot_python_pkg
directory, create a new file calledpublisher.py
:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class [PublisherNode]
def init(self):
super().init('publisher_node')
self.publisher = self.create_publisher(String, 'hello_topic', 10)
self.timer = self.create_timer(1.0, self.publish_message)
self.message_count = 0
def publish_message(self):
message = String()
message.data = f'Hello, world! {self.message_count}'
self.publisher.publish(message)
self.message_count += 1
self.get_logger().info(f'Published: "{message.data}"')
def main(args=None):
rclpy.init(args=args)
publisher_node = PublisherNode()
rclpy.spin(publisher_node)
publisher_node.destroy_node()
rclpy.shutdown()
if name == 'main':
main()
Create a Python Subscriber: Similarly, create a new file called subscriber.py inside your package’s my_robot_python_pkg directory:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class SubscriberNode(Node):
def __init__(self):
super().__init__('subscriber_node')
self.subscription = self.create_subscription(String, 'hello_topic', self.receive_message, 10)
def receive_message(self, message):
self.get_logger().info(f'Received: "{message.data}"')
def main(args=None):
rclpy.init(args=args)
subscriber_node = SubscriberNode()
rclpy.spin(subscriber_node)
subscriber_node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Now, run the publisher and subscriber in separate terminals:
Terminal 1:
ros2 run my_robot_python_pkg publisher
Terminal 2:
ros2 run my_robot_python_pkg subscriber
You should see the publisher sending messages and the subscriber receiving them.
Using ROS2 Services with Python
In this section, we will create a simple Python service and client using ROS2.
First, create a new file called add_two_ints.srv inside your package’s srv directory. Define the service as follows:
int64 a
int64 b
---
int64 sum
Modify your package.xml file to include the following dependencies:
<depend>builtin_interfaces</depend>
<depend>rosidl_default_generators</depend>
<depend>rosidl_default_runtime</depend>
Next, edit the CMakeLists.txt file to generate service code for Python:
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"srv/AddTwoInts.srv"
)
After making these changes, build your package:
cd ~/ros2_ws
colcon build
source install/setup.bash
Now, create a Python service in a new file called add_two_ints_server.py:
import rclpy
from rclpy.node import Node
from my_robot_python_pkg.srv import AddTwoInts
class AddTwoIntsServer(Node):
def __init__(self):
super().__init__('add_two_ints_server')
self.service = self.create_service(AddTwoInts, 'add_two_ints', self.handle_add_two_ints)
def handle_add_two_ints(self, request, response):
response.sum = request.a + request.b
self.get_logger().info(f'{request.a} + {request.b} = {response.sum}')
return response
def main(args=None):
rclpy.init(args=args)
server = AddTwoIntsServer()
rclpy.spin(server)
server.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Finally, create a Python service client in a new file called add_two_ints_client.py:
import sys
import rclpy
from rclpy.node import Node
from my_robot_python_pkg.srv import AddTwoInts
class AddTwoIntsClient(Node):
def __init__(self, a, b):
super().__init__('add_two_ints_client')
self.client = self.create_client(AddTwoInts, 'add_two_ints')
request = AddTwoInts.Request()
request.a = a
request.b = b
while not self.client.wait_for_service(timeout_sec=1.0):
self.get_logger().info('Waiting for service to become available...')
self.future = self.client.call_async(request)
self.future.add_done_callback(self.handle_response)
def handle_response(self, future):
response = future.result()
self.get_logger().info(f'{response.sum}')
rclpy.shutdown()
def main(args=None):
if len(sys.argv) != 3:
print('Usage: ros2 run my_robot_python_pkg add_two_ints_client <value a> <value b>')
sys.exit(1)
a = int(sys.argv[1])
b = int(sys.argv[2])
rclpy.init(args=args)
add_two_ints_client = AddTwoIntsClient(a, b)
rclpy.spin(add_two_ints_client)
add_two_ints_client.destroy_node()
if name == 'main':
main()
Now, run the service and client in separate terminals:
Terminal 1:
ros2 run my_robot_python_pkg add_two_ints_server
Terminal 2:
ros2 run my_robot_python_pkg add_two_ints_client 5 7
Conclusion
In this guide, we have explored ROS2 and its integration with Python for creating powerful robotic systems. We have covered the basics of ROS2, such as nodes, topics and services and demonstrated how to create Python packages, publishers, subscribers and services in ROS2. With this knowledge, you can now start building more advanced robotic applications using ROS2 and Python.