How to fly a S107 helicopter with the Kinect?
This is not a step by step tutorial. I will provide the Arduino code that gets the Helicopter flying, but the rest is up to you to be creative.
So let’s get to the hard part first. Getting the Arduino to talk to the S107. The S107 speaks a specific language transmitted over a 38 kHz signal.
The signal structure that I used for the S107 is as follows:
(Note: Channel "A" uses Throttle Values 0 to 127. Channel "B" uses Throttle Values 128 to 255.)
With that, let’s look at the code: Here is a nice formatted link to the Arduino File.
// Connect (+) of IR LED to 5Vcc
// connect (-) to pin 4 with a resistor in line. For best results make a transistor circuit with external power source
#define RED 4 // the output pin of the IR LED
void setup() {
pinMode(RED, OUTPUT); // set IR LED (Pin 4) to Output
}
void loop() {
//Do you magic here. The code directly below just throttles up to 40 and back down to 0.
//You can get data from the serial port, a joystick, or whatever. You just need to translate your input into values between 0 and 127.
//Pass those values to Transmit( ) as an integer between 0 and 127 for Channel "A"; or 128 to 255 for Channel "B" and that's it!
int t;
for (t = 0; t < 40; t++) {
Transmit(63, 63, t, 63); //Rudder = 63, elevator = 63, throttle = t, trim = 63
// Transmit(63, 63, ((40 - t) + 128), 63);
//This would cause Channel "B" to throttle down
}
for (t = 40; t > 0; t--) {
Transmit(63, 63, t, 63);
// Transmit(63, 63, ((40 - t) + 128), 63);
//This would cause Channel "B" to throttle up
}
} //End loop()
void Transmit(byte rudder, byte elevator, byte throttle, byte trim) {
static byte Code[4];
byte mask = 128; //bitmask
int i;
Code[0] = rudder; // 0 -> 127; 63 is the midpoint.
Code[1] = elevator; // 0 -> 127; 63 is the midpoint.
Code[2] = throttle; // 0 -> 127; 0 is throttle off
Code[3] = trim; // Haven't messed with this
OutPulse(2002); // Start 38Khz pulse for 2000us (2002us is evenly divided by 26)
delayMicroseconds(2000); // 2000us off.
for (i = 0; i<4; i++) { // Loops through the Code[i]
for (mask = 128; mask > 0; mask >>=1) { // See Arduino reference for bit masking (really cool stuff!)
OutPulse(312); // Sends 312 pulse each loop
if(Code[i] & mask) { //If both bit positions are 1 you get 1
delayMicroseconds(688); // send 1 (700 off)
}
else {
delayMicroseconds(288); // send 0 (300 off)
}
} //End mask loop
} //End i loop
OutPulse(312); //Send 300 microsecond Closing Pulse
delay(60);
} // End Transmit
void OutPulse(int Pulse) { //sends 38Khz pulses over the Pulse Length
int p;
for(p = 0; p < (Pulse / 26) - 1; p++) { //Takes about 26 microseconds per loop
digitalWrite(RED, HIGH);
delayMicroseconds(10);
digitalWrite(RED, LOW);
delayMicroseconds(10);
}
} //End OutPulse
As you can see, all you need to do is feed the void Transmit() with integer values between 0 and 127 (or 128 to 255 for Channel "B" ). Do this from the void loop().
You can actually alternate between the "A" and "B" channel without any problems (that I've encountered).
You may also see that there is no code in there for communicating with the Kinect. I wanted to give a clean version of the S107 code. The Kinect serial input requires more code in the void loop().
Reading from the serial is a lot of hassle. I will make an update soon to explain how to read from the serial port.
For the Kinect project, I used the Microsoft Kinect SDK software to determine the location of my hands relative to head and hips. This gave me a y-coordinate distance that could be scaled from 0 to 127.
The Kinect can also be used to measure distances relative to the sensor. Again, this data can easily be converted to scaled z-coordinate values between 0 and 127.
The fun part was determining the best use of x, y and z coordinates. You only have 2 hands, so controlling a 3 channel Heli takes some thinking.
Also fun is determining how to initialize the Heli (interlocks to avoid premature takeoff) and how to incorporate a kill switch.
I hope that this will help inspire some creativity to use the Kinect with the Arduino boards.
Check back for updates.