Go Down

Topic: Decoding Radio Control signal pulses (Read 75871 times) previous topic - next topic


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.


Dec 08, 2010, 12:07 pm Last Edit: Dec 08, 2010, 12:07 pm by gmv Reason: 1
@ 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.  :-/



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.


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 WWW.parallax.com 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


Jan 07, 2011, 10:19 pm Last Edit: Jan 08, 2011, 08:46 am by x-sven Reason: 1
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 [font=Courier]ServoDecode.cpp[/font] we can find out that the servo are counted from 1 to a number defined by MAX_CHANNELS:

[font=Courier]for(byte chan = 1; chan <=  MAX_CHANNELS; chan++)[/font]

...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):
[font=Courier]else if(Channel <= MAX_CHANNELS) { ... [/font]
The second (21-07-08):
[font=Courier]else if(Channel < MAX_CHANNELS) {  ...[/font]

The declaration of "Channel" :

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

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 ;-)

Code: [Select]

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

Code: [Select]

 PCMSK0  = (1<<PCINT2);  //Un-mask PCINT2
 PCICR   = (1<<PCIE0);   //Enable the PORTB pin change interrupt

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...

Code: [Select]

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,

Go Up