How to Run ROS 2 on Multiple Machines

In this tutorial, we will learn how to run ROS 2 on different machines using the ROS_DOMAIN_ID environment variable. 

We will use the built-in demo_nodes_cpp package as an example, running the talker node on one machine to broadcast “Hello World” messages over a topic called /chatter. We will run the listener node on another machine.

Prerequisites

  • You have ROS 2 installed on multiple computers.

Directions

First, ensure both computers are on the same network.

  • Connect both machines to the same WiFi network or connect them using an Ethernet cable.

We will now set the ROS_DOMAIN_ID on the first machine. 

The ROS_DOMAIN_ID is like a unique channel number that allows ROS 2 nodes to communicate with each other when they are set to the same value, preventing interference from other ROS 2 systems on the same network. The default ROS_DOMAIN_ID is 0, and safe values range from 0 to 101, inclusive.

Open a terminal on the first machine.

Set the ROS_DOMAIN_ID to a valid integer value, e.g., 5:

export ROS_DOMAIN_ID=5

Run the talker node:

ros2 run demo_nodes_cpp talker
1-demo-nodes-cpp-talker-ros2

Set the ROS_DOMAIN_ID on the second machine (listener).

Open a terminal on the second machine.

Set the ROS_DOMAIN_ID to the same value as the first machine:

export ROS_DOMAIN_ID=5

Run the listener node:

ros2 run demo_nodes_cpp listener

Observe the communication. The listener node on the second machine should receive messages from the talker node on the first machine.

2-demo-nodes-listener-other-machine

Press CTRL + C on the second machine (the one with the listener node).

Experiment with different ROS_DOMAIN_ID values.

Set a different ROS_DOMAIN_ID on the second machine, e.g., 8:

export ROS_DOMAIN_ID=8

Run the listener node again:

ros2 run demo_nodes_cpp listener

Observe that the listener node no longer receives messages from the talker node because they are on different ROS domains.

3-nothing-received

Make the ROS_DOMAIN_ID change permanent

Open the .bashrc file in a text editor:

gedit ~/.bashrc

Add the following line at the end of the file:

export ROS_DOMAIN_ID=5

Save the file and exit the text editor.

Source the .bashrc file or open a new terminal for the changes to take effect:

source ~/.bashrc

You can now rerun the listener.

ros2 run demo_nodes_cpp listener

Everything is working again.

By following these steps, you can run ROS 2 nodes on different machines using the ROS_DOMAIN_ID environment variable to ensure they communicate on the same ROS domain.

That’s it! Keep building!

Coordinate Frame Basics and the Right-Hand Rule of Robotics

Welcome to this tutorial on three-dimensional coordinate frames for robots. Understanding 3D coordinate frames is essential for robots to determine their position and navigate the world effectively. Whether it’s picking up an item, avoiding obstacles, or moving around a room, robots rely on these frames to plan their movements with precision.

The Coordinate Axes

1-coordinate-frames-axes

A 3D coordinate frame consists of three perpendicular axes that intersect at a common point called the origin. Each axis is typically represented by a different color for easy identification:

  • X-axis (red): Points forward.
  • Y-axis (green): Points to the left.
  • Z-axis (blue): Points upward.

Think of these axes as directions in space that help describe any position or movement. 

The Right-Hand Rule

2-right-hand-rule-of-robotics

To remember the orientation of the coordinate axes, use the right-hand rule:

  1. Hold out your right hand with your thumb, index finger, and middle finger all perpendicular to each other.
  2. Assign your fingers to the axes:
    • Index Finger: Points along the positive x-axis (forward).
    • Middle Finger: Points along the positive y-axis (left).
    • Thumb: Points along the positive z-axis (upward).

Understanding Rotation: Roll, Pitch, and Yaw

The right-hand rule helps us understand the basic orientation of our coordinate frame, but robots need to do more than just move along straight lines. They also need to rotate and change their orientation in space. This brings us to three fundamental types of rotation: roll, pitch, and yaw. Remember those terms…roll, pitch, and yaw.

Let’s relate these terms to head movements:

roll-pitch-yaw
  • Roll (rotation around the x-axis) is like tilting your head from side to side, as if you’re touching your ear to your shoulder.
  • Pitch (rotation around the y-axis) is like nodding your head up and down.
  • Yaw (rotation around the z-axis) is like shaking your head ‘no’.

Now let’s relate these to the right-hand rule:

  • Rotate your hand as if turning a doorknob. That is roll.
  • Rotate your hand up and down, as if nodding your head “yes.” That is pitch
  • Rotate your hand left and right, as if shaking your head “no.”. That is yaw.

Coordinate Frame Hierarchy

Now that we understand how individual coordinate frames work and how objects can rotate within them, let’s explore how robots use multiple coordinate frames together. This system of related frames, known as a coordinate frame hierarchy, is important for robots to understand their place in the world and how their parts relate to each other.

World Coordinate Frame

3-world-coordinate-frame

The world coordinate frame, which can often be referred to as the map frame, serves as the fixed, global reference point for all robots and objects in a given environment. It never moves or changes, providing a stable point of reference. This frame is often placed at a convenient location, such as the center of a room’s floor or the battery charging station.

Think of the world frame as the “ground truth” of the environment. All other coordinate frames are ultimately referenced back to this frame, allowing different robots and sensors to understand each other’s positions and coordinate actions.

Robot-Specific Frames

Base Frame

5-base-frame

The base frame is attached to the robot’s base or body and moves with the robot as it navigates. 

For mobile robots, the base frame changes position relative to the world frame as the robot moves around.

For robotic arms, the base frame is typically fixed at the bottom/mount point of the arm. This fixed base frame serves as the primary reference point for all joint movements and gripper positions.

Sensor Frames 

6-sensor-frame

Think of sensor frames like the eyes and ears of the robot. Each camera, distance sensor, or touch sensor has its own frame (i.e. x, y, and z axis) that tells the robot what that sensor can “see” or “feel” from its specific location on the robot.

Joint Frames 

7-joint-frame

For robots with arms or moving parts, each joint (like your elbow or wrist) has its own frame. These frames help the robot know how each joint is bent or twisted.

End-Effector Frame

8-end-effector-frame

This is like the robot’s “hand” – it’s the frame at the very end of a robotic arm where tools or grippers are attached. When a robot needs to pick something up or use a tool, it uses this frame to know exactly where its “hand” is.

Frame Relationships

Understanding the relationships between different frames is key to controlling a robot’s movements and interpreting its sensor data.

For example, imagine you want a robotic arm to pick up a ball on a table. The arm’s movements are defined in its local frame, but the ball’s position is given in the world (map) frame. By transforming the ball’s world coordinates into the arm’s frame, the robot can accurately reach and grasp it.

Practical Example

Consider a self-driving car:

  • The car’s starting position is the origin of its coordinate frame.
  • Moving forward means it’s traveling in the positive x direction.
  • Turning left or right involves rotation around the z-axis, which is its yaw movement.
  • If the car moves sideways, that’s along the y-axis.
  • If the car could jump (imagine it could), that would be along the z-axis.

Make Sure You Understand Coordinate Frames

Coordinate frames form the foundation of a robot’s spatial understanding. By maintaining clear relationships between different frames—such as the world (map) frame, robot base frame, sensor frames, and manipulator frames—robots can effectively plan and execute complex tasks.

By understanding 3D coordinate frames, you’ll be better equipped to program and control robots, whether you’re working on simple projects or advanced robotic systems. 

To learn more about common coordinate frames specific to ROS 2 mobile robots, check out this tutorial.

That’s it. Keep building!

How to Save Your ROS 2 Project on GitHub

In this tutorial, I will show you how to store your ROS 2 project in a repository on GitHub.

Follow along with me click by click, keystroke by keystroke.

In case you’re not familiar with GitHub, GitHub is an online platform specifically designed for software development. It offers several key functionalities:

  • Version control: This allows you to track changes made to code over time. Think of it like a time machine for your code, letting you revert to previous versions if necessary.
  • Code storage: GitHub acts as a secure and centralized location to store and manage code projects. Think of it like cloud storage specifically for your code.
  • Collaboration: Teams can work together on projects by sharing code, discussing changes, and merging different contributions seamlessly.
  • Open-source contribution: GitHub is a hub for open-source projects, where developers can publicly share their code, contribute to existing projects, and learn from others.

Prerequisites

  • You have created a ROS 2 package inside a workspace.
  • I have created a ROS 2 workspace that is at this path /home/ubuntu/ros2_ws/.

My package is called ros2_fundamentals_examples and is at this path: /home/ubuntu/ros2_ws/src/ros2_fundamentals_examples/

You can see the complete repository here on GitHub.

Install Git

The first thing you need to do is install Git. Open a new terminal window, and type:

sudo apt-get update
sudo apt-get install git -y

Check the git version you have.

git --version

Configure Git

Configure your git username and email.

git config --global user.name "John Doe"
git config --global user.email "johndoe@example.com"
git config --global init.defaultBranch main

Initialize Git

Move to inside your project folder.

cd  ~/ros2_ws/src/ros2_fundamentals_examples/

Initialize the folder as a Git repository by running:

git init

This command allows you to start tracking changes to the files within that directory.

1-git-init

Add and Commit the Files to Your Local Repository

Add the files in your folder to the repository with the following command:

git add .

Commit your staged files to your local repository with:

git commit -m "Initial commit"

Create the Remote Repository on GitHub

Go to GitHub and log in.

Click on the “+” icon in the upper right corner and select “New repository.”

Name your repository.

Add a description (optional).

Choose whether the repository will be public or private.

Ignore the rest of the options.

Click “Create repository.”

Link the Local Repository to the Remote Repository

After creating your repository on GitHub, you’ll get a URL for that repository that looks like this: “https://github.com/…./ros2_fundamentals.git” 

Go back to a terminal window, and link your local repository to GitHub with this command:

cd  ~/ros2_ws/src/ros2_fundamentals_examples/
git remote add origin <repository-URL>

Now log in to your GitHub account again.

Creating a Fine-Grained Personal Access Token

A personal access token is like a special key that lets you access your GitHub account from other apps or scripts. It’s more secure than using your password because you can control what the token is allowed to do. 

Here are the official steps, but we will walk through everything together now.

First, verify your email address, if it hasn’t been verified yet.

In the top-right corner of the GitHub page, click on your profile picture.

From the menu, click “Settings.”

In the left sidebar of the settings page, scroll down until you see “Developer settings.”

Click on “Developer settings.”

In the left sidebar, under Personal access tokens, click Fine-grained tokens.

Click Generate new token.

Follow the steps to authenticate your identity on GitHub.

Under Token name, enter a name for the token.

Under Resource owner, select a resource owner. The token will only be able to access resources owned by the selected resource owner.

Under Expiration, select an expiration for the token.

Optionally, under Description, add a note to describe the purpose of the token.

Under Repository access, select which repositories you want the token to access.

If you selected Only select repositories in the previous step, under the Selected repositories dropdown, select the repositories that you want the token to access.  I will select the ros2_fundamentals_examples repository.

Under Permissions, select which permissions to grant the token. Depending on which resource owner and which repository access you specified, there are repository and account permissions. You should choose the minimal permissions necessary for your needs. 

I will grant “Read and write” permissions to all of the resources. If “Read and write” is not available for a particular resource, select “Read-only”.

Click Generate token.

Copy the personal access token that you see, and save it somewhere safe.

Push Code to GitHub

Finally, push your code from your local repository (the folder on your computer) to GitHub (the remote folder) with:

cd  ~/ros2_ws/src/ros2_fundamentals_examples/
git push -u origin main

Enter your GitHub Username.

Then, when it asks for your password, enter the personal access token you created in the previous section.

With this command we have created a two-way connection between your local code and GitHub.

The git push -u origin main command uploads your local code to GitHub while simultaneously setting up a tracking relationship between your local and remote branches. 

The -u (or –set-upstream) flag tells Git to remember this connection, so in the future you can simply use git push or git pull without needing to specify where to push to or pull from. 

origin refers to your GitHub repository, and main is the name of your branch. 

Now if you go back to GitHub, you can see your repository.

Git Command Overview

When you make changes to your code on your computer, and want to get these code changes saved to GitHub, here is how you do it:

git add . 

This command picks up all your new code changes and gets them ready to be saved. It’s like gathering up all your files into a neat pile.

git commit -m "description of changes" 

This command saves these changes on your computer with a message explaining what you did. It’s like putting that pile of files into a labeled folder.

git push 

This command sends all your saved changes to GitHub. Think of it like uploading your folder to the cloud so others can see it and you have a backup.

You’ll repeat these three steps each time you want to update your code on GitHub. 

And if you’re working with other people, you should always download their changes first using git fetch, git status, and then git pull (one command right after the other) before you start working.

git fetch checks GitHub to see what changes exist – it’s like looking at a list of updates available but not downloading them yet. It tells you what’s different between your code and GitHub’s code.

git status shows you exactly what’s different between your local code and the code on GitHub after you’ve fetched. It’s like comparing your version with GitHub’s version to see what’s changed.

git pull actually downloads those changes from GitHub to your computer, bringing your local code up to date. It’s like clicking “download” on those updates you found with fetch and status.

These three commands help you safely check for and get any updates before you start working, which helps avoid conflicts with other people’s code changes.

Remove the Need to Use a Username and Password

If you want to not have to use a username and password every time you run “git push”, you can use SSH keys. This page has the official instructions on how to do that.

Here is the process…

Generate an SSH key pair (if you don’t already have one) by running:

ssh-keygen -t ed25519 -C "your_email@example.com"

When you get prompted for a password or saving location, just keep pressing Enter, which will accept the default.

Start the ssh-agent in the background.

eval "$(ssh-agent -s)"

Add your SSH private key to the ssh-agent:

ssh-add ~/.ssh/id_ed25519

Add the SSH public key to your Git server.

cat ~/.ssh/id_ed25519.pub

Copy the entire result to your clipboard by highlighting everything and copying it.

Go to your GitHub account “Settings” by clicking your profile icon in the upper right of the website.

Look for “SSH and GPG keys”.

Add a New SSH key.

Paste the copied key as an “Authentication Key”. Also add a title (you can make it whatever you want).

Click Add SSH key.

Go back to the main page of your repository on GitHub.

Find the SSH URL by clicking the green button labeled “Code”.

Copy the SSH URL that is in there.

Switch your repository’s remote URL to SSH by going to your Ubuntu Linux terminal window, and moving to the directory of your repository.

cd <path to your your local repository>

For example:

cd  ~/ros2_ws/src/ros2_fundamentals_examples/
git remote set-url origin git@github.com:username/repository.git

To confirm everything is setup properly, type:

git pull

If you get asked about the authenticity of the host, just type yes and press Enter.

That’s it.

Using SSH keys is a more secure and convenient method for machines where you regularly push changes, as it doesn’t require entering your credentials after the initial setup.

Keep building!