Arduino interface RC receiver ar6110

I'm fairly new to arduino and writing code so please bear with me. I have a spektrum ar6110 receiver along with an arduino duemilanove. The goal is to be able to receive each of the 6 signals from the ar6110 and then print them and then turn around and output the signal to 6 servos. I believe I have the servo half of it down but I cannot figure out the input half. I have tried looking on Google and other sites with no luck. I have found partial topics but no full explanations on how to do it. The end goal of this is to have it on a helicopter with a few sensors so that I can either fly it in manual mode to flip a switch and have it stabilize itself. Any help would be greatly appreciated.

Nick

I'm working on something similar, and I found out that the easiest way to get input from an RC receiver is to use something called TT-RecEnc (http://tt-rc.ath.cx/SHOP/ITEM-10), is a small board capable of reading up to eight inputs from an RC receiver, and outputs an PPM signal, that is an signal with all the eight servo signals in a series, this signal can be connected to the one of the external interrupts on Arduino, and easily decoded.

I have some simple code for decoding if you are interested.

Thats good to know that is one option. Do you know if there is any way to do it without that extra board? I have seen it done but I just don't know what the code is.

I have read in multiple channels from an RC receiver using one pin for each channel.
I will post the code I have.

It should be possible to tie all the odd channels to one pin and all the even channels to another pin, and get any number of channels on just 2 pins. This assumes that the channels are produced sequentially (which I believe is accurate). I will have to try this at home some time, because I hate giving up all those inputs. Some diodes similar to this:

If you are reading an odd number of channels, I understand that you can go on a single pin, just calculating the even channel durations by the gap between the odd channel signals.

But on to my code for individual pins for each channel.
I have code in 3 tabs. The first:

#include <math.h>
#include <Servo.h>

//prototypes
void serviceServos(long pFrameCounter);
void computeThrottle();

int Chan1Interrupt = 5; // pin 18
int Chan2Interrupt = 4; // pin 19
int Chan3Interrupt = 3; // pin 20
int Chan4Interrupt = 2; // pin 21
int Chan5Interrupt = 1; // pin 3
int Chan6Interrupt = 0; // pin 2
long StartMillis=0;
long FrameCounter=0;
unsigned long Chan1_startPulse, Chan2_startPulse, Chan3_startPulse, Chan4_startPulse, Chan5_startPulse, Chan6_startPulse;
volatile double Chan1_val, Chan2_val, Chan3_val, Chan4_val, Chan5_val, Chan6_val;
volatile double Chan1_val_last, Chan2_val_last, Chan3_val_last, Chan4_val_last, Chan5_val_last, Chan6_val_last;

Servo ServoArray[5];
volatile long OutputThrottle[5];


void setup()
{
  //////////////////////   For the Servo_in subroutine!!!!! ////////////////////

  attachInterrupt(Chan1Interrupt, Chan1_begin, RISING);
  attachInterrupt(Chan2Interrupt, Chan2_begin, RISING);
  attachInterrupt(Chan3Interrupt, Chan3_begin, RISING);
  attachInterrupt(Chan4Interrupt, Chan4_begin, RISING);
  attachInterrupt(Chan5Interrupt, Chan5_begin, RISING);
  attachInterrupt(Chan6Interrupt, Chan6_begin, RISING);
  
  int i;          
  for (uint8_t i=1;i<=4;i++)
    ServoArray[i].attach(22+i, 1000, 2000);
  StartMillis = millis();
}


void loop()

{ 
  long LocalMillis;
  long LocalFrameCounter;
  LocalMillis = millis();
  LocalFrameCounter = (LocalMillis - StartMillis) / 20;

  if (LocalFrameCounter > FrameCounter) 
  {
    FrameCounter = LocalFrameCounter;
    serviceServos(FrameCounter);
  }
}

more on a later post since I exceeded the max

Next tab, RC_In

void Chan1_begin()           // enter Chan1_begin when interrupt pin goes HIGH.
        {
          Chan1_startPulse = micros();     // record microseconds() value as Chan1_startPulse
          detachInterrupt(Chan1Interrupt);  // after recording the value, detach the interrupt from Chan1_begin
          attachInterrupt(Chan1Interrupt, Chan1_end, FALLING); // re-attach the interrupt as Chan1_end, so we can record the value when it goes low
        }

void Chan1_end() 
        {
         Chan1_val = micros() - Chan1_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan1Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan1Interrupt, Chan1_begin, RISING);
         if (Chan1_val < 1000 || Chan1_val > 2000) { Chan1_val = Chan1_val_last;}
         else {Chan1_val_last = Chan1_val;}
        }

void Chan2_begin()           // enter Chan2_begin when interrupt pin goes HIGH.
        {
          Chan2_startPulse = micros();     // record microseconds() value as Chan2_startPulse
          detachInterrupt(Chan2Interrupt);  // after recording the value, detach the interrupt from Chan2_begin
          attachInterrupt(Chan2Interrupt, Chan2_end, FALLING); // re-attach the interrupt as Chan2_end, so we can record the value when it goes low
        }

void Chan2_end() 
        {
         Chan2_val = micros() - Chan2_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan2Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan2Interrupt, Chan2_begin, RISING);
         if (Chan2_val < 1000 || Chan2_val > 2000) { Chan2_val = Chan2_val_last;}
         else {Chan2_val_last = Chan2_val;}
        }
        
void Chan3_begin()           // enter Chan3_begin when interrupt pin goes HIGH.
        {
          Chan3_startPulse = micros();     // record microseconds() value as Chan3_startPulse
          detachInterrupt(Chan3Interrupt);  // after recording the value, detach the interrupt from Chan3_begin
          attachInterrupt(Chan3Interrupt, Chan3_end, FALLING); // re-attach the interrupt as Chan3_end, so we can record the value when it goes low
        }

void Chan3_end() 
        {
         Chan3_val = micros() - Chan3_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan3Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan3Interrupt, Chan3_begin, RISING);
         if (Chan3_val < 1000 || Chan3_val > 2000) { Chan3_val = Chan3_val_last;}
         else {Chan3_val_last = Chan3_val;}
       }
        
void Chan4_begin()           // enter Chan4_begin when interrupt pin goes HIGH.
        {
          Chan4_startPulse = micros();     // record microseconds() value as Chan4_startPulse
          detachInterrupt(Chan4Interrupt);  // after recording the value, detach the interrupt from Chan4_begin
          attachInterrupt(Chan4Interrupt, Chan4_end, FALLING); // re-attach the interrupt as Chan4_end, so we can record the value when it goes low
        }

void Chan4_end() 
        {
         Chan4_val = micros() - Chan4_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan4Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan4Interrupt, Chan4_begin, RISING);
         if (Chan4_val < 1000 || Chan4_val > 2000) { Chan4_val = Chan4_val_last;}
         else {Chan4_val_last = Chan4_val;}}
        
void Chan5_begin()           // enter Chan5_begin when interrupt pin goes HIGH.
        {
          Chan5_startPulse = micros();     // record microseconds() value as Chan5_startPulse
          detachInterrupt(Chan5Interrupt);  // after recording the value, detach the interrupt from Chan5_begin
          attachInterrupt(Chan5Interrupt, Chan5_end, FALLING); // re-attach the interrupt as Chan5_end, so we can record the value when it goes low
        }

void Chan5_end() 
        {
         Chan5_val = micros() - Chan5_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan5Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan5Interrupt, Chan5_begin, RISING);
         if (Chan5_val < 1000 || Chan5_val > 2000) { Chan5_val = Chan5_val_last;}
         else {Chan5_val_last = Chan5_val;} 
        }
        
void Chan6_begin()           // enter Chan6_begin when interrupt pin goes HIGH.
        {
          Chan6_startPulse = micros();     // record microseconds() value as Chan6_startPulse
          detachInterrupt(Chan6Interrupt);  // after recording the value, detach the interrupt from Chan6_begin
          attachInterrupt(Chan6Interrupt, Chan6_end, FALLING); // re-attach the interrupt as Chan6_end, so we can record the value when it goes low
        }

void Chan6_end() 
        {
         Chan6_val = micros() - Chan6_startPulse;  // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue. 
         detachInterrupt(Chan6Interrupt);  // detach and get ready to go HIGH again
         attachInterrupt(Chan6Interrupt, Chan6_begin, RISING);
         if (Chan6_val < 1000 || Chan6_val > 2000) { Chan6_val = Chan6_val_last;}
         else {Chan6_val_last = Chan6_val;} 
        }

Last tab, service servos

void serviceServos(long pFrameCounter)
{
  long iteration;
  computeThrottle();
  for (uint8_t OutputChannel=1;OutputChannel <= 4;OutputChannel++)
    ServoArray[OutputChannel].writeMicroseconds(OutputThrottle[OutputChannel]);
}

void computeThrottle()
{
  long ChannelIn[7];
  long Tfactor=800;
  long AEfactor=100;
  long Rfactor=100;
  cli();       //disable interrupts
  ChannelIn[1] = Chan1_val;  // return the last valid pulse width for this channel
  ChannelIn[2] = Chan2_val;  // return the last valid pulse width for this channel
  ChannelIn[3] = Chan3_val;  // return the last valid pulse width for this channel
  ChannelIn[4] = Chan4_val;  // return the last valid pulse width for this channel
  ChannelIn[5] = Chan5_val;  // return the last valid pulse width for this channel
  ChannelIn[6] = Chan6_val;  // return the last valid pulse width for this channel
  sei();         // enable interrupts
  

    OutputThrottle[1] = (ChannelIn[3] * Tfactor - (ChannelIn[2]-1500) * AEfactor  + (ChannelIn[4]-1500) * Rfactor )/1000;
    OutputThrottle[2] = (ChannelIn[3] * Tfactor - (ChannelIn[1]-1500) * AEfactor  - (ChannelIn[4]-1500) * Rfactor )/1000;
    OutputThrottle[3] = (ChannelIn[3] * Tfactor + (ChannelIn[2]-1500) * AEfactor  + (ChannelIn[4]-1500) * Rfactor )/1000;
    OutputThrottle[4] = (ChannelIn[3] * Tfactor + (ChannelIn[1]-1500) * AEfactor  - (ChannelIn[4]-1500) * Rfactor )/1000;
  
}

Can you tell me the connections that you made on your board?

I should have stated that this is on a Mega.

So, for inputs:

int Chan1Interrupt = 5; // pin 18
int Chan2Interrupt = 4; // pin 19
int Chan3Interrupt = 3; // pin 20
int Chan4Interrupt = 2; // pin 21
int Chan5Interrupt = 1; // pin 3
int Chan6Interrupt = 0; // pin 2

These are the 6 channels from the RC Servo. (that I hope to cut down to 1 or 2 with future modifications)

And outputs to the servos:

I have a Duemilanove. is there any way to use your code is my board? what would i have to modify to make it work. also how would i go about having it print to the serial monitor the values of each of the channels?

If I had the diodes, I would wire this up and try it using 2 pins. But I don't. I should order some to try out.

As of right now I plan on using the 6 channels as their own channels and not combine anything. I'm not tight on pins so I'm good for now.

I bet that you are. The Mega has 6 external interrupts. The other boards have 2.

http://www.arduino.cc/en/Reference/AttachInterrupt
Most Arduino boards have two external interrupts: numbers 0 (on digital pin 2) and 1 (on digital pin 3). The Arduino Mega has an additional four: numbers 2 (pin 21), 3 (pin 20), 4 (pin 19), and 5 (pin 18).

That is why I mentioned the alternate configuration tying multiple channels to a single pin. If you receiver is putting out an odd number of channels (or more channels that you need to read) then you could do this on a single pin. If you are trying to get all channels off of a receiver that has an even number of channels, then I think you need 2 pins. (since you do not have the 'rise' of the next channel to signal the end of the last even channel)
Think, because I have not tried it.

Here is a pic I hacked together to show what the signal would look like.

oh i thought it was just any digital pin i needed.

Do you know if there is any way to do it without that extra board? I have seen it done but I just don't know what the code is.

There are information on the internet that explains how to hack into the receiver and find the PPM signal internal.

But if you want, you can just connect all channels from the receiver into single inputs, and use input change trigger. I have never done it, but if my memory serves me well, the AeroQuad uses this approach, look at it's code. Google Code Archive - Long-term storage for Google Code Project Hosting.