RPIO.PWM now works on Pi Zero, B2 and B3

Reik Hua sent me his copy of the mailbox code just as I’d started looking into using the mailbox for RPIO.PWM, thus saving me loads of time and brain-ache!  He uses it for his quadcopter with B2 and B3 Raspberry Pis, and I’ve just tested it on Zoe, the Pi Zero and it worked there perfectly too.  Reik Hua has kindly agreed to me passing this on to Chris Hager who owns the RPIO code on GitHub, thus making it generally available to all and allowing me to discard another personal hack from my repository.

What’s the fuss about?  With the new kernel version in May, the RPIO code stopped working as it was assuming a fixed memory address for the DMA.  The mailbox provides the actual address which had changed with the new kernels.  So not only does the RPIO now work with 0’s, 2’s and 3’s – it’s also now future proofed.  And that’s why I could show Zoe back in the air yesterday!

Mailbox

I’ve found out that fixing the RPIO.PWM code for the new PiZero (and a B2 and B3) shouldn’t be that hard.  From ‘joan’ on the RPi forum and Chris who wrote the RPIO.PWM code, I’ve found out that the right way to access DMA for PWM is via a ‘mailbox’ instead of building a page map, and even better, Chris pointed me at the ServoBlaster code changes it made to swap from the pagemap to the mailbox method.  RPIO.PWM is derived from ServoBlaster, and so the upgrade to ServoBlaster is almost a direct fit for the required update to RPIO.PWM.

So once more, I now have the key I can start with.  But for now, it’s back to testing the merge of the new LEDDAR code into Phoebe’s HoG code.

Tangerine nightmare [NOW FIXED]

OK, nightmare is a bit of an exaggeration, but the RPi B2 and her Tangerine PiBow case arrived today, so I installed the basics are per the Zoe instructions, and did a quick test run which failed almost instantly because the RPIO PWM didn’t recognise the RPi B2.  That’s not really a surprise – what surprises me if that it hadn’t barfed on the B+ and A+ as the RPIO code dates back to March 2013.  Looks like I’ll have to fix this and see if metachris will add the fix to the master.


Turns out I’d fixed this already, and then forgotten about it. I’ve uploaded the tweaked version to my GitHub along with updating Zoe’s build instructions.

Zoe the Zero – 2 – Initial Installation

First step is to flash your (at least) 8GB micro SD card with the latest Jessie.  Currently that’s the 2015-11-21 version.

To setup a PiZero, because it only has one USB port, you need a powered (at least) 4 port USB hub, a mini HDMI to HDMI adapter, and a micro USB to USB A adapter.  With that you can set up a PiZero with keyboard, mouse, WiFi dongle and screen, and so get it connected to the internet.

Once connected the next step is to change the various bits of system configuration:

  • expand file system
  • set minimal GPU memory as she’ll be headless
  • christen her – zoe in my case
  • enable I2C
  • boot to console login prompt
  • overclocking – mine seems happy in Turbo mode @ 1GHz! – CPU temperature showing 38.4 degrees
/opt/vc/bin/vcgencmd measure_temp

I’ve found the only way I can guarantee each of these steps works is to reboot between each.

Next step is to update the code to the latest

sudo apt-get update
sudo apt-get dist-upgrade

Next install the various tools required

sudo apt-get install i2c-tools python-smbus python-dev

Next install the RPIO library – ignore the build warnings

git clone https://github.com/metachris/RPIO.git
cd RPIO
sudo python setup.py install
cd ..

If you are installing onto a RPi B2 (the 4 core), then you need to replace the RPIO/source/c_gpio/cpuinfo.c with this one before building:

cpuinfo.c

Next install my performance enhanced GPIO library from GitHub

git clone https://github.com/PiStuffing/Quadcopter
cd Quadcopter
tar xvf GPIO.tgz
cd GPIO
cd source
touch *
cd ..
sudo python setup.py install
cd ..

I think that’s everything.  Next step is to get and populate the pHat – it’ll be a couple of weeks before I get hold of this, so don’t hold your breath for the next update.

Installing RPIO

RPIO is used to provide the hardware PWM signals to drive the ESCs.

Before you can use any of the Python code for your quadcopter, you need to install and build RPIO:


cd ~
sudo apt-get install gcc python-dev python-setuptools
git clone https://github.com/metachris/RPIO.git
cd RPIO
sudo python setup.py install

Once it’s installed, make sure you have the quadcopter python code from 26 January 2014 (or later) – it includes additional function to stop all the debug logging from RPIO which can inhibit performance and smother your screen with debug logs.

Tinkering with Time

Nothing to do with Dr Who’s 50th anniversary episode (though it was good, wasn’t it!).

For a while I’ve been interested in doing some performance profiling on Phoebe’s code, and had got lots of good advice from the Raspberry Pi forum.

So while I was waiting for the glue to dry on her reconstructed frame last night, I knocked some very simple profiling code into Phoebe’s main loop and it threw out these figures.

loop speed 110.699372 loops per second
% fsm: 24.976521
% sensors: 50.086001
% eangles: 2.017404
% iangles: 0.420382
% angles_filter: 0.626013
% sensor_angles: 0.980850
% speed_pids: 5.348638
% angle_pids: 5.303506
% pid_outputs: 10.328892

The fact the FSM code took 25% of the time amazed me as it’s only simple – however a quick dig shows it also includes the main logging – rather than logging once per loop, logging every 0.1s reduced the FSM percentage significantly.

The next point of interest is the 50% reading the sensors.  It set a train of thought rolling

  • 100 loops per second = 10ms period per loop
  • 50% of each loop is reading the sensors = 5ms per loop dedicated to reading the sensors
  • The MPU6050 is currently configured to update the output registers 200 times a second – therefore each batch of data will be there for 5ms
  • which makes me wonder whether that sample rate is fast enough or will we get data misses sometimes?

Some code tinkering showed it could be improved by upping the sampling speed to 250Hz in the MPU6050 configuration.  I tried 333Hz also, but that was then updating samples faster than they could be read leading to errors, and reducing performance.

Now there’s not much point going beyond 250Hz – the PWM can only be updated @ 300Hz anyway (an RPIO PWM limit), but still, I’m pleased; this opens up a lot more time in the code that I can use for listening on a TCP socket for RC commands.

So here’s the improved figures:

loop speed 164.855286 loops per second
fsm: 4.010887
sensors: 58.669735
eangles: 2.894867
iangles: 0.672797
angles_filter: 1.054403
sensor_angles: 1.599324
speed_pids: 7.927051
angle_pids: 7.947845
pid_outputs: 15.304528

Three points:

  • the overall loop speed is up to 165 per second or 0.00606ms per loop
  • the FSM time is now down to 0.25 ms per cycle compared to the previous 2.25ms – nearly a factor of 10 improvement
  • the sensor read time is down to 3.6ms from 4.5ms

There may be further improvements in sensor reading to be made by making it interrupt driven running in another thread waking the main thread up only when there is new data – I might have a play with that, but for the moment, this is good enough.

Actually combined with the changes I made previously, I’m pretty chuffed at this improvement – from 50 loops per second to 165 while actually adding new code / function!

…but the MPU6050 is still playing up

The MPU6050 is the gyro + accel sensor. I have a new version (same chip, different breakout board) which should mean it’s better pinned to the breadboard.

ProtoPi + MPU6050 Breadboard

ProtoPi with new MPU6050 + RPIO PWM

I’ve incorporated the code change to make sure the DLPF (digital low pass filter) takes effect…

and actually, the results are looking a lot better, except for this…

Vertical acceleration and speed

Vertical acceleration and integrated speed

So the prototype (ProtoPi) was sitting on the desktop, going nowhere. The accelerometer looks very good – the acceleration (navy blue) is integrating to a flat line vertical speed (pink), which means the sensors are nicely balanced. Except of course when one of those whopping spikes appears which throw the vertical speed integration way out (meaning that the drone thought it started travelling at 0 cm/s vertically, then dropped at 20cm/s before descending further to 80cm/s. If this was a live run, the PIDs would try to counteract these dodgy readings, powering up the motors and slapping the drone head-first into the ceiling!!!

I have to assume these are garbage reads from the MPU6050, even though the code now has interrupt handling to only read the data when it’s ready and waiting.

So I’m throwing this out to the world at large for suggestions…please, I beg you!

RPIO PWM is the way to go…

Once I got the Raspberry Pi (aka ProtoPi from now on) installed, imported RPIO, wired it up to my iPad mini tablet via an iMSO digital oscilloscope, it took just a few mins to write the code to prodoce 4 PWM gpio outputs, each using the same PWM channel, but each with their own set of pulses.

RPI.PWM use

RPIO PWM, 1 channel, 4 GPIO outs each with their own pulses

Here’s the code used to do this:

Even better there was 0 CPU used while the pulses were running.

Next step depends on the delivery of the breakout for the MPU6050 to pin it firmly to the breadboard.

No Hesitation, Repetition or Deviation

Although neither the drone nor alarm pi projects are even phase 1 complete (phase 1 for the drone is safe automaton takeoff, hover and land, and for the alarm is independent alarm control), I’m strongly considering moving from the RPi.GPIO library to the RPIO library for a number of reasons:

  • RPIO interrupts can be used to wake socket.select() calls, whereas RPi.GPIO runs a separate thread which can only wake a socket.select() on the make thread by sending a SIGINT – functional but ugly
  • RPIO supports hardware PWM across any GPIO port whereas currently, I use I2C to connect to a PWN breakout chipset

While using the RPi.GPIO works fine, RPIO just feels better. So once phase 1 of both projects are complete, I’m going to add phase 1.5 which is the switchover to RPIO (or perhaps merge the best of both).

In passing, I’m also considering moving over to PiPi once it’s available in the Wheezy distro – the drone is running full speed currently with no sleeps. Moving to PiPi means I can start introducing time.sleep() as the precursor to TCP socket inputs via socket.select(). Currently the space in the CPU cycles from using interpreted Python is feeling a bit small to stably introduce remote control.

Offloading the burdened drone

My drone code is a hard loop (no sleeps or other time blocking commands). Due to being written in interpreted Python, currently each loop around the code, checking the sensors, running the PIDs and updating the PWM takes about 0.015s. That seems pretty fast but I’m starting to wonder if it’s fast enough – the integrations, particularly of the accelerometer, are drifting. So what to do?

  • One step is to not run any irrelevant daemons – trouble is I have no idea how to find them
  • Another is to move from interpreted Python to compiled Python – for this I have to wait unti PyPy comes out of alpha release
  • Yet another would be to bring the PWM driving the motor ESCs away from the PWM I2C breakout board, and instead use RPIOs RPi DMA (direct memory access) PWM – but again, that’s in beta.

So for the moment, I think I’ll stick with what I’m doing, and assume there’s a bug in my integrals or PIDs – fingers crossed (again!).