ppm (sum) in to servo output, possible timer issue

I have an arduino project I am working on that involves reading a ppm stream from a receiver and spitting out servo control.
In between there is some GPS goodness to act as a RTH.
This is a personal project I'm doing for fun, I already have OSDs I like and don't fell like spending $200+ for a full OSD RTH fancy thing when all I want to something very simple. For use in rc cars, gliders etc that only require steering or the rudder to turn, things like that.

Anywho the reason I have come and asked for help, I have ppm decoding (using timer 1) and I was planning on using the servotimer2 library for driving my servos but these 2 bits of code don't play nice together. Although it works, every ~30s or so all the outputs glitch (I suspect they all drop to 1000 or 0, ether way the throttle cuts for a moment and servos twitch.) which makes it non usable (on servos the effect is almost unnoticeable but on esc's/motors the effect is rather dramatic). All the ppm decoding code I have found uses timer 1 so that can't change, the servo library built into arduino can't be used as it uses timer 1 and software servo is less then ideal as well.

I'm trying to stick with using a 328 as I have a number of them and they are cheap, I could use a 2560 as it has extra timers that could be used to drive servos with the default library but this is a lazy method and costs considerably more. I also fly multicopters and as shown by multiwii 328s are capable of doing the above job + alot more so it is possible, but maybe not with such simple code.....

I have tried multiple sets of hardware so can rule that out.
I have also constructed this very minimal code snipit to test the bare ppm in servo out functions together, before this I thought it could have been the GPS code casing the issues.

Talking to a friend he suspects that there is a clash between the 2 timers that cases this issue.
Looking at the inputs and outputs with serial prints shows nothing out of the ordinary, without getting the scope out it is otherwise hard to narrow the problem down more, I have reached the limit of my skill set for the time.

If anyone has run into something similar or has an idea of whats happening that'd be great.

Thanx Hadley

// libraries
#include <ServoTimer2.h> 

// pins for servos
#define rollPin  3
#define throttlePin 7

// declare variables for servos
ServoTimer2 servoRoll;    
ServoTimer2 servoThrottle;

//*************ppm capture variables*****************
#define ICP_PIN      8	          // this interrupt handler must use pin 8
#define TICKS_PER_uS 2            // counter increments by two counts each microsecond (at 16mhz)
#define SYNC_GAP_LEN 3000         // synch gap 3000 microseconds long
volatile unsigned int pulses[9];  // array holding channel pulses width value in microseconds
volatile uint8_t  channel = 1;	  // number of channels detected so far in the frame (first channel is 1)


//*********************timer for ppm stream receiving*************************************
ISR(TIMER1_CAPT_vect){
  if( bit_is_set(TCCR1B ,ICES1)){  //rising edge detected because bit ICES1=1

  }
  else{            //falling edge detected]

    TCNT1 = 0;		   // reset the counter
    if(ICR1 > SYNC_GAP_LEN*TICKS_PER_uS){
      channel = 1;
    }
    else{
      pulses[channel++] = ICR1/TICKS_PER_uS;
    }
  }
  TCCR1B ^= _BV(ICES1);   // toggle bit ICES1 to trigger on the other edge       
}

//*********************************************************************************************

void setup(){   


  Serial.begin(38400);

  //Comfigure ppm stream in on pin 8
  pinMode(ICP_PIN,INPUT);


  TCCR1A = 0x00;	   // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled
  TCCR1B = B00000010;     //0x02;	   // 16MHz clock with prescaler means TCNT1 increments every .5 uS (cs11 bit set
  TIMSK1 = _BV(ICIE1);   // enable input capture interrupt for timer 1

    // attach a pin to the servos and they will start pulsing
  servoRoll.attach(rollPin);     
  servoThrottle.attach(throttlePin);

}

//************************************************************************************************
void loop(){

  //Write values to outputs
  servoRoll.write(pulses[1]);
  servoThrottle.write(pulses[2]);
}

The timer theory sounds plausible.

As a workaround just to prevent the glitches being so annoying while you figure out how to fix the problem, you could do a sanity check on the received pulse length and smooth out abrupt changes? I guess you would only need to deal with a few samples. If the problem is reproducible, it would be worth writing a test sketch that looks for the glitch and captures a range of samples before/after so that you can see exactly what's happening. That would make it easier to design a workaround, and might also give you some extra insight into what's going wrong.

you could do a sanity check on the received pulse length and smooth out abrupt changes

I'm guessing you mean the ppm sum received by the arduino? I have checked and although each channel fluctuates by up to ~8us it is nowhere near (at least)1000us glitch that can be observed.
Would a short video of the glitch in action help explain??
In the above sketch each channels values are being feed straight though from ppm to 2 outputs, so the input and output is the same value. I can use my soundcard Oscope to get a trace on the signal being feed to the servo, would be interesting to see how the glitch being seen by the servos/esc.
Will report back once I get some data.

Try this, its a PPM reader, servo driver that uses timer1 only. The same library manages reading the PPM and generating the servo signals so no clashes.

and the reason I wrote it -

PM me if you want a zip file rather than cutting and pasting web pages

Duane B

rcarduino.blogspot.com

I was really keen to try it out so quickly copied all the files from your blog and chucked them in the appropriate locations. The example code complies fine but when I copy the ppm input demo code from your blog I get the following error "multiple definition of `__vector_1'". I saw there are some comments on the blog that pertain to a similar error but didn't really have a resolved answer.
How do you increase the number of ouput serovs as well??
Sorry I may bombard you with a torrent of questions as I figure this out.
Hadley

Hi,

change this in the cpp file

void CRCArduinoPPMChannels::begin()
{
 m_sOutOfSynchErrorCounter = 0;
 attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING);
}

to this

void CRCArduinoPPMChannels::begin()
{
 m_sOutOfSynchErrorCounter = 0;
 /* We dont need this if using the sample sketch
 attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING);
 */
}

That should do it.

I will dig out the PPM Output for you as well, probably tomorrow, remind me if I don't

Duane B

Sorry, needs another line to enable interrupts, will advise in a few minutes.

Duane B

Add this to the setup function in the main sketch, I will update the original link with these two changes -

// enable the external interrupt
EIMSK = 1;  //1 - enable external interrupt 1
EICRA = 3; //3 - enable interrupt on rising edge only

Any problems let me know

Duane B

Ok have done the above mods and I still run into the vector 1 error.
Just to make sure - I am talking about using the sketch found at the bottom of this page

In work at the moment, so can't help but try this -

Use the original cpp and h files without modification, but remove this from the test sketch -

ISR(INT0_vect) {
 CRCArduinoPPMChannels::INT0ISR();
}

Hi,

Your not the only person to have had trouble combining the code from the two posts on this basis I will remove the code from both posts and reference them both to a new post, it will make it easier for everyone and easier for me to manage.

Duane

Hi,

Your not the only person to have had trouble combining the code from the two posts on this basis I will remove the code from both posts and reference them both to a new post, it will make it easier for everyone and easier for me to manage.

Duane

Got it kind of working but the servo output was very jerky.
I'll wait until you've made up a new post and try again

Hi,

How many channels are you reading and how many are you outputting ?

Did you change these defines to match ?

#define RC_CHANNEL_OUT_COUNT 4

#define RC_CHANNEL_IN_COUNT 3

3 and 4 are correct for my test setup, you most likely have a different number of channels coming in and will need to update the 3 to whatever it is that you have - leave the 4 for now we will come back to it.

Duane B

rcarduino.blogspot.com

Reading 8 channels outputting at least 8 as well.

Will update that and get back to you with results.

Edit: 1 bit of clarification. I have changed that lump of code to this

#define RC_CHANNEL_IN_COUNT 8
// two ticks per us, 3000 us * 2 ticks = 6000 minimum frame space
#define MINIMUM_FRAME_SPACE 16000
#define MAXIMUM_PULSE_SPACE 5000

Does MAXIMUM_PULSE_SPACE need to be changed as well?
I'm going to guess ether 1500 or 1066?? if it does need changed.

I need to create a FAQ or something similar for using the library, the interface is not the nicest - I did consider auto detection of the number of channels, its easily done but slows the ISR down slightly if the number of channels is not set at compile time.

Anyway just set the number of input channels to 8 for now, and once thats working nicely we will adjust the output channels.

Duane B.

Seeing as your online now I'll grab my arduino and see if I cant get it sorted

And a FAQ would be great help. This is the only code I've come across to deal with both ppm in and servo out and would be a benefit to many people I imagine

Internally its nice code, it just has a bit of an awkward interface to get started. Let me know how you get on

Duane.

Also where in the code can I chuck a set of serial.prints so I can confirm the inputs are correct, its very much hot and miss with just a servo plugged in atm? In uS would be good.

I also edited a post on the previous page, I think you may have missed it.

"Edit: 1 bit of clarification. I have changed that lump of code to this

#define RC_CHANNEL_IN_COUNT 8
// two ticks per us, 3000 us * 2 ticks = 6000 minimum frame space
#define MINIMUM_FRAME_SPACE 16000
#define MAXIMUM_PULSE_SPACE 5000

Does MAXIMUM_PULSE_SPACE need to be changed as well?
"