ROS 2

Index

Installation (Humble Hawksbill)

Note

This is being attempted in the Ubuntu 22.04 operating system.

Set Locale

Make sure there is a locale which supports UTF-8. If in a minimal environment (such as a docker container), the locale may be something minimal like POSIX. Test with the following settings.

locale  # check for UTF-8

sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

locale  # verify settings

Set up Sources

Add ROS 2 apt repository to the system. First ensure that Ubuntu Universe repository is enabled.

sudo apt install software-properties-common
sudo add-apt-repository universe

Add ROS 2 GPG keys.

sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

Add the repository to sources list.

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

Install ROS 2 Packages

Update repository and existing packages first.

sudo apt update
sudo apt upgrade

For the Desktop Install (Recommended) which includes ROS, RViz, demos, tutorials.

sudo apt install ros-humble-desktop
sudo apt install ros-dev-tools
Note

For on the ROS-Base Install (Bare Bones) which contains Communication libraries, message packages, command line tools. No GUI tools.

sudo apt install ros-humble-ros-base
sudo apt install ros-dev-tools

Sourcing the Environment

Referring to the previous section on ROS packages, we can permanently source the ROS installation by running:

echo "source /opt/ros/humble/setup.bash" >> .bashrc

Create Local Workspace

Sometimes, required packages cannot be installed from the ROS repositories. In that case you will have to build from source. Alternatively, you may also be developing packages for ROS, and that will also require building from source. To do this, we need to create a local ROS workspace.

mkdir -p ros_workspace/src
cd ros_workspace # This is the root
cd src # All the packages go in here (clone into this space)
cd ..
colcon build # The build tool for ROS 2

In the workspace root, there will now be a build, install and log directory.

To source the workspace so that the binaries can be accessed through the ros2 CLI, run:

source install/local_setup.bash

Distributed System

DDS (Data Distribution Service) plays a crucial role in ROS (Robot Operating System), especially in ROS 2. It acts as the underlying connectivity framework that facilitates communication between different parts of a ROS-based system.

  1. Middleware Layer - DDS is used as the default middleware. This means that DDS is responsible for the efficient and reliable exchange of information between different nodes (components) of a ROS 2 system. It's a layer that sits between the ROS application layer and the network, managing data exchange and communication.
  2. Vendor Agnosticism - Is designed to be DDS vendor-agnostic. This means it can work with different DDS implementations, such as eProsima's Fast DDS, RTI's Connext DDS, Eclipse Cyclone DDS, and GurumNetworks GurumDDS. This flexibility allows users to choose a DDS implementation that best fits their specific requirements.
  3. Key Functions Provided by DDS - DDS provides several essential services in ROS 2, including discovery (finding and connecting to other nodes in the network), message serialization (converting data to a format suitable for transmission), and publish-subscribe transport (managing how messages are sent and received).
  4. Enhanced Features - Brings enhanced features compared to ROS 1, such as distributed discovery (eliminating the need for a central master for node discovery), more granular quality of service settings, and potentially more efficient intra-process communication through shared memory.

Setting ROS2 Params

Create a params.yaml file in the ros2 package under a config directory:

your_package/
├── config
│ └── params.yaml
├── launch
│ └── test_params.launch.py
├── package.xml
├── ...

In it, include the parameters for each node:

node_1:
  ros__parameters:
    some_text: "abc"
    location: # This is recognised as location.x, location.y, location.z
	    x: 0.1
	    y: 0.2
	    z: -0.5

node_2:
  ros__parameters:
    int_number: 27
    float_param: 45.2

node_3:
  ros__parameters:
    int_number: 45

your_amazing_node:
  ros__parameters:
    bool_value: True
    int_number: 5
    float_number: 3.14
    str_text: "Hello Universe"
    bool_array: [True, False, True]
    int_array: [10, 11, 12, 13]
    float_array: [7.5, 400.4]
    str_array: ['Nice', 'more', 'params']
    bytes_array: [0x01, 0xF1, 0xA2]
    nested_param:
      another_int: 7

These parameters need to be declared in the nodes as well:

import rclpy
from rclpy.node import Node

class TestYAMLParams(Node):

    def __init__(self):
        super().__init__('your_amazing_node')
        self.declare_parameters(
            namespace='',
            parameters=[
                ('bool_value', None),
                ('int_number', None),
                ('float_number', None),
                ('str_text', None),
                ('bool_array', None),
                ('int_array', None),
                ('float_array', None),
                ('str_array', None),
                ('bytes_array', None),
                ('nested_param.another_int', None)
            ])

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

if __name__ == '__main__':
    main()

OR if using C++

...
this->declare_parameter("bool_value", rclcpp::PARAMETER_BOOL);
this->declare_parameter("int_number", rclcpp::PARAMETER_INT);
this->declare_parameter("float_number", rclcpp::PARAMETER_DOUBLE);
this->declare_parameter("str_text", rclcpp::PARAMETER_STRING);
...

This can be included in runtime with:

ros2 run ros2_tutorials test_yaml_params --ros-args --params-file ~/ros2_ws/src/ros2_tutorials/config/params.yaml

It is also a good idea to include this in the CMakeLists.txt or setup.py to copy it over into build.

...
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
        (os.path.join('share', package_name, 'config'), glob('config/*.yaml'))
    ],
...
...
install(DIRECTORY
  launch
  DESTINATION share/${PROJECT_NAME}
)
install(DIRECTORY
  config
  DESTINATION share/${PROJECT_NAME}
)
...

This way, you can include the parameters in a launch file:

from ament_index_python.packages import get_package_share_directory
import os
import launch
import launch_ros.actions

def generate_launch_description():
    config = os.path.join(
        get_package_share_directory('ros2_tutorials'), # Make sure to include the config dir in CMakeLists.txt
        'config',
        'params.yaml'
        )
    return launch.LaunchDescription([
        launch_ros.actions.Node(
            package='ros2_tutorials',
            executable='test_yaml_params',
            output='screen',
            parameters=[
                config
            ],
            name='test_yaml_params'),
  ])