Installation

https://docs.ros.org/en/humble/Installation.html

Install ROS2

Binary packages

Binary packages are precompiled versions of the software that can be installed directly using a package manager (e.g. apt). nstalling from packages is the recommended method, as it installs necessary dependencies automatically and also updates alongside regular system updates.

Building from source

When you install from source, you download the raw code and compile it on your system. Building from source is recommended for platforms where binaries aren’t available or supported. Building from source also gives you the option to install the absolute latest version of the software.


Configure ROS2 Environment

picture 11
The ROS 2 development environment needs to be correctly configured before use. This can be done in two ways: either sourcing the setup files in every new shell you open, or adding the source command to your startup script. ROS 2 relies on the notion of combining workspaces using the shell environment. β€œWorkspace” is a ROS term for the location on your system where you’re developing with ROS 2. The core ROS 2 workspace is called the underlay. Subsequent local workspaces are called overlays. When developing with ROS 2, you will typically have several workspaces active concurrently.

  • Option 1: Source the setup files in each shell manually
# Replace ".bash" with your shell if you're not using bash
# Possible values are: setup.bash, setup.sh, setup.zsh
source /opt/ros/humble/setup.bash

You will need to run this command in every new terminal session to access ROS 2 commands, unless you automate the sourcing.

  • Option 2 (Recommended): Add sourcing to your shell startup script
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
  • Apply the changes to current terminal. From now on, ROS 2 commands will be available in all new terminal sessions automatically.
source ~/.bashrc

Create a Workspace

picture 10
A ROS workspace is a directory with a particular structure. Commonly there is a src subdirectory. Inside that subdirectory is where the source code of ROS packages will be located. Typically the directory starts otherwise empty.

  • Source main ROS2 installation as underlay
source /opt/ros/humble/setup.bash

It is important that we have sourced the environment for an existing ROS 2 installation that will provide our workspace with the necessary build dependencies for the example packages. This is achieved by sourcing the setup script provided by a binary installation or a source installation, i.e., another colcon workspace (see Installation). We call this environment an underlay.

  • Create directory
mkdir -p ros2_ws/src
cd ros2_ws/src
  • Clone the ros_tutorials repo, which contains turtlesim package, into the src folder
git clone https://github.com/ros/ros_tutorials.git -b humble
  • From the root of your workspace, resolve any missing package dependencies
    • Packages declare their dependencies in the package.xml file
# cd if you're still in the ``src`` directory with the ``ros_tutorials`` clone
cd ..
rosdep install -i --from-path src --rosdistro humble -y

Note: if you get the your rosdep installation has not been initialized yet error, run:

sudo rosdep init
rosdep update
  • Build the workspace with colcon
colcon build

Other Colcon build arguments

  • --packages-up-to builds the package you want, plus all its dependencies, but not the whole workspace (saves time)
  • --symlink-install saves you from having to rebuild every time you tweak python scripts
  • --event-handlers console_direct+ shows console output while building (can otherwise be found in the log directory)
  • --executor sequential processes the packages one by one instead of using parallelism
  • View the new directories colcon has created
    • The install directory is where your workspace’s setup files are, which you can use to source your overlay.
ls
# build  install  log
  • The directory structure of your ROS2 workspace (training_ws) should look like this:

Directory Structure

training_ws/
β”œβ”€β”€ build/                   
β”œβ”€β”€ install/                 
β”‚   └── local_setup.bash     
β”œβ”€β”€ log/                     
└── src/                     
    └── ros_tutorials/       
        β”œβ”€β”€ turtlesim/       
        └── other_packages/  
  • build/: Contains the build files generated by colcon build.
  • install/: Contains the installed packages and setup files necessary for running the workspace.
  • log/: Contains logs of the build process for debugging and analysis.
  • src/: The source directory where all ROS2 packages are placed. In this case, it contains the cloned ros_tutorials repository, which includes the turtlesim package.
  • Open a new terminal and source the setup file for your main ROS 2 installation.
  • Next, source the local_setup file from the training_ws overlay to enable access to the packages within the training_ws workspace.
source /opt/ros/humble/setup.bash
# cd into ros2_ws
source install/local_setup.bash
  • run turtle_sim package
ros2 run turtlesim turtlesim_node

picture 9


Build a Workspace Using Colcon

colcon is an iteration on the ROS build tools catkin_make, catkin_make_isolated, catkin_tools and ament_tools

  • Install colcon
sudo apt install python3-colcon-common-extensions
  • Add the source code to the ROS2 examples
cd ros2_ws/src
git clone https://github.com/ros2/examples src/examples -b humble
.
└── src
    └── examples
        β”œβ”€β”€ CONTRIBUTING.md
        β”œβ”€β”€ LICENSE
        β”œβ”€β”€ rclcpp
        β”œβ”€β”€ rclpy
        └── README.md

4 directories, 3 files
  • Build the workspace by running colcon build in the root of the workspace
    • --symlink-install allows the installed files to be changed by changing the files in the source space (e.g. Python files or other non-compiled resources) for faster iteration
cd ..
colcon build --symlink-install
  • The output will be in the install directory
.
β”œβ”€β”€ build
β”œβ”€β”€ install
β”œβ”€β”€ log
└── src

4 directories, 0 files
  • run tests for the packages we just built
colcon test
  • Source the environment
    • colcon will have generated bash/bat files in the install directory to help set up the environment.
    • These files will add all of the required elements to your path and library paths as well as provide any bash or shell commands exported by packages
source install/setup.bash

Tips

  • If you do not want to build a specific package, place an empty file named COLCON_IGNORE in the directory and it will not be indexed.
  • If you want to avoid configuring and building tests in CMake packages, you can pass: --cmake-args -DBUILD_TESTING=0.
  • If you want to run a single particular test from a package:
colcon test --packages-select YOUR_PKG_NAME --ctest-args -R YOUR_TEST_IN_PKG  
  • run a subscriber node from the examples
ros2 run examples_rclcpp_minimal_subscriber subscriber_member_function
  • In another terminal, run a publisher node
source install/setup.bash
ros2 run examples_rclcpp_minimal_publisher publisher_member_function

Create publisher and subscriber node

you will create nodes that pass information in the form of string messages to each other over a topic. The example used here is a simple β€œtalker” and β€œlistener” system; one node publishes data and the other subscribes to the topic so it can receive that data.

The code used in these examples can be found here.

  • Create a package
cd ros2_ws/src
ros2 pkg create --build-type ament_python --license Apache-2.0 py_pubsub
  • Write the publisher node
cd py_pubsub/py_pubsub
wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py
  • Add dependencies
  • Open the package.xml file to add the dependencies
    • In this step, you will declare that your package depends on rclpy and std_msgs to run.
cd ..  # Navigate to the parent directory where your package.xml is located
nano package.xml  # Open the file in nano editor
# Add the following lines
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
  • Add an entry point
    • Add 'talker = py_pubsub.publisher_member_function:main' within the console_scripts brackets
  • The contents of the setup.cfg file should be correctly populated automatically
    • This tells setuptools to put your executables in lib, because ros2 run will look for them there.
[develop]
script_dir=$base/lib/py_pubsub
[install]
install_scripts=$base/lib/py_pubsub
  • Write the subscriber node
    • The subscriber’s callback gets called as soon as it receives a message
cd py_pubsub
wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py
  • Add the entry point for the subscriber node below the publisher’s entry point
entry_points={
        'console_scripts': [
                'talker = py_pubsub.publisher_member_function:main',
                'listener = py_pubsub.subscriber_member_function:main',
        ],
},
  • Check for missing dependencies before building
rosdep install -i --from-path src --rosdistro humble -y
  • Build
# cd into ros2_ws
colcon build --packages-select py_pubsub
  • Run the talker node in a new terminal
source install/setup.bash
ros2 run py_pubsub talker
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...
  • Run the listener node in another terminal
source install/setup.bash
ros2 run py_pubsub listener
[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"
rqt_graph

Recap: Useful commands


Topics and Turtlesim

https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Introducing-Turtlesim/Introducing-Turtlesim.html

https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Topics/Understanding-ROS2-Topics.html

Turtlesim is a lightweight simulator for learning ROS 2. It illustrates what ROS 2 does at the most basic level to give you an idea of what you will do with a real robot or a robot simulation later on.

This tutorial touches upon core ROS 2 concepts, like nodes, topics, and services. All of these concepts will be elaborated on in later tutorials; for now, you will simply set up the tools and get a feel for them

  • start turtlesim
ros2 run turtlesim turtlesim_node
[INFO] [1729587409.041614825] [turtlesim]: Starting turtlesim with node name /turtlesim
[INFO] [1729587409.072164425] [turtlesim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
  • Use rqt_graph to see the running node and topics it’s subscribed to
    • Click refresh if window is blank
rqt_graph

picture 0

  • use turtlesim
    • Open another terminal to run a new node to control the turtle
ros2 run turtlesim turtle_teleop_key

Refresh rqt_graph to see how teleop node is interacting w/ the turtlesim node

picture 1
In this setup, the /teleop_turtle node publishes velocity commands to /turtle1/cmd_vel, which is consumed by /turtlesim to move the turtle. Additionally, action-related topics handle feedback and status for rotating the turtle to specific angles. The rqt_graph visually represents the connections between nodes and the topics they communicate over.

  • Show list of active topics
ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
  • Show list of active topics with topic type
ros2 topic list -t
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim/msg/Color]
/turtle1/pose [turtlesim/msg/Pose]
  • Show these topics in rqt_graph by unchecking the boxes under Hide: picture 2

  • See data being published on a topic

    • /teleop_turtle will publish data over /turtle1/cmd_vel topic when you use the keys to move the turtle
ros2 topic echo /turtle1/cmd_vel
linear:
  x: 0.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: -2.0
---
linear:
  x: 0.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 2.0
  • View the publisher publishing data over cmd_vel topic with 2 subscribers subscribed to it
    • Uncheck debug box
    • /_ros2cli5009 is the node created by the echo command picture 3

Show info on topics including number of publishers and subscribers

  • Twist messages have x,y,z components for angular and linear velocity

picture 4

picture 5

 ros2 topic info /turtle1/cmd_vel
Type: geometry_msgs/msg/Twist
Publisher count: 0
Subscription count: 2
  • Show the details of a message- the structure of data it expects
ros2 interface show geometry_msgs/msg/Twist
  • This same structure was shown with the echo command earlier
# This expresses velocity in free space broken into its linear and angular parts.

Vector3  linear
        float64 x
        float64 y
        float64 z
Vector3  angular
        float64 x
        float64 y
        float64 z
  • Pubish data direclty to a topic from the command line
ros2 topic pub <topic_name> <msg_type> '<args>'
  • Example using YAML syntax
    • With no command-line options, ros2 topic pub publishes the command in a steady stream at 1 Hz.
ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"

Try the spawn service

  • Use rqt to call the /spawn service and create another turtle picture 8

Create a package

picture 12
A package is an organizational unit for your ROS 2 code. If you want to be able to install your code or share it with others, then you’ll need it organized in a package. With packages, you can release your ROS 2 work and allow others to build and use it easily.

Package creation in ROS 2 uses ament as its build system and colcon as its build tool. You can create a package using either CMake or Python, which are officially supported, though other build types do exist.

ROS2 Python packages

my_package/
β”œβ”€β”€ package.xml    # File containing meta-information about the package
β”œβ”€β”€ resource/
β”‚   └── my_package # Marker file for the package.
β”œβ”€β”€ setup.cfg      # Required when a package has executables, so `ros2 run` can locate them.
β”œβ”€β”€ setup.py       # Contains instructions for how to install the package.
└── my_package/    # A directory with the same name as your package, used by ROS 2 tools to locate your package; it 
                   # contains `__init__.py`.

ROS2 CMake Packages

my_package/  
β”œβ”€β”€ CMakeLists.txt      # Describes how to build the code within the package  
β”œβ”€β”€ include/  
β”‚   └── my_package/     # Directory containing the public headers for the package  
β”œβ”€β”€ package.xml         # File containing meta-information about the package  
└── src/                # Directory containing the source code for the package  

tf2

sudo apt-get install ros-humble-rviz2 ros-humble-turtle-tf2-py ros-humble-tf2-ros ros-humble-tf2-tools ros-humble-turtlesim
  • Run demo to start turtlesim with 2 turtles
    • The tf2 library was used to create 3 coordinate frames
      • world frame
      • turtle1 frame
      • turtle2 frame
    • A tf2 broadcaster publishes the turtle coordinate frames
    • A tf2 listener computes the difference in turtle frames to follow the main turtle
ros2 launch turtle_tf2_py turtle_tf2_demo.launch.py
  • Run the following command in another terminal
ros2 run turtlesim turtle_teleop_key

tf2 tools

ros2 run tf2_tools view_frames
[INFO] [1736039682.543490745] [view_frames]: Listening to tf data for 5.0 seconds...
[INFO] [1736039687.555903700] [view_frames]: Generating graph in frames.pdf file...
[INFO] [1736039687.558138009] [view_frames]: Result:tf2_msgs.srv.FrameGraph_Response(frame_yaml="turtle1: \n  parent: 'world'\n  broadcaster: 'default_authority'\n  rate: 62.706\n  most_recent_transform: 1736039687.554910\n  oldest_transform: 1736039682.531490\n  buffer_length: 5.023\nturtle2: \n  parent: 'world'\n  broadcaster: 'default_authority'\n  rate: 62.705\n  most_recent_transform: 1736039687.554977\n  oldest_transform: 1736039682.531442\n  buffer_length: 5.024\n")

picture 16

  • Use tf2_echo to debug or analyze transformations in a ROS system by displaying the relative pose (position and orientation) between two coordinate frames
ros2 run tf2_ros tf2_echo [source_frame] [target_frame]
  • Show the transfrom of turtle2 frame with respect to turtle1 frame
ros2 run tf2_ros tf2_echo turtle2 turtle1

picture 18

  • Use rviz2, a visualization tool, to examine the tf2 frames
ros2 run rviz2 rviz2 -d $(ros2 pkg prefix --share turtle_tf2_py)/rviz/turtle_rviz.rviz

picture 19

In the context of the ROS tf (transform) framework, the transform data provides the relationship between the two frames: the turtle1 frame (reference) and the turtle2 frame (follower). This includes:

Components of the Transform

  1. Translation (Position Difference):

    • The difference in position between turtle1 and turtle2, usually expressed as a 2D vector ((dx), (dy)) in the turtle1 frame. This tells you where turtle2 is relative to turtle1’s position.
  2. Rotation (Orientation Difference):

    • The difference in orientation between turtle1 and turtle2, often expressed as a single angular value ((yaw)) in 2D (since turtlesim operates in a plane). This tells you how much turtle2 needs to rotate to face the direction of turtle1.

Transform in Action

  1. The listener node continuously receives the transformation data (translation and rotation) between turtle1 and turtle2.

  2. The control logic uses this transform to:

    • Compute the angular difference (needed to rotate turtle2).
    • Compute the linear distance (needed to move turtle2 forward).
  3. These calculated differences are used to set the velocities for turtle2:

    • Angular Velocity aligns turtle2 with turtle1.
    • Linear Velocity moves turtle2 toward turtle1.

Example

  1. Given Information:

    • turtle1 is at the origin: ((0, 0)).
    • turtle2 starts at ((1.544, 3.544)) and faces 0 degrees (along the positive x-axis).
  2. Relative Translation:

    • The position vector from turtle2 to turtle1 is:
  3. Distance Between Turtles:

    • The Euclidean distance between the two turtles is:

    Substituting the values:

  4. Angle to Face Turtle1:

    • The angle turtle2 needs to rotate to face turtle1 is given by:

    Substituting:

    This evaluates to:

  5. Action Plan:

    • Angular Velocity: Rotate turtle2 by ( \theta ) until it aligns with the vector pointing to turtle1.
    • Linear Velocity: Move turtle2 forward along this vector to close the distance.

Code with Motion Strategy

The ROS implementation will first align turtle2 with the direction of turtle1 and then move it forward:

#!/usr/bin/env python3
import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
import math
 
def calculate_angle_and_distance(turtle1_pose, turtle2_pose):
    # Relative position
    dx = turtle1_pose.x - turtle2_pose.x
    dy = turtle1_pose.y - turtle2_pose.y
 
    # Distance between turtles
    distance = math.sqrt(dx**2 + dy**2)
 
    # Angle that turtle2 needs to face
    desired_angle = math.atan2(dy, dx)
 
    return desired_angle, distance
 
def move_turtle2():
    rospy.init_node('turtle2_follow', anonymous=True)
 
    # Publishers and subscribers
    pub = rospy.Publisher('/turtle2/cmd_vel', Twist, queue_size=10)
    turtle2_pose = rospy.wait_for_message('/turtle2/pose', Pose)
    turtle1_pose = rospy.wait_for_message('/turtle1/pose', Pose)
 
    rate = rospy.Rate(10)  # 10 Hz
 
    while not rospy.is_shutdown():
        # Calculate required angle and distance
        desired_angle, distance = calculate_angle_and_distance(turtle1_pose, turtle2_pose)
 
        # Angle difference (rotation needed for turtle2)
        angle_difference = desired_angle - turtle2_pose.theta
 
        # Normalize the angle difference to [-pi, pi]
        angle_difference = math.atan2(math.sin(angle_difference), math.cos(angle_difference))
 
        # Velocity commands
        twist = Twist()
 
        # Rotate to align with turtle1
        if abs(angle_difference) > 0.01:  # Allow small tolerance
            twist.angular.z = 2.0 * angle_difference  # Proportional control
            twist.linear.x = 0.0  # No forward motion until aligned
        else:
            # Move forward when aligned
            twist.angular.z = 0.0
            twist.linear.x = 1.5 * distance  # Proportional control
 
        # Publish velocity
        pub.publish(twist)
 
        # Update current pose
        turtle2_pose = rospy.wait_for_message('/turtle2/pose', Pose)
 
        rate.sleep()
 
if __name__ == '__main__':
    try:
        move_turtle2()
    except rospy.ROSInterruptException:
        pass

Expected Behavior

  1. turtle2 computes the angle difference (\theta) and rotates to face turtle1.
  2. Once aligned, it moves forward along the computed direction vector, closing the distance between the two turtles.

This ensures turtle2 correctly rotates to face turtle1 and moves toward it, respecting the given scenario.