‘Scoping the Modbus

Using the LEDDAR One on Phoebe, I had to drop her sampling rate to 500Hz to prevent FIFO overflow.  This isn’t bad, but I decided to investigate why adding LEDDAR into the mix has slowed the processing down significantly.  Out with my OSCIUM iMSO-104 iPad scope.

The following allows a crude estimate of the the baud rate to be at least 50kbps:



This shows the time the LEDDAR One takes for a request / response processing – about 3ms

Request / Response timing

Request / Response timing

This shows the reaction time to the rising edge data ready interrupt (DRI); since the Quadcopter and the test code only poll the interrupt every 10ms, this is fine too.

Interrupt response

Interrupt response

What’s also visible is the cost of doing 3 individual reads of the registers (about 20ms) compared to reading 5 registers in a single shot which drops it down to about 5ms as shown below:

One-shot registers read

One-shot registers read

I’ve swapped Phoebe to use the one-shot read as above, and as a result, she’s running the IMU at 1kHz again while running the LEDDAR.

epoll and IMU interrupt interaction

epoll doesn’t differentiate between rising and falling edges – an edge is just an edge. The RPi.GPIO option to specify edge trigger is pointless given epoll doesn’t support it.  The RPi.GPIO code has code that calls epoll_wait() twice, thus reading the rising and falling edge when a button is pushed by a human.  Perfectly fine solution for “wait for button, then flash LED” type problems.

But for the IMU, the IMU interrupts and the epoll code need to be in sync about working together.  So I change both the HoG python- and my GPIO ‘C’ code.

  • EPOLLONESHOT detects an edge and then stops watching meaning there’s no backlog of interrupts building up while the python code is processing the corresponding sensor data.
  • Don’t call epoll_wait() twice to capture both rising and falling edge of a button – it will block permanently second time round with EPOLLONESHOT
  • The MPU6050 is started prior to enabling epoll otherwise epoll blocks waiting for interrupts that IMU has not been configured to send yet
  • Probably better to ask the IMU to clear the interrupt only once the data registers have been read – this then means epoll will not be watching for interrupts at the point there is a falling edge.
  • Set pull down on the interrupt GPIO pin.

This is what the ‘scope showed as a result:

Latching ONESHOT

Latching ONESHOT

The rising edge is triggered by the IMU when new data is ready to be read.  The falling edge is when the python code reads that data over I2C causing the IMU to drop the interrupt pin.

The screen spans 20ms, with a pulse every 2ms.  Hence there should be 10 rising edges, but if you count, there are only 9.  The wide pulse in the middle took more than 2ms between raising the interrupt and the data being read: a sample was lost.  I didn’t have to take lots of screen shots to capture this; this was the first screen shot I took.  The code is set to do motion processing every 5 reads, and I presume that’s the cause of the longer pulse; capturing a sample and doing motion processing takes more than 2ms.  Any screen shot will contain at least one wider pulse like this.

Overall, that’s pretty good news: the IMU interrupt, and the GPIO and HoG code are working well together.  I clearly need to reduce the time motion processing takes – and it looks like the reduction is relatively small.  Also that explains the difference in flight times measured based in interrupt- and time.time(): the HoG code reads only 5 out of 6 samples, so code relying on interrupt timing appears to take less time than it actually does (5 x 2ms < 12ms).

P.S. I’m assuming the mid-width pulse are due to Linux scheduling of my code.  That’s no problem as it’s not causing loss of samples – only the motion processing pulse is taking more than 2ms.

You’re ‘aving a laugh

I separated the data ready interrupt frequency (666Hz) from the IMU ADC sampling rate (500Hz) with the intention that this might prove better timing accuracy and therefore better angles and velocities.

In flight, timing was better, angle were probably better, but unexpectedly, vertical velocity was completely shot – both Phoebe and Chloe rose to about 4m, and their height increased during hover, and descended slowing during descent before dropping out of the sky from 3m on landing.  Phoebe partially snapped off her USB port, and after an hour trying to desolder and replace it, I gave up and ordered a new A+ arriving today.

In addition, it’s seems now like the 666Hz was just someone having a laugh* at my expense – the one flight I got yesterday was capturing data ready interrupts at 677Hz. This could be

  • 500Hz plus noise or
  • 1kHz with missed samples
  • a code bug

I checked the data ready interrupt frequency with my ‘scope when the new A+ arrived with the ADC sampling frequency set to 500Hz:

500Hz 50us data ready interrupt

500Hz 50us data ready interrupt

Given the ‘scope is saying the hardware interrupt is running at 500Hz, why does the code think it’s running at > 660Hz – clearly something in my customized GPIO library is causing double counting – probably not flushing the epoll fd after a read?

*Unrelated to the Quadcopter, but related to someone having a laugh at my expense, I ordered 2 new monitors yesterday to replace my work and home computers – more screen space for the large number of open apps at work and better full screen viewing of files, and full sRGB colour space rendering for editing photos at home.  I ordered them as a huge motivation to stop smoking.  I can’t afford them unless I give up smoking which costs me £300 a month.  Shortly after ordering, I was sorting out my work PC in preparation for the new monitor, and while the existing monitor was off its vesa wall-mount it smashed to the floor and would only show a white screen.  So stopping smoking is now mandatory, not optional!

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.


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.