Pages: [1]   Go Down
Author Topic: Reading a RC Airplane Receiver  (Read 3339 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi All!
I have been working on an autopilot using the arduino since the start of the summer. In order for this project to work correctly, it is essential that I can switch between radio control and arduino (autopilot) control. In a earlier attempt, I used the arduino to throw some 5v relays so the servos signal wire would switch between the radio receiver and the arduino. In an effort to reduce power consumption/simplify the circuit, I am trying to read the receiver directly, and then the arduino gets to choose if it passes the signal through to the servos or if it should be on autopilot.
So when I upload my code to my arduino, the code works perfectly, it as if the receiver was controlling the servos by itself. However, when I switch to battery power, there is no response, even though the arduino is powered. It as if the i need to upload code every time for the arduino to work correctly.

my code comes from the website rcarduino. i stole most of mine from http://rcarduino.blogspot.com/2012/04/how-to-read-multiple-rc-channels-draft.html

I do not have a picture of my circuit right now but I can easily describe it: the servos still receive power from the receiver. The signal wire from the receiver is sent to an arduino input. Another arduino output is then connected to the servo signal input. I have tried powering both the arduino and receiver seperately, and together (ideally i would like to have one battery at the end). So I have 11.1V lipo battery going to the arduino's DC jack, and then the 5v out from the arduino goes to the receiver.
_sorry, maybe i can post a picture later_

any suggestions would be appreciated!!

here is a copy of the code i am running:

#include <Servo.h>
#include <PinChangeInt.h>

//Declare Receiver Inputs to read channel signals
#define ESC_IN 8
#define ELEVATOR_IN 13
#define AILERON_IN 11
//Declare bit-flags to indicate if which channels have new signals
#define ESC_FLAG 1
#define ELEVATOR_FLAG 2
#define AILERON_FLAG 4
//Holds update flags defined above
volatile uint8_t bUpdateFlagsShared;
//Shared variables are updated by the ISR
volatile uint16_t ESC_IN_SHARED, ELEVATOR_IN_SHARED, AILERON_IN_SHARED;
//These are used to to to record rising edge of a pulse
uint32_t ESC_START, ELEVATOR_START, AILERON_START;
//Declare servos
Servo esc, elevator, aileron;

void setup(){
Serial.begin(9600);
//Attach Servos
esc.attach(7);
elevator.attach(12);
aileron.attach(10);
//Attaches interrupts using PinChangeInt library
PCintPort::attachInterrupt(ESC_IN, escRead, CHANGE);
PCintPort::attachInterrupt(ELEVATOR_IN, elevatorRead, CHANGE);
PCintPort::attachInterrupt(AILERON_IN, aileronRead, CHANGE);
}
//void loop(){}

void loop(){
//local variables to hold channel inputs
static uint16_t ESC, AILERON, ELEVATOR;
//local updated flags
static uint8_t bUpdateFlags;
//check shared flags to see if we have a new signal
if(bUpdateFlagsShared){
  noInterrupts();
  bUpdateFlags = bUpdateFlagsShared;
  if(bUpdateFlags & ESC_FLAG){
    ESC = ESC_IN_SHARED;
  }
  if(bUpdateFlags & ELEVATOR_FLAG){
    ELEVATOR = ELEVATOR_IN_SHARED;
  }
  if(bUpdateFlags & AILERON_FLAG){
    AILERON = AILERON_IN_SHARED;
  }

 bUpdateFlagsShared = 0;
 interrupts();

}
if(bUpdateFlags & ESC_FLAG){
  esc.writeMicroseconds(ESC);
}
if(bUpdateFlags & ELEVATOR_FLAG){
  elevator.writeMicroseconds(ELEVATOR);
}
if(bUpdateFlags & AILERON_FLAG){
  aileron.writeMicroseconds(AILERON);
}
  bUpdateFlags = 0;
}

void escRead(){
  if(digitalRead(ESC_IN) == HIGH){
    ESC_START = micros();
  }else{
    ESC_IN_SHARED = (uint16_t) (micros() - ESC_START);
    bUpdateFlagsShared |= ESC_FLAG;
  }
}

void elevatorRead(){
  if(digitalRead(ELEVATOR_IN) == HIGH){
    ELEVATOR_START = micros();
  }else{
    ELEVATOR_IN_SHARED = (uint16_t) (micros() - ELEVATOR_START);
    bUpdateFlagsShared |= ELEVATOR_FLAG;
  }
}

void aileronRead(){
    if(digitalRead(AILERON_IN) == HIGH){
    AILERON_START = micros();
  }else{
    AILERON_IN_SHARED = (uint16_t) (micros() - AILERON_START);
    bUpdateFlagsShared |= AILERON_FLAG;
  }
}

Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suspect the 5V from Arduino is not delivering enough current for the receiver, I am not certain what the current limit is, but I think it's a mximum of 100mA. I would suggest you power the RC receiver via a 1Amp 7805/7806 voltage regulator taking it's input from the 11.1V LiPo battery, so you still have one battery only.

Cheers,
John
Logged

0
Online Online
Shannon Member
****
Karma: 222
Posts: 12715
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Absolutely - if you are trying to power the servos directly from the 5V output from the Arduino it will simply crash, don't power motors or servos from the logic 5V rail ever - you can damage the logic chips as motors can put out horrible voltage spikes (inductive load).

Normally you would power receiver and servos from a 6V or 7.2V battery pack - some receivers output a clean 5V (BEC), some don't, I believe.  Try powering Arduino separately for now - it needs clean power.
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Full Member
***
Karma: 0
Posts: 101
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry for hijacking your thread.
Im also about to make a rc plane controlled by the arduino processor. But at the moment Ill just go for stabilization and then upgrade with a barometer and such.

However, to the point where Im hijacking ur thread! Does your interrupt work good? I mean, when I try to go for interrupt with reciever it seems like its interrupting every second..
You know ur
Code:
#include <PinChangeInt.h>
, is it highlighted with orange colour? mine is grey but if you compare with others they have orange color..

Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It should be interrupting at least 50 times per second for each channel.

Try the single channel version first, its all on the blog along with explanations of what you should expect.

Duane B

rcarduino.blogspot.com
Logged


Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You know ur
Code:

#include <PinChangeInt.h>

, is it highlighted with orange colour? mine is grey but if you compare with others they have orange color..

This may mean that you have not installed the pin change int library, see here for details -

http://rcarduino.blogspot.com/2012/03/need-more-interrupts-to-read-more.html

Duane B

rcarduino.blogspot.com
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

John & Mark,
That was exactly the problem. I am now powering the arduino from the brushless motor esc. I previously had to power the receiver through the arduino so that the pulseIn function would work correctly. Now that I am using interrupts it seems that it is fine to power it through the esc.

Freak-
As I said I basically store this code directly from rcarduino. However, it is working much MUCH better than using the pulseIn () function. You may want to set up your interrupts differently depending on how you are trying to schedule your board.
First you should run the code off of rcarduino. What are specifically do you need you arduino to do in your aiplane?
I would highly recommend joining the site www.diydrones.com, you can find me there with the same username.
Please keep posting so we can help you out
I believe that DuaneB may be right, have you installed the library?
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 101
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello again,

Ive now come a bit further with the project.
Quote
* Values from sensors (GYRO AND ACC.)
* Values from receiver (using a libraries called PPMrcIn and Statistic)
* The sensor will only do its work when the transmitter is not sending any new values/directions
- So, if you are flying the plane manually and then put your transmitter away. The plane will stabilize itself (roll and pitch)

I will post a bit of the code, showing my algorithms. And here I need you guys to help me improve my code.

One thing I know that is not working well, is the automatic stabilizer.
Lets say:
* Plane is straightforward = roll and pitch has a value of 180 degrees.
* Plane is leaning = roll has a value of 160 (which means leaning 20 degrees to the left, I believe)
--> Divide value by 2 and insert it in servo.write() function.

The problem is that the indication of the servos gets to small.
Should I make it into several intervals instead, or will it take to much memory?

Code:
Servo YAW_SERVO;
Servo PITCH_SERVO;
Servo ROLL_SERVO;

int flag_roll = 0;
int flag_pitch = 0;
int flag_yaw = 0;

//////////////////////////////////////////////
//////     INITIATION OF  SERVOS       ///////
//////////////////////////////////////////////
void init_servo_motor(){
  YAW_SERVO.attach(SERVO_YAW_PIN);
  PITCH_SERVO.attach(SERVO_PITCH_PIN);
  ROLL_SERVO.attach(SERVO_ROLL_PIN);
}


//////////////////////////////////////////////
//////     READING THE RECEIVER AND      /////
//////  MANIPULATING THE SERVOS THROUGH IT ///       
//////////////////////////////////////////////
void read_receiver(){
    YAW.readSignal();
    PITCH.readSignal();
    ROLL.readSignal();
//  THROTTLE.readSignal();

   
          //////////////////////////////////////////////
          ///    CONTROL SERVO THROUGH RECEIVER     ////
          //////////////////////////////////////////////
      if(ROLL.getVersus() != 0){
      ROLL_SERVO.write(map((ROLL.getSignal()), 1000,2000,0,179));
      flag_roll = 0;
      Serial.println("RECEIVER ROLL");
    }
    if(PITCH.getVersus() != 0){
      PITCH_SERVO.write(map((PITCH.getSignal()), 1000,2000,0,179));
      flag_pitch = 0;
      Serial.println("RECEIVER PITCH");
    }
    if(YAW.getVersus() != 0){
      YAW_SERVO.write(map((YAW.getSignal()), 1000,2000,0,179));
      flag_yaw = 0;
      Serial.println("RECEIVER YAW");
    }

    //CHECKING IF ALL OF THE LEVERS OF THE RECEIVER ARE OFF   
    if(ROLL.getVersus() == 0 && PITCH.getVersus() == 0 && YAW.getVersus() == 0){
      control_servo_sensor();
    }

 
}



void control_servo_sensor(){
 
    //////////////////////////////////
    ///    CONTROLLING THE SERVOS ////
    ///          WITH SENSOR      ////
    //////////////////////////////////
   
  get_sensor_values();
   
  // THIS IS FOR THE ROLL SERVO  //
    if(kalAngleX < 177 || kalAngleX > 182){
     
      Serial.println("SENSOR ROLL ");
      Serial.print(kalAngleX);
     
      int value_roll = kalAngleX/2;   
      ROLL_SERVO.write(value_roll);
     
      flag_roll = 0;
  }
 
    // THIS IS FOR THE PITCH SERVO //
  if(kalAngleY < 182 || kalAngleY > 185){   
   
    Serial.println("SENSOR PITCH ");
    Serial.print(kalAngleY);
   
    int value_pitch = kalAngleY/2;
    PITCH_SERVO.write(value_pitch);
   
    flag_pitch = 0;
  }
   
       /////////////////////////////////////////////////////////////////////// 
       // RESET TO ZERO POSITION JUST FOR SAFETY (ROLL, PITCH, YAW SERVOS) //
       ///////////////////////////////////////////////////////////////////////
       
     if(flag_roll == 0 && ROLL.getVersus() == 0 && kalAngleX > 177 && kalAngleX < 182){ 
       Serial.println("RESETING ROLL");
       
       ROLL_SERVO.write(90);
       flag_roll = 1;
   }

   if(flag_pitch == 0 && PITCH.getVersus() == 0 && kalAngleY > 182 && kalAngleY < 185){
     Serial.println("RESETING PTCH");
     PITCH_SERVO.write(90);
     flag_pitch = 1;
   }
   
     if(flag_yaw == 0 && YAW.getVersus() == 0){
     Serial.println("RESETING PTCH");
     YAW_SERVO.write(90);
     flag_yaw = 1;
   }
 

}





PS. Yes, I have the pinchangeint library installed. But lets forget about that since Ive found a quite good library now that satisfies me.
Cheers!
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 101
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bump!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm still a bit of an Arduino n00b, but I have been flying RC planes and helis for years. I have considered an autopilot/drone project myself, the Arduino is ideal for this purpose.

The main advice I can offer on your approach is to program the autopilot a little more like you fly the plane. Halving the roll error as you're doing, for instance, means your plane theoretically will never actually level itself, as it just keeps halving the error without actually eliminating it. In The Real World (tm) of course, chances are the plane will get bounced past neutral as you get the error smaller and smaller. But the concept still holds, it seems like this would yield sluggish recovery response, possibly not enough to overcome the airplane's actual upset. This depends largely on the geometry and control throws of your plane, though...if you are not getting the recovery you want, why not just increase your rate of correct? Go 1:1 on the roll angle vs servo position, rather than 2:1.

But back to my point on making the autopilot fly more like you: when you want to change bank angle, it really doesn't matter if the desired change is 20* or 120*, you are probably going to throw in a similar amount of aileron to get the response you want. And you won't gradually reduce aileron deflection with bank angle until you are very close to the bank angle you want....actually for a lot of flying types, you may leave the aileron angle at a pretty extreme deflection, and quickly release it when you reach your desired angle (nice how our RC models flit around and respond like they're on rails most of the time). Perhaps you should decide on a narrow range of aileron deflection (say between 50% and 75%) and adjust your aileron correction within that range based on the amount of roll angle error. In that example, the smallest aileron deflection you'd see would be 50%, until you are within some very close range of your desired bank angle, at which point you'd release the ailerons (depending on your model you would want some dampening code, to prevent "pilot"-induced oscillations...this could be something like what you're doing now, but with a little more sophistication).

Quick question: is your gyro (and other sensors) giving you absolute values, or relative values (ergo, relative to the previous cycle)?

Hope this gives you some ideas...I'm looking forward to exploring this area myself once I get into my own autopilot system!

Matt
Logged

0
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you looked at the Ardupilot project?

The Ardupilot Mega already does this.  It uses a separate ATmega328 (i.e. and arduino processor) to decode RC receiver outputs.

The design team decided to use a separate processor for this decoding.  IIRC the reason was to increase accuracy and offload computation to make more resources available for the rest of the flight code.

-j
Logged

Pages: [1]   Go Up
Jump to: