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:
- Subscribes to sensor data
- Processes the data
- Publishes control commands
- Provides a service for parameter updates