How to Load a URDF File into RViz – ROS 2

In this tutorial, I will show you how to load a URDF File into RViz. Universal Robot Description Format (URDF) is the standard ROS format for robot modeling.

Prerequisites

  • ROS 2 Foxy Fitzroy installed on Ubuntu Linux 20.04 
    • If you are using another ROS 2 distribution, you will need to replace ‘foxy’ with the name of your distribution everywhere I mention ‘foxy’ in this tutorial. 
    • I highly recommend you get the newest version of ROS 2. If you are using a newer version of ROS 2, you can still follow all the steps in this tutorial.
  • You have already created a ROS 2 workspace. The name of our workspace is “dev_ws”, which stands for “development workspace.”

You can find the entire code for this project here on my Google Drive.

What is URDF?

A URDF (Universal Robot Description Format) file is an XML file that describes what a robot should look like in real life. It contains the complete physical description of the robot.

You can learn more about URDF files here.

Install Important ROS 2 Packages

First, we need to install some important ROS 2 packages that we will use in this tutorial. Open a new terminal window, and type the following commands, one right after the other.

sudo apt install ros-foxy-joint-state-publisher-gui
sudo apt install ros-foxy-xacro

The format of the commands above is:

sudo apt install ros-<ros2-distro>-joint-state-publisher-gui
sudo apt install ros-<ros2-distro>-xacro

You will need to replace <ros2-distro> with the ROS 2 distribution you are using. In this case, I am using ROS 2 Foxy Fitzroy, which is ‘foxy’ for short.

Create a ROS 2 Package

Let’s create a ROS 2 package inside our workspace. My workspace is named dev_ws.

In a new terminal window, move to the src (source) folder of your workspace.

cd ~/dev_ws/src

Now create the package using the following command.

ros2 pkg create --build-type ament_cmake two_wheeled_robot

Create Extra Folders

Move inside the package.

cd ~/dev_ws/src/two_wheeled_robot/

Create some extra folders with the following names. We will not use all of these folders. I just like to have these folders in every package I create in case I need to use them.

mkdir config launch maps meshes models params rviz urdf worlds

Type the following command to verify the folders were created.

dir

Now build the package by typing the following command:

cd ~/dev_ws
colcon build

Let’s add a script to our bashrc file which enables us to use the following command to move to the package from any directory inside our terminal window.

colcon_cd two_wheeled_robot

Where ‘cd’ means “change directory”.

Note that in ROS 1, we typed roscd to change directories. In ROS 2, we use the colcon_cd command instead of roscd.

Open a terminal window, and type the following commands, one right after the other:

echo "source /usr/share/colcon_cd/function/colcon_cd.sh" >> ~/.bashrc
echo "export _colcon_cd_root=~/dev_ws" >> ~/.bashrc

Now open a new terminal window.

To go directly to the basic_mobile_robot ROS 2 package, type:

colcon_cd two_wheeled_robot

This command above will get you straight to the two_wheeled_robot package from within any directory in your Linux system. The format is:

colcon_cd [ROS 2 package name]

Create the URDF File

In this section, we will build our mobile robot step-by-step. Our robot will be defined in a Universal Robot Descriptor File (URDF), the XML file that represents a robot model.

Open a new terminal window, and type:

colcon_cd two_wheeled_robot
cd urdf

Make sure you have the Gedit text editor installed.

sudo apt-get install gedit

Create a new file named two_wheeled_robot.urdf.

gedit two_wheeled_robot.urdf

Inside this file, we define what our robot will look like (i.e. visual properties), how the robot will behave when it bumps into stuff (i.e. collision properties), and its mass (i.e. inertial properties). 

Type this code inside the URDF file.

Save and close the file.

Now go to the meshes folder.

cd ~/dev_ws/src/two_wheeled_robot/meshes

Add this STL file to your meshes folder. A mesh is a file that allows your robot to look more realistic (rather than just using basic shapes like boxes and spheres).

Rather than use the STL files I provided, you can use a program like SolidWorks to generate your own STL files. You can also use a program called Blender to create DAE files. URDF files support meshes in either STL or DAE format.

Add Dependencies

Let’s add some packages that our project will depend on. Go to the package.xml file.

cd ~/dev_ws/src/two_wheeled_robot/

OR

colcon_cd two_wheeled_robot 
gedit package.xml

After the <buildtool_depend> tag, add the following lines:

<exec_depend>joint_state_publisher</exec_depend>
<exec_depend>robot_state_publisher</exec_depend>
<exec_depend>rviz</exec_depend>
<exec_depend>xacro</exec_depend>

Save the file, and close it.

1-package_xml

We will be using the Joint State Publisher and the Robot State Publisher. We will also be using RViz to visualize our robot model.

Create the Launch File

Let’s create a launch file. Open a new terminal window, and type:

colcon_cd two_wheeled_robot
cd launch
gedit two_wheeled_robot.launch.py

Copy and paste this code into the file.

# Author: Addison Sears-Collins
# Date: September 14, 2021
# Description: Launch a two-wheeled robot URDF file using Rviz.
# https://automaticaddison.com

import os
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import Command, LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare

def generate_launch_description():

  # Set the path to this package.
  pkg_share = FindPackageShare(package='two_wheeled_robot').find('two_wheeled_robot')

  # Set the path to the RViz configuration settings
  default_rviz_config_path = os.path.join(pkg_share, 'rviz/rviz_basic_settings.rviz')

  # Set the path to the URDF file
  default_urdf_model_path = os.path.join(pkg_share, 'urdf/two_wheeled_robot.urdf')

  ########### YOU DO NOT NEED TO CHANGE ANYTHING BELOW THIS LINE ##############  
  # Launch configuration variables specific to simulation
  gui = LaunchConfiguration('gui')
  urdf_model = LaunchConfiguration('urdf_model')
  rviz_config_file = LaunchConfiguration('rviz_config_file')
  use_robot_state_pub = LaunchConfiguration('use_robot_state_pub')
  use_rviz = LaunchConfiguration('use_rviz')
  use_sim_time = LaunchConfiguration('use_sim_time')

  # Declare the launch arguments  
  declare_urdf_model_path_cmd = DeclareLaunchArgument(
    name='urdf_model', 
    default_value=default_urdf_model_path, 
    description='Absolute path to robot urdf file')
    
  declare_rviz_config_file_cmd = DeclareLaunchArgument(
    name='rviz_config_file',
    default_value=default_rviz_config_path,
    description='Full path to the RVIZ config file to use')
    
  declare_use_joint_state_publisher_cmd = DeclareLaunchArgument(
    name='gui',
    default_value='True',
    description='Flag to enable joint_state_publisher_gui')
  
  declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
    name='use_robot_state_pub',
    default_value='True',
    description='Whether to start the robot state publisher')

  declare_use_rviz_cmd = DeclareLaunchArgument(
    name='use_rviz',
    default_value='True',
    description='Whether to start RVIZ')
    
  declare_use_sim_time_cmd = DeclareLaunchArgument(
    name='use_sim_time',
    default_value='True',
    description='Use simulation (Gazebo) clock if true')
   
  # Specify the actions

  # Publish the joint state values for the non-fixed joints in the URDF file.
  start_joint_state_publisher_cmd = Node(
    condition=UnlessCondition(gui),
    package='joint_state_publisher',
    executable='joint_state_publisher',
    name='joint_state_publisher')

  # A GUI to manipulate the joint state values
  start_joint_state_publisher_gui_node = Node(
    condition=IfCondition(gui),
    package='joint_state_publisher_gui',
    executable='joint_state_publisher_gui',
    name='joint_state_publisher_gui')

  # Subscribe to the joint states of the robot, and publish the 3D pose of each link.
  start_robot_state_publisher_cmd = Node(
    condition=IfCondition(use_robot_state_pub),
    package='robot_state_publisher',
    executable='robot_state_publisher',
    parameters=[{'use_sim_time': use_sim_time, 
    'robot_description': Command(['xacro ', urdf_model])}],
    arguments=[default_urdf_model_path])

  # Launch RViz
  start_rviz_cmd = Node(
    condition=IfCondition(use_rviz),
    package='rviz2',
    executable='rviz2',
    name='rviz2',
    output='screen',
    arguments=['-d', rviz_config_file])
  
  # Create the launch description and populate
  ld = LaunchDescription()

  # Declare the launch options
  ld.add_action(declare_urdf_model_path_cmd)
  ld.add_action(declare_rviz_config_file_cmd)
  ld.add_action(declare_use_joint_state_publisher_cmd)
  ld.add_action(declare_use_robot_state_pub_cmd)  
  ld.add_action(declare_use_rviz_cmd) 
  ld.add_action(declare_use_sim_time_cmd)

  # Add any actions
  ld.add_action(start_joint_state_publisher_cmd)
  ld.add_action(start_joint_state_publisher_gui_node)
  ld.add_action(start_robot_state_publisher_cmd)
  ld.add_action(start_rviz_cmd)

  return ld

Save the file, and close it.

You can read more about Launch files here.

Add the RViz Configuration File

Let’s add a configuration file that will initialize RViz with the proper settings so we can view the robot as soon as RViz launches.

Open a new terminal window. Type:

colcon_cd two_wheeled_robot
cd rviz
gedit rviz_basic_settings.rviz

Add this code.

Save the file, and close it.

Build the Package

Now we need to build the package. Open a new terminal window, and type:

colcon_cd two_wheeled_robot
gedit CMakeLists.txt

Add the following snippet to CMakeLists.txt file above the if(BUILD_TESTING) line.

install(
  DIRECTORY config launch maps meshes models params rviz src urdf worlds
  DESTINATION share/${PROJECT_NAME}
)

Save the file and close it.

2-cmakelists

Build the project.

cd ~/dev_ws/
colcon build

In the future, if you would like to build the two_wheeled_robot package only, you can type:

colcon build --packages-select two_wheeled_robot

Launch the Robot in RViz

Open a new terminal, and launch the robot.

cd ~/dev_ws/
ros2 launch two_wheeled_robot two_wheeled_robot.launch.py
3-mobile-robot-1

——

By the way, if you want to see the available arguments you can pass to the launch file from the terminal window, type:

ros2 launch -s two_wheeled_robot two_wheeled_robot.launch.py
4-show-options

And if you want to set the value of an argument (e.g. launch the robot without RViz), you can do something like this:

ros2 launch two_wheeled_robot two_wheeled_robot.launch.py use_rviz:='False'

——

Here is the output after we launch the robot in RViz:

The joint state publisher GUI has sliders that enable you to move the wheels.

If something goes wrong with the launch, close everything down, restart Linux, and launch again.

Check whether you have properly set up the collision properties by enabling Collision Enabled under RobotModel on the left pane.

You can see in the image that I have modeled the base_link as a box for collisions. I could have just as easily used the STL model itself (which was used for visualization) as the collision geometry, but I decided to go with the simpler box representation to give me more flexibility to alter the collision areas if necessary. Also, Gazebo (a popular robotics simulator) recommends using simpler collision geometry to increase performance.

5-collision-enabled

View the Coordinate Frames

Let’s see the coordinate frames. We first need to install the necessary software.

sudo apt install ros-foxy-tf2-tools

Check out the coordinate frames.

colcon_cd two_wheeled_robot
ros2 run tf2_tools view_frames.py

As of ROS Galactic, this command is:

ros2 run tf2_tools view_frames

In the current working directory, you will have a file called frames.pdf. Open that file.

evince frames.pdf

Here is what my coordinate transform (i.e. tf) tree looks like:

6-frames-pdf

If we want to see the coordinate transformation from one link to another, we can type the following command. For example, what is the position and orientation of the front caster wheel relative to the base_link of the robot?

The syntax is:

ros2 run tf2_ros tf2_echo <parent frame> <child frame>

We open a terminal window, and type:

ros2 run tf2_ros tf2_echo base_link front_caster

Here is the output. With respect to the base_link reference frame, the front caster wheel is located at (x=0.217 meters, y=0 meters, and z=-0.1 meters). 

7-tf2-echo

The rotation value is in quaternion format. You can see that the rotation values are all 0s, indicating that the orientation of both coordinate frames is equivalent (i.e. the x, y, and z axes of both coordinate frames point in the same direction).

Remember that, by convention:

  • x-axis is red
  • y-axis is green
  • z-axis is blue 

To see an image of the architecture of our ROS system, open a new terminal window, and type the following command:

rqt_graph

Select the “Nodes/Topics (all) option in the upper-left part of the screen, and then click the refresh arrow right next to it.

8-rqt-graph

You can see how the joint state publisher GUI manipulates the joint states (i.e. the angle of each wheel joint). This data feeds into the robot state publisher. The robot state publisher publishes the coordinate frame relationships to tf, and the updated robot model feeds into RViz, the robot model visualization program.

That’s it! 

When you’re done, press CTRL+C in all terminal windows to shut everything down.

How to Install Ubuntu 20.04 and VirtualBox on Your Computer

In this tutorial, we will install Ubuntu and Virtual Box on our personal computer. My machine is running Windows 10. Let’s walk through this whole process, step-by-step, so you understand how to do it no matter what operating system you have.

Ubuntu is a popular distribution (i.e. flavor) of the Linux operating system and is fully supported by ROS, the most popular framework for writing robotics software.

The process for installing Ubuntu has a lot of steps, so be patient and don’t give up if something isn’t working. Let’s get started!

You Will Need

Directions

Download the Ubuntu Image

Check Ubuntu Releases to find the latest version of Ubuntu that has long term support (LTS). As of the date of this writing, the latest version is Ubuntu 20.04 LTS (Focal Fossa), so click on that one. 

1-ubuntu-releasesJPG

Download the 64-bit PC (AMD64) desktop image (.iso file). It is a large file (about 2.5GB) and will take quite a while to download. Just go do something else and come back to it when it is finished.

Before you install the Ubuntu you just downloaded, you need to install Virtual Box. Virtual Box extends the capabilities of your host computer (i.e. your laptop or desktop PC) by enabling you to install and run an operating system in a new environment on top of your current operating system (Windows 10 in my case). The environment the new operating system will run in is known as a virtual machine (or guest).

Install VirtualBox

Go to the VirtualBox downloads page and select the version that is compatible with your computer. Install it. Once you’re done, your screen should look like this:

2-install-virtual-boxJPG

Detailed installation instructions for all operating systems (Windows, Mac OS, Linux, and Solaris) can be found in the instruction manual.

You can now delete the original executable file for VirtualBox (the one with the .exe extension). You don’t need it anymore.

Create a Virtual Machine

Now that VirtualBox is installed on your computer, we need to create a new virtual machine.

Open Virtual Box and click the New button in the toolbar.

10-start-virtual-boxJPG

Type in a descriptive name for your operating system. You can stick with the default machine folder. The machine folder is where your virtual machines will be stored. I prefer to install it on the D drive where I have more space.

3-name-and-operating-systemJPG

Also, select the operating system that you want to later install (Linux and Ubuntu_64 in the Type and Version fields).

Click Next to proceed.

The default memory size for me is 1024 MB. That is not sufficient for our purposes, so let’s raise it to 6470 MB, and then click Next to proceed.

4-raise-to-6470JPG

Make sure “Create a virtual hard disk now” is selected, and click Create.

5-create-virtual-machineJPG

Select “VirtualBox Disk Image (VDI)”, and click Next.

6-select-virtual-box-disk-imageJPG

Choose a Fixed size virtual hard disk so that you have better performance, and click Next.

7-fixed-sizeJPG

Go with something like 50 GB for the hard disk space. Then click Create.

8-go-with-50gbJPG

It will take several minutes to create the virtual hard disk, so be patient.

9-creating-hard-driveJPG

Install Ubuntu

Double-click on the left panel where you see the name of the virtual machine you just created.

10-double-click-left-panelJPG

A startup window will appear.

Click the Folder icon next to Empty. A popup box will appear that is titled “Optical Disk Selector.”

Click Add.

11-optical-disk-selectorJPG

Find the Ubuntu image you downloaded earlier in this tutorial. It is a .iso file. Select it.

Click Choose.

Click Start to proceed with that Ubuntu image.

Ubuntu should start launching.

12-ubuntu-launchingJPG

Click on “Install Ubuntu” to install Ubuntu. You should see a window that looks something like this.

13-install-ubuntuJPG

Click “Continue” to save the keyboard layout. The default English one is fine.

Select “Normal installation” and “Download updates while installing Ubuntu.” Then click Continue.

14-updates-and-other-softwareJPG

Select “Erase disk and install Ubuntu”. Then click “Install Now”.

15-install-nowJPG

Click Continue when it asks “Write the changes to the disks?”.

You will get to a point where you will need to set your time zone. It will be a big map of the world that should automatically detect your location. Click Continue.

Type in a computer name and pick a username and password. I select the “Log in automatically” option.

When installation is complete, click “Restart Now.”

16-restart-nowJPG

A message will say “Please remove the installation medium, then press ENTER:”. Just ignore it.

Go to File -> Close in the upper left part of the window.

Select “Power off the machine.” Click OK.

In the “Oracle VM Virtual Box Manager” window, highlight your virtual machine and click the green arrow up top that says “Start”.

You should now see your Ubuntu Linux desktop.

18-homepageJPG

Click the small white arrow in the upper-right portion of the screen. “Power Off” the machine.

19-power-off-machineJPG

Alternatively, you can open up a terminal window and type the following command:

sudo shutdown -h now

Highlight your virtual machine and go to Settings → Display and change your Video Memory to 128 MB. This will give you ample video memory. Click OK.

20-ample-video-memoryJPG

Also go to Settings → System → Processor, and adjust the number of CPUs to 4. Then Click OK.

21-4-cpusJPG

To make your screen larger, log back into Linux and go to your Settings. Then go to Display, and select your desired resolution.

resolution

If you have issues where your screen flips to portrait mode and gets stuck there, press CTRL + Alt + F1 to return to the login screen to fix the resolution.

You can follow this tutorial to enable clipboard sharing.

Congrats! You’re done!

How to Use GPS With the Robot Localization Package – ROS 2

In this tutorial, we will integrate GPS data into a mobile robot in order to localize in an environment.

3b-launch-the-robot

The official instructions for doing this are on this page, but we will walk through the entire process below.

You can get the entire code for this project here.

Let’s get started!

Prerequisites 

You have completed the Ultimate Guide to the ROS 2 Navigation Stack (also known as Nav2). We will not be using the Navigation Stack, but that Ultimate Guide helps you set up all the packages that you will use in this tutorial.

If you know ROS 2 and understand how to read Launch files, you should be able to follow along with this tutorial quite well without having to go through the Ultimate Guide.

Calculate the Magnetic Declination of Your Location

First, we need to calculate the magnetic declination in radians.

Go to this page.

Enter your latitude and longitude, and click “Calculate”. If you don’t know your latitude and longitude, you can look it up by zip code.

My magnetic declination is 5° 20′ W. 

1-magnetic-declination

Convert that value to decimal format. Since the units above are 5 degrees and 20 minutes, this value is the following in decimal format:

5.333333 degrees

Now we need to convert that value to radians.

5.333333 degrees = 0.093084220955 radians.

Set the Latitude, Longitude, and Elevation in the World File

We need to set the latitude, longitude, and elevation of the origin in Gazebo.

Go to your world file. Open a terminal window, and type:

colcon_cd basic_mobile_robot
cd worlds/basic_mobile_bot_world
gedit smalltown.world

Inside the <spherical_coordinates> tag at the bottom of the file, modify the latitude, longitude, and elevation to wherever you are. Here is my smalltown.world file.

I am in Atlanta, Georgia. My latitude is 33.83, and my longitude is -84.42. The elevation at this location is 836.6 feet, which is 254.99568 meters.

Save the file and close it.

When we load Gazebo:

  • x = East
  • y = North
  • z = Up

So, for example, if the robot is in Atlanta and heading in the positive x-direction in the world coordinate frame, the robot is moving eastward, and we should expect the longitude to get less negative (i.e. move towards 0).

If the robot is heading in the positive y-direction in the world coordinate frame, the robot is moving northward, and we should expect the latitude to increase (i.e. move towards 90 degrees).

Set the Configuration Parameters

We now need to specify the configuration parameters of the ekf_node by creating a YAML file.

Open a new terminal window, and type the following command to move to the basic_mobile_robot package:

colcon_cd basic_mobile_robot
cd config
gedit ekf_with_gps.yaml

Copy and paste this code inside the YAML file.

Save and close the file.

You can get a complete description of all the parameters on this page

Create a Launch File

Open a new terminal window, and move to your launch folder.

colcon_cd basic_mobile_robot
cd launch
gedit basic_mobile_bot_v6.launch.py

Copy and paste this code into the file.

Save the file, and close it.

Build the Package

Now build the package by opening a terminal window, and typing the following command:

cd ~/dev_ws
colcon build --packages-select basic_mobile_robot

Launch the Robot

Open a new terminal, and launch the robot.

cd ~/dev_ws/
ros2 launch basic_mobile_robot basic_mobile_bot_v6.launch.py
3-launch-the-robot

Call a ROS service to set the GPS’s origin for the navsat_transform node.

ros2 service call /datum robot_localization/srv/SetDatum '{geo_pose: {position: {latitude: 33.83, longitude: -84.42, altitude: 254.99568}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}}'
3c-service-call

Now let’s check out the coordinate frames. Open a new terminal window, and type:

ros2 run tf2_tools view_frames.py

In newer versions of ROS 2, you might have to type:

ros2 run tf2_tools view_frames

In the current working directory, you will have a file called frames.pdf. Open that file.

evince frames.pdf

Here is what my coordinate transform (i.e. tf) tree looks like:

2-transform_tree

Check out the topics.

ros2 topic list

We can see the raw GPS data.

ros2 topic echo /gps/fix
4-gps-fix

We can see the GPS data after we have processed the raw GPS data through an Extended Kalman Filter.

ros2 topic echo /gps/filtered
5-gps-filtered

The pose of the robot in the map frame before data processing through an Extended Kalman Filter.

ros2 topic echo /odometry/gps
7-odometry-gps

The pose of the robot in the map frame after data processing through an Extended Kalman Filter. This value below is a combination of wheel encoder information, IMU data, and GPS data.

ros2 topic echo /odometry/global
6-odometry-global

The pose of the robot with respect to the starting point of the robot (i.e. with respect to the odom frame). This value below is a combination of wheel encoder information and IMU data.

ros2 topic echo /odometry/local
8-odometry-local

To steer the robot, open a new terminal window, and type the following command:

rqt_robot_steering

If you go straight down the positive x-axis, you will notice that the latitude value is getting less negative. This trend makes sense given the robot’s eastward trajectory.

That’s it! Keep building!