For those of you who are into electronics, here is my take on an open source Arduino Xbee remote controls system with telemetery Very simple software an the very popular Arduino platform, lots of support from a wide user goup
This is the airframe that flew in the video above. Its a bit too heavy.
The receiver board in Yellow Plane
The whole board and micro weighs in at 22 grams. The supply will be a 3C Lipolly. My Xbee needs around 220mA and the Arduino draws 100 mA driving all 6 servo PWM signals, and not the motors. All up say 750mA in a 750mAh 3C
Its probably not suitable for a small plane due to its weight but is does allow for expansion and data acquisition and live telemetery. There are eight 10 bit analogue inputs and six PWM servo drive outputs.
The test pilot Richard who flew Yellow Plane thought the control was good on its maiden flight, despite ending in a crash :) which I latter determined was caused an incorrectly configured charger causing the battery to not be fully charged. It is always easy to overlook the simple things in engineering, as my school reports often said must try harder.
Here is my calculation spread sheet for Yellow Plane if anyone sees anything I'm doing wrong in this spread sheet please let me know
This was the setup prior to the maiden flight. I'm more into the tech than flying but am improving so, so deferred the maiden flight to an experienced pilot content to film her instead.
Inside the transmitter box with the Arduino Uno gathering the control positions and sending them via the Xbee to the plane.
The receiver Circuit Diagram
This layout allows me to add components between the Xbee and the Arduino, so If i came up with an autopilot it could catch the data from the TX modify /override it and forward the data to the RX Arduino
This is the Arduino Nano I used in the RX supplied by Hobby King, they are always out of stock now it seems as they are only US$9.95
There is a smaller lighter version without the USB which I will experiment with in due course.
The Software
Here is the current RX code and the TX Code for anyone who is interested, you can figure out the wiring from the code as I really only did a pencil drawing while I was soldering.
Two way comms @ 38,400 baud seems reliable, other folks on the www seem to agree with this. The Xbee's are in the out the box wire replacement mode all set to defaults except baud is set to 38,400 with the X-CTU Utility
The rest is in a pretty simple bit of code shown below. The electrical circuit can be determined from the code, I will draw it up as its only on a pad soon.
Two Xbee Pro S1 60mW alleged 1500 meter range out doors
TX Arduino Uno
RX Arduino Nano 328
I am a believer in the simplest code/solution to do the job so here is my wee bit of code for. I pass back telemetery every 5 frames from the TX with 20ms frames.
Its nice smooth and responsive
I sample the analogue inputs on power up (wInd off zero or WOZ in the code) so the joysticks can be nulled.
The loop samples all channels MAX_SAMPLE times then make an average. This method seemed to work better than a rolling average which introduces noticeable lag on the servos. Next the 10 bit values from the analogue controls are scaled to 1790 bananas, this is degrees X 10. The pot values are sampled at 200 micro second-ish intervals and a 10 point average is acquired in around 8mS.
A couple of other sites seem to concur that a 10mS dead air period with an Xbee is preferable, I have seen this first hand, the TX and RX are nicely in sync with the current regime, servos are nice and quiet and don't jitter when static. Any jitter I do see seems to be related to analogue noise there are 0.5uF caps between ground and the wiper of the pots, also the pot cans are grounded and the signal cables are screened for the short distance between the transducer and the Arduino.
A packet is constructed including the TX Xbee's rssi and the state of the digital switched on the box. The packet is sent over the air with a simple checksum. There is an LED that flashes faster as the RSSI time increases, should give me warning if going out of range
if(rssi == 0)
digitalWrite(4,HIGH);
if( (tick % (rssi / 10) ) == 0)
{
if(digitalRead(4) == HIGH)
digitalWrite(4,LOW);
else
digitalWrite(4,HIGH);
}
At the end of loop I wait for the n microseconds based on how long it took the get to the end of the loop, giving a 20mS frame rate, the typical wait is around 8 mS at the end of the processing section, which gives some free air for the Xbee, and seems to give better responsiveness than transmitting back to back as fast as possible.
The TX packet is quite small at max of around 70 bytes so it fits in a single Xbee frame which is helpful and preferable.
The next flight will use gyro stability utilizing and old KK board and the programmable RX. This is Yellow plane 1.5 which is now replaced with YP 2.0 an altogether prettier lighter twin boom inverted V tail design.
In most systems the TX does all the clever stuff like mixing and variable rates. In this design the RX can do it which means if you have a stability algorithm it can be used by an auto pilot or any other mad scheme you can dram up.
Here is the gyro working on Yellow Plane 2 during the build
This routine calculates the servo positions and adds the gyro compensation
void UpdateServos()
{
//Digital inputs TX code helper
//TxVal[8] |= (digitalRead(5) << 0);//joy 2 push
//TxVal[8] |= (digitalRead(6) << 1);//pb
//TxVal[8] |= (digitalRead(7) << 2);//slide
//TxVal[8] |= (digitalRead(8) << 3);//toggle
//Throttle TxVal[1]
//Rotary pot TxVal[2]
//Joy 1 X TxVal[3]
//Joy 1 Y TxVal[4]
//Joy 2 X TxVal[5]
//Joy 2 Y TxVal[6]
//rssi TxVal[7]
//digital TxVal[8]
//micros() TxVal[9]
//Use the pot as the gain for all channels for now
float GainPot = (float)(TxVal[2]) * 0.001f;
//Get the target values from the TX
int PitchTarg = (TxVal[3] / 10);
int RollTarg = (TxVal[4] / 10);
int YawTarg = (TxVal[6] / 10);
//Prime the Target WOZ values
if(PitchTargWOZ == 9999)
PitchTargWOZ = PitchTarg;
if(RollTargWOZ == 9999)
RollTargWOZ = RollTarg;
if(YawTargWOZ == 9999)
YawTargWOZ = YawTarg;
//Get the Centered target values
float PitchTargCentred = (float)(PitchTarg - PitchTargWOZ);
float RollTargCentred = (float)(RollTarg - RollTargWOZ);
float YawTargCentred = (float)(YawTarg - YawTargWOZ);
//Calculate gains
float PitchGain = GainPot * 1.0f;
float RollGain = GainPot * 1.0f;
float YawGain = GainPot * 1.0f;
//Get Gyro values
float PitchGyro = (float)(AnIn[2] - AnInWOZ[2]);
float RollGyro = (float)(AnIn[1] - AnInWOZ[1]);
float YawGyro = (float)(AnIn[0] - AnInWOZ[0]);
//Calc P error
float PitchError = (float)PitchTargCentred + PitchGyro;
float RollError = (float)RollTargCentred + RollGyro;
float YawError = (float)YawTargCentred + YawGyro;
//Apply gains
int PitchTrim = (int)(PitchError * PitchGain);
int RollTrim = (int)(RollError * RollGain);
int YawTrim = (int)(YawError * YawGain);
//Constaring trim authority
PitchTrim = constrain(PitchTrim, -30, 30);
RollTrim = constrain(RollTrim, -30, 30);
YawTrim = constrain(YawTrim, -30, 30);
//Dump the trim value
if((TxVal[9] & 0x4) == 0)
{
PitchTrim = 0;
RollTrim = 0;
YawTrim = 0;
}
//Calc flap anglke
int Flaps = 0;
//Apply flaps
if((TxVal[9] & 0x8) == 0)
Flaps = -25;
//Throttle
val = TxVal[1] / 10;
val = map(val, 1, 179, 30, 179);
val = constrain(val, 1, 165); // scale it to use it with the servo (value between 0 and 180)
servo[0].write(val); // sets the servo position according to the scaled value
//Vee tail
//Left Elevator Joy 1 Y TxVal[4]
val = (YawTarg + YawTrim) + (PitchTargCentred + PitchTrim);
val = constrain(val, 15, 165);
val = map(val, 0, 179, 135, 45); // scale it to use it with the servo (value between 0 and 180)
servo[1].write(val); // sets the servo position according to the scaled value
//Right Elevator Joy 1 Y TxVal[4]
val = (YawTarg + YawTrim) - (PitchTargCentred + PitchTrim);
val = constrain(val, 15, 165);
val = map(val, 0, 179, 135, 45); // scale it to use it with the servo (value between 0 and 180)
servo[2].write(val); // sets the servo position according to the scaled value
//Left Flaperon
val = 90 + (RollTargCentred + Flaps) + RollTrim;
val = constrain(val, 15, 165);
val = map(val, 0, 179, 165, 15); // scale it to use it with the servo (value between 0 and 180)
servo[3].write(val); // sets the servo position according to the scaled value
//Right Flaperon
val = 90 + (RollTargCentred - Flaps) + RollTrim;
val = constrain(val, 15, 165);
val = map(val, 0, 179, 165, 15); // scale it to use it with the servo (value between 0 and 180)
servo[4].write(val); // sets the servo position according to the scaled value
//Joy 2 x nose Wheel
val = (TxVal[6] / 10);
val = map(val, 0, 179, 55, 125);
servo[5].write(val); // sets the servo position according to the scaled value
}
Hope you folks out there find this project interesting, as you can imagine I was thrilled (if that's not too nerdy) to see her fly at all crash of no crash
Log In to reply
Log In to reply
http://code.google.com/p/nextcopterplus/source/browse/#svn%2Ftrunk%2FOpenAero2%2Fsrc
Log In to reply
Log In to reply
Log In to reply
This was more of a learning engineering excise, my background is in data acquisition so I like to keep some skills in that area. Raspberry Pi, Arduino & Xbee are all over the web and so well priced. I want to build a device like an i86 or KK board that can utilize low cost radio gear and still facilitate some fancy control systems, just to see what happens.
I love the x19 Hummingbird VTOL quad/plane on this site works so well that guy is a great designer I think, maybe for my next plane ?
Log In to reply
Log In to reply
Its been a bit busy here with Christmas, and a berivement hoping to fly the new V tail variant over the break
Log In to reply