Skip to main content

Weeks 3-5: ROS 2 Fundamentals

Learn the Robot Operating System (ROS 2) - the industry-standard framework for building robotic systems.

Creating ROS 2 Nodes with Python

Nodes are the fundamental building blocks of ROS 2. Each node performs a specific computational task.

Simple ROS 2 Node Example

import rclpy
from rclpy.node import Node

class MinimalNode(Node):
def __init__(self):
super().__init__('minimal_node')
self.get_logger().info('Hello from ROS 2!')

def main(args=None):
rclpy.init(args=args)
node = MinimalNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Topic-Based Communication

Topics enable publish-subscribe communication between nodes.

Publisher Example

from std_msgs.msg import String

class PublisherNode(Node):
def __init__(self):
super().__init__('publisher_node')
self.publisher = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(1.0, self.publish_message)
self.counter = 0

def publish_message(self):
msg = String()
msg.data = f'Hello ROS 2: {self.counter}'
self.publisher.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.counter += 1

Subscriber Example

class SubscriberNode(Node):
def __init__(self):
super().__init__('subscriber_node')
self.subscription = self.create_subscription(
String, 'chatter', self.listener_callback, 10)

def listener_callback(self, msg):
self.get_logger().info(f'Received: "{msg.data}"')

Services and Actions

Services (Request-Response)

from example_interfaces.srv import AddTwoInts

class ServiceNode(Node):
def __init__(self):
super().__init__('service_node')
self.srv = self.create_service(
AddTwoInts, 'add_two_ints', self.add_callback)

def add_callback(self, request, response):
response.sum = request.a + request.b
return response

Actions (Goal-Feedback-Result)

Actions are used for long-running tasks that can be preempted and provide periodic feedback. They consist of a goal, feedback, and a result.

import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
from example_interfaces.action import Fibonacci # Assuming this action is available

class FibonacciActionClient(Node):
def __init__(self):
super().__init__('fibonacci_action_client')
self._action_client = ActionClient(self, Fibonacci, 'fibonacci')

def send_goal(self, order):
goal_msg = Fibonacci.Goal()
goal_msg.order = order

self._action_client.wait_for_server()
self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback)
self._send_goal_future.add_done_callback(self.goal_response_callback)

def goal_response_callback(self, future):
goal_handle = future.result()
if not goal_handle.accepted:
self.get_logger().info('Goal rejected :(')
return

self.get_logger().info('Goal accepted :)')
self._get_result_future = goal_handle.get_result_async()
self._get_result_future.add_done_callback(self.get_result_callback)

def get_result_callback(self, future):
result = future.result().result
self.get_logger().info(f'Result: {result.sequence}')
rclpy.shutdown()

def feedback_callback(self, feedback_msg):
self.get_logger().info(f'Received feedback: {feedback_msg.feedback.sequence}')

def main(args=None):
rclpy.init(args=args)
action_client = FibonacciActionClient()
action_client.send_goal(10)
rclpy.spin(action_client)

if __name__ == '__main__':
main()

Building ROS 2 Packages

Package Structure

my_robot_pkg/
├── package.xml
├── setup.py
├── my_robot_pkg/
│ ├── __init__.py
│ └── my_node.py
└── launch/
└── my_launch.py

Creating a Package

# Create workspace
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src

# Create package
ros2 pkg create my_robot_pkg --build-type ament_python \
--dependencies rclpy std_msgs

# Build
cd ~/ros2_ws
colcon build
source install/setup.bash

Launch Files

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot_pkg',
executable='my_node',
name='robot_controller',
parameters=[{
'max_speed': 1.0,
'use_sim_time': True
}]
)
])

Weekly Exercise

Build a simple robot controller that:

  1. Subscribes to sensor data
  2. Processes the data
  3. Publishes control commands
  4. Provides a service for parameter updates