---
title: 'ROS production: our prototype as a snap [3/5]'
description: This is the third blog post in this series about ROS production. In the
  previous post we came up with a simple ROS prototype. In this post we’ll package
  that prototype as a snap. For justifications behind why we’re doing this, please
  see the first post in the series. We know from the previous post  […]
url: https://canonical.com/blog/ros-production-our-prototype-as-a-snap-35?format=md
---

1. [Blog](https://canonical.com/blog)
2. Article

---

[Kyle Fazzari](https://canonical.com/blog/author/kyrofa "More about Kyle Fazzari")

on 21 April 2017

# ROS production: our prototype as a snap [3/5]

[developers](https://canonical.com/blog/tag/developers)
[robotics](https://canonical.com/blog/tag/robotics)
[sc:series:ros-prototype-to-production](https://canonical.com/blog/tag/scseriesros-prototype-to-production)
[Snap](https://canonical.com/blog/tag/snap)
[snapcraft](https://canonical.com/blog/tag/snapcraft)
[snapcraft.io](https://canonical.com/blog/tag/snapcraft-io)
[Tutorial](https://canonical.com/blog/tag/tutorial)
[Ubuntu Core](https://canonical.com/blog/tag/ubuntu-core)

Share on:* [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://www.canonical.com/blog/ros-production-our-prototype-as-a-snap-35 "Share on Facebook")
* [Twitter](https://twitter.com/share?text=ROS%20production%3A%20our%20prototype%20as%20a%20snap%20%5B3/5%5D&url=https://www.canonical.com/blog/ros-production-our-prototype-as-a-snap-35&hashtags=ubuntu "Share on Twitter")
* [LinkedIn](https://www.linkedin.com/shareArticle?mini=true&url=https://www.canonical.com/blog/ros-production-our-prototype-as-a-snap-35&title=ROS%20production%3A%20our%20prototype%20as%20a%20snap%20%5B3/5%5D "Share on LinkedIn")

---

---

## Newsletter signup

Get the latest Canonical news and updates in your inbox.

Work email:

\*I agree to receive information about Canonical's
products and services.

By submitting this form, I confirm that I have read and agree to [Canonical's Privacy Policy](https://canonical.com/legal/data-privacy).

Sign up

> 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>.

This is the third blog post in [this series about ROS production](https://blog.ubuntu.com/2017/04/06/from-ros-prototype-to-production-on-ubuntu-core). In the [previous post](https://blog.ubuntu.com/2017/04/13/ros-production-our-prototype) we came up with a simple ROS prototype. In this post we’ll package that prototype as a snap. For justifications behind *why* we’re doing this, please see the first post in the series.

We know from the previous post that our prototype consists of a single launch file that we wrote, contained within our **prototype** ROS package. Turning this into a snap is very straight-forward, so let’s get started! Remember that this is also a video series, feel free to watch the video version of this post:

## Prerequisites

This post will assume the following:

* You’ve followed the previous posts in this series
* You know what snaps are, and have completed the “[create your first snap](https://tutorials.ubuntu.com/tutorial/create-your-first-snap#0)” tutorial
* You have a store account at <https://dashboard.snapcraft.io>
* You have a recent Snapcraft installed (2.28 is the latest as of this writing)

## Create the snap

The first step toward a new snap is to create the **snapcraft.yaml**. Put that in the root of the workspace we created in the previous post:

```
$ cd ~/workspace
$ snapcraft init
Created snap/snapcraft.yaml.
Edit the file to your liking or run `snapcraft` to get started
```

Do as it says, and make that file look something like this:

```
name: my-turtlebot-snap  # This needs to be a unique name
version: '0.1'
summary: Turtlebot ROS Demo
description: |
  Demo of Turtlebot randomly wandering around, avoiding obstacles
  and cliffs.

grade: stable
confinement: devmode

parts:
  prototype-workspace:
    plugin: catkin
    rosdistro: kinetic
    catkin-packages: [prototype]

apps:
  system:
    command: roslaunch prototype prototype.launch --screen
    plugs: [network, network-bind]
    daemon: simple
```

Let’s digest that section by section.

```
name: my-turtlebot-snap
version: 0.1
summary: Turtlebot ROS Demo
description: |
  Demo of Turtlebot randomly wandering around, avoiding obstacles
  and cliffs.
```

This is the basic metadata that all snaps require. These fields are fairly self-explanatory. The only thing I want to point out specifically here is that the **name** must be globally unique among all snaps. If you’re following this tutorial, you might consider appending your developer name to the end of this example.

```
grade: stable
confinement: devmode
```

**grade** can be either **stable** or **devel**. If it’s **devel**, the store will prevent you from releasing into one of the two stable channels (**stable** and **candidate**, specifically)– think of it as a safety net to prevent accidental releases. If it’s **stable**, you can release it anywhere.

**confinement** can be **strict**, **devmode**, or **classic**. **strict** enforces confinement, whereas **devmode** allows all accesses, even those that would be disallowed under **strict** confinement (and logs accesses that would otherwise be disallowed for your reference). **classic** is even less confined than **devmode**, in that it doesn’t even get private namespaces anymore (among other things). There is [more extensive documentation on confinement available.](https://docs.snapcraft.io/snap-confinement)

I personally always use **strict** confinement unless I know for sure that the thing I’m snapping won’t run successfully under confinement, in which case I’ll use **devmode**. I typically avoid **classic** unless I never intend for the app to run confined. In this case, I know from experience this snap won’t run confined as-is, and will require **devmode** for now (more on that later).

```
parts:
  prototype-workspace:
    plugin: catkin
    rosdistro: kinetic
    catkin-packages: [prototype]
```

You learned about this in the Snapcraft tour, but I’ll cover it again real quick. Snapcraft is responsible for taking many disparate parts and orchestrating them all into one cohesive snap. You tell it the parts that make up your snap, and it takes care of the rest. Here, we tell Snapcraft that we have a single part called **prototype-workspace**. We specify that it builds with Catkin, and also specify that we’re using Kinetic here (as opposed to Jade, or the default, Indigo). Finally, we specify the packages in this workspace that we want included in the snap. In our case, we only have one: that **prototype** package we created in the previous post.

```
apps:
  system:
    command: roslaunch prototype prototype.launch --screen
    plugs: [network, network-bind]
    daemon: simple
```

This is where things get a little interesting. When we build this snap, it will include a complete ROS system: roscpp, roslib, roscore, roslaunch, your ROS workspace, etc. It’s a standalone unit: you’re in total control of how the user interacts with it. You exercise that control via the **apps** keyword, where you expose specific commands to the user. Here, we specify that this snap has a single app, called **system**. The command that this app actually runs within the snap is the **roslaunch** invocation we got from the previous post. We use **plugs** to specify that it requires network access ([read more about interfaces](https://docs.snapcraft.io/interface-management)), and finally specify that it’s a simple daemon. That means this app will begin running as soon as the snap is installed, and also run upon boot. All this, and the user doesn’t even need to know that this snap uses ROS!

That’s actually all we need to make our prototype into a snap. Let’s create the snap itself:

```
$ cd ~/workspace
$ snapcraft
```

That will take a few minutes. You’ll see Snapcraft fetch **rosdep**, which is then used to determine the dependencies of the ROS packages in the workspace. This is only **prototype** in our case, which you’ll recall from the previous post depends upon **kobuki\_node** and **kobuki\_random\_walker**. It then pulls those down and puts them into the snap along with roscore. Finally, it builds the requested packages in the workspace, and installs them into the snap as well. At the end, you’ll have your snap.

## Test the snap

Even though we’re planning on using this snap on Ubuntu Core, snaps run on classic Ubuntu as well. This is an excellent way to ensure that our snap runs as expected before moving on to Ubuntu Core. Since we already have our machine setup to communicate with the Turtlebot, we can try it out right here. The only hitch is that **/dev/kobuki** isn’t covered by any interface on classic Ubuntu (we can make this work for Ubuntu Core, though, more on that later). That’s why we used **devmode** as the confinement type in our snap. We’ll install it with devmode here:

```
$ sudo snap install --devmode path/to/my.snap
```

Right after this completes (give it a second for our **app** to fire up), you should hear the robot sing and begin moving. Once you remove the snap it’ll stop moving:

```
$ sudo snap remove my-turtlebot-snap
```

How easy is that? If you put that in the store, anyone with a Turtlebot (no ROS required) could **snap install** it and it would immediately begin moving just like it did for you. In fact, why don’t we put it in the store right now?

## Put the snap in the store

#### Step 1: Tell Snapcraft who you are

We’re about to use Snapcraft to register and upload a snap using the store account you created when satisfying the prerequisites. For that to happen, you need to sign in with Snapcraft:

```
$ snapcraft login
```

#### Step 2: Register the snap name

Snap names are globally unique, so only one developer can register and publish a snap with a given name. Before you can publish the snap, you need to make sure that snap name is registered to you (note that this corresponds to the **name** field in the **snapcraft.yaml** we created a few minutes ago):

```
$ snapcraft register <my snap name>
```

Assuming that name is available, you can proceed to upload it.

#### Step 3: Release the snap

In the tour you learned that there are four channels available by default. In order of increasing stability, these channels are edge, beta, candidate, and stable. This snap isn’t quite perfect yet since it still requires **devmode**, so let’s release it on the beta channel:

```
$ snapcraft push path/to/my.snap --release=beta
```

Once the upload and automated reviews finish successfully, anyone in the world can install your snap on the computer controlling their Turtlebot as simply as:

```
$ sudo snap install --beta --devmode my-turtlebot-snap
```

In the [next post in this series](https://blog.ubuntu.com/2017/04/27/ros-production-obtaining-confined-access-to-the-turtlebot-45), we’ll discuss how to obtain real confined access to the Turtlebot’s udev symlink on Ubuntu Core by creating a **gadget** snap, moving toward our goal of having a final image with this snap pre-installed and ready to ship.

*This article originally appeared on [Kyle Fazzari’s blog](https://kyrofa.com/posts/ros-production-our-prototype-as-a-snap-3-5).*

#### Related posts

---

[Jonathan Beri](https://canonical.com/blog/author/jmberi)

18 June 2026

### [So you need to add microcontrollers to your fleet: now what?](https://canonical.com/blog/microcontrollers-ubuntu-core-golioth)

Ubuntu and Linux

Ubuntu tech blog

Your Ubuntu Core fleet is running beautifully. OTA updates roll out in minutes. Every device is strictly confined, cryptographically attested, and carrying a 10 to 15 year long term support (LTS) commitment. The operational team sleeps soundly. Then the product roadmap meeting happens. The industrial floor needs vibration sensors on every ...

---

[Gabriel Aguiar Noury](https://canonical.com/blog/author/g-aguiar-noury)

16 June 2026

### [A look into Ubuntu Core 26: Building a local AI inference appliance in a virtual machine](https://canonical.com/blog/ubuntu-core-26-ai-box)

Internet of Things

Ubuntu tech blog

Welcome to this blog series which explores innovative uses of Ubuntu Core. Throughout this series, Canonical’s Engineers will show what you can build with this Core 26 release, highlighting the features and tools available to you.  In this first blog, Farshid Tavakolizadeh, Engineer Manager for Canonical’s Industrial team, will show you h ...

---

[Gabriel Aguiar Noury](https://canonical.com/blog/author/g-aguiar-noury)

4 June 2026

### [A look into Ubuntu Core 26: Deploying AI models on Renesas RZ/V series for production](https://canonical.com/blog/ubuntu-core-26-ai-renesas)

Internet of Things

Ubuntu tech blog

Welcome to this blog series which explores innovative uses of Ubuntu Core. Throughout this series, Canonical’s Engineers will show what you can build with our releases, highlighting the features and tools available to you. In this blog, Asa Mirzaieva, engineer from the Silicon Alliances team, will show you how to deploy optimised AI model ...
