Using a small helicopter controller with Arduino

I have a small model helicopter that uses Infra Red for the remote control. I have never been able to do much more than bounce it off the ceiling, but thought that I could do something with the remote control. This control has two joysticks, one for motor speed and one to turn the helicopter left or right, in addition it has a three way switch to select one of three channels.

I have used an Arduino with an Infra Red receiver before to decode signals from various television and other controllers, and in all these devices the code received related to a single key pressed. There are a number of Arduino sketches available to decode IR signals using a three pin IR receiver sensor such as the TSOP 1738B shown below

  

For a good introduction to using these devices visit this page. The widely spaced pin is usually the output pin, the centre pin is often 5 volts and the other pin is Gnd. I used a device from an old VCR, and it was unmarked.

When experimenting with the helicopter control I found that the sketch I was using gave unpredictable results. I tried several sketches but found the one posted on the Adafruit site designed for the Trinket worked the best. This code needed to be modified to work on an Arduino UNO and the code is shown below. You can see the original article from Adafruit here

Connect the output pin of the Infra Red receiver to Arduino pin 2, the Vcc and Gnd pins to Arduino 5 volts and Gnd respectively.


// IR Decoder modified from the Adafruit code for the Trinket
//
// We need to use the 'raw' pin reading methods because timing is very important here
// and the digitalRead() procedure is slower!
//
// connect the output pin from the Infra Red reciever to Arduino pin 2
// connect the Gnd pin to Arduino Gnd pin
// connect the Vcc pin to 5 volts on the Arduino
//
// in my controller the following information is sent (left to right)
// bytes 1 and 2 are the channel number from 0x80 to 0x82
// byte 3 is the speed, from 0 to 0xE
// byte 4 is the trim control left = 0xF, off = 0x0 and Right = 0x1
// byte 5 is the left/right turn control, centre is 7
// move left and it goes from 0xF to 0xA
// move right and it goes from 6 to 1
// bytes 6,7 and 8 are normally 0xFFF but can be 0x7FF
// these bytes seem to have no meaning
//
//
#define IRpin_PIN PIND // Use port D this is pins 0 to 7
#define IRpin 2 // connect IR Decoder to pin 2

#define MAXPULSE 5000 // the maximum pulse we'll listen for - 5 milliseconds
#define NUMPULSES 100 // max IR pulse pairs to sample
#define RESOLUTION 2 // // time between IR measurements

// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[100][2]; // pair is high and low pulse
uint16_t currentpulse = 0; // index for pulses we're storing
uint32_t irCode = 0;

String speedValueString = ""; // value of speed joystick
String fullCode = ""; // IR code full version

void setup(void) {
Serial.begin(9600);
Serial.println("Ready to decode IR!");
pinMode(IRpin, INPUT); // Listen to IR receiver on pin D2
}

void loop(void) {
uint16_t numpulse=listenForIR(); // Wait for an IR Code
// Process the pulses to get a single number representing code
for (int i = 0; i < 32; i++) {
  irCode=irCode<<1;
  if((pulses[i][0] * RESOLUTION)>0&&(pulses[i][0] * RESOLUTION)<500) {
    irCode|=0;
  }
  else
  {
    irCode|=1;
  }
}
//
printcode();
//
Print IR code
//
}

void printcode(void) {
// values for speed etc are extracted here
fullCode = "0x" + String(irCode, HEX);
Serial.println(fullCode); // this is the complete word

/* once you know how the data string is made up
you can extract the code as shown in this example
*/

// un-comment the following lines
//speedValueString = fullCode.substring(4,5);
//Serial.print("Speed = ");
//Serial.println(speedValueString);
}

uint16_t listenForIR() { // IR receive code
currentpulse = 0;
while (1) {
unsigned int highpulse, lowpulse; // temporary storage timing   highpulse = lowpulse = 0; // start out with no pulse length
while (IRpin_PIN & _BV(IRpin)) { // got a high pulse   highpulse++;
delayMicroseconds(RESOLUTION);
if (((highpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
return currentpulse;
}
}
pulses[currentpulse][0] = highpulse;
while (! (IRpin_PIN & _BV(IRpin))) { // got a low pulse
lowpulse++;
delayMicroseconds(RESOLUTION);
if (((lowpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
return currentpulse;
}
}
pulses[currentpulse][1] = lowpulse;
currentpulse++;
}
}


What makes decoding the data from the helicopter remote control different from a television remote control is that it contains several pieces of information. The controller sends the channel number, the speed and direction all in a single 8 byte word, different helicopter controllers may use a different format and I will explain how I decoded mine.

If you run the code shown above, the switch to the Serial Monitor after a few seconds you will see the message Ready to receive IR! No data will be shown until you operate a control. Un-check AutoScroll as this makes it easier to see what’s going on, then push the speed joystick up to full, a screen similar to that shown below will be displayed.  

 

Note, I am numbering the 8 byte word from left to right to make it easier to work with once it has been converted to a string. Ignoring the 0x, all the numbers start with 81, but the third number is increasing as I increased the speed, the remaining numbers stay the same. This means that the third byte is Speed and it varies from 0 to 15 (decimal). Return the speed joystick to zero and after a few second the controller will stop transmitting, I assume this is to stop the helicopter flying off into the distance.

My helicopter has three ‘channels’, A, B and C. Using the same procedure start with the channel set to A. In my case the 8 Digit number started with 80, B gave 81 and C was 82.

Now move the Left/Right joystick, at rest byte 5 was zero. Moving the Joystick to the left byte 5 changed from 0xF to 0xA. Moving back to the centre and then to the right byte 5 went from 1 to 7.

The last control was a Trim switch and I found this on byte 4. At rest it was Zero and pressing L gave 0xF and pressing R gave 0x1.

Bytes 6,7 and 8 were always either 0xFFF or 0x7FF, so I assumed these had no function.

To extract the data I use the following code

speedValueString = fullCode.substring(4,5);
Serial.print("Speed = ");
Serial.println(speedValueString);

Once you can extract the information you can do whatever you like. I used this to control a Hovercraft, the speed joystick controlled the main motor and the Left/Right controlled two motors used for steering. The Trim control was used to switch the power to the main motor off and on.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s