Best approach for PPM?


8 posts
by magicstix » Sat Jul 21, 2012 1:28 am
Hi all,
I originally got my raspberry pi to be the flight computer on a quadcopter. The flight control board expects Pulse-Period Modulation inputs where a high pulse between 1 ms and 2 ms is sent on its input pins followed by some period of a low signal to represent the position of a transmitter's control stick (which in this case is the pi).

I wanted to just bit-bang this out using the GPIO pins, but my concern is whether or not I can get this precision timing using straight up Linux. I know the pi has a pin dedicated for PWM, but I need 6 channels, so that's not really useful... :(

Does anyone think I'll be able to get stable 1-2ms pulses out of the pins on a fairly regular basis? The length of the pulse being accurate is more important than the period of the overall waveform being accurate. If not, what would be some suggestions? Has anyone tried compiling their pi kernel with some real-time extensions like Xenomai or RTAI?
Posts: 12
Joined: Sat Jul 14, 2012 5:33 pm
by joan » Sat Jul 21, 2012 8:04 am
My Pi is currently showing 8495 interrupts per second (enter the command vmstat). Given that, I'm confident that it could handle millisecond pulse timing at the interrupt level.

I'd be looking at C (gcc) with wiringPi and interrupt handling.
User avatar
Posts: 6565
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by magicstix » Sun Jul 22, 2012 2:05 am
I actually need *sub* millisecond precision, probably on the order of 5-10 microseconds or so.

It seems wiringPi can't guarantee proper timing any better than the bcm2835 library can. I've been able to get some PPM pulses out, but their periods are very unreliable and I can't seem to get better than 100 uS accuracy using the delayMicroseconds routines... :(

This seems kind of surprising given that I2C can do much higher data rates. I'm wondering if I'd need to write a kernel driver to handle the bit-banging so I can get better timer resolution...
Posts: 12
Joined: Sat Jul 14, 2012 5:33 pm
by audigex » Fri Sep 28, 2012 4:02 pm
I would have thought a better approach may be to use an Arduino for hardware control, and the RPI for higher level mission based things, video processing etc.

The Arduino is perfectly suited to direct hardware control - people already use it as such with great success: the main problem is that they run out of grunt before the really interesting higher level computation can be done.

An ArduPi combination could be the best of both worlds.
Posts: 16
Joined: Wed Sep 19, 2012 1:37 pm
by Grumpy Mike » Fri Sep 28, 2012 5:00 pm
joan wrote:My Pi is currently showing 8495 interrupts per second (enter the command vmstat). Given that, I'm confident that it could handle millisecond pulse timing at the interrupt level.

Misplaced confidence, just because interrupts are going off at that rate does not mean the Pi can service them. Under Linux you can't get a steady software generated pulse shorter than about 100mS.

the main problem is that they run out of grunt before the really interesting higher level computation can be done.

Where as the Pi (running Linux) never had that grunt in real time to begin with.
User avatar
Posts: 791
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
by jojopi » Fri Sep 28, 2012 5:24 pm
Grumpy Mike wrote:Misplaced confidence, just because interrupts are going off at that rate does not mean the Pi can service them. Under Linux you can't get a steady software generated pulse shorter than about 100mS.
I am finding it hard to understand what either of these statements is supposed to mean. Surely you are not saying that kernel is reporting interrupts that it knew about but somehow never managed to service? Or that the fastest you can switch a GPIO from a user process under Linux is 5Hz?
User avatar
Posts: 2132
Joined: Tue Oct 11, 2011 8:38 pm
by gordon@drogon.net » Fri Sep 28, 2012 8:35 pm
Hm. Old thread re-surfaced :)

the latest wiringPi is capable of reasonably accurate 5-10uS timings, however it will consume 100% CPU while its doing it and the rest of the system really isn't up to it. The Pi is not a "hard" real-time controller suitable for flight control IMO. There is just too many things to go wrong in the time-scales involved - the kernel will interrupt you, you might have a delay of a few milliseconds on reading the IMU and before you know it, you're upside down which is not a good place to be in a quadcopter....

I did a UAV project last year for a client and I was completely gob-smacked at just how clumsy RC really is - it's not moved on at all in 50 years. The modern 'digital' controllers - yes, fantasic, but they still take the PPM signal, decode it into PWMs, them sample the PWM into the microcontroller, then send it to the subsystems as PWM - some of which then decode it further, or re-encode it into some other weird format, or who knows what. So many protocol changes, so much "stick wiggling". Shame my client pulled out, it was just getting to the exciting part!

Stick to an arduino - look at the ardupilot mega boards and systems. Use the Pi as a ground control station.

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1544
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by jojopi » Fri Sep 28, 2012 9:50 pm
gordon@drogon.net wrote:the latest wiringPi is capable of reasonably accurate 5-10uS timings, however it will consume 100% CPU while its doing it and the rest of the system really isn't up to it. The Pi is not a "hard" real-time controller suitable for flight control IMO. There is just too many things to go wrong in the time-scales involved - the kernel will interrupt you, you might have a delay of a few milliseconds on reading the IMU and before you know it, you're upside down which is not a good place to be in a quadcopter....
The best case timing accuracy is certainly orders of magnitude better than the worst case preemption/interrupt latency.

The C program for Linux below calls gettimeofday in a tight loop during even seconds, and reports its biggest delays; in other words, time that it has lost due to hardware interrupts or software preemption. In odd seconds it sleeps so that other processes can catch up and we can exercise the SD and USB subsystems. (It is also important that a realtime process not use 100% cpu for a long period, or the kernel may throttle it to avoid deadlock.)

With the program running under sudo, interactive performance for the rest of the system is obviously abysmal. Not even the echoing of input characters will happen until the start of the next odd second. Nevertheless it is possible for other processes to access the network and SD card, and the consequences of this will spill into the even seconds.

The absolute worst delay I have ever seen is 502µs, and cases over half that are extremely rare. I suspect that if we wanted to improve on this we could do so by disabling subsystems, or changing the kernel command line or configuration. I have not yet investigated that.

Anyway, I believe that microsecond timing should be possible in the best cases, and nearest-millisecond timing even in the worst.

Code: Select all
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sched.h>

int main()
{
  struct sched_param param;
  struct timeval tv[2];
  int i, elap, max = 0, maxx = 0;
  param.sched_priority = sched_get_priority_max(SCHED_FIFO);
  if (sched_setscheduler(0, SCHED_FIFO, &param) < 0)
    perror("warning: sched_setscheduler");
  if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0)
    perror("warning: mlockall");
  for (;;) {
    gettimeofday(tv, 0);
    for (i=1; ; i=!i) {
      gettimeofday(tv+i, 0);
      elap = (tv[i].tv_sec-tv[!i].tv_sec)*1000000 +tv[i].tv_usec-tv[!i].tv_usec;
      if (elap > maxx) maxx = elap;
      if (elap > max) printf("delayed by %dµs, max %dµs\n", max=elap, maxx);
      if (tv[i].tv_sec & 1) break;
    }
    usleep(1000000 - tv[i].tv_usec);
    max = max*7/8; // next second, report delays that are nearly as big
  }
}
User avatar
Posts: 2132
Joined: Tue Oct 11, 2011 8:38 pm