Decoding Radio Control signal pulses

I have subscribed to your rcgroups thread and will follow it with interest.

If you get any info from JETI (or if anyone else with one of those receivers has a scope) I will see if I can help get it working with the library.

Thank you for our interest!

I'll post information here if I find something on the Jeti issue.

Cheers Alexander

Hi all, It's my first post on this Forum ;) I start programming Arduino only few weeks ago. My problem is use the ServoDecode Library to grab 7 ch from a modifyed Graupner RX. The RX send the impulse train all toghether on one wire connected to digital pin of Arduino 2009. I add Servodecode library to my sketch and I have this errors compiling the library: (also with the example sketch)

o: In function __vector_13': C:\DOCUME~1\ADMINI~1\IMPOST~1\Temp\build1989424199835515901.tmp/ServoDecode.cpp:45: multiple definition of__vector_13'

C:\DOCUME~1\ADMINI~1\IMPOST~1\Temp\build1989424199835515901.tmp\ServoDecode\ServoDecode.cpp.o:D:\arduino-0018\arduino-0018\libraries\ServoDecode/ServoDecode.cpp:45: first defined here

o: In function __vector_10': C:\DOCUME~1\ADMINI~1\IMPOST~1\Temp\build1989424199835515901.tmp/ServoDecode.cpp:52: multiple definition of__vector_10'

C:\DOCUME~1\ADMINI~1\IMPOST~1\Temp\build1989424199835515901.tmp\ServoDecode\ServoDecode.cpp.o:D:\arduino-0018\arduino-0018\libraries\ServoDecode/ServoDecode.cpp:52: first defined here

o: In function __vector_13': C:\DOCUME~1\ADMINI~1\IMPOST~1\Temp\build1989424199835515901.tmp/ServoDecode.cpp:45: multiple definition ofpulseEnd'


and many more.....

I'm running Arduino 018 with the library taken from the start of this thread.

Any help will be apreciated and sorry for my bad english ;)


are you sure you tried the code and the example sketch exactly as posted at the start of this thread? they compile okay for me using 0018

@mem I copy/past the code in the first page, maybe happend something during copy. May I ask u the link of the library as file and not as code. just to be sure of the file structure.



This forum does not have a mechanism to upload files but if you compare the beginning and end of the code you copied you should be able to see if there were any characters added or removed.

Problem Solved... was my fault. the example file was in the same dir of the library.... moved away and now i'm able to read data from my 7 ch RX :D

Just to save time in experiment what is the minum delay between two reading loops ? 20ms will be enaugh ?

The data is updated at the rate it comes in typically every 20ms. Each read turns interrupts off while getting the data so I would not read it more quickly than every 10ms or so.

Vince and Mem, check here for a design that uses diodes to encode a PPM stream from individual servo pulses:

Sorry, here is the link:

mem, I've been working with the Mega and this library interfaced with a Multiplex Profi 403 transmitter. I ran the following sketch:

int pin = 49;  // set this to the pin connected to your receiver
unsigned long duration;

void setup()
  pinMode(pin, INPUT);

void loop()
  duration = pulseIn(pin, HIGH);

with the following result:


the ppm signal appears to have a fixed mark and variable space, so I changed the sketch above to monitor the signal space instead with the following result:


Adding the two together, it seems I'm sucessfully detecting anywhere from 997 to 1980ms pulses in the ppm signal. Now that I'm confident I'm on the correct signal pin, I try the example sketch and get the following result:

The decoder is READY
Cx0= 5935  Cx1= 1936  Cx2= 2056  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 820  Ch2= 1823  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 7034  Cx1= 1040  Cx2= 2039  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1590  Ch2= 2039  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 8133  Cx1= 1137  Cx2= 2139  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1686  Ch2= 2023  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 9232  Cx1= 767  Cx2= 2236  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1317  Ch2= 2123  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
Ch1= 1866  Ch2= 2006  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 7884  Cx1= 917  Cx2= 2219  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1466  Ch2= 1990  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 8983  Cx1= 2016  Cx2= 1990  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 2086  Ch2= 1990  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
Ch1= 1450  Ch2= 1973  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 6631  Cx1= 1190  Cx2= 1973  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1740  Ch2= 1973  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is in Failsafe
Cx0= 8733  Cx1= 1287  Cx2= 1956  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1836  Ch2= 1956  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 9832  Cx1= 1723  Cx2= 1956  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 941  Ch2= 1940  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 9928  Cx1= 1490  Cx2= 1940  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1037  Ch2= 2040  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 11027  Cx1= 808  Cx2= 1923  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1357  Ch2= 1923  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is READY
Cx0= 12126  Cx1= 904  Cx2= 1907  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1500  
Ch1= 1453  Ch2= 2240  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500  
The decoder is in Failsafe
Cx0= 13225  Cx1= 2003  Cx2= 2240  Cx3= 1131  Cx4= 1500  Cx5= 1500  Cx6= 1500  Cx7= 1237  
Ch1= 1367  Ch2= 1890  Ch3= 1131  Ch4= 1500  Ch5= 1500  Ch6= 1500  Ch7= 1500

The transmitter is 7 channel with a 25ms ppm signal period.

Any insight why the above is happening?

Thanks in advance, Billy

Good news: It's working! Bad news: No 'smoking gun' to explain the results of my previous post. During troubleshooting, I reduced the delay from 500ms to 50ms and Voila! Oddly enough, I changed the delay back to 500ms and the library continued to function properly. I seem to recall another poster in this thread having a similar experience...

Regardless, the library is now fully functional in my application! Now onto the next step of manipulating the servo signals and encoding back into a ppm stream, but that belongs in another thread.

Thanks for a great library, mem!!!

Good to hear you have it working. I can't shed any light on what happened, I have not experienced anything similar.

@ mem.

Is it possible for you to make some changes on the servoDecode lib in order that we could use Timer2 as well and thus decoding frames with more than 8 servos, i´ll not need to drive any servo, only need to see each pulse width on the screen. Since it uses Timer1 and servoTimer2 is free i think it could be used for this purpose (ex: 12 channels).

again, thanks mem and sorry to make too many questions. :-/


@GMV ServoDecode uses a capability within 16 bit timers to time pulse durations entirely in hardware. This enables very accurate measurements but it does require a 16 bit timer . A standard Arduino only has one of these - Timer0 and Timer2 are 8 bit timers and do not have the capability needed by ServoDecode.

right again, so do you think it can be done with 2 x atmega 168/328, i ask this because at the moment i use my own ATM168 Pcb and i would like to use the MEGA board for other applications but since it seems very difficult to implent such task perhaps ordering another MEGA wouldn´t be a bad ideia.

Do you have any ServoDecode type lib that use more than one 16bit timer and could be used with the Mega board for decode more than 8 servos ? thanks


If your transmitter sends more than 8 channels you can set the constant MAX_CHANNELS to the appropriate value.

If you want to decode output from two transmitter/receivers using one mega board then the code in post #70 could be modified to add support for timer5 which would provide another 8 channels. Unfortunately I don’t have the time to do this. Perhaps someone else reading this thread could pick this up, although using two ATmega328 boards the cheaper option.

mem, thanks !!! ;)


Im tring to use a gyroscope that send the angle in signal for arduino so I have dificult to comunicate with this system. the especification from at LISY300 information is The LISY300 Gyroscope Module is a single-axis yaw rate sensor providing up to 300°/s full scale rotation detection at up to 88 Hz. Useful in balancing robots or auto-pilot systems, the LISY300 Gyroscope Module can detect how many degrees it has turned on its planar axis allowing the host microcontroller to stabilize the platform or correct for drift.


  • ± 300°/s full scale
  • Easy SPI interface
  • Small DIP form factor

Application Ideas:

  • R/C Helicopter stabilization
  • Auto-pilot system for R/C airplanes
  • Balancing robot

Key Specifications:

  • Power requirements: 3.4 VDC to 6.5 VDC (5 VDC recommended) @ 5.25 mA
  • Communication: SPI (4 MHz max)
  • Dimensions: 0.75 x 0.69 x 0.47 in (19.18 x 17.56 x 11.95 mm)
  • Operating temp range: +32°F to +158°F (0°C to +70°C)

Any body can help-me ? since the forum have decoding radio contrl signal pulse Nilo

Hi, I was really happy to find a lot of hints in this thread to decoding the PPM-Stream of my receiver. I thank you all and would like to give some experience back to the community...

My first observation was some inconsistency of numbering the channels. From ServoDecode.cpp we can find out that the servo are counted from 1 to a number defined by MAX_CHANNELS:

for(byte chan = 1; chan <= MAX_CHANNELS; chan++)

...but, in the test sketch on page 3 the first for-statement start's at zero. So watch out and use the right numbering!

Moreover, the comparison of an older and a newer version by Beebee on page 9 of the "ISR(TIMER1_CAPT_vect)" function indicates an issue with the "else if"-statement.

The first (11-06-08): else if(Channel <= MAX_CHANNELS) { ... The second (21-07-08): else if(Channel < MAX_CHANNELS) { ...

The declaration of "Channel" :

static volatile byte Channel; // number of channels detected so far in the frame (first channel is 1),

indicates it goes from one to MAX, but at some points its reset to zero. Due to the pre-increment (Pulses[++Channel] =...) it seems not to make a difference, but it may be misleading this way... And I'm not sure about the "else if"-statemant (from above). I selected to let Channel start from zero (because I'm more used to it) and changed the code accordingly...

I'm using a DIY-Drones ARDUIMU to decode the PPM-stream. This board has only the digital-I/Os 10...13 (=PB2...PB5) accessible. Therefore, I have to use on of these pins. Instead of using the TIMER0 CAPT ISR the PCINT0 is used to measure the puls width. It's my first ISR so I hope I did it right, at least - it works for me ;-)

static volatile unsigned int tics;  // holds tics from Timer1


  tics = TCNT1;   /* Read TCNT1 */
  if ( LOW == digitalRead(PPM_PIN) ) //End of channel
    TCNT1 = 0;   //Reset Timer1
    if(tics >= SYNC_GAP_LEN){   // is the space between pulses big enough to be the SYNC
    else if(Channel < MAX_CHANNELS) {  // check if its a valid channel pulse and save it
        if( (tics >= MIN_IN_PULSE_WIDTH)  && (tics <= MAX_IN_PULSE_WIDTH) ){ // check for valid channel data
          Pulses[Channel++] = tics / TICKS_PER_uS;  // store pulse length as microsoeconds
        else if(State == READY_state){
          State = FAILSAFE_state;  // use fail safe values if input data invalid
          Channel = 0; // reset the channel count
        } //ELSE IF
    } //ELSE IF
  } //IF
} //ISR

The PPM-signal is connected to PIN 10. The PORTB pin change interrupt is activated by

  PCMSK0  = (1<

Last minor issue: Sometimes, when I connect the receiver and without activating the transmitter first, the state stays in "no_sync". Then, the ppm-signal remains at zero. But, this is not valid (e.g. when directly given to a servo). I like to have signals between MIN_IN_PULSE_WIDTH and MAX_IN_PULSE_WIDTH. Therefore, I've changed the "GetChannelPulseWidth( )"-method to give the failsafe values...

int ServoDecodeClass::GetChannelPulseWidth( uint8_t channel)
  // this is the access function for channel data
  int result = 0; // default value
  if( channel <  MAX_CHANNELS)  {
     if( ((State == FAILSAFE_state) || (State == NOT_SYNCHED_state)) && (Failsafe[channel] > 0 ) )
           result = Failsafe[channel]; // return the channels failsafe value if set and State is Failsafe
     else if( (State == READY_state) || (State == FAILSAFE_state) )
        cli();        //disable interrupts
        result =  Pulses[channel] ;  // return the last valid pulse width for this channel
        sei(); // enable interrupts
  return result;

I hope this helps somebody!? Best regards, Sven