Skip to main content

Your submission was sent successfully! Close

Thank you for signing up for our newsletter!
In these regular emails you will find the latest updates from Canonical and upcoming events where you can meet our team.Close

Thank you for contacting our team. We will be in touch shortly.Close

  1. Blog
  2. Article

gbeuzeboc
on 25 September 2024


The TurtleBot3 robot is a standard platform robot in the ROS community, and it’s a reference that Canonical knows well, since we’ve used it in our tutorials. As a matter of fact, we use it to demonstrate some of our work, such as distributing a ROS stack through snaps. This robot embeds two boards, a Raspberry Pi 4 that runs Ubuntu and the ROS stack, and an embedded board called the OpenCR. This board is the interface between the Raspberry Pi and the motors, the IMU and the battery.

The OpenCR board does not run an OS like Ubuntu. Instead, the microcontroller runs a firmware that can be upgraded as shown in the documentation, and it uses a connection via USB to the Raspberry Pi for robot control (data exchange and motor operation) and firmware updates for the OpenCR board itself.

The version of the firmware used on the robot must match the ROS distro: a ROS noetic snap won’t be able to operate with the OpenCR board if it uses the firmware version that is compatible with ROS 2 Humble. In that case, we need to update the OpenCR board.

We’ve recently published a tutorial on how to create a custom Ubuntu Core image for the TurtleBot3 that ships with everything necessary for out of the box operations (except for the automation of the firmware update). By adding the firmware update to a snap, we will make sure to never face incompatibility between the firmware version and the ROS distribution, as well as to always run the latest version of the firmware.

Over the course of this blog, we explore the solution we employed to keep the OpenCR firmware up to date from within a snap. The approach taken in this blog is just an example of how we can update a firmware with a snap. Other ways are possible, and we could explore other possibilities in the future.

The context

We are not starting from scratch. Indeed, the TurtleBot3 already has a defined procedure to update firmware.

Additionally, in the robotics documentation, we have already worked with the TurtleBot3 and developed snaps for it.

These will be the starting point of our work here, so make sure to familiarise yourself with these to better follow along.

The OpenCR scripts

In the OpenCR firmware update documentation, we see that we need binaries hosted on the GitHub repository: github.com/ROBOTIS-GIT/OpenCR-Binaries.

These binaries contain the firmware as well as the tools to flash the update from a host. We must include them in a snap and reproduce the instructions from the documentation in the snap to be able to update the firmware.

Sharing access to the port

In the TurtleBot3 Ubuntu Core image tutorial, we’ve shipped as part of the Ubuntu Core image the turtlebot3c-bringup snap that launches the ROS node that communicates with the OpenCR board over the /dev/ttyACM0 port.

The firmware update uses the same port and cannot run when the ROS node is running, since they need the very same resource.

Since those two processes are conflicting, we chose to ship the firmware updater in the very same snap that makes use of the OpenCR board to control the robot. This way, we ease their orchestration for the purpose of this post. 

Update the firmware from the snap

First, we focus on writing a snap application that updates the firmware without bothering with the orchestration. We ship the firmware update files and add an application to update it.

Add the firmware files to the snap

The first step is to add the OpenCR-Binaries repository to our snap. We download and decompress the tarball into the $SNAP/opencr directory.

Additionally, in the same part, we list the libc6:armhf for the runtime of our snap. This is because the binary to upload the firmware is built for armhf (32 bits). Two interesting things to note here: first, how we distinguish between the architecture in the snapcraft.yaml; and second, how an arm64 architecture can stage packages from its 32 bit equivalent (armhf in this case) and vice versa.

Scripts to facilitate the firmware flashing

The OpenCR update documentation mentions that there are some environment variables to specify, and so we need to write a script of the whole process.

First, the script proceeds with some preparation:

  • Since we provide the update only for the robot with a Raspberry Pi, the script exits if it is not running on arm architecture.
  • Define the OPENCR_PORT to /dev/ttyACM0, which is the default port.
  • Define the OPENCR_MODEL from the turtlebot3c-model snap configuration already present.

Finally, the firmware update is executed with the proper configuration.

Firmware update application

With the custom script that we’ve added, we now add an application to our snap.

The opencr-update application is simply calling the script and declaring, as a plug, the raw-usb interface. With this interface, the application is capable of accessing the /dev/ttyACM0 port.

And that is all we need to be able to manually update the firmware of the OpenCR board from the snap. Note that when manually updating, we should first make sure to stop the turtlebot3c-bringup.core daemon.

From there, wouldn’t it be great to push our luck and make the flashing automatic? So that we could remotely update the firmware without any human intervention. Let’s see how we can make that a seamless experience.

Orchestrate the firmware update

We’ve already reviewed the ROS orchestration with snaps in a previous blog. As we want to flash the firmware when the snap updates, we will use the same mechanism: snap hooks.

Flash on update hooks

As represented in the following diagram, we use the default-configure hook to flash the firmware on the first install after the gadget configuration. Furthermore, we also use the post-refresh hook to update the firmware after a snap update and before the turtlebot3c.core application is started.

To avoid duplication, our default-configure-script simply calls the post-refresh-script where the logic is implemented. Similarly to the app, we added the raw-usb interface to the hooks in the snapcraft.yaml so they can access the OpenCR port.

The opencr-auto-update configuration

The turtlebot3c-bringup snap is meant to run on Ubuntu Core as well as Ubuntu Desktop/Server. In some situations, we may not want the turtlebot3c-bringup snap to update or attempt to update the firmware. For that reason, we introduce a configuration to our snap called opencr-auto-update to enable/disable the firmware auto-update feature.

We first define it in our install hook and set the default value to false.

Additionally, we make sure in our configure hook to properly validate the given input.
With the auto-update happening in our post-refresh hook, we make sure to check for the opencr-auto-update value before flashing.

Update only on firmware change

Because we ship the firmware in the turtlebot3c-bringup snap, it might happen that we update our snap without updating the firmware. In fact, the firmware is unlikely to change. Additionally, it’s preferable to limit the flashing of a microcontroller to save the flash memory.

For those reasons, we included a mechanism to update the firmware only when it changes. As the following diagram shows, after a firmware update, we generate a hash from the directory of our snap that contains the firmware and save it for later comparison. Then, on the next update, we regenerate the hash and compare it with the one saved to verify if there is any change. In case of an update, we flash the new firmware and then save the new hash for later comparison.

Using this functionality in the post-refresh hook, we can ensure that the firmware is only updated if necessary.

Conclusion

I hope that reading this blog has piqued your interest and shown you that even microcontrollers can be remotely flashed and kept up to date with snaps.

Snaps can run applications on the host, but they can also carry and flash firmwares. This way, we benefit from the OTA update feature of snaps for devices that cannot even run an OS.

The approach taken in this blog could surely benefit from various improvements. For example, a backup strategy in case the flashing goes wrong. Since almost every microcontroller has its own flashing method, you can adapt the strategy used in this blog to your specific use cases.
If you have any feedback, questions or ideas regarding firmware update with snaps, please join our forum or contact us and let us know what you think. Furthermore, have a look at the Canonical robotics documentation if you want to learn more about snaps for robotics applications.

Related posts


gbeuzeboc
15 June 2023

ROS architectures with snaps

Robotics Article

Choosing the right architecture can be hard, but we want to help. In this blog, we’ll look at different architectures and their pros and cons. We’ll also show you how to apply the chosen architecture to a mobile robot software stack with three essential apps. With this blogpost, we will see the different ROS architectures ...


gbeuzeboc
24 April 2023

Optimise your ROS snap – Part 5

Robotics Article

Welcome to Part 5 of our “Optimise your ROS snap” blog series. Make sure to check Part 4. This fifth part is going to cover two different optimisations. The first one, covers the compression algorithm. The second one, is about implementing extremely risky but efficient file deletion. We are going to present two completely different ...


gbeuzeboc
27 April 2023

Optimise your ROS snap – Part 6

Robotics Article

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 did. We will provide a critique for every optimisation that we tried along this series of blogs. Finally, we have reached the last part of this ...