This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Getting Started

Okay! Let’s build things

This chapter is to get you started in ROS building some first practical projects and finish building the demo.

Information to complete this course:

  • Basic Programming Knowledge.

    • Basis of Programming.
    • Comfortable using Python.

  • You need to have a minimum Linux CLI experience

  • You installed ROS and all Prerequisites (explained below)

Prerequisites

This course target ROS2 humble and the official guide recommends Ubuntu 22.04 Jammy Jellyfish because there are official debian packages; even so they offers Tier3 support for Ubuntu 20.04 Focal or Debian 11 but you need to build it from source.

Installation

To install ROS2 humble we recommend to follow the official guide.

Remember to install the full desktop version ros-humble-desktop.

Ubuntu 22.04

Install

Ubuntu 20.04/Debian11

Build from source

and finally, install colcon the build tool

$ sudo apt install python3-colcon-common-extensions

Setup

Remember to source this file /opt/ros/humble/setup.bash or equivalent in your shell to be able to access ROS2 commands.

Or execute this command and relaunch your terminal,

echo 'source /opt/ros/humble/setup.bash' >> ~/.bashrc

substitute .bashrc for your rc file. Ex: ~/.zshrc

Try it out!

1 - Building the Demo

A more real approach to learn the ROS basis.

Now, we can clone a template to solve a real time project to truly demonstrate your knowledge. Let’s code!

Problem to solve

As we delve into the world of autonomous driving software development, we are faced with the daunting task of navigating complex algorithms and cutting-edge technology. Yet, here we are, confronted with a GUI that seems to have been designed by someone who learned to code in their sleep xd.

One of the key components of autonomous driving software is the ability to detect and respond to environmental stimuli, such as obstacles, traffic signals, and other vehicles.

To illustrate this concept, we will be using a GUI that simulates a simple autonomous vehicle. The vehicle is represented by a red square that moves forward and bounces off the walls. The vehicle is equipped with a sensor that detects points in front of it, represented by circles. The goal of this exercise is to use ROS2 to control the orientation of the vehicle based on the location of the nearest point detected by the sensor.

This exercise is similar to what real-world autonomous driving software does. In a self-driving car, sensors such as lidar, radar, and cameras are used to detect obstacles, pedestrians, and other vehicles. The software then analyzes this data and generates control signals to adjust the vehicle’s speed and direction to avoid collisions and reach the desired destination.

By completing this exercise, you will gain practical experience in using ROS2 to control a simulated autonomous vehicle.

Building the demo

You can give the demo a try by cloning the code, building it, and executing the launch file that starts the whole system.

$ git clone https://github.com/martimolanes/sigue_lineas
$ cd sigue_lineas
$ colcon build && source install/setup.bash
$ ros2 launch demo_launcher demo.launcher.py

2 - First steps

First steps into recreating the demo

Creating the workspace

We’re going to start by making the workspace that will hold all our ROS packages.

$ mkdir ~/demo && cd ~/demo
$ mkdir src

We won’t do cd to any other directory, we will always work from this path. This makes it less confusing because the ROS build will write the build files to the current working directory, and we don’t want to make a mess.

Creating the packages needed

Ultimately, we will have the following structure:

PackageBuild typeNotes
worldament_pythonHandles all logic and physics of the car
driverlessament_pythonAlgorithm for calculating the steer
um_msgsament_cmakeContains all custom messages
qt_interfaceament_pythonThis package will be provided by us

To make these packages, we can start using the following command:

$ ros2 pkg create PACKAGE --build-type BUILD_TYPE --destination-directory src --dependencies rclpy

The last package, qt_interface, can be downloaded from this repository and imported into src.


Once we have our packages set up, we can go to the next chapter!

3 - Implementing world

Writing logic and physics for the world

Creating the node

Most nodes will share basic boilerplate which can be copied from the examples ROS gives:

$ cp /opt/ros/$ROS_DISTRO/share/launch_testing_ros/examples/talker.py src/world/world/world.py

Now rename your node World and add the following lines:

class World(Node):
    def __init__(self):
      super().__init__('world')
      self.generate_waypoints()

    def generate_waypoints(self):
        self.waypoints = []

        WIDTH = 200 
        HEIGHT = 100 

        for i in range(30):
            angle = i * 2 * math.pi / 30
            x = math.cos(angle) * WIDTH
            y = math.sin(angle) * HEIGHT
            self.waypoints.append(Waypoint(x=x, y=y, idx=i))

This code generates the waypoints that the car will follow. As you can see, we are just drawing an ellipse (that you can resize by tweaking with the WIDTH and HEIGHT values), but the shape can be any shape you want.

However, if you tried to execute this code, you’d face an error because Waypoint is a custom message that we haven’t defined yet.

Defining the Waypoint message

We need to create a message to represent a point in space. If you have read the previous chapters, you know that messages are defined in the um_msgs directory. In said package, create a directory msg and a file called Waypoint.msg inside that directory, such that the structure of the package is:

src/um_msgs/
├── CMakeLists.txt
├── include
│   └── um_msgs
├── msg
│   └── Waypoint.msg
├── package.xml
└── src

If you’re not sure how to implement this, check the reference .

A waypoint is defined as such:

float64 x
float64 y
uint16 idx

And since we’re at it, we can also define Waypoints.msg like this:

Waypoint[] waypoints

Publishing the waypoints

After importing the message (from um_msgs.msg import Waypoint), we can already execute our world node. All it does is generate the waypoints, but we don’t do anything with them. Let’s publish them.

In the __init__ method, include the following lines:

def __init__(self):
    ...
    self.waypoints_publisher = self.create_publisher(Waypoints, '/world_waypoints', 10)
    self.waypoints_publisher_timer = self.create_timer(3.0, self.publish_waypoints)

These lines of code create a ROS publisher object and a timer object that periodically calls a callback function to publish messages to a specific ROS topic. Note that you can’t rename this topic because qt_interface reads from it.

Next, define the callback function:

def publish_waypoints(self):
    msg = Waypoints(msg=self.waypoints)
    self.waypoints_publisher.publish(msg)

Note that this is also a method in our node and should be indented to the same height as __init__.

Executing the code

Finally, if we execute this code and the interface, we should already see our waypoints being rendered into the canvas.

world showing waypoints