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