Robots y modelos

Notas sobre pruebas, modelado y aventuras en Java y Android

Running UML-RT models on a Raspberry Pi-based rover

with one comment

Last year, I joined the Papyrus Industry Consortium to help push forward the development of Eclipse Papyrus, one of the most actively developed open-source UML environments currently. The Papyrus IC consortium is working towards increasing the use of Papyrus for teaching, research and industrial use. Among those activities, they decided to provide a limited number of rovers for these purposes, and I applied for one with the goal of attracting some of my students to the idea of model-driven software engineering (MDSE).

After my return from MoDELS’17 (and the excellent tutorial on Papyrus-RT there), I spent the odd hours here and there getting the Rover example project from its supporting material to run, and making some adjustments (which are now on Github). It took a while and a good bit of trial and error, so I thought I might as well do a write-up in case somebody may find it useful :-). I’ll talk about the rover first, then present a high-level view over the UML-RT models, and finally dive into the setup of the Pi and the PC.

The rover

Here’s how it looks right now – at the moment, I am only using one ultrasonic range finder, so it isn’t quite that smart:


The provided kit has more than that, of course, and I made some changes to make the whole thing slightly more convenient. Here’s what I have right now:

  • The base is the Rover5 chassis (the version without encoders). This chassis has two DC motors and a 6 AA-sized battery holder. I spliced a small switch (visible on the top right of the rover below) on the positive cable of the battery holder, so I could turn on/off the robot without disconnecting the power or removing the batteries. (Edit: still, these don’t last nearly enough! I’m currently using a small USB power bank by Anker, and the rover is much happier for it.)
  • For the brains, a Raspberry Pi 3 and the requisite microSD card.
  • In order to control the motors, a pre-assembled dual Pololu MC33926 DC motor driver add-on board for the Pi. These allow you to use 3 GPIO pins to control each of the motors – just strip those cables from the Rover5 chassis and screw those and the battery holder into the terminal block :-). As suggested in the manufacturer’s datasheet, I bought separately and soldered on a Pololu D24V10F5 5V regulator, so I could feed the Pi from the same input as the motors.
  • For detecting obstacles, the kit included:
    • Two HC-SR04 ultrasonic range finders. These output distance as the duration of a DC pulse – you can see one facing forwards below. I found these quite “noisy” until I applied a sliding 5-median filter to the results as recommended here by a manufacturer of a similar ultrasonic range finder.
    • Four Sharp infrared range finders. These output distance as a DC voltage, requiring the use of the included MCP3208 analog to digital converter (the little chip on the front). I haven’t used these yet, but the wiring will be something to see!
  • For orientation, an HMC5883L magnetometer – basically a digital compass after some processing. It measures the strength of the Earth’s magnetic field as a 3D vector, providing it through the I2C bus, and from there you have to compute your heading. I started trying this out, but I was getting odd headings – I may need to do some calibration.
  • The kit also includes a Pi-compatible camera, an LED you can toggle at will for various purposes, and some breadboards and cabling. There were some 3D-printed parts that I haven’t used yet as well.

The models, and the code

UML-RT (UML for Real Time) is an extended subset of UML which allows you to create executable models that operate in a reactive and time-aware manner. The system is divided into capsules that exchange messages over their ports. Each connected pair of ports follows a protocol, which specifies which messages can be sent in which direction.

High level structure and messaging: capsules, ports and protocols

To illustrate the concepts a bit, we will go through the models in the sample model that we will run on the rover. Let’s start with the top-level capsule, which looks a lot like a UML component diagram:


In the figure above, we can see that the system is divided into two capsules: the control algorithm itself, and the rover hardware. They exchange messages over two ports: one for motor control, and one for obstacle detection. For instance, the protocol for motor control has these messages listed in the Model Explorer view:


The “out” messages allow the control capsule to send commands to the rover capsule, whereas the “in” messages are for the rover capsule to send notifications back to the control capsule.

Let’s look into the rover capsule now:


The rover capsule contains two capsules: one for the motor control, and one for obstacle detection. Each of them handles the messages for their respective ports.

Capsule behaviour: state machines

In order to handle those messages, we need to associate behaviour to the basic capsules. This is done through state machines, which are drawn pretty much like standard UML state machines. The Papyrus-RT code generator will turn these into C++ code, so we can weave C++ fragments within state entry/exit actions and transition guards and effects.

In this project, we have state machines for engine control, obstacle detection and the main control algorithm. They are all very much similar, but let’s focus on an extremely simplified version of the state machine for the control algorithm. Supposing we simply went forward until we get close to an obstacle, and then we stopped, the state machine would look like this:


We have an initial STANDBY state in which we wait for 2 seconds (using the “timer” system port from the Papyrus-RT runtime library), and then we transition into the MOVE_FORWARD state. Upon entry, we run a fragment of C++ code that logs a short message (“log” is also from the runtime library), sends the “moveForward” message to the engine capsule, and then sends the “startDetection” message to the obstacle detection capsule.

From that state, we have a guarded transition to STOP_MOVING_FORWARD (as indicated by the yellow shield icon) which will stop the detection of obstacles. The guard is a small C++ boolean expression that checks if we are within 30cm of an obstacle. Upon entry, the STOP_MOVING_FORWARD state will ask the motor to stop.

There is also a hidden looping transition from MOVE_FORWARD to itself whenever it receives an “obstacle detected” message that is over the distance threshold. That transition simply logs the sensed distance as its effect.

Let’s check the state machine for the engine controller as well:


This state machine is slightly more complex, but not that much more: we start in an IDLE state, and then we can move forward or backwards until we are told to stop, or turn around a certain angle. One limitation in the current model is that since we do not have yet encoders in the wheels, nor a magnetometer to tell us the heading, we can only turn for a duration proportional to the angle we are asked. This is obviously rather unreliable,  as the real angle will depend on timing and on the friction coefficient of our surface, but that’s a matter for another time :-).

Once we have our models ready, it’s a matter of right-clicking on the root node of the Model Explorer (having the rover.di file open in the editor), and selecting “(Re)Generate (all) code”, like here:


That will generate a CDT project with all the code we need. It should only be a matter of compiling it and sending it off to the Pi to run, right? Well, there’s a few things to prepare before we can do that. Let’s start with the Pi, and then return to our PC.

Setting up the Pi: SSH over Bluetooth

Now that we know about the robot and about the models, we’ll dive into the configuration of the Pi and the main PC.

The Pi boots from the microSD card, so we need to install an OS into it. For the sake of convenience, I chose a recent version of the Raspbian distro with its desktop environment. It comes with wiringPi preinstalled, which is the library used in the sample project to manipulate the GPIO pins for the robot and the HC-SR04 range finder. There wasn’t much to do here – until I realised I needed to have the laptop talk to the Pi.

In most environments, it would be a matter of connecting the Pi to the same Wi-Fi network as my laptop, and then SSH/SFTP to it normally. However, due to network security concerns in my organisation, this wasn’t an option. Instead, I would have to use a Bluetooth connection to connect my laptop directly to the Pi. (If you don’t have this problem, feel free to skip ahead!)

I originally experimented with a serial terminal over RFCOMM and using the OBEX profile for file transfer. Neither worked as well as I wanted: Ctrl-C didn’t work over RFCOMM (something about not having the right ioctl, and therefore no job control), and OBEX was clunky to use and slow.

Luckily, I found out that Bluetooth also has a Personal Area Network (PAN) profile, which allows you to set up a proper IP-based network across multiple devices. One of them (the laptop) acts as the hub or network access point (NAP), while the rest connect to it. The handy bt-pan script worked a treat for setting this up, once I made sure both sides trusted each other with bluetoothctl.

However, I wanted the PAN to be set up automatically as soon as I turned on the Pi, so I wouldn’t need to plug it to a monitor and keyboard at the beginning every time. That took longer than I thought, but essentially it boiled down to setting up the systemd-networkd and net-bnep* services as recommended by the author of bt-pan. The configuration of the net-bnep and net-bnep-client services is explained there, but systemd-networkd isn’t really discussed much so I’ll describe the minimal setup here.

Run these commands in the laptop and the Pi:

sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd

In the laptop, place this in /etc/systemd/network/25-bridge.netdev in order to set up the “bnep” bridge required by bt-pan automatically:


Also in the laptop, place this in /etc/systemd/network/ to assign an IP address for the laptop in this bridge:


In the Pi, you only need to place a similar file in /etc/systemd/network/ and it will reconfigure the bnep0 interface once the net-bnep-client service has brought it up:


Set up the net-bnep* services, and this should work a treat – I can now SSH and SFTP into the Pi while keeping the IT staff at my university happy :-). It’d be great if I could get the Pi to access the internet through my laptop, but I haven’t needed it yet.

Setting up the PC: Papyrus-RT and cross-compilation

Assuming you have installed Papyrus-RT following the official instructions (do not forget setting up UMLRTS_ROOT!), you have a few aditional steps before you can produce a binary that the ARMv8 processor in the Pi will be able to run. There is a pretty good-looking tutorial in about this, even explaining how to set up remote debugging, but it is Windows-specific. My instructions will be based on a Linux system.

Cross compiler support in Eclipse CDT

First, you will need to go to “Help > Install New Software…” and install the cross-compiler support for Eclipse CDT:

Screenshot from 2017-10-12 23-21-53

Installation of a cross-compiler for the Pi

Once that is done and Eclipse has restarted, we need to set up our cross-compilation environment. Luckily, the excellent crosstool-ng project has exactly what we need. It’s a matter of grabbing the source code, compiling it and installing it into our system. I ran these commands in my Ubuntu 16.10 system:

git clone
cd crosstool-ng
git checkout crosstool-ng-1.23.0
sudo apt-get install gperf bison flex makeinfo texinfo help2man
./configure --prefix=/usr/local
sudo make install

We should have now the ct-ng script available in /usr/local/bin. According to “uname -a”, my Raspbian installation is 32 bits, so let’s use ct-ng to create a cross compiler environment with the 32-bit Raspberry Pi 3 preset:

cd ..
mkdir -p ctng/pi
cd ctng/pi
ct-ng armv8-rpi3-linux-gnueabihf
ct-ng build

If we follow all the defaults, after a good while (we *are* compiling GCC after all!), we should have in ~/x-tools/ a directory with a full cross-compilation environment to the ARMv8 GNU Linux ELF binaries that the Raspbian system in the Pi is expecting.

Cross-compilation of wiringPi and the Papyrus UML-RT runtime

The next bit is to cross-compile the two basic libraries required by our generated C++ code (wiringPi and the Papyrus UML-RT runtime), and install them in a “staging area” next to our cross-compilation environment.

The build scripts in the official sources of wiringPi are not designed to accept cross-compilers or non-standard installation locations, so I made some adjustments in my Github fork. We will need to run these commands:

git clone
cd WiringPi
./build-crosstool ~/x-tools/armv8-rpi3-linux-gnueabihf armv8-rpi3-linux-gnueabihf-

This will install the libraries into a “staging area” close to the sysroot (system root) of our cross compilation environment, without mixing the two.

The Papyrus UML-RT runtime is better prepared in this regard. From the root folder, we need to locate the plugins/org.eclipse.papyrusrt.rts*/umlrts/build/buildtools folder, create a copy of the x86-gcc-4.3 folder named “pi3”, then tweak the pi3/ file inside:

cd /directory/with/papyrusrt
cd plugins/org.eclipse.papyrusrt.rts*/umlrts/build/buildtools
cp -r x86-gcc-4.3 pi3
nano pi3/

You should change the values of CC (the C compiler), AR (the static library archiver) and LD (the linker) so they match the names of your crosscompilers:

# Compiler
# Archiver
# Linker

Once you have done that, go back to the main umlrts folder and start the build:


Once it’s done, you should have a lib/linux.pi3/librts.a static library that you can link into your cross-compiled binaries for the rover.

Finishing up the CDT project for cross-compilation

We have the cross-compiler, and the two basic dependencies have been cross-compiled as well. Time to set up our CDT project. Right-click on the project in the “Project Explorer” or “Package Explorer” views, and select “Properties”. Go to the “C++ Build > Tool Chain Editor” and pick the “Cross GCC” one (you did install the cross compiler support in CDT, right?).


Switch to the “Settings” section, and enter the common prefix to all your cross-compiler binaries and the path to the “bin” directory in your x-tools environment for the Pi:


Go to the “Build Variables” section and add an XTOOL_STAGING build variable that points to the root of our x-tools environment for the Pi:
Screenshot from 2017-10-17 18-00-04

Go back to the Settings section, and ensure the C++ compiler has the right include path:

Screenshot from 2017-10-17 18-02-02

Check that the linker has the right library search path, and that it will link any libraries that we need:

Screenshot from 2017-10-17 18-02-26

Thankfully, we only need to do this once. We can now select the project and hit Ctrl+B to build the whole thing. After some time, we should be able to see something like this in our console:

Building target: Rover_CDTProject
Invoking: Cross G++ Linker
armv8-rpi3-linux-gnueabihf-g++ -L"/home/antonio/x-tools/armv8-rpi3-linux-gnueabihf/lib" -L"/home/antonio/Desktop/papyrus-tutorial/Papyrus-RT/Papyrus-RT/plugins/org.eclipse.papyrusrt.rts_1.0.0.201707181457/umlrts/lib/linux.pi3" -o "Rover_CDTProject" ./src/ControlSoftware.o ./src/Detection.o ./src/DetectionSensor.o ./src/Engine.o ./src/EngineController.o ./src/Rover.o ./src/Top.o ./src/TopControllers.o ./src/TopMain.o -lrts -lwiringPi -lpthread
Finished building target: Rover_CDTProject

18:03:31 Build Finished (took 1s.621ms)

The binary will be created in the “Debug” subdirectory of our project. If we check with the “file” utility in GNU/Linux, we’ll see it’s an ARM binary:

$ file Rover_CDTProject
Rover_CDTProject: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/, for GNU/Linux 4.10.8, not stripped

Deploying to the Pi and running the code

The last bit is to send the executable to the Pi itself. Since we have a network set up between the two, we can use good old SCP for it:

user@pc $ scp Debug/Rover_CDTProject pi@

Once it is on the Pi, SSH to it and then run the executable with root rights:

user@pc $ ssh pi@
pi@pi $ sudo ./Rover_CDTProject

We should start to receive messages about the rover, and it should start moving around. Finally!

Note: we need root rights because the C++ code uses wiringPiSetup(). To run under a non-root user, we would need to carefully tweak permissions and use wiringPiSetupSys() instead, as documented here.

Next steps

Whew, that was a long article! It takes quite a few steps to set up, but when it’s ready, it’s a matter of tweaking the model / C++ code, regenerating, and then SCP’ing the binary over to the rover. It could be even faster with remote debugging over the SSH connection, I suppose.

There’s still many things we could do: the rover right now is quite silly, as it only uses one sensor and the speed / turning time is constant, rather than controlled by some type of feedback lock (ideally, a PID controller). It would also be nice to integrate the magnetometer, so it could really drive straight and turn X degrees “for real”.

As usual, contributions to the sample models are always welcome!

Written by bluezio

17 de octubre de 2017 a 19:18

Publicado en Uncategorized

Una respuesta

Subscribe to comments with RSS.

  1. […] Running UML-RT models on a Raspberry Pi-based rover […]


Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de

Estás comentando usando tu cuenta de Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s

A %d blogueros les gusta esto: