Go Down

Topic: Decoding Radio Control signal pulses (Read 55015 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

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131