How to build a snap using ROS 2 Humble

This article was last updated 1 year ago.


Please note that this blog post has out technical information that may no longer be correct. For latest updated documentation about robotics in Canonical please visit https://ubuntu.com/robotics/docs.

We’ve recently celebrated the release of ROS 2 Humble Hawksbill with a post detailing how to get started developing for the new release in containers. In addition, we shared an overview of the new features included with this new release, particularly its enhanced security features.

This week we are tackling the logical next step in software development: packaging. Indeed, once we’re done developing our super cool ROS 2 Humble application, we still have to get it out into the hands of our users.

In this post, we are going to see how to package a ROS 2 Humble application as a snap with an ‘hello world’-like example.

A ROS 2 Humble snap you said?

Snaps are app packages for desktop, cloud and IoT that are easy to install, secure, cross‐platform and dependency‐free.


Snaps are the ideal deployment solution for ROS-based applications in that they are a self-contained, sandboxed, cross distribution packaging solution. Not to mention that they natively support ROS to ease your packaging journey. You can find further information about all the features they offer on the dedicated robotics page!

Setting up snapcraft

Firstly, let’s get the tool that allows us to create snaps: snapcraft.

sudo snap install --classic snapcraft

We will also install LXD which snapcraft uses as a backend for clean, confined and reproducible packaging,

sudo snap install lxd
sudo lxd init --minimal

Note that we have initialized LXD with a bunch of default parameters. Head to the LXD documentation if you prefer to specify some of those parameters yourself.

We are all set up to package our first example, so let’s do just that.

A talker-listener example

For this example, we’ll take it easy as we won’t even need to write any code. Instead, we are going to package one of the ROS 2 demo from the GitHub repository. I’ve picked a demo from the ‘demo_nodes_cpp‘ package, more specifically the ‘talker_listener.launch.py‘ demo.

As its name suggests, this demo launches a ‘talker’ which publishes a string message on a ROS 2 topic. together with a ‘listener’ which reads said message. Both print the message sent/received to the console to easily follow along. And of course both are launched at once from a single launch file.

While this example may seem a little too simple, it is an ideal first contact with snaps. We will see how easy it is to package ROS 2 applications with snaps.

The snapcraft.yaml file

Snapcraft relies on the ‘snapcraft.yaml’ configuration file to drive the packaging process. So, let us create one,

mkdir -p ~/ros2_ws/first_snap/
cd ~/ros2_ws/first_snap/
touch snapcraft.yaml

and then populate it as follows,

name: ros2-talker-listener
version: '0.1'
summary: ROS 2 Humble talker/listener example
description: |
This example launches a ROS 2 Humble talker and listener.

base: core22
confinement: strict

apps:
ros2-talker-listener:
command: opt/ros/humble/bin/ros2 launch demo_nodes_cpp talker_listener.launch.py
plugs: [network, network-bind]
extensions: [ros2-humble]

parts:
ros-demos:
plugin: colcon
source: https://github.com/ros2/demos.git
source-branch: humble
source-subdir: demo_nodes_cpp
stage-packages: [ros-humble-ros2launch]

Believe it or not, this is all we need to create our snap. But let us inspect this file more closely.

Breaking it all down

We can identify 3 distinct blocks in the aforementioned snapcraft.yaml file.

At the top of the file, there is some boiler-plate that is common to most snaps. The snap name, version etc. Nothing unusual here. Then comes base: core22 which is a base snap that will provide a runtime environment to our application based on Ubuntu 22.04. The last entry in this block is confinement: strict which states that our application is strictly confined. In other words, it cannot access any resource on the host machine.

The second block, apps, specifies the application(s) that’s exposed from the snap. Here, a single application is listed whose command is very familiar. Furthermore, our application also lists some interfaces in the plugs section. Note that Interfaces allow our confined application to access specific resources of the host machine. In this case, our snap will have access to network-related interfaces that allow for the ROS 2 topics to flow. Finally, the extensions: [ros2-humble] will automatically fill up some other fields which are common to ROS 2 Humble snaps. In case you are curious about what an extension does, note that you can ‘expand’ it. Reveal all of its secrets by issuing the following command,

snapcraft expand-extensions

At last we are taking a look at the third block: parts. The parts tag defines the different pieces that make up our final application. They include a source entry for the source code such as local files, a tarball, or as in this example, a GitHub repository at a specific branch. What’s more, a ‘part’ can include build-packages, which are only required at build time unlike stage-packages which are only needed at runtime. Most importantly, each part is handled by a plugin. Here we are using the colcon plugin, which makes use of the familiar build tool in ROS 2. Then again this plugin has its own options, which you can review with the command,

snapcraft help colcon

You can find further information about the global metadata, the parts and their own metadata, the colcon plugin, extensions, and more in the documentation.

Now that the snapcraft.yaml file is defined, it is time to build the snap.

Building the ROS 2 Humble snap

To build the snap, issue the command snapcraft in a terminal,

$ snapcraft
Starting Snapcraft

* metallic sound of software being forged *

Created snap package

Snap, reveal yourself,

$ ls
ros2-talker-listener_0.1_amd64.snap snapcraft.yaml

Surely, there it is!
How about we install it now? To do so, type,

$ sudo snap install --dangerous ros2-talker-listener_0.1_amd64.snap
ros2-talker-listener 0.1 installed

The use of the --dangerous flag since we are installing a snap from disk instead of using the store.

Ok, but does it bite work?

$ ros2-talker-listener
[INFO] [launch]: All log files can be found below /home/ubuntu/snap/ros2-talker-listener/x6/ros/log/2022-05-24-15-24-50-823207-localhost-24895
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [talker-1]: process started with pid [24944]
[INFO] [listener-2]: process started with pid [24946]
[talker-1] 2022-05-24 15:24:51.341 [RTPS_TRANSPORT_SHM Error] Failed to create segment ac1bbb6c86049e8a: Permission denied -> Function compute_per_allocation_extra_size
[listener-2] 2022-05-24 15:24:51.346 [RTPS_TRANSPORT_SHM Error] Failed to create segment e75bbd4ac39608ab: Permission denied -> Function compute_per_allocation_extra_size
[talker-1] 2022-05-24 15:24:51.348 [RTPS_MSG_OUT Error] Permission denied -> Function init
[listener-2] 2022-05-24 15:24:51.348 [RTPS_MSG_OUT Error] Permission denied -> Function init
[talker-1] [INFO] [1653420292.379305200] [talker]: Publishing: 'Hello World: 1'
[listener-2] [INFO] [1653420292.380423139] [listener]: I heard: [Hello World: 1]
[talker-1] [INFO] [1653420293.379072149] [talker]: Publishing: 'Hello World: 2'
[listener-2] [INFO] [1653420293.379286698] [listener]: I heard: [Hello World: 2]
[talker-1] [INFO] [1653420294.379120962] [talker]: Publishing: 'Hello World: 3'
[listener-2] [INFO] [1653420294.379682258] [listener]: I heard: [Hello World: 3]
...

Yes it does! How great.
What’s even greater is that you could install and run this snap on another computer even if it doesn’t have ROS 2 installed! Heck, you could install and run this snap on another Linux distribution from 4 years ago!

Note that the error message from FastDDS, the underlying DDS library, does not prevent the application from running. In other words we can safely ignore that for now. If you want to know more about how shared-memory plays along with snap, we covered the topic at length in a dedicated blog: “How to use ROS 2 shared memory in snaps”.

What’s next?

We have seen in this post how to create a snap for a ROS 2 Humble application. While this demo is fairly trivial, packaging a more complex ROS stack isn’t much more complicated. To demonstrate that, have a look at the series “How to set up TurtleBot3 in minutes with snaps” where I detail how to snap the entire Turtlebot3.

Furthermore, we’ve seen how you can effectively and easily package your ROS 2 application. How about distributing it now? Have a look at how to do so with the store here.

Finally, do feel free to ask any questions on the snapcraft forum, or on ROS answers. I’d love to hear any feedback you have.


Talk to us today

Interested in running Ubuntu in your organisation?

Newsletter signup

Get the latest Ubuntu news and updates in your inbox.

By submitting this form, I confirm that I have read and agree to Canonical's Privacy Policy.

Are you building a robot on top of Ubuntu and looking for a partner? Talk to us!

Contact Us

Related posts

Optimise your ROS snap – Part 6

Welcome to Part 6 of our “Optimise your ROS snap” blog series. Make sure to check Part 5. This sixth and final part will  summarise every optimisation that we...

Optimise your ROS snap – Part 4

Welcome to Part 4 of our “optimise your ROS snap” blog series. Make sure to check Part 3 before. This fourth part is going to explain what dynamic library...

Optimise your ROS snap – Part 3

Welcome to Part 3 of our “optimise your ROS snap” blog series. Make sure to check Part 2. This third part is going to present safe optimisations consisting of...