chipKIT® Development Platform

Inspired by Arduino™

what is the best way to read a rc receiver output?

Created Wed, 29 Feb 2012 02:04:42 +0000 by alphamike


alphamike

Wed, 29 Feb 2012 02:04:42 +0000

what is the best way to read a rc receiver output? I am building a robot that is controlled by a airplane controller, but I was wondering if the compiler has been fixed to be able to use attach interrupt ? this is the code that i am currently using, but it is too jumpy and it does not always read the output (ie. the output shows up as a zero).

unsigned long counter = 0;
unsigned long Channel1Value;
unsigned long Channel2Value;
unsigned long lastgood1;
unsigned long lastgood2;
unsigned long InitialSteer;
unsigned long InitialThrottle;
boolean Right;
//motor stuff
long Steer;
int Thrust;
int RightMotor;
int LeftMotor;
int Chan1 = 2;
int Chan2 = 3;
int newVal1;
int newVal2;
#define MotorLimit 3200
/**************************************************************
 * Subroutine to exit saft start;
 ***************************************************************/
void exitSafeStartBoth()  
{  
  Serial3.print(0x83, BYTE);  
}  

void motorStopBoth()
{ 
  Serial3.print(0xE0, BYTE);
}
/**************************************************************
 * Subroutine to control right motor= motorRight(speed, direction);
 ***************************************************************/
void setMotorSpeedleft(int speedleft)
{
  if (speedleft < 0)
  {
    Serial3.print(0xAA, BYTE);
    Serial3.print(0xa, BYTE);
    Serial3.print(0x6, BYTE); // motor reverse command
    speedleft = -speedleft; // make speed positive
  }
  else
  {
    Serial3.print(0xAA, BYTE);
    Serial3.print(0xa, BYTE);  
    Serial3.print(0x5, BYTE); // motor forward command
  }
  Serial3.print((unsigned char)(speedleft & 0x1F), BYTE);
  Serial3.print((unsigned char)(speedleft >> 5), BYTE);
}

/**************************************************************
 * Subroutine to control left motor
 ***************************************************************/
void setMotorSpeedright(int speedright)
{
  if (speedright < 0)
  {
    Serial3.print(0xAA, BYTE);
    Serial3.print(0xd, BYTE);
    Serial3.print(0x06, BYTE); // motor reverse command
    speedright = -speedright; // make speed positive
  }
  else
  {
    Serial3.print(0xAA, BYTE);
    Serial3.print(0xd, BYTE);  
    Serial3.print(0x05, BYTE); // motor forward command
  }
  Serial3.print((unsigned char)(speedright & 0x1F), BYTE);
  Serial3.print((unsigned char)(speedright >> 5), BYTE);
}



void setup()
{
  Serial3.begin(19200);
  Serial.begin(19200);
  Serial.println("Ready");
  pinMode (Chan2, INPUT); 
  pinMode (Chan1, INPUT); 
  InitialSteer = pulseIn (Chan1, HIGH); //read RC channel 1
  lastgood1 = InitialSteer;
  InitialThrottle = pulseIn (Chan2, HIGH); //read RC channel 2
  lastgood2 = InitialThrottle; 
}

void loop()
{
  newVal1 = pulseIn(Chan1, HIGH, 50000);
  newVal2 = pulseIn(Chan2, HIGH, 35000);
  if (newVal1 > 0 || newVal2 > 0)
  {
  
    //  counter++;  // this just increments a counter for benchmarking the impact of the pulseIn's on CPU performance
    if(newVal1 >= Channel1Value || newVal1 <= Channel1Value)
    {
      Channel1Value = newVal1;
    }
    if(newVal2 >= Channel2Value || newVal2 <= Channel2Value)
    {
      Channel2Value = newVal2; //read RC channel 2
    }
    if (Channel1Value == 0)
    {
      Channel1Value = lastgood1;
    } 
    else 
    {
      lastgood1 = Channel1Value;
    }

    if (Channel1Value < InitialSteer) 
    {
      Right = false;
    } 
    else
    {
      Right = true;
    }
    Steer = Channel1Value - InitialSteer;
    RightMotor = Thrust - Steer;
    LeftMotor = Thrust + Steer;

    if (RightMotor > 3200) 
    {
      RightMotor = 3200;
    }
    if (LeftMotor > 3200) 
    {
      LeftMotor = 3200;
    }
    Thrust = map(Channel2Value, 3645, 5565, -(MotorLimit), MotorLimit); 
    Thrust = constrain (Thrust, -(MotorLimit), MotorLimit); //just in case

    LeftMotor = constrain (LeftMotor, -3200, 3200);
    RightMotor = constrain (RightMotor, -3200, 3200);
    exitSafeStartBoth();
    setMotorSpeedleft(LeftMotor);
    setMotorSpeedright(RightMotor);
  }


  else 
  {
    motorStopBoth();
  }



  Serial.print ("Channel 1: ");  // if you turn on your serial monitor you can see the readings.
  Serial.println (Channel1Value);
  Serial.print("Channel 2: ");
  Serial.println (Channel2Value);
  Serial.println(LeftMotor);
  Serial.println(RightMotor);
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");

  delay(50);
}

sorry if the code is confusing, im not all that good as you can tell


KM6VV

Wed, 29 Feb 2012 19:38:39 +0000

I'd use the Servo Decode function. I hope it's ready for ChipKIT.

[url]http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230065255[/url]

Alan KM6VV


alphamike

Sun, 04 Mar 2012 13:36:51 +0000

I'm trying to decode all six channels from the receiver. I read somewhere that unless you use attach interrupt, the code will run too slow.


dangeljs

Sun, 04 Mar 2012 16:56:29 +0000

Have you ever thought of using the input capture module? There are 5 of them on the uno, so you would have to softcode your last channel. I've been able to use two channels for a pair of ultrasonic sensor and they worked great for range testing (better than pulsein). I'm sure it could be adjusted to fit you needs and save some processing overhead.


alphamike

Sun, 04 Mar 2012 22:39:50 +0000

What is that command and how do you use it. I am using the max32 plugged into a pcb I produced and the channels are pinned to 7-2. If i need to I could make a new pcb


dangeljs

Mon, 05 Mar 2012 00:08:28 +0000

It's not really a command, but a module inside the chip that would need to be configured. I'm attaching a sketch of how I used it, but understand that because of the way I'm using it I know when the pulse goes low and am just timing until the pulse goes high. I like this better than pulsein because it can be used as non-blocking so I could process other things while waiting for the rising edge. You may be able to configure it to start counting on a negative going edge then capture the timer value on the positive edge. You will have to read the datasheet though for more details. The Max 32 also only has 5 I.C. modules located on pins 48,74,38,49, and 8 which are not remappable unfortunately. Sorry if the code seems sloppy, it was hastily thrown together to test out the range finders. I actually just modified some code that was posted on the forum and used it.

Hope it is of some use.

Jason


alphamike

Mon, 05 Mar 2012 02:03:05 +0000

I'm not sure if the input capture will work for me. just because i Would rather not make a new pcb. is attach interrupt even possible for what I am trying to do? I also looked into servo decode and could not find anything about it for chipkit..


dangeljs

Mon, 05 Mar 2012 04:25:30 +0000

I'm not sure which interupt you are refering too (assuming Change Notification (CN)), but looking at the pins that are used for it you may not have much luck either. Looking at the Pinout table provided by Digilent the only pin that would fit your pins is pin 4. I don't know about the servo decode library, so maybe someone else could enlighten you on the topic.

Good luck what ever you decide.


KurtE

Mon, 05 Mar 2012 14:18:24 +0000

Alternatively depending on your RC receiver you can hack on the receiver to get just one input for the 6 channels. I played around with this awhile ago to connect to a different processor (Basic Atom Pro)... I did it for the Hitec 6... More details in the forum thread: http://www.lynxmotion.net/viewtopic.php?f=21&t=6629

I found details for doing this type of receiver as well as some others by goggle of terms like "intercept ppm" or the like.

Kurt


Jacob Christ

Mon, 16 Apr 2012 02:22:57 +0000

We just posted the chipKIT source for the PONTECH UAV100 to github today:

https://github.com/pontech/uav100

Product details:

http://www.pontech.com/details/138

In this code we are capturing 8 PPM signals with 15-bit resolution using the CN interrupts.

This may help some people trying to do the same.

Jacob


KM6VV

Mon, 16 Apr 2012 19:47:12 +0000

Hi Jacob,

is the GitHub Zip complete? Looks like the pic32lib has no files, and GPS only has GPS.h. TokenParser has no files, but needs at least TokenParser.h.

19 files?

Maybe I need something else?

Maybe point me to the notes needed to compile?

I am not current on the PIC lib, come to think of it.

Thanks!

Alan KM6VV


Jacob Christ

Tue, 17 Apr 2012 00:34:21 +0000

Hi Jacob, is the GitHub Zip complete? Looks like the pic32lib has no files, and GPS only has GPS.h. TokenParser has no files, but needs at least TokenParser.h. 19 files? Maybe I need something else? Maybe point me to the notes needed to compile? I am not current on the PIC lib, come to think of it.

the pic32lib and TokenParsers are submodules so you need to do a submodule update. The gps code is not complete and there is only a header.

If you look at github.com/pontech you should see the submodules. I was able to pull and update the whole project.

Jacob

NOTE: There are a couple of other issues as well that have been fixed in MPIDE to get this to compile, I'll will have to put a readme together.


KM6VV

Tue, 17 Apr 2012 00:48:55 +0000

OK, I get it!

Thanks,

Alan KM6VV


Ernie

Tue, 15 May 2012 05:10:06 +0000

What voltage are the signals from the RC receiver you are using? I ask because a lot of the PIC32 I/O lines don't seem to be 5 volt tolerant, especially on on the smaller packages like the PIC32MX250F128B etc. I know having built a few multi-copters myself, that RC receivers can have a lot of channels. I have mostly used ATmega chips which run on 5volts, I haven't tried a PIC32 as a flight controller yet, though no doubt will one day.


Jacob Christ

Tue, 15 May 2012 05:39:48 +0000

The UAV100 has buffered inputs.

Jacob


ajitnayak

Mon, 19 Nov 2012 10:43:25 +0000

you can download simple bare program on chipkit32 using mpide IDE 023

you will start receiving data.

ex:

void setup() { } void loop() { }

and open serial monitor to view the data