RC Receiver signal read

Hi all,

Here is the code i have to read my RC signals from the Receiver. Is there any ways to improve this??
e.g. using interrupts!!

//Pin connections to RC Receiver
  const int CH1Pin = 3;
  const int CH2Pin = 5;
  const int CH3Pin = 6;
  const int CH4Pin = 9;
  const int CH5Pin = 10;
  const int CH6Pin = 11;

// Chanel stat1 vals
  unsigned long CH1;
  unsigned long CH2;
  unsigned long CH3;
  unsigned long CH4;
  unsigned long CH5;
  unsigned long CH6;  
  
// variable used in the "chst_cut" to store 
  int chst_1;

float chst_cut(int b){
  chst_1 = b/100;
  chst_1 = round (chst_1);
  chst_1 = chst_1 * 100;
  return chst_1;
}  
void setup() {
  // put your setup code here, to run once:
  pinMode(CH1Pin, INPUT);
  pinMode(CH2Pin, INPUT);
  pinMode(CH3Pin, INPUT);
  pinMode(CH4Pin, INPUT);
  pinMode(CH5Pin, INPUT);
  pinMode(CH6Pin, INPUT);


  Serial.begin(9600);

}

void loop() {
// pulseIn() is used to read the signals from the receiver (not the best way!!!)
     CH1 = (pulseIn (CH1Pin, HIGH));
     CH2 = (pulseIn (CH2Pin, HIGH));
     CH3 = (pulseIn (CH3Pin, HIGH));
     CH4 = (pulseIn (CH4Pin, HIGH));
     CH5 = (pulseIn (CH5Pin, HIGH));
     CH6 = (pulseIn (CH6Pin, HIGH));

// rounding 
    CH1 = chst_cut(CH1);
    CH2 = chst_cut(CH2);
    CH3 = chst_cut(CH3);
    CH4 = chst_cut(CH4);
    CH5 = chst_cut(CH5);
    CH6 = chst_cut(CH6);

//Packing values in Serial buffer
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH1);
  Serial.println("");
  
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH2);
  Serial.println("");
  
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH3);
  Serial.println(""); 
  
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH4);
  Serial.println("");
  
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH5);
  Serial.println("");
  
  Serial.print("U*"); //A header
  Serial.print("A");  //a token to indicate the message payload
  Serial.print(CH6);
  Serial.println("");
         

    

}
byte CHPins [6] = { 3, 5, 6, 9, 10, 11 } ;

unsigned long CH [6] ;

void setup ()
{
  for (byte i = 0 ; i < 6 ; i++)
    pinMode (CHPins [i], INPUT) ;
  Serial.begin (115200) ;   // no point using glacially slow baud rate over USB
}

void loop ()
{
  for (byte i = 0 ; i < 6 ; i++)
    CH [i] = chst_cut (pulseIn (CHPins [i], HIGH)) ;

etc etc - arrays dead handy, use they whenever appropriate. byte is perfectly large enough type
for pin numbers and counting to 6, but use int if you like.

You are right to suppose that there is a better way. pulseIn() is a blocking function so can slow down the response when used for many channels.

Here is an example of using an interrupt to read one RC channel.

#include <Servo.h>
Servo myServo;

const byte rcPin = 2;  //Rx output connected to this input pin
volatile int pulseLength;  //holds the length of the input pulse.  volatile because it is updated by the ISR
volatile unsigned long pulseStart = 0;  //time the pulse started.  Used in calculation of the pulse length
volatile boolean newPulse = false;  //flag to indicate that a new pulse has been detected
const byte servoPin = 7;    //servo ouyput pin

unsigned long stepPeriod = 5;  //time between servo steps when sweeping
unsigned long stepStart = 0;  //time the sweep step started
unsigned long currentTime = 0;  //name says it all
int servoIncrement = 1;  //how many degrees to move the servo with each sweep step
const byte sweepStart = 50;  //angle to start the sweep at
const byte sweepEnd = 130;    //angle to stop the sweep at
const byte servoHome = 90;    //servo home position when not sweeping
byte servoPos = servoHome;    //set initial servo position
boolean sweeping = false;    //indicate sweeping is not initially happening

void setup()
{
  attachInterrupt(0, rcInput, CHANGE);  //when interrupt 0 (pin 2 of Uno) detects a chanhe of state execute this function
  Serial.begin(115200);
  myServo.attach(servoPin);
  myServo.write(servoHome);
}

void loop()
{
  if (newPulse)  //if we have detected a new pules
  {
    newPulse = false;  //turn off the indicator
    if (pulseLength >= 1500)  //if pulse length greater than 1500 microseconds
    {
      sweeping = true;  //turn on sweeping flag
    }
    else
    {
      myServo.write(servoHome);  //otherwise move servo to home position
      sweeping = false;  //turn off sweeping flag
    }
  }

  if (sweeping)  //if sweeping is true
  {
    currentTime = millis();  //get the current time
    if (currentTime - stepStart > stepPeriod)  //if enough time has elapsed  
    {
      stepStart = currentTime;  //save vthe current time
      servoPos += servoIncrement;  //increment the servo position
      if (servoPos <= sweepStart || servoPos >= sweepEnd)  //if servo position is past either limit
      {
        servoIncrement *= -1;  //change the servo direction
      }
    }
    myServo.write(servoPos);  //move the servo to its new position
  }
}

// the interrupt routine starts here
//it is executed at any time that pin 2 (interrupt 0 on a Uno) changes state.
void rcInput()
{
  if (digitalRead(rcPin) == HIGH)  //if the pin is HIGH
  {
    pulseStart = micros();  //save the current time in microseconds
  }
  else
  {
    if (pulseStart && (newPulse == false))  //otherwise if we are timing and this is not a new pulse
    {
      pulseLength = (int)(micros() - pulseStart);  //calculate the pulse length
      pulseStart = 0;  //reset the pulse start time to zero
      newPulse = true;  //set flag to indicate that we are timing a new pulse
    }
  }
}

It reads one channel and then depending on the pulse length either sweeps a servo or sends it to a home position.

The main restriction when using interrupts is that most Arduinos only have very few hardware interrupts but there is an alternative known as pin change interrupts that extend the number of available interrupts at the expense of more complicated programming.

As a matter of interest what do you intend to do with the intercepted RC channel data ?

Hi @UKHeliBob,

thanks for the example code!!

I'm upgrading my RC car to use micro controllers and make a AutoPilot version of it soon.

I have my code on git hub f you want to have a look:

I'm using a 6 channel radio to control the car and accessories like Lights etc. At the moment i'm working on the program lag. have prototyped a few boards but have problems with power management!!

As you mentioned interrupts stop the program till their done! So i was thinking to have a micro controller reading the channels constantly and pack them in the serial buffer and the second micro controller execute the rest of the code.

In the next phase there will be a third micro controller reading all the sensor values and doing the same.

please look at my repositories @ https://github.com/AmirRajabifar

@MarkT I added the fore loops but the readings from the channels are not VALID!!!

//Pin connections to RC Receiver
 byte CHPins [6] = {3, 5, 6, 9, 10, 11};
 char Headers [] = {'a', 'b', 'c', 'd', 'e', 'f'};
// Chanel stat1 vals
 unsigned long CH [6];

 
// variable used in the "chst_cut" to store 
 int chst_1;

float chst_cut(int b){
 chst_1 = b/100;
 chst_1 = round (chst_1);
 chst_1 = chst_1 * 100;
 return chst_1;
}  
void setup() {
 // put your setup code here, to run once:
 for (byte i = 0; i < 6; i++){
   pinMode(CHPins [i], INPUT);
 }
 Serial.begin(250000);

}

void loop() {
// pulseIn() is used to read the signals from the receiver (not the best way!!!)
 for (byte i = 0; i < 6; i ++){
   CH [i] = chst_cut (pulseIn (CHPins [i], HIGH));
 }

//Packing values in Serial buffer
 for (byte a = 0; a < 6; a ++){
    for ( byte b = 0; b < 6; b++){
     Serial.print("U*");
     Serial.print(Headers [b]);
     Serial.print(CH [a]);
     Serial.println("");
     delay(50);
    }
 }

/*  
 Serial.print("U*"); //A header
 Serial.print("A");  //a token to indicate the message payload
 Serial.print(CH1);
 Serial.println("");
 
 Serial.print("U*"); //A header
 Serial.print("B");  //a token to indicate the message payload
 Serial.print(CH2);
 Serial.println("");
 
 Serial.print("U*"); //A header
 Serial.print("C");  //a token to indicate the message payload
 Serial.print(CH3);
 Serial.println(""); 
 
 Serial.print("U*"); //A header
 Serial.print("D");  //a token to indicate the message payload
 Serial.print(CH4);
 Serial.println("");
 
 Serial.print("U*"); //A header
 Serial.print("E");  //a token to indicate the message payload
 Serial.print(CH5);
 Serial.println("");
 
 Serial.print("U*"); //A header
 Serial.print("F");  //a token to indicate the message payload
 Serial.print(CH6);
 Serial.println("");
*/         

   

}

Why have you got a double nested for loop?

As you mentioned interrupts stop the program till their done!

Actually, I such no such thing. The pulseIn() function blocks program execution until either a pulse is received or a timeout occurs.

Whilst ISRs also block program execution until they are complete they can be written as quick "in and out" routines so the holdup is minimal and they can deal with pulses being received at any time but process the data at a convenient time.

If you code it correctly I don't see why you would need multiple processors.

@MarkT,
to write the headers and the CH1,2,.....

It writs everything in the Serial buffer perfectly but the values i'm getting for each channel is not what it's suppose to be!!

it seems to be reading from one channel only!!

@UKHeliBob,

I'm totally aware of what you're saying. But it's a bit hard for me to get my head around interrupts!!