Introduction: Intro to Model Airplane Autopilot!!!
I am twenty years old. I picked up my arduino for the first time this Christmas, and I've been keeping busy on my arduino applications so that I can bring you this instructable. I hope that it helps!!!
The purpose of this project was to build a stepping stone from remote controlled flight to completely autonomous flight. This initially seemed like a daunting process, but by breaking it up it becomes manageable. I think that if you have completed any kind of autonomous robot, and you have access to an RC airplane, you are in good position to take on autonomous flight. If you haven't done so already I would HIGHLY recommend visiting the site http://diydrones.com. There are TONS of relevant threads with many helpful members. Plus, plenty of inspiration. If you'd like, please look me up; my username is waymond91.
You can buy a complete platform for developing your own autonomous flyer as well as download a complete code!!!
However, as is with many instructables members, funds are limiting, and there is limitless satisfaction trying to build it yourself from the ground up...
I had two primary objectives when beginning this project:
1) Achieve sustained level flight using our autopilot program
2) Ability to switch between radio controlled and arduino controlled flight
I strongly recommend that you already have some experience flying RC airplanes, otherwise you should look for your own plane and get some stick time. I will not be covering how to construct your own airplane, I am trying to focus on the autopilot. Maybe try and retrofit a plane you already have/
You will be at a great advantage if you already are familiar with:
The arduino programing environment (I have fun using my ubuntu terminal to download and explore new arduino libraries)
The arduino servo library
The arduino wiring library (for I2C communication - if needed)
Basic understanding of arrays and pointers
If these things are new to you, I hope my instructable is helpful. You should be able to figure it out anyways. There are lots of supplemental sites with great info!! You may want to consider trying a PING robot or a line follower :)
Otherwise plow on ahead!
We will be learning:
How to clean and interpret data using PID loops and cascading PID loops.
All of the videos in this instructable are found in hyperlinks, I am sorry I couldn't get the embedding to work :(
Here is one of my first tests, as you can see, we still have some jittering to deal with:
Step 1: Sensors
We are using two sensors to help control our airplane: an accelerometer to determine the planes angular position, and a gyroscope to determine the planes angular velocity.
These are standard sensors when trying to construct your own IMU (inertial measurement unit). I used ossep brand sensors based off the ADXL345 accelerometer, and MPU 3050 gyroscope. http://osepp.com/learning-centre/start-here/gyroscope-sensor-module/ & http://osepp.com/learning-centre/start-here/accelerometer-sensor-module/
The Pros of using these sensors:
Available at Frys
Code available online
I2C protocol makes wiring easy
Headers are bigger than the actual circuit
Electric motor easily induces noise on the sensor/wires (may not be due to this specific brand)
Converting outputs to proper units took me a while
I will go over how to clean up sensor values a little later.
I do not think you should have to use I2C protocol to get this plane off the ground, it is just what was available to me at the time. There are lots of other good IMU units available online. Check Sparkfun!!
don't forget adafruit
While I am adding links... I have only tried the diavolino with some success but these small arduino compatibles look like they'd fit in a model plane nicely.
Step 2: Control Method: Proportional Integral Derrivative Control
When our autopilot is running, it will sense the angular attitude of the plane and the desired attitude. The difference between the desired and the actual is called the error. We will then change our servo output angles, to change our control surface angles (ailerons and elevator) to correct the error. The problem becomes, how do we relate our sensor input to our servo outputs?
The solution: A PID controller.
A PID controller uses three terms to calculate an output that should correct the error.
output = (kp*error)+(ki*errorSum)+(kd*dError);
The first term (the proportional term) looks at our current inputs (pitch & roll in our case) and compares it to the desired position aka setpoint (0 degrees for level flight). The calculated error (difference) is multiplied by a constant (KP) to contain the value within our output range (0 to 180 deg is servo range, but it is typically smaller once installed in an RC aircraft). Basically, the greater the error, the greater the necessary change.
The second term is the integral term. It sums all previous error (as captured by the proportional term) over time. If the error remains uncorrected for too long, the integral term grows larger thus increasing the magnitude of our output until the correction is made. Again, multiply it by you constant (KI) to contain the term within the output range *WARNING* It is possible that if you collect errors for too long the integral term will exceed your output capability. This is called INTEGRAL WINDUP. This took me a long time to fix. I was able to minimize the term by limiting the scope of time through which I viewed my error. In order to keep the first two terms from overcorrecting our error we must look to the third term.
The derivative term (dError) looks at the rate that your sensor inputs are approaching your setpoint in order to project when the error will be corrected. The derivative term can be used to slow down the output if it is correcting too fast and is likely to overshoot the setpoint. Multiply it by the constant KD to keep the output within the possible range.
The PID is a very powerful feedback controller (i.e. it uses past outputs and inputs to calculate the new output). It will greatly benefit you to do some outside reading if you have not used them before. Actually, the wikipedia page does a very good job of explaining the concepts involved. If you know calculus, the PID can become very intuitive tool. http://en.wikipedia.org/wiki/PID_controller#Control_loop_basics
Once you understand how it works, please look at the structure section on the feedforward control loop.
Step 3: Demo PID Controller
Eflite Outrunner Motor
35 Amp ESC
11.1 V LiPo battery
An old saw horse for a stand
The controller looks at the angle the arm is hanging at using our accelerometer and gyroscope, and uses that data to determine how much current to throw the motor in order to make the arm level.
Because the ESC is used to plug your motor into a radio reciever bus designed for servos, it is relatively easy to control a brushless AC motor with an ESC on an Arduino thanks to the Servo.h + Servo.cpp in your libraries folder. I believe the servo protocol uses pulse position modulation (PPM) which can be achieved using a PWM pin on your arduino with servo.write() function.
It is important to be saftey conscious when running these motors, as they go extremely fast. *ALWAYS wear saftey glasses* *Leave the propeller OFF until you absolutely need it*
You will have to write a function to arm(); your ESC so that you can set its speed. Basically you need to write the ESC low, high, and then low again.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226292633 This forum goes over how to control a brushless motor, and is where I got framework for my arm(); function and setSpeed (); function.
You could just use a servo.write(0-180) to set your speed on your esc, but you can also map it on a scale of 0-100. You can download the motor_functions at the bottom of the step. If it doesn't work please tell me!! I can simply add it into the instructions!!
Using these functions gives you full motor control. You will have to fidget with your own code for your particular ESC. By declaring our sensor functions independently from the loop we can now run the motor and sensors at the same time. This is where I hit my first major setback. Because the motor draws so much current from the battery, it was inducing currents in my I2C bus. My sensor would work fine when the motor was off, but when the motor was running the values were pretty much meaningless.
I took the following steps to clean up the noise:
I added a ferrite ring to the esc (retrospectively, this probably just protects the ESC from noise- learned to use these after my Zagi crashed http://www.hobbyking.com/hobbyking/store/__23206__Clip_On_Soft_Ferrite_Rings_5pc_.html)
I mounted the sensors as far away as possible from the motor
Twisted all my wires to try and minimize current induction
I found these websites to help deal with my problem:
http://diydrones.com/forum/topics/pid-controller-i2c-bus-noise-from-esc?xg_source=activity //this is a thread I started on DIY drones
This seemed minimize sensor error, but still about 5 out of every 20 values were off by +-10 degrees. To clean this up I mediated the sensor values by:
Building an aray to hold 20 values as they appeared chronologically
Building an array that held the last 20 values sorted in (ascending or descending order; it doesn't matter because we are looking for the median)
I used a bubble sort to help sort my values
I found this website to help explain how to sort array efficiently:
You will have to construct multiples of these sorting functions for multiple values (x, y, z; dx, dy, dz)
My bubble sort and median functions can be downloaded at the bottom of the step!
Now that your sensors values are congruent and you have control over your AC motor, we can begin actual PID control!
The wikipedia page does a good job explaining how your program should be structured using psuedocode. There are many, many ways to implement this. It depends on how long you want to use your feedback for you integral and derrivative terms.
you can find my PID_sample at the bottom of this step!!
Tuning the PID: There are many ways to tune a PID. You can by software, guess and check, I'd try using the Zieger Nichols method.
Any way, you start by only running your output with the proportional error. set KP so that the proportional term never exceeds output capacity. Basically, the system will oscillate, you want it to dampen around your setpoint (or at the very least not increase over time!). Once you have found an appropriate KP you can either set KD or KI. Different people say different things when it comes to which one to do first, but integral term will accelerate an undercorrection toward the setpoint while the derrivative term will slow down an overcorrection.
After playing with the code for a while it should become apparent how adaptive this type of controller is to your particular system. Remember, try and feedforward as much as you know how to! Once you are comfortable go ahead and install the controller!!
Step 4: Setting Up the Plane
For initial testing I used a glider, so there would be no possibility of motor interference. Once level flight is achieved I have a Zagi ready to go and a multiplex Twin Star for possible drones.
I added the system to my Swift AT (Aileron Trainer). I really like this glider. Doesn't take too much wind to fly and is capable of a variety of manuevers. Flying with a glider is great if you got the wind, you can fly for hours (no motor/ engine no need to come down and refuel).
Our new board set up will be very similar to our orignial PID; we will be running two PID loops back forth very quickly to control pitch and roll with the elevator and ailerons. This should allow ample testing time in good wind.
I am using Airtronics radio equipment with a 6 channel transmitter/receiver. I used the fifth channel on the radio (a landing gear toggle) to set the autopilot on & off from the transmitter. Connect to a servo wire from the receiver and connect it to a digital input to measure the the pulse length of the two positions (toggle on/toggle off). Use the pulseIn() function to do so. Once you have a value from the two states pick one to indicate off and one for on. When the arduino reads and ON signal it should send out a digital HIGH to flip a relays or trigger some transistors. I used relays because I did not want my signal passing through a transistor (a descision I would later regret).
You can see the schematics I drew for wiring up a circuit that would throw one servo from the radio to the arduino. There are two: one for transistors and one for a radio. Note the positon of PNP and NPN transistors. When the arduino output wire is low the servo signal defaults to the radio, when it is written high it switches to the board. Likewise, on the relay circuit, the normally closed terminal is connected to the radio, and the normally open to the arduino.
you can find my functions for for the autopilot_engage at the bottom of this step
Here is a video showing the arduino receiving radio input and throwing an led, later used to arm the autopilot:
Step 5: Here Is My Code and My Schematic!
The code starts us off by navigating with only proportional error. You will have to fill in your own KP KI KD after some trial and error.
Make sure your plane is balanced before you take off! Engage the autopilot before throwing your plane and check that the throws are oriented to the correct direction.
The fallback function (at the end of the code) is used to throw the control back to the reciever. make sure you include this function at your sensor errors, or anywhere else you could get caught in a loop and you may want control back from the autopilot!
Download the code below
Step 6: Success & Failure
Plane self corrects when running autopilot *more trials pending favorable winds*
Switching capability between radio and arduino
Use of PID control can easily be tuned to stabalize a system
Arduino Fio did not really have enough juice to run the sensors and switch my 5v relays (FIo operates on 3.3v)
Possible remedies = different arduino (perhaps the nano?) or use transistors **RESULTS PENDING**
Gyroscope data not yet in use
Possible remedies = stop typing up the project and go figure it out :P
Step 7: Future Development
The next step in my little adventure will involve:
controlling a powered plane (we already have shown we can control all of the individual systems)
Using a GPS to monitor the planes position and altitude (hopefully to be obtained from this contest!!!)
Developing cascading PIDs: one PID to calculate the necessary angle needed to reach a waypoint (GPS location) and another to set the plane to that attitude so that it can reach those waypoints.
Thank you for checking out my instructable! If you have any feedback, questions or comments please let me know!!! If you would like to continue to see the transition between RC flight and autonomous flight, please upvote and provide feedback. I am trying to place in the robotics competition and with any luck we'll have a new GPS from one of the prizes ;) I am doing everything I can to make this switch as manageable and as visible as possible so the process does not become overwhelming to take on by yourself.