CMPSC 304 Robotic Agents
Press Space or → to advance
Topics: Weeks 10 through 14
Work together with your team, but only one person answers at a time!
🔴 🟢 ⚫ 🟠
🔴 Red: A physical sensor or actuator that is wired directly to the robot’s onboard computer
🟢 Green: A single process that performs one job and communicates through topics, services, or actions
⚫ Black: A YAML configuration file that defines all of the robot’s launch parameters
🟠 Orange: A single cell inside an occupancy grid map that stores a probability value
A node is an independent process in the ROS2 computation graph.
Command: ros2 node list shows all running nodes.
🔴 Red: Publishers must know the identity of all subscribers
🟢 Green: Each topic can only have one publisher and one subscriber
⚫ Black: Publishers and subscribers are decoupled — neither knows who the other is
🟠 Orange: Subscribers send acknowledgments back to publishers after each message
Activity 5–6: Lidar publishes to /scan; Cartographer subscribes to build the map.
🔴 Red: An obstacle (wall)
🟢 Green: Unknown / unexplored space
⚫ Black: Free space — safe to traverse
🟠 Orange: The robot’s current position
Activity 6: The .yaml file specifies free_thresh and occupied_thresh to convert pixel values. resolution gives meters-per-pixel.
🔴 Red: Builds a map of the environment from lidar scans
🟢 Green: Plans the shortest path from start to goal
⚫ Black: Estimates the robot’s position on a known map using a particle filter
🟠 Orange: Controls the robot’s wheel motors directly
AMCL answers: “Where am I on this map?”
Key distinction: SLAM builds the map. AMCL uses an existing map to localize.
🔴 Red: Services are faster than topics
🟢 Green: Services use a request/response pattern; topics use one-way publish/subscribe
⚫ Black: Topics can only carry sensor data; services carry commands
🟠 Orange: There is no difference — they are two names for the same thing
| Topics | Services |
|---|---|
| Continuous data streams | One-shot request → response |
| Fire and forget | Client waits for result |
| Many-to-many | One-to-one per call |
E.g., /cmd_vel, /scan | E.g., /spawn, /set_pen |
Activity 9: Service definitions use --- to separate request fields from response fields.
Twist message control a ground robot’s forward speed and turning?
🔴 Red: linear.z (forward) and angular.x (turn)
🟢 Green: linear.x (forward) and angular.z (turn)
⚫ Black: linear.y (forward) and angular.y (turn)
🟠 Orange: position.x (forward) and orientation.z (turn)
linear.x + angular.zTwist has sub-fields: linear (x,y,z) and angular (x,y,z).
linear.x — forward/backward speed (m/s)linear.y — lateral (sideways) speed — always 0 for differential-drive robotsangular.z — rotation rate (rad/s), positive = turn leftActivity 8: drive_pattern.py publishes Twist to /turtle1/cmd_vel. TurtleBot3 uses TwistStamped (adds a timestamp header).
resolution: 0.05 m/cell and inflation_radius: 0.20 m. How many cells outward from a wall does inflation extend?
🔴 Red: 2 cells
🟢 Green: 20 cells
⚫ Black: 4 cells
🟠 Orange: 5 cells
Calculation: inflation_radius / resolution = 0.20 / 0.05 = 4 cells
robot_radius → inscribed (cost 253)Activity 7: 14×14 costmap grid exercise used exactly these values.
🔴 Red: Global is for simulation; local is for real robots
🟢 Green: Global covers the entire map for path planning; local covers a small area around the robot for obstacle avoidance
⚫ Black: Global uses lidar; local uses the camera
🟠 Orange: No difference — same costmap at different zoom levels
NavigateToPose) instead of publishing to a topic?
🔴 Red: Actions are faster than topics
🟢 Green: Actions provide feedback during execution, a result on completion, and can be cancelled
⚫ Black: Actions can carry larger messages than topics
🟠 Orange: Actions are required for any message that includes position data
Actions are for long-running goals (e.g., navigate to a point).
P4 Part 3: The waypoint node sends goals via NavigateToPose action, using send_goal_async() and a result_callback to chain waypoints.
map_saver_cli, what two files are created?
🔴 Red: map.png (color image) and map.json (waypoints)
🟢 Green: map.pgm (grayscale image) and map.yaml (metadata: resolution, origin, thresholds)
⚫ Black: map.bag (rosbag) and map.urdf (robot model)
🟠 Orange: map.csv (grid values) and map.xml (configuration)
.pgm image + .yaml metadata.pgm — Grayscale image; white=free, black=occupied, grey=unknown.yaml — Metadata including:
resolution: meters per pixel (e.g., 0.05)origin: [x, y, yaw] of the bottom-left cornerfree_thresh / occupied_thresh: probability cutoffsActivity 6: Real-world map dimensions = pixel count × resolution.
rclpy.spin(node) do?
🔴 Red: Rotates the robot in a circle
🟢 Green: Runs the event loop, processing timer callbacks and incoming messages
⚫ Black: Sends a single message and exits
🟠 Orange: Compiles the ROS2 package before running
rclpy.spin(node) is the event loop — like Arduino’s loop().
spin(), the node exits immediatelyrclpy.init() → create node → rclpy.spin() → rclpy.shutdown()Activity 9: wall_avoider.py uses create_subscription() instead of a timer — both work with spin().
🔴 Red: Open-loop uses Wi-Fi; closed-loop uses Bluetooth
🟢 Green: Open-loop executes commands without reading sensors; closed-loop adjusts behavior based on sensor feedback
⚫ Black: Open-loop runs on a timer; closed-loop runs on a subscriber
🟠 Orange: Open-loop is for simulation only; closed-loop is for physical robots
Activity 8: drive_pattern.py = open-loop (timer-based, ignores pose). Activity 9: wall_avoider.py = closed-loop (subscriber reads pose, reacts).
Nav2 = closed-loop: AMCL updates position from lidar; local planner adjusts in real time.
Covered in: Writing ROS2 Nodes slides (publisher+timer vs subscriber patterns) + Activities 8 & 9.
✋ First hand up gets to answer!
Twist to /cmd_vel
AMCL localizes robot on the map
Global planner finds a path on the global costmap
Goal pose is received by Nav2
Local planner follows path using the local costmap
Robot reaches the goal
Write the numbers 1–6 next to each step
Twist to /cmd_velxy_goal_tolerance)Nav2 pipeline: Goal → AMCL → Global Planner → Local Planner → /cmd_vel → Done
$ ros2 topic info /cmd_vel
Type: geometry_msgs/msg/Twist
Publisher count: 2
Subscription count: 1
$ ros2 topic info /scan
Type: sensor_msgs/msg/LaserScan
Publisher count: 1
Subscription count: 3
a) How many nodes are publishing velocity commands?
b) How many nodes are consuming the lidar data?
c) Is it a problem that two nodes publish to /cmd_vel? Why?
a) 2 nodes are publishing velocity commands to /cmd_vel.
b) 3 nodes are consuming (subscribing to) the lidar data on /scan.
c) Yes, it can be a problem! Two publishers on /cmd_vel means both are sending competing velocity commands to the robot. The robot will execute whichever message arrives last, causing jerky or unpredictable behavior.
# = wall, . = free), with inflation_radius = 4 cells and resolution = 0.05 m/cell, mark every free cell that falls within the inflation buffer as I. Leave cells outside the buffer as .
| # | # | # | # | # | # | # | # |
| # | . | . | . | . | . | . | # |
| # | . | . | . | . | . | . | # |
| # | . | . | # | # | . | . | # |
| # | . | . | # | # | . | . | # |
| # | . | . | . | . | . | . | # |
| # | . | . | . | . | . | . | # |
| # | # | # | # | # | # | # | # |
Same approach as Activity 7: check each . cell’s distance to the nearest #. If ≤ 4 cells, mark it I.
Every interior cell is ≤ 4 cells from a #, so all become I:
| # | # | # | # | # | # | # | # |
| # | I | I | I | I | I | I | # |
| # | I | I | I | I | I | I | # |
| # | I | I | # | # | I | I | # |
| # | I | I | # | # | I | I | # |
| # | I | I | I | I | I | I | # |
| # | I | I | I | I | I | I | # |
| # | # | # | # | # | # | # | # |
# = higher cost)ros2 node listros2 topic echo /scanros2 topic hz /turtle1/poseros2 service listros2 topic info /cmd_velA. Shows publisher/subscriber counts and message type for a topic
B. Prints live laser distance measurements as they arrive
C. Lists all available request/response endpoints
D. Shows all running processes in the ROS2 graph
E. Reports the publish rate (~62 Hz) of a topic
| Command | Match | What It Does |
|---|---|---|
ros2 node list | D | Lists all running nodes (processes) |
ros2 topic echo /scan | B | Prints live messages from the lidar topic |
ros2 topic hz /turtle1/pose | E | Measures publish rate (~62 Hz for turtlesim pose) |
ros2 service list | C | Lists available services (e.g., /spawn, /set_pen) |
ros2 topic info /cmd_vel | A | Shows type, publisher count, subscriber count |
Key: echo = see data, hz = see rate, info = see metadata, list = see everything.
| Concept | What It Does | Key Detail |
|---|---|---|
| Node | Independent process in ROS2 graph | One job per node |
| Topic | Named channel for pub/sub messaging | Decoupled, many-to-many |
| Service | Request/response communication | One-shot, --- separator in definition |
| Action | Long-running goal with feedback | Goal → feedback → result; cancellable |
| Twist | Velocity command | linear.x + angular.z |
| SLAM | Build map + track position simultaneously | Inputs: lidar + odometry |
| Occupancy grid | Grid map: 0=free, 100=occupied, −1=unknown | .pgm + .yaml files |
| AMCL | Localize on a known map | Particle filter converges over time |
| Costmap | Cost grid for path planning | Global (full map) + Local (around robot) |
| Inflation | Expand obstacles for safety | cells = inflation_radius / resolution |
| Nav2 pipeline | Full navigation stack | Goal → AMCL → Planner → Controller → /cmd_vel |
| Sim-to-real gap | Behavior difference sim vs. reality | Noise, drift, latency, docking, battery |
ros2 node list # See all running nodes
ros2 topic list # See all active topics
ros2 topic echo /scan # View live messages on a topic
ros2 topic hz /scan # Check publish rate
ros2 topic info /cmd_vel # See type + publisher/subscriber counts
ros2 service list # See all available services