Introduction: Arduino Drone | Quadcopter (3D Printed)

About: Hi, my name is Nikodem Bartnik. I'm 19 years old. I am into designing, making, programming and electronics. In the future, I want to start a company and make my own products. As for now, you can find my work o…

Some time ago (over 8 months) I was thinking about what I can build. I wanted to make an interesting robot/device that will be challenge for me and will encourage me to learn new things. I thought about the lot of robots but a lot of them were posted on the internet. And i thought about making a drone completly by myself, including flight controller, pilot, program and frame design. This is by far the longest build i have made, it takes a lot of time and effort to make it but finaly after over 8 months it's ready and i am here to share it with you as completly open source project.

I just started my facebook fanpage!If you want to see what I am making, be up to date with my projects or need some help feel free to like it, thanks!

Here is link to video if you use an app

Info for begginers:

This project is not the simple one. You need some basic knwoledge of arduino programming, PCB's and electronics to make it. If you haven'y done anything like that before I advise you to start with something simpler like:

Arduino sensitive robot

DIY bike tachometer (speedometer)

Very Simple Robot for Beginners

But if you really want to make it, you should try, I am always here to help you.

My apel to you! :)

I am participate in contests right here on instructables. In one of them (microcontroller contest) there is macbook air as a grand prize. It could help me with calibrating PID for my drone because right now I haven't any laptop that I can go outside with so there is no way to calibrate it perfectly. I am also working on an app with my friend we want to publish it before holidays. We have a very very good idea for it and it can be very popular, I can't tell you what is it I can just tell you name of it - Socialize. We are finishing android version of this app. As you may know to make an iphone app you need t have apple computer. We haven't one and we haven't money for it :( So it will also help me with developing IOS version of our map that I will inform you about shortly. If you want to vote for my project you can do it by clicking vote! in upper right corner and then selecting contest in which you want vote for me. Thanks everyone! :D

Step 1: LUDWIK DRONE THE WINNER!!!!

For some reasons and because of my friend lukmar I named my drone Ludwik. And Ludwik took part in International robotic tournament in Rybnik in Poland and it won first place in freestyle category! I even print for this contest like this label with Ludwik dron :) Above is the photo from this contest.

Step 2: Why My Own Program, Frame, Pilot and PCB?

You can ask why do you wrote your own program for it? Why do you made custom 3D printed frame (see next steps to see why I failed with it)? And additionaly custom pilot and PCB's. Basically because I can :) I like making things on my own and learning how they works. Thanks to this type of thinking I learned a lot about quadcopters and how they works.

Code

The biggest problems I had with code for stabilizing it, it wasn't hard to write it but very hard to adjust and to get rid off some bugs. It's still not perfect but much closer to it and it works really good so far. When my code was ready I started to adjust PID regulators (here you can read something more about PID) and this was a terrible thing, I almost destroyed my room because of some really small bug in my code (for some reasons my code was decrementing int infinitely and when it reaches minimum value it goes to maximum value of int and my drone turned on motors 100% and hit wall and doors in my room). For a long time my PID regulator was adjusted very bad but every day I was closer to make it perfect. While this adjusting I broke my 3D printed frame 4 times :(

Something about 3D printed frame

At the beggining I thought that it can be very usefull to make 3d printed frame. It was really possible that I will broke it at least few times (I was right :)) but after 7 broken parts I decided to buy one, mainly because it is much stronger and rigid. I broke this frame during first flight with it :(

Pilot

Main reason is money. If you want to buy a pilot for drone you need to spend at least $50, thats quite a lot. So I build my own for like $20. And the good thing about it is that I can create as many channels as I want :)

PCB's

Because of my own code and my own pilot I have to make PCB's. I made 3 of them. The first one is power distributor for motors, second one is pilot and third one is of course flight controller. All of them use through hole componnents to make it easier to solder. In my final version I am not using power distribution board because my frame already have that.

Step 3: Quick Story

I want to write this quick story of building of this drone, if you don't wnat to read it just go to next step. I want to warn you that english is not my mother language and it's really common that there will be some mistakes, sorry for that.

I started building it in june 2016. Right now when I writing this it's March 2017 so it took me 9 months to make it. Mainly because of bad weather, rain, snow, windy days.

The first thing that I bought was motors, ESC's and battery from amazon. There is no amazon :( So I asked my uncle to buy me those parts (thanks uncle). Then I designed my 3D printed frame and print out everything. Then I started prototyping I mount aruino UNO with a breadboard on my frame connect MPU-6050 (this is gyroscope and accelerometer) and the best thing my "controller" :) which was breadboard with potentiometer connected with 5 meters long cables to arduino uno on my quadcopter :D It looked pretty funny and it wasn't very safe but it gave my posibility to test my drone fast without dealing with radio yet. I also create some kind of holder for my drone to test it at home without the possibility of destroying something including me by drone. I also made some odd experiments with this drone, fortunately, my dad takes a few photos of it so you can see it above :) (thanks dad). During those experiments, I destroyed 2 lipo batteries (to be honest I don't know when and how). By testing it and flying in bad conditions or with bugs in my code I broke 3d printed frame 7 times. After 9 months of building, breaking, experimenting it is finally ready. But it's not a final version I still want to make some improvements, and I hope that you the makers will help me in it. I share all of those as open source so you can modify it, and do whatever you want (not for commercial use) remember to mention about my project somewhere.

I hope you enjoy this quick story. Right now we can start building a drone :D

Step 4: Parts

For this project we need a lot of parts, because it is actually a little bit complicated. The overall cost of them is about $200 not so much for a drone, but it's because we create a flight controller and pilot by ourselfes. Here is complete list with links to parts that I bought from different suppliers:

  • Motors - I just bought the cheapest one, that works easily for this kind of drone.
  • ESC's - depends on motors that you choose max current of ESC should be a little bit bigger than max current of motor. It must have BEC because the flight controller is powered by it. We will also 4 of them.
  • Battery - 3S (11.1V) Li-Po should be around 3000mAh to get 15 mins of flight time. Make sure that it can deliver enough current.
  • Frame - at the beginning it was 3D printed and in the feature, it will be, but for now I used very popular F450 frame.
  • LiPo charger - you must charge lipo batteries with a special charger with a balancer. Remember to choose right power plug
  • Propellers - can be different but this one works the best. I advise you to buy some more, they are easy to break. They need to have a hole not thread. You choose some other color if you want
  • Battery protection/monitor - never connect battery to anything without it, I destroyed 2 Lipo's because I forgot about it

And here are parts for flight controller:

  • Atmega328 - I advise you to buy it in local shop
  • NRF24L01 - radio modul, we need it to create radio communication, remember to buy version with external antena because it has much bigger range
  • MPU6050 - gyroscope and accelerometer in one module
  • Some smaller parts:
    • capacitors 22pF (x2)
    • capacitor 10uF
    • resistor 4,7kOhm
    • 3,3V linear stabilizer
    • some goldpins (female and male)

The last thing is pilot:

  • NRF24L01 - radio modul, we need it to create radio communication, remember to buy version with external antena because it has much bigger range
  • Atmega328 - I advise you to buy it in local shop
  • Joysticks - 2 of them
  • Some smaller parts:
    • capacitors 22pF (x2)
    • capacitor 10uF (x2)
    • resistor 4,7kOhm
    • 3,3V linear stabilizer
    • LED diode

Step 5: Prototyping

The first thing to do was protyping, to check how everything works and if circuits are good connected. I screwed up arduino UNO to drone frame and mounted mpu6050 in breadboard which was fixed to frame with double sided tape. "Pilot" which was equal to potentiometer in breadboard wired with 5m long cables to my drone. At this point I created the world's first wire drone :) After testing, in my wooden frame, outdoor tests and some changes in connections design I created eagle schematic and then PCB. Above you can see some photos of my drone with a lot of cables on the top.

On one of those photos you can see red cable with black tape on it, guess what is this :) it's some kind of kill switch which just cut off power for arduino board.

This frame for testing a drone is made out of wood just to hold it in place and let it rotate on one axis, thats all.

Step 6: Code Explonation

Flight controller

This code isn't as hard as you can think. It just use 3 PID algorithms for stabilizng it in 3 axis (x, y, z also cold pitch, yaw and roll), code for getting angles from mpu6050's DMP (digital motion processing), and also handle radio receiving and some basic math to calculate data received by radio. It stabilize itself at 100 times a second (100Hz) that's enaugh for this drone.

PID algorithms:

There are a lot of great explonations of how PID works, and because I not a good teatcher I woldn't try to explain how it works. I use those values for PID bcause after lot's of test I find them best one, but they still can be better, Kd is much to big. I am not the PID tune expert and I have never done it on any other drone then this. For different motors, propellers, frame this value can be different. If you will find better one send them to me and I will test it on my drone.

MPU6050:

This code is just copied from MPU6050 library. I wanted to write my own, faster library for it but I couldn't find any good datasheet of it and I was to lazy :) If there is ready library which works fine (but could be faster) why not to use it?

NRF24L01

Here are just few lines to receive array of 8 bit numbers from pilot and convert it to throttle and rotation on x, y and z axis. You can also add more values and using them turn on lights on drone or anything you like.

Pilot

Code for pilot is straight forward. Just reads joystick values and send them over NRF24L01 that's all, nothing complicated. Radio speed is reduced to increase range.

Both codes you can find below.

<p>#include "I2Cdev.h"<br>#include <servo.h>
#include <spi.h>
#include "RF24.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
//we need this to see nrf24l01 configuration in serial
#include "printf.h"</spi.h></servo.h></p><p>//end of libraries ###############################################</p><p>MPU6050 mpu;</p><p>float x_rotation, y_rotation, z_rotation;
Servo motor1;
Servo motor2;
Servo motor3;
Servo motor4;
bool first_loop = true;
//radio
RF24 radio(9,10);
uint8_t data[6];
const uint64_t pipe = 0xE8E8F0F0E1LL;
long last_received;
int controll_number = 159;</p><p>//values = 5.2, 0.02, 1500
//variables for movement and positions ###########################################
//for my quadcopter this are the best settings for pid
float x_kp = 5, x_ki = 0.02, x_kd = 1100; //values for PID X axis
int max_pid = 300;
float x_p_out, x_i_out, x_d_out, x_output; //outputs for PID
float x_now, x_lasttime = 0, x_timechange;
float x_input, x_lastinput = 0, x_setpoint = 0;
float x_error, x_errorsum = 0, x_d_error, x_lasterror;</p><p>//values = 5.2, 0.02, 1500
float y_kp = 5, y_ki = 0.02, y_kd = 1100; //values for PID Y axis
float y_p_out, y_i_out, y_d_out, y_output; //outputs for PID
float y_now, y_lasttime = 0, y_timechange;
float y_input, y_lastinput = 0, y_setpoint = 0;
float y_error, y_errorsum = 0, y_d_error, y_lasterror;</p><p>float z_kp = 2, z_ki = 0, z_kd = 0; //values for PID Z axis
float z_p_out, z_i_out, z_d_out, z_output; //outputs for PID
float z_now, z_lasttime = 0, z_timechange;
float z_input, z_lastinput = 0, z_setpoint = 0;
float z_error, z_errorsum = 0, z_d_error, z_lasterror;</p><p>//set it to 0 and see on serial port what is the value for x and y rotation, use only if your flightcontroller board is not perfevtly leveled. If your board is perfectly leveled set it to 0
float x_level_error = 0;
float y_level_error = 0;</p><p>/*
 * 
 * 
 * JUNE 2016 - APRIL 2017
 * C by Nikodem Bartnik
 * nikodem.bartnik@gmail.com
 * nikodembartnik.pl
 * 
 * 
 * 
 */</p><p>#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
int motor1_power;
int motor2_power;
int motor3_power;
int motor4_power;</p><p>float allmotors_power = 600;</p><p>// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer</p><p>// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container</p><p>VectorFloat gravity;    // [x, y, z]            gravity vector</p><p>float rotation[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
int safe_lock = 1;</p><p>volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}</p><p>void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif</p><p>printf_begin();</p><p>    Serial.begin(115200);</p><p>    Serial.println("Initializing I2C devices...");
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);</p><p>    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
//    bmp.begin();  
    radio.begin();
    delay(1000);
    radio.setDataRate(RF24_250KBPS);
    radio.setPALevel(RF24_PA_MAX);</p><p>    radio.openReadingPipe(1,pipe);
    radio.startListening();
    
   </p><p>    // load and configure the DMP
    Serial.println("Initializing DMP...");
    devStatus = mpu.dmpInitialize();</p><p>    // gyro offsets here
    mpu.setXGyroOffset(87);
    mpu.setYGyroOffset(77);
    mpu.setZGyroOffset(110);
    mpu.setZAccelOffset(2287); 
    mpu.setYAccelOffset(-1283);
    mpu.setXAccelOffset(-3083);</p><p>    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {</p><p>        Serial.println("Enabling DMP...");
        mpu.setDMPEnabled(true);</p><p>        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();</p><p>      
        dmpReady = true;</p><p>        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print("DMP Initialization failed (code ");
        Serial.print(devStatus);
        Serial.println(")");
    }</p><p>    motor1.attach(5);
    motor2.attach(8);
    motor3.attach(7);
    motor4.attach(4);
    pinMode(A0, INPUT);
    pinMode(A1, INPUT);
    digitalWrite(A0, LOW);
    motor1.write(0);
    motor2.write(0);
    motor3.write(0);
    motor4.write(0);</p><p>radio.printDetails();
}</p><p>void loop() {</p><p>    if (radio.available()) {
    
    bool done = false;
    while (!done){
     
     done = radio.read(data, sizeof(data));</p><p>    // Serial.print("Controll number: ");
     //Serial.println(data[0]);
     
      if((millis()-last_received) < 3000){
        if(data[0] == controll_number){
          Serial.print("DATA1: ");
          Serial.println(data[1]);
          allmotors_power = map(data[1], 0, 255, 800, 1500);
          if(allmotors_power < 0){
            allmotors_power = 0;
          }</p><p>          
     //allmotors_power = map(data[1], 0, 255, 800, 1600);
     x_setpoint = data[3] - 20;
     y_setpoint = data[2] - 20;
     Serial.print("PID OUT X: ");
     Serial.print(x_rotation);
     Serial.print(" PID OUT Y: ");
     Serial.print(y_rotation);
     Serial.print("Z NOW: ");
     Serial.println(z_rotation);
     Serial.print(" TIME: ");
     Serial.println(millis());</p><p>Serial.print("MOTORS POWER: ");
Serial.println(allmotors_power);
  
     
        }
     }
     // Serial.println(data[1]);
      if(done == true){
      last_received = millis();
      }
  }   
 }</p><p> if((millis()-last_received) > 3000 && allmotors_power > 0){
    safe_lock = 0;
     }
 
    // if programming failed, don't try to do anything
   // if (!dmpReady) return;</p><p>   
    while (!mpuInterrupt && fifoCount < packetSize) {
     
    }</p><p>    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();</p><p>    // get current FIFO count
    fifoCount = mpu.getFIFOCount();</p><p>    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
       </p><p>    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();</p><p>        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;</p><p>    if(safe_lock == 1){
   
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(rotation, &q, &gravity);</p><p>          x_rotation = rotation[1] * 180/M_PI - x_level_error;
            y_rotation = rotation[2] * 180/M_PI - y_level_error;
            z_rotation = rotation[0] * 180/M_PI;</p><p>/*
          if(pressure_loop_number == 10){
           // Serial.print("Preasure: ");
            //Serial.println(bmp.readAltitude());
            pressure_loop_number = 0; 
            allmotors_power = 1000;
           }
            pressure_loop_number++;  
*/</p><p>           if(first_loop == true){
            z_setpoint = z_rotation;
          //  current_altitude = bmp.readAltitude();
            //set_altitude = current_altitude;
            first_loop = false;
           }
          
            
            
        motor1_power = allmotors_power;
        motor2_power = allmotors_power;
        motor3_power = allmotors_power;
        motor4_power = allmotors_power;
          if(allmotors_power > 1500){
               allmotors_power = 1500;
                
                
                }</p><p>                 
                 x_output = calculatePID(0, x_rotation);
                 y_output = calculatePID(1, y_rotation);
                 z_output = calculatePID(2, z_rotation);</p><p>                 motor1_power += x_output/2;
                 motor1_power += z_output;
                 motor4_power -= x_output/2;
                 motor4_power += z_output;</p><p>                 motor2_power -= y_output/2;
                 motor2_power -= z_output;
                 motor3_power += y_output/2;
                 motor3_power -= z_output;
                 
             
                motor1.writeMicroseconds(motor1_power);
                motor4.writeMicroseconds(motor4_power); 
                motor2.writeMicroseconds(motor2_power);
                motor3.writeMicroseconds(motor3_power); 
                mpu.resetFIFO();
               
     
    }else{
                motor1.write(0);
                motor2.write(0);
                motor3.write(0);
                motor4.write(0);
    }
}
}</p><p>   float calculatePID(int _axis, float _angel){</p><p>      // X AXIS
      if(_axis == 0){
                 x_now = millis();
                 x_timechange = x_now - x_lasttime;
                 x_error = x_setpoint - _angel;
                 x_p_out = (x_kp * x_error);
                
                 x_errorsum = (x_errorsum + x_error);
                 if(x_errorsum > 1023){
                  x_errorsum = 1023;
                 }
                 if(x_errorsum < -1023){
                  x_errorsum = -1023;
                 }
                 x_i_out = x_ki * x_errorsum;
                 x_d_error = (x_error - x_lasterror) / x_timechange;
                 x_d_out = x_kd * x_d_error;
                 x_lasterror = x_error;
                 x_output = x_p_out + x_i_out + x_d_out;
                 if(x_output > max_pid){
                  x_output = max_pid;
                 }else if(x_output < -(max_pid)){
                  x_output = -(max_pid);
                 }
                 x_lasttime = millis();
                 return x_output;
      }</p><p>      // Y AXIS
      else if(_axis == 1){
                 y_now = millis();
                 y_timechange = y_now - y_lasttime;
                 y_error = y_setpoint - _angel;
                 y_p_out = (y_kp * y_error);</p><p>                 y_errorsum = (y_errorsum + y_error) * y_timechange;
                 if(y_errorsum > 1023){
                  y_errorsum = 1023;
                 }
                 if(y_errorsum < -1023){
                  y_errorsum = -1023;
                 }
                 y_i_out = y_ki * y_errorsum;
                 y_d_error = (y_error - y_lasterror) / y_timechange;
                 y_d_out = y_kd * y_d_error;
                 y_lasterror = y_error;
                 y_output = y_p_out + y_i_out + y_d_out;
                 if(y_output > max_pid){
                  y_output = max_pid;
                 }else if(y_output < -(max_pid)){
                  y_output = -(max_pid);
                 }
                 y_lasttime = millis();
                 return y_output;</p><p>                 // ALTITUDE
     // } else if(_axis == 2){
      //           return (set_altitude - current_altitude) * 20;
      }else if(_axis == 2){
                 z_now = millis();
                 z_timechange = z_now - z_lasttime;
                 z_error = z_setpoint - _angel;
                 z_p_out = (z_kp * z_error);</p><p>                 z_errorsum = (z_errorsum + z_error) * z_timechange;
                 if(z_errorsum > 1023){
                  z_errorsum = 1023;
                 }
                 if(z_errorsum < -1023){
                  z_errorsum = -1023;
                 }
                 z_i_out = z_ki * z_errorsum;
                 z_d_error = (z_error - z_lasterror) / z_timechange;
                 z_d_out = z_kd * y_d_error;
                 z_lasterror = y_error;
                 z_output = z_p_out + z_i_out + z_d_out;
                 if(z_output > max_pid){
                  z_output = max_pid;
                 }else if(z_output < -(max_pid)){
                  z_output = -(max_pid);
                 }
                 z_lasttime = millis();
                 return z_output;</p><p>                 // ALTITUDE
     // } else if(_axis == 2){
      //           return (set_altitude - current_altitude) * 20;
      }else{
        return 0;
      }</p><p>      
      
    }</p>
<p>/*</p><p> * 
 * 
 * JUNE 2016 - APRIL 2017
 * C by Nikodem Bartnik
 * nikodem.bartnik@gmail.com
 * nikodembartnik.pl
 * 
 * 
 * 
 */</p><p>#include <spi.h><br>#include "RF24.h"</spi.h></p><p>#define MAX_TILT 20</p><p>RF24 radio(9,10);</p><p>int a = 0;
uint8_t data[6];
int controll_number = 159;
int safe_lock = 0;
int x_offset, y_offset;</p><p>const uint64_t pipe = 0xE8E8F0F0E1LL;</p><p>void setup(void){
  
  Serial.begin(57600);</p><p> pinMode(4, OUTPUT);
 pinMode(3, INPUT);
 pinMode(A0, INPUT);
 pinMode(A1, INPUT);
 pinMode(A2, INPUT);
 pinMode(A3, INPUT);
 digitalWrite(3, HIGH);
 digitalWrite(4, HIGH);</p><p>  radio.begin();</p><p>radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_MAX);</p><p>    radio.openWritingPipe(pipe);
  radio.printDetails();</p><p>}</p><p>void loop(void)
{
  if(!digitalRead(3)){
    Serial.print("LOW 1");
    delay(1000);
    if(!digitalRead(3)){
      Serial.print("LOW 2");
    delay(1000);
    if(!digitalRead(3)){
      Serial.print("LOW 3");
      if(safe_lock == 0){
        safe_lock = 1;
      }else{
        safe_lock = 0;
      }
    
  }
  }
  }</p><p>int power = map(analogRead(A2), 0, 1023, 0, 255);
int x = map(analogRead(A1), 0, 1023, 0, 255);
int y = map(analogRead(A0), 0, 1023, 0, 255);
int rotation = map(analogRead(A3), 0, 1023, 0, 255);</p><p>if(x > 150){
  x = map(x, 150, 255, 0, MAX_TILT);
}else if(x < 105){
  x = map(x, 105, 0, 0, -MAX_TILT);
}else{
  x = 0;
}</p><p>if(y > 150){
  y = map(y, 150, 255, 0, MAX_TILT);
}else if(y < 105){
  y = map(y, 105, 0, 0, -MAX_TILT);
}else{
  y = 0;
}</p><p>if(rotation > 150){
  rotation = map(rotation, 150, 255, 0, MAX_TILT);
}else if(rotation < 105){
  rotation = map(rotation, 105, 0, 0, -MAX_TILT);
}else{
  rotation = 0;
}</p><p>  data[0] = controll_number;
  data[1] = power;</p><p>  // + 10 because you can't send negative number
  data[2] = x + MAX_TILT;
  data[3] = y + MAX_TILT;
  data[4] = rotation + MAX_TILT;
  data[5] = safe_lock;</p><p>radio.write( data, sizeof(data) );</p><p> delay(8);
}</p>

Step 7: Flight Controller PCB (and Power Distribution)

Right there you can find all files including .brd, .sch and .pdf for printing. And some photos of how I made them. Traces are very small so the board is not so easy to make. There are not a lot to write about so just enjoy the photos and files :)

How to make PCB's

I also made a power distribution board and it was used on 3D printed version of my drone, but right now I am not using it since frame that I bought have power distribution board build in to the frame.

Step 8: Pilot

Quick story of pilot. The first version of it was potentiometer on a breadboard as I mentioned earlier. It was connected to drone with 5 meters long cables. Then I build real wireless pilot on breadboard with arduino pro mini, two joysticks and battery. Work's great but this mess with cables are so bad. So while I was waiting for my frame I decided to design and make PCB for it. And thats the final version, max size of PCB in free eagle version to make it more handy. Looks pretty good, works perfectly. I added right there 2 switches for eventual light switching or maybe even some kind of thrower :) Schematic, PCB and program for it you can find in previous steps.

Step 9: Failed 3D Printed Frame

This is my 3D printed frame for my drone it's bad, don't print it. I just put it right there to show you how I made it, how it looks like and how you shouldn't design a frame for a drone. Printing time all parts for this frame is about 13 hours. I broke 7 part of it and after that I decided to give up at this point with this frame and buy one. I prefered to focus on my program and then when I finish it completly I will design comletly new frame, that will be stronger and smaller (this one is actually a little to big).

To design all of those parts I used fusion360 in my opinion the best 3D designing software. You can check it out here. I also recommend you to watch fusion360's youtube channel there are a lot of great tutorials, updates and usefull tips.

I also broke down 2 Li-Po batteries :(

Step 10: Some Usefull 3D Prints

Because some parts that were 3D printed are usefull I put .stl files here if you like to print them out. There is just antena holder for flight controller (you need to drill new hole in PCB just don't drill through traces) and holder for PCB of flight controller. I put a small like sponge under this holder to limit vibrations and srcew it down with M3 screws.

Step 11: Assembly

There are some photos and quick explonation of how to assemble all parts of drone. First of all you have to assemble the frame, there are 4 arms and 2 main plates it's very simple. After that you can mount your brushless motor on frame. Use 4 short screws to mount them on the arms (screws can't be too long because they can damage colis of the motor). Then you can solder ESC to the motor. Remember that left front motor and rear right must be soldered in the same way. Right front and rear left must be connected in the same way but you have to swap 2 phases of motor. I mount ESC to frame with zip tie. Remember to tight propellers very strongly, it is very usefull to use tiny screwdriver for it.

Step 12: Testing and Upgrades

I spent most time of making it on this stage. It was endless code changing, testing, code changing testing and so on. Above you can see some photos of it. One time when I test stabilization and I added piece of code to decrement throttle continously to make it landing softly after radio disconnection (right now I know that it is impossible without barometer or GPS). I forgot to add in this code protection at some level to don't let the number infinitly down. And what happens when number go infinitly down? At some point in to goes from max minus to max plus and then my drone has turned their motors with full throttle it goes up with this frame hit my door and wall and fall. I was on the opposit side. It was so close to hit me. And that's the reason that I wear ski helmet during rest of tests :)

Step 13: First Really Successful Flight

There were a lot of problems during this build some of them because of my errors some of them no. One time I forgot to add minus on the y axis and my drone instead of stabilize itself, was doing exactly opposite thing. But after a lot of troubles, I achieved first succesful flight, 10 perfect seonds of flying :) just up and down but it was stable and that's what I wanted to have. Above you can see video from one of the firsts flights (with 3D printed frame) and this was the first time that I thought that maybe it will finaly work. And then winter came it was snowing, it was cold and wet. I spend most time at home doing other things than drone. I was skiing and drone was waiting for better weather. At February 2017 I started working on it again I changed a program a little bit and do more test. It was better and better every test.And after some time I achieved this what you can see right now. It's not perfect but it's very good and the most important thing it's mine! There are still things to do to make it better, the most important one is calibrating PID for roll and pitch but there is no way for me to do it right now, I haven't laptop, but I need one to go outside with it and with drone and calibrate it by changing PID constants slightly, uploading program, testing and repeat as long as it will hover perfectly. Because I haven't a laptop I can't do this :(

And here is my request to you

If you like my project and want to help me, vote for me in contests (in microcontroller contest the prize is macbook air which could help my with fine-tuning this project). Thanks!

Step 14: The Final Version (0.1) and What's Next

So as I said this is the (not) final version. For now I will finish this build (Last thing to do is PID calibrating). I just want to go for some other builds and learning new things. But if you want you can help me with this project, we can work together on it to make the best, the simplest arduino drone that anyone can make. If you have build my project send me some photos of it on ma mail (nikodem.bartnik@gmail.com) or in the comments bellow.

If you have any questions just ask in the comments, on my mail or on my new facebook fanpage! I am here to help you. You can also write what you think about this project or how to improve it.

Thanks for reading don't forget to follow me on instructables, on facebook and on youtube.

Have a nice day everyone!

Microcontroller Contest 2017

First Prize in the
Microcontroller Contest 2017

Design Now: In Motion Contest

Third Prize in the
Design Now: In Motion Contest

Robotics Contest 2017

First Prize in the
Robotics Contest 2017