Close

Get Real(time)

A project log for Bobble-Bot

Demonstration robot for learning principles of real-time control using Raspberry Pi, RT Linux, and ROS.

James HolleyJames Holley 06/23/2019 at 20:040 Comments

One of the coolest features of Bobble Bot's software is the realtime kernel running on the Raspberry Pi.  Admitting that I think the realtime kernel is 'cool' just shot me up in the rankings of "Most Likely to Get a Wedgie in the Near Future," but whatever, I'm going to tell you about it anyway.

In the controls world, timing and speed are everything.  Jitter is the deviation from true periodicity of a periodic signal, or in layman's terms, the difference in time of when you expect your control loop to execute, and the actual time it does.  This has been studied extensively and leads to a conclusion we all knew was coming - if your control loop doesn't execute consistently, there are going to be problems.  

When we get asked about Bobble Bot and the control system, a lot of times people ask "Why didn't you use a microcontroller?"  This is an excellent question - microcontrollers are built to execute control loops at a given rate- no operating system, deterministic servicing of interrupts and quick writes to communication ports or GPIO.  This minimizes the effort you have to go through to mitigate problems with jitter.  However, microcontrollers have limited functionality and a steeper learning curve for developers.  The Raspberry Pi was designed to "put the power of computing and digital making into the hands of people all over the world" - in layman's terms again, it's a really accessible cheap computer for teaching programming to people.  So, we thought it would be super owesome if we could merge both worlds - give control loop access to people via the Raspberry Pi so they are able to work on and experiment with control systems that have demanding requirements.  To make this happen, we chose the Raspberry Pi + Realtime Linux Kernel.

The realtime kernel for Linux is becoming more popular and is working its way into the mainline development.  Better yet, a group of developers have integrated the RT patches into the Raspbian 4.14-y kernel.  I was also happy to find another hackaday project dedicated to testing this kernel!  Building the kernel is documented here, with the only notable exception for the version we are using for Bobble Bot is setting CONFIG_HZ_1000=y and CONFIG_HZ=1000, which increases the scheduler base frequency (click here for more details on the scheduler if you want them).

RT-Tests were then used to test the latency of the realtime kernel (bottom) against the standard kernel (top).  

These charts make it pretty clear - if you want to make sure a thread is executed at a consistent rate, you are going to need the realtime kernel.  Also, the latency of the regular kernel exceeded 16 ms at one point - for an unstable system like Bobble Bot, this could cause a fall.

Even though these charts do a pretty good job of illustrating what you get with the RT Kernel, I wanted to provide another example you can test on your own.  This is just a small piece of C++ code that toggles a pin on the Raspberry Pi in a RT thread.  DISCLAIMER: This is just a bit of test code.  I think using delays and iostreams in a RT thread is usually bad practice, but for the sake of getting a little program off the ground, we're doing it anyway.

gpio-rt-test.c

#include <pthread.h>
#include <sys/mman.h>
#include <wiringPi.h>
#include <iostream>

int main(int argc, char **argv)
{
  struct sched_param param;

  // Using GPIO pin 21 - feel free to use whatever is convenient for the test
  const unsigned int GPIO_PIN = 21;

  // Comment out the section below to remove RT scheduling
  param.sched_priority=sched_get_priority_max(SCHED_FIFO);
  if(sched_setscheduler(0,SCHED_FIFO,¶m) == -1){
    std::cout << ">>> Failed to schedule RT thread." << std::endl;
    return -1;
  }
  if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
    std::cout << ">>> Failed to lock memory." << std::endl;
    return -1;
  }
  // End of section to comment out for RT scheduling

  wiringPiSetup();

  pinMode(GPIO_PIN, OUTPUT);

  for(;;)
  {
    //std::cout << ">>> Setting pin high." << std::endl;
    digitalWrite(GPIO_PIN, HIGH); delay(1);
    //std::cout << ">>> Setting pin low." << std::endl;
    digitalWrite(GPIO_PIN, LOW); delay(1);
  }

  return 0;
}

Compile this with:

g++ -o gpio-rt-test gpio-rt-test.c -l wiringPi

and run with:

sudo ./gpio-rt-test

I then hooked up my oscilloscope to the pin and measured the resulting waveform.  The regular thread is the top image, the RT thread is the bottom image.

The GPIO for the RT thread executes at exactly 1 ms - or at least close enough to 1 ms given my oscilloscope settings.  You can easily juxtapose this with the non-rt thread in the top picture. I saved the RT thread wave in light blue for comparison.  You can see that the GPIO is late and the falling edge is also occurring at different times - this is a recipe for high jitter.  Give this a try on your own Raspberry Pi. 

Discussions