Skip to main content

ROS 2 Cheatsheet

Installation & Setup

# Install ROS 2 Humble (Ubuntu 22.04)
sudo apt update && sudo apt install ros-humble-desktop

# Source ROS 2
source /opt/ros/humble/setup.bash

# Add to ~/.bashrc for automatic sourcing
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc

Workspace Management

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

# Build workspace
colcon build --symlink-install

# Source workspace
source install/setup.bash

# Clean build
rm -rf build install log
colcon build

Package Management

# Create package (C++)
ros2 pkg create my_package --build-type ament_cmake --dependencies rclcpp

# Create package (Python)
ros2 pkg create my_package --build-type ament_python --dependencies rclpy

# List packages
ros2 pkg list

# Get package info
ros2 pkg prefix my_package

Node Commands

# List running nodes
ros2 node list

# Get node info
ros2 node info /my_node

# Run node
ros2 run package_name node_name

# Run node with remapping
ros2 run package_name node_name --ros-args -r __node:=new_name

Topic Commands

# List topics
ros2 topic list

# Show topic type
ros2 topic type /my_topic

# Echo topic data
ros2 topic echo /my_topic

# Show topic info
ros2 topic info /my_topic

# Publish to topic (String)
ros2 topic pub /my_topic std_msgs/msg/String "data: 'Hello'"

# Publish at rate (10 Hz)
ros2 topic pub -r 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5}, angular: {z: 0.0}}"

# Show message definition
ros2 interface show geometry_msgs/msg/Twist

Service Commands

# List services
ros2 service list

# Show service type
ros2 service type /my_service

# Call service
ros2 service call /my_service std_srvs/srv/Empty

# Call service with arguments
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5, b: 3}"

# Show service definition
ros2 interface show std_srvs/srv/Empty

Parameter Commands

# List parameters
ros2 param list

# Get parameter value
ros2 param get /my_node my_param

# Set parameter value
ros2 param set /my_node my_param 10.5

# Dump parameters to file
ros2 param dump /my_node > params.yaml

# Load parameters from file
ros2 param load /my_node params.yaml

Launch Files

Python Launch File (my_launch.py):

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='my_package',
executable='my_node',
name='my_node',
parameters=[{'param1': 10, 'param2': 'value'}],
remappings=[('/input', '/camera/image')],
output='screen'
)
])

Launch Commands:

# Run launch file
ros2 launch my_package my_launch.py

# Run with arguments
ros2 launch my_package my_launch.py use_sim_time:=true

Python Node Template

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class MyNode(Node):
def __init__(self):
super().__init__('my_node')

# Parameters
self.declare_parameter('frequency', 10.0)
freq = self.get_parameter('frequency').value

# Publisher
self.publisher = self.create_publisher(String, 'output_topic', 10)

# Subscriber
self.subscription = self.create_subscription(
String, 'input_topic', self.callback, 10
)

# Timer
self.timer = self.create_timer(1.0/freq, self.timer_callback)

self.get_logger().info(f'Node initialized at {freq} Hz')

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

def timer_callback(self):
msg = String()
msg.data = 'Hello ROS 2'
self.publisher.publish(msg)

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

if __name__ == '__main__':
main()

C++ Node Template

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

class MyNode : public rclcpp::Node
{
public:
MyNode() : Node("my_node")
{
// Parameters
this->declare_parameter("frequency", 10.0);
double freq = this->get_parameter("frequency").as_double();

// Publisher
publisher_ = this->create_publisher<std_msgs::msg::String>("output_topic", 10);

// Subscriber
subscription_ = this->create_subscription<std_msgs::msg::String>(
"input_topic", 10,
std::bind(&MyNode::callback, this, std::placeholders::_1));

// Timer
timer_ = this->create_wall_timer(
std::chrono::milliseconds(static_cast<int>(1000 / freq)),
std::bind(&MyNode::timer_callback, this));

RCLCPP_INFO(this->get_logger(), "Node initialized at %.1f Hz", freq);
}

private:
void callback(const std_msgs::msg::String::SharedPtr msg)
{
RCLCPP_INFO(this->get_logger(), "Received: '%s'", msg->data.c_str());
}

void timer_callback()
{
auto msg = std_msgs::msg::String();
msg.data = "Hello ROS 2";
publisher_->publish(msg);
}

rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MyNode>());
rclcpp::shutdown();
return 0;
}

Transforms (TF2)

# View transform tree
ros2 run tf2_tools view_frames

# Echo transform
ros2 run tf2_ros tf2_echo base_link camera_link

# Static transform publisher
ros2 run tf2_ros static_transform_publisher 0 0 1 0 0 0 base_link camera_link

Python TF2 Example:

from tf2_ros import TransformBroadcaster, Buffer, TransformListener
from geometry_msgs.msg import TransformStamped

# Broadcasting transforms
broadcaster = TransformBroadcaster(self)

t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'world'
t.child_frame_id = 'robot'
t.transform.translation.x = 1.0
t.transform.rotation.w = 1.0

broadcaster.sendTransform(t)

# Listening to transforms
tf_buffer = Buffer()
tf_listener = TransformListener(tf_buffer, self)

transform = tf_buffer.lookup_transform('world', 'robot', rclpy.time.Time())

Actions

Action Client Example:

from rclpy.action import ActionClient
from example_interfaces.action import Fibonacci

action_client = ActionClient(self, Fibonacci, 'fibonacci')
action_client.wait_for_server()

goal_msg = Fibonacci.Goal()
goal_msg.order = 10

future = action_client.send_goal_async(goal_msg)
future.add_done_callback(self.goal_response_callback)

Recording & Playback

# Record all topics
ros2 bag record -a

# Record specific topics
ros2 bag record /camera/image /cmd_vel

# Play bag file
ros2 bag play my_bag/

# Get bag info
ros2 bag info my_bag/

Debugging Tools

# RQt (GUI tools)
rqt

# RQt Graph (visualize nodes/topics)
rqt_graph

# Plot topic data
ros2 run rqt_plot rqt_plot

# RViz (3D visualization)
rviz2

# Robot State Publisher
ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:="$(cat robot.urdf)"

Common Message Types

# String
std_msgs/msg/String

# Numbers
std_msgs/msg/Int32, Float64

# Pose
geometry_msgs/msg/Pose
geometry_msgs/msg/PoseStamped

# Twist (velocity)
geometry_msgs/msg/Twist

# Transform
geometry_msgs/msg/TransformStamped

# Image
sensor_msgs/msg/Image

# Point Cloud
sensor_msgs/msg/PointCloud2

# Joint State
sensor_msgs/msg/JointState

Quality of Service (QoS)

from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy

# Sensor QoS (best effort, small history)
sensor_qos = QoSProfile(
reliability=ReliabilityPolicy.BEST_EFFORT,
history=HistoryPolicy.KEEP_LAST,
depth=5
)

# Reliable QoS (for critical data)
reliable_qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
history=HistoryPolicy.KEEP_ALL
)

# Use in subscription
self.create_subscription(Image, '/camera/image', callback, sensor_qos)

Useful Aliases

Add to ~/.bashrc:

alias r2='source /opt/ros/humble/setup.bash'
alias cb='colcon build --symlink-install'
alias cw='cd ~/ros2_ws && source install/setup.bash'
alias kn='ros2 node list'
alias kt='ros2 topic list'

Common Issues & Solutions

Issue: Package not found

# Rebuild workspace
cd ~/ros2_ws
colcon build --packages-select my_package
source install/setup.bash

Issue: Transform lookup failed

# Check TF tree
ros2 run tf2_tools view_frames
# Verify transform is being published
ros2 topic echo /tf

Issue: Cannot communicate between nodes

# Check ROS_DOMAIN_ID matches
echo $ROS_DOMAIN_ID

# Set domain (0-232)
export ROS_DOMAIN_ID=0