How to build ROS 2 Eloquent Snaps

Ted Kern

on 14 December 2019

The end of 2019 brings about the latest ROS 2 release – Eloquent Elusor. Despite an ever growing set of features and some changes throughout the ecosystem, packaging with snaps is as easy as always. Let’s go through a quick example!

Prerequisites

You’ll need two tools: “snapcraft,” the program that builds snaps, and “multipass,” the VM management tool that is used by snapcraft to conduct snap builds without cluttering your development machine. You can get both of these from the snap store.

At the time of this writing, the latest stable release of snapcraft is version 3.8. Until the next release comes out, in order to build Eloquent snaps, you’ll need to grab it from edge.

$ snap install snapcraft --edge --classic

If you already have snapcraft stable installed, you can change to edge using:

$ snap refresh snapcraft --edge

Multipass is grabbed the same way, requiring the --beta flag since the version at the time of writing is 0.9.0

$ snap install multipass --classic --beta

Getting Started

Create the snapcraft.yaml

First of all, create a new workspace directory and add a snapcraft.yaml.

~$ mkdir eloquent-snap
~$ cd eloquent-snap/
~/eloquent-snap$ snapcraft init
Created snapcraft.yaml.
Go to https://docs.snapcraft.io/the-snapcraft-format/8337 for more information about the snapcraft.yaml format.

Open snap/snapcraft.yaml, and make the following changes:

name: eloquent-talker-listener-arnatious
version: "0.1"
summary: Eloquent ROS2 Example
description: |
 A ROS2 workspace containing a talker and a listener.
 
grade: devel
confinement: strict
base: core18
 
parts:
 colcon-part:
   plugin: colcon
   source: https://github.com/ros2/demos.git
   source-branch: eloquent
   colcon-rosdistro: eloquent
   colcon-source-space: demo_nodes_cpp
   build-packages: [make, gcc, g++]
   stage-packages: [ros-eloquent-ros2launch]
 
apps:
 eloquent-talker-listener-arnatious:
   command: opt/ros/eloquent/bin/ros2 launch demo_nodes_cpp talker_listener.launch.py
   plugs: [network, network-bind]

Let’s take an in depth look at this manifest.

name: eloquent-talker-listener
version: "0.1"
summary: Eloquent ROS2 Example
description: |
 A ROS2 workspace containing a talker and a listener.

This is the metadata any snap requires. The only caveat to this section is that the name must be unique on the snap store. Appending your developer name to the snap is an option to get around this (like I did).

grade: devel
confinement: strict
base: core18

grade should be either stable or devel, with devel locking out the ability to publish to the “stable” and “candidate” channels.

confinement can be strict, devmode, or classic. These are documented in detail on snapcraft.io, but in short: strict enforces tight confinement, restricting access to the system for security; devmode allows full access without any restriction but logs all accesses that strict would prevent; classic is unconfined, without its own private namespace or other security features.

Generally, you should always target “strict” confinement unless there’s specific features that confinement will prevent. “Classic” snaps, like snapcraft itself or text editors like Visual Studio Code, have no containment and run without protection. Classic snaps need manual approval.

The base keyword specifies the special snap providing things like a minimal set of core libraries for our snap’s runtime environment. We’re just using the “core18” snap, which bundles a minimal rootfs based on Ubuntu Bionic (18.04).

parts:
 colcon-part:
   plugin: colcon
   source: https://github.com/ros2/demos.git
   source-branch: eloquent
   colcon-rosdistro: eloquent
   colcon-source-space: demo_nodes_cpp
   build-packages: [make, gcc, g++]
   stage-packages: [ros-eloquent-ros2launch]

Snapcraft builds packages piecemeal, in small parts that are combined together. These are reflected by the part entries in the snapcraft.yaml. colcon-part is specified here as pulling the source code from a remote Github repository, though it can just as easily pull source code from a local directory or any source control system.

The colcon plugin is used here to build the package, with the colcon-rosdistro argument specified as eloquent, the colcon-source-space specified as the demo_nodes_cpp directory containing just the talker/listener package we care about. We specify the packages that provide the commands we need to build the ROS nodes under build-packages. stage-packages contains ros2launch, as we’ll need the launch verb it provides as part of the entry point to our snap.

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

We need to express how users will interact with this package. Since we’re packaging ~our~ project, we want the snap to expose our project’s verbs. We define these user interactions as “apps” in the apps” section.

In general, these verbs are invoked using <snap-name>.<app>. An entry in apps with the same name as the snap, like “eloquent-talker-listener-arnatious” above, can be invoked with just the snap name. Calling this app invokes the script in the command field, in this case roslaunch-ing the talker/listener system out of the demo_nodes_cpp package.

Lastly, we specify the interfaces the snap needs access to outside of confinement – in this case network and network-bind. This allows the snap to access the network and be accessed from the network, respectively. You can read more about interfaces on the snapcraft site.
Build the Snap
Now that we’ve defined the snapcraft.yaml, we can build the snap itself. Make sure you’re in the correct directory (above the “snap/” directory containing the “snapcraft.yaml”) and invoke “snapcraft.”

~$ cd eloquent-snap
~/eloquent-snap$ snapcraft
<omitted for brevity>
Snapped colcon-talker-listener-arnatious_0.1_amd64.snap

If you neglected to install multipass earlier, snapcraft may prompt you to do so.

The build process may take several minutes. During that time, the colcon plugin will install rosdep and use it to determine the dependencies specified in the package.xml of the packages, fetching and unpacking them into your snap. At the end, the result is squashed into a .snap file.

Test the Snap

To install the snap we just built before publishing it, we run

~/eloquent-snap$ sudo snap install --dangerous eloquent-talker-listener-arnatious_0.1_amd64.snap
eloquent-talker-listener-arnatious 0.1 installed

The --dangerous flag is required to install snaps from locations other than the store. The snapd daemon responsible for running snaps requires any snap to be cryptographically verified from the snap store, unless the --dangerous flag is used.

Finally, we invoke the snap:

$ eloquent-talker-listener-arnatious
[INFO] [launch]: All log files can be found below /home/arnatious/snap/eloquent-talker-listener-arnatious/x1/.ros/log/2019-12-11-07-56-04-973199-arnatious-ubuntu-1910
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [talker-1]: process started with pid [28330]
[INFO] [listener-2]: process started with pid [28331]
[talker-1] [INFO] [talker]: Publishing: 'Hello World: 1'
[listener-2] [INFO] [listener]: I heard: [Hello World: 1]
[talker-1] [INFO] [talker]: Publishing: 'Hello World: 2'
[listener-2] [INFO] [listener]: I heard: [Hello World: 2]
[talker-1] [INFO] [talker]: Publishing: 'Hello World: 3'
[listener-2] [INFO] [listener]: I heard: [Hello World: 3]
…

The snap runs without issue on the machine, regardless of linux distro or whether ROS is on the machine. You can now push to the the snap store – where anyone running snapd can install and run it.

I hope this gives you a good look at how to build ROS 2 Eloquent snaps! Feel free to ask questions on the Snapcraft forums or on the ROS Forums.

Internet of Things

From home control to drones, robots and industrial systems, Ubuntu Core and Snaps provide robust security, app stores and reliable updates for all your IoT devices.

Newsletter signup

Select topics you’re
interested in

In submitting this form, I confirm that I have read and agree to Canonical’s Privacy Notice and Privacy Policy.

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

Contact Us

Related posts

Learn snapcraft by example – multi-app client-server snap

Over the past few months, we published a number of articles showing how to snap desktop applications written in different languages – Rust, Java, C/C++, and...

Snapcraft tricks: Improve release flexibility with pull and build overrides

Sometimes, software projects are simple – one architecture, one version, one release. But often, they can be complex, targeting multiple platforms, and with...

How to install Ubuntu with the new Raspberry Pi Imager

The Raspberry Pi Foundation recently released their new “Raspberry Pi Imager” and we love it.  It’s a new tool that makes getting going with the Raspberry Pi...