Intermediate Tier Exercises
Test Your Skills in Perception, TF2, SLAM, and Navigation
Overview
These exercises test your practical skills from the Intermediate tier:
- I1: Camera and Depth Data Processing
- I2: TF2 Coordinate Frames
- I3: SLAM Toolbox Configuration
- I4: Nav2 Basics
Complete these exercises before moving to the Advanced tier.
Exercise 1: Image Processing Pipeline
Task: Create a perception node that combines camera and depth data.
Requirements
- Subscribe to both
/camera/image_rawand/depth_camera/depth/image_raw - Synchronize the two image streams (use
message_filters) - For each synchronized pair:
- Find the center pixel of the color image
- Get the depth value at that pixel
- Publish a
PointStampedmessage with the 3D position
Starter Code
from message_filters import Subscriber, ApproximateTimeSynchronizer
# Create synchronized subscribers
rgb_sub = Subscriber(self, Image, '/camera/image_raw')
depth_sub = Subscriber(self, Image, '/depth_camera/depth/image_raw')
sync = ApproximateTimeSynchronizer([rgb_sub, depth_sub], queue_size=10, slop=0.1)
sync.registerCallback(self.synced_callback)
def synced_callback(self, rgb_msg, depth_msg):
# Your code here
pass
Success Criteria
- Messages are synchronized within 100ms
- 3D point is published at 10+ Hz
- Depth values are in meters
Exercise 2: Custom TF Broadcaster
Task: Create a TF broadcaster for a simulated pan-tilt camera.
Requirements
- Broadcast a
camera_panframe that rotates around Z axis - Broadcast a
camera_tiltframe that rotates around Y axis - Accept pan and tilt angles as ROS 2 parameters
- Update transforms at 50 Hz
Frame Hierarchy
base_link
└── camera_mount (static: 0, 0, 0.5)
└── camera_pan (dynamic: rotates around Z)
└── camera_tilt (dynamic: rotates around Y)
└── camera_optical (static: rotation only)
Success Criteria
- Can set pan angle via parameter
- Can set tilt angle via parameter
- TF tree visible in RViz2
- Frames update smoothly
Exercise 3: SLAM Parameter Tuning
Task: Optimize SLAM Toolbox for a specific environment.
Scenario A: Long Corridor
- Environment: 50m long, 2m wide corridor
- Challenge: Limited features, potential drift
Recommended parameters to tune:
minimum_travel_distancemax_laser_rangeresolution
Scenario B: Cluttered Office
- Environment: Many desks, chairs, and small obstacles
- Challenge: Dynamic objects, feature-rich but noisy
Recommended parameters to tune:
resolutionscan_buffer_sizeloop_search_maximum_distance
Tasks
- Create a parameter file for each scenario
- Run SLAM in both environments
- Compare map quality
Success Criteria
- Corridor map has minimal drift
- Office map captures desk/chair layout
- Both maps are suitable for navigation
Exercise 4: Waypoint Navigation
Task: Create a node that navigates through multiple waypoints.
Requirements
- Define a list of 4+ waypoints (x, y, yaw)
- Navigate to each waypoint in sequence
- Wait at each waypoint for 3 seconds
- Handle navigation failures gracefully
- Report progress (e.g., "Reached waypoint 2/4")
Starter Code
class WaypointNavigator(Node):
def __init__(self):
super().__init__('waypoint_navigator')
self.waypoints = [
(1.0, 0.0, 0.0), # x, y, yaw
(1.0, 1.0, 1.57),
(0.0, 1.0, 3.14),
(0.0, 0.0, -1.57),
]
self.current_waypoint = 0
# Your code here: set up action client
def navigate_to_next_waypoint(self):
# Your code here
pass
Success Criteria
- Robot visits all 4 waypoints
- Pauses 3 seconds at each
- Handles at least one navigation failure
- Returns to start position
Exercise 5: Integrated Challenge
Task: Build a complete perception-to-navigation pipeline.
Scenario
Your robot must:
- Detect an orange cone in the camera image
- Estimate the cone's 3D position using depth data
- Transform the position to the map frame
- Navigate to 0.5m in front of the cone
- Stop and report success
Components Needed
- Color detection (I1): Find orange pixels
- Depth lookup (I1): Get distance to cone
- TF transform (I2): Convert camera→map frame
- Navigation goal (I4): Send to Nav2
Hints
# Color detection (HSV range for orange)
lower_orange = np.array([10, 100, 100])
upper_orange = np.array([25, 255, 255])
mask = cv2.inRange(hsv_image, lower_orange, upper_orange)
# Find centroid of orange region
moments = cv2.moments(mask)
cx = int(moments['m10'] / moments['m00'])
cy = int(moments['m01'] / moments['m00'])
Success Criteria
- Detects orange cone in various positions
- Accurately estimates 3D position (within 20cm)
- Transforms to map frame correctly
- Navigates to goal position
- Stops at appropriate distance
Self-Assessment Checklist
Before moving to the Advanced tier, confirm you can:
- Use cv_bridge to process camera images
- Process depth images to find distances
- Create static and dynamic TF transforms
- Look up transforms between frames
- Configure and run SLAM Toolbox
- Save and load maps
- Launch Nav2 with a pre-built map
- Send navigation goals programmatically
- Monitor navigation status
Debugging Tips
Image Processing Issues
# Check if images are being published
ros2 topic hz /camera/image_raw
ros2 topic echo /camera/image_raw --once | head -20
TF Issues
# View TF tree
ros2 run tf2_tools view_frames
# Check specific transform
ros2 run tf2_ros tf2_echo base_link camera_link
# Monitor TF errors
ros2 run tf2_ros tf2_monitor
Navigation Issues
# Check Nav2 node status
ros2 lifecycle list /planner_server
ros2 lifecycle list /controller_server
# Monitor navigation feedback
ros2 action list
ros2 topic echo /navigate_to_pose/_action/feedback
Next Steps
Congratulations on completing the Intermediate tier exercises!
If you completed these successfully, you're ready for:
If you struggled with any exercises, review the corresponding lesson before continuing.