Professional Documents
Culture Documents
Date: Date:
Date:
DRONE USING ARDUINO
MICROCONTROLLER
A Project Report
Submitted in partial fulfillment of the
Requirements for the award of the Degree of
Vikram Roy
(Seat Number: )
CERTIFICATE
This is to certify that the project entitled “DRONE USING ARDUINO MICROCONTROLLER”
is bonafied work of Vikram Roy bearing Seat No:
submitted in partial fulfillment of the requirements for the award of Degree of BACHELOR OF
SCIENCE in INFORMATION TECHNOLOGY from University of Mumbai
External Examiner
The goal is best achieved by treading the path of excellence with discipline and deep
insight. We would have never succeeded in completing our task without the cooperation,
encouragement and help provided to us by various teachers and guides.
With deep sense of gratitude, we express our sincere thanks to our esteemed and worthy
guide, Mrs. Awantika Deshpande, for her valuable guidance in carrying out this project under
his/her effective supervision, encouragement, enlightenment and cooperation.
We feel indebted to express our deep sense of gratitude towards Mrs. Vandana Sharma
(Principal), Mrs. Vanita Sabharwal (HOD Information Technology) and Mrs. Awantika
Deshpande (Project Coordinator) who have been a constant source of inspiration for us throughout
this project.
We would also like to thank all faculty members and non-teaching staff for their kind
support without vacillation.
The acknowledgement would be incomplete if we do not mention the emotional support
and blessings provided by our parents and friends. We had a pleasant enjoyable and fruitful
company with them. Last but not the least we would like to thank all the people who directly or
indirectly helped us in this project.
DECLARATION
I hereby declare that the project entitled, “DRONE USING ARDUINO
MICROCONTROLLER” done at Department Of Information & Technology, Dnyan Ganga
Education Trust’s Degree College Of Arts, Commerce, & Science, University Of Mumbai in
partial fulfillment of the requirements for the award of degree of BACHELOR OF SCIENCE
(INFORMATION TECHNOLOGY) is a record of original dissertation work done by me, under
the guidance and supervision of Mrs. Awantika Deshpande, and it has not formed the basis for the
award of any Degree/Diploma/Associate ship/ Fellowship or other similar title to any candidate of
any University.
Signature of Candidate
Date:
TABLE OF CONTENT
Chapter 1: Introduction .......................................................................................................... 1
1.1 Backgrounds .................................................................................................................... 1
1.2 Objectives ......................................................................................................................... 2
1.3 Purpose, Scope, and Applicability .................................................................................2
1.3.1 Purpose ........................................................................................................................2
1.3.2 Scope ............................................................................................................................2
1.3.3 Applicability ................................................................................................................ 3
1.3.4 Achievement ............................................................................................................... 3
Chapter 2: Survey of Technologies ....................................................................................... 4
2.1 Existing system ............................................................................................................... 4
2.2 Purpose System .............................................................................................................. 4
2.3 Requirements Specification .......................................................................................... 4
2.4 Hardware Requirements ............................................................................................... 5
2.5 Software Requirements ................................................................................................. 5
2.6 Justification of selection of Technology ...................................................................... 5
2.6.1 Arduino unoR3… ...................................................................................................... 5
2.6.2 MPU 6050….............................................................................................................. 10
2.6.3 Camera Module OV6770 .......................................................................................... 11
2.6.4 Micro SD card Reader Module .................................................................................. 13
2.6.5 Transmitter and Receiver ...........................................................................................14
2.6.6 A2212/10T 1400KV BLDC Motors .......................................................................... 17
2.6.7 ESC’s (Electronic Speed Controller) ......................................................................... 18
2.6.8 Frame ............................................................................................................................. 19
2.6.9 Propellers ................................................................................................................... 20
2.6.10 Battery......................................................................................................................21
2.6.11 Battery charger ........................................................................................................ 22
2.6.12 Some Small Components .......................................................................................... 23
2.6.13 Arduino IDE ............................................................................................................ 24
2.6.14 C++ ......................................................................................................................... 25
2.6.15 MS excel… .............................................................................................................. 26
Chapter 3: System design......................................................................................................28
3.1 Module Division ............................................................................................................. 28
3.2 Entity Relationship Diagram ....................................................................................... 30
3.3 Work Flow Diagram ...................................................................................................... 31
3.4 Data Flow Diagram ....................................................................................................... 32
3.5 Class Diagram ................................................................................................................ 33
3.6 Component Diagram ..................................................................................................... 34
3.7 Deployment Diagram ....................................................................................................35
3.8 User Interface Design ................................................................................................... 36
3.9 Schematics Diagram ......................................................................................................37
Chapter 4: Implementation and Testing… ......................................................................... 38
4.1 Coding ............................................................................................................................ 38
4.2 Testing Approach .......................................................................................................... 98
4.2.1 Units Testing…......................................................................................................... 98
4.2.2 Integrated Testing… ................................................................................................ 100
Chapter 5: Result and Discussion ...................................................................................... 101
5.1 Test Reports ................................................................................................................. 101
5.2 User Documentation .................................................................................................... 101
5.2.1 Screen short .............................................................................................................102
Chapter 6: Conclusions ....................................................................................................... 106
6.1 Conclusion .................................................................................................................... 106
6.2 Limitation of the System ............................................................................................. 106
6.4 Future Scope ................................................................................................................ 106
Chapter 7: Bibliography… ................................................................................................. 107
LIST OF TABLES
Table 1. Arduino Summary ...................................................................................................... 6
Table 2. MPU 6050Pin configuration ..................................................................................... 11
Table 3. Units Testing…......................................................................................................... 98
LIST OF FIGURES
Fig 1. Arduino Uno R3 ............................................................................................................. 7
Fig 2. MPU 6050 ....................................................................................................................... 10
Fig 3. OV7670 Camera Module ................................................................................................12
Fig 4 Micro SD Card Reader Module. ..................................................................................... 13
Fig 5. Fly sky CT6B 6 Channel Transmitter ................................................................................ 16
Fig 6. FS-R6B Receiver ............................................................................................................ 17
Fig 7. 2212/10T 1400kv BLDC Motors .................................................................................... 18
Fig 8. 30A Electronic Speed Controller ....................................................................................... 19
Fig 9. Frame ............................................................................................................................. 20
Fig 10. Propellers ...................................................................................................................... 21
Fig 11. LiPo battery ................................................................................................................... 22
Fig 12. Imax B3PRO Charger .................................................................................................... 23
Fig 13. Diode and Registers ....................................................................................................... 24
Fig 14. Arduino IDE ...................................................................................................................... 24
Fig 15. C++ ..............................................................................................................................25
Fig 16. Basic Modules ........................................................................................................... 28
Fig 17. Entity Relationship Diagram ......................................................................................... 30
Fig 18. Work Flow Diagram ..................................................................................................... 31
Fig 19. Data Flow Diagram ....................................................................................................... 32
Fig 20. Class Diagram ............................................................................................................... 33
Fig 21. Component Diagram ...................................................................................................... 34
Fig 22. Deployment Diagram .................................................................................................... 35
Fig 23. User Interface Diagram ................................................................................................. 36
Fig 24. Schematics Diagram for Drone .................................................................................. 37
Fig 25. Schematics Diagram for Camera .....................................................................................37
Fig 26. Drone Setup coding and Uploading ........................................................................ 102
Fig 27. Calibration of Setup Code with Transmitter .............................................................102
Fig 28. Searching For MPU-6050 ......................................................................................... 103
Fig 29. Calibrating PID with the help of Gyroscope ............................................................. 103
Fig 30. Esc’s Calibrating coding and uploading .................................................................. 104
Fig 31. Flight Controller Code for Drone ............................................................................. 104
Fig 32. Connection to Arduino .............................................................................................105
Fig 33. Drone ........................................................................................................................ 105
CHAPTER 1
INTRODUCTION
1.1 Background
In this modern age of technology, quadcopter has become one of the most popular inventions
in the field of science. A quadcopter is also known as UAV (Unmanned Aerial Vehicle) uses four
Propellers for lift and stabilization.
Research and development of Unmanned Aerial Vehicle (UAV) and Micro Aerial Vehicles
(MAV) are getting high encouragement nowadays, since the application of UAV and MAV can apply
to variety of area such as rescue mission, military, film making, agriculture and others. In U.S. Coast
Guard maritime search and rescue mission, UAV that attached with infrared cameras assist the mission
to search the target.
Quadcopter or quad rotor aircraft is one of the UAV that are major focuses of active researches
in recent years. Compare to terrestrial mobile robot that often possible to limit the model to kinematics,
Quadcopter required dynamics in order to account for gravity effect and aerodynamic forces.
Quadcopter operated by thrust that produce by four motors that attached to it body. It has four input
force and six output states, and it is an under-actuated system, since this enable Quadcopter to carry
more load
Recreational use is increasing as well, a small remote-controlled quadcopter can be bought to
flight in our living room or garden. There is no physical contact between the surroundings and the
quadcopter and no coordination between the quadcopter. It would have the capabilities to collaborate
the number of possibilities grows even further. For example, a group of Drone would be able to
efficiently and autonomously search a missing person in a large area by sharing data between. Or, the
combined load capacity of a group of quadcopters can be used to deliver medicine in remote areas.
This bachelor thesis focuses on the use of a commercially available quadcopter platform.
Drone, to perform a task that requires physical collaboration and interaction: moving a mass. In this
way a clear interaction between the quadcopters and their surroundings is present. As preliminary step
towards the view of collaborating aerial robots the choice was made to perform this task in an indoor
scenario where position feedback is present. Starting off with position control, additional controller
logic can be implemented to counteract the forces imposed by a mass connected to the quadcopter. The
choice is made for the Drone, a generalized approach is chosen where possible to encourage reuse of
this research’s outcome and deliverables.
1.2 Objectives
The main objective of this project is to make a quadcopter which could be used in security as
well as in package delivering operations. The quadcopter will be controlled by an Arduino
microcontroller which will be program flexible according to the user. The flight will be made stable
with the accumulation of various sensors like the gyroscope, accelerometer. A camera is attached to
capture the photos or videos for security and for some occasions. The quadcopter is controlled using
Transmitter and receiver to increase its range.
1.3.1 Purpose
The goal of the project is to develop a quadcopter that can deliver food and product through
drone. Big companies such as DHL, Amazon, Dominos, and FedEx are testing using the drone for local
transport of their items. It could significantly lower human labour and speed up delivery times.
Drones have numerous uses in the defence, military, tactical, and modern warfare
world. These unmanned aerial systems are used to the air strikes purpose. They travel around
suspected locations as controlled from the navy individual and they are operated in certain
areas to fulfil army operations of government. Small size and powerful cameras make them
suitable for bomb detection purposes. Thus, these drones are apt to make us informed about
unexploded bombs thus saving lives.
1.3.2 Scope
The scope of the project is:
i. Quadcopter stability during unconditional weather.
ii. Quadcopter is controlled by Arduino base microcontroller and MPU 6050
(gyroscope + accelerometer) sensor.
iii. Quadcopter is operated by brushless motor controlled by electronic speed controller.
1.3.3 Applicability
This project will help the police for security reasons.
A Group of Drone can be used for finding the criminals or persons.
Drone can be used to keep watch on some isolated locations to make sure all
the areas are safe.
It will also help in delivery of good within a short span of time from anywhere
we need a parcel or the package.
It can be used for Photography of some occasions.
1.4 Achievements
The goal of the project is to construct an Arduino system that includes the principle of
aviation. The system should be user friendly for the operator. The main goals have been
allocated to following sub goals:
1. Building a quadcopter regarding the security and delivering purpose.
2. To obtain the stability of the quadcopter in bad weather.
Implementing camera in addition to security purpose
CHAPTER 2
SYSTEM ANALYSIS
2.1 Existing System
The most commonly used system for delivery of goods is via delivery boys. The time taken for
delivery is much more time consuming. With the help of drones the delivery would be much more
faster and efficient.
The existing system can only be used for entertainment purpose not for commercial use.
The existing system does not have the ability to get a stable flight and the controlling of the drone
is much harder than it looks.
The existing system does not have the camera module hence it cannot be used for security
purposes.
1.0 pin out: added SDA and SCL pins that are near to the AREF pin and two other new pins placed
near to the RESET pin, the IOREF that allow the shields to adapt to the voltage provided from the
board. In future, shields will be compatible both with the board that use the AVR, which operate
with 5V and with the Arduino Due that operate with 3.3V. The second one is a not connected pin
that is reserved for future purposes.
Stronger RESET circuit.
Atmega 16U2 replace the 8U2.
"Uno" means one in Italian and is named to mark the upcoming release of Arduino 1.0. The Uno and
version 1.0 will be the reference versions of Arduino, moving forward. The Uno is the latest in a series
of USB Arduino boards, and the reference model for the Arduino platform; for a comparison with
previous versions, see the index of Arduino boards.
SUMMARY: -
Microcontroller ATmega328
Operating Voltage 5V
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)
POWER
The Arduino Uno can be powered via the USB connection or with an external power supply.
The power source is selected automatically. External (non-USB) power can come either from an AC-
to-DC adapter (wall-wart) or battery. The adapter can be connected by plugging a 2.1mm centre-
positive plug into the board's power jack. Leads from a battery can be inserted in the Gnd and Vin pin
headers of the POWER connector.
The board can operate on an external supply of 6 to 20 volts. If supplied with less than 7V, however,
the 5V pin may supply less than five volts and the board may be unstable. If using more than 12V, the
voltage regulator may overheat and damage the board. The recommended range is 7 to 12 volts.
VIN: The input voltage to the Arduino board when it's using an external power source (as opposed
to 5 volts from the USB connection or other regulated power source). You can supply voltage
through this pin, or, if supplying voltage via the power jack.
5V: the regulated power supply used to power the microcontroller and other components on the
board. This can come either from VIN via an on-board regulator, or be supplied by USB or another
regulated 5V supply.
3V3: A 3.3-volt supply generated by the on-board regulator. Maximum current draw is 50 mA.
GND: Ground pins.
MEMORY
The ATmega328 has 32 KB (with 0.5 KB used for the bootloader). It also has 2 KB of Static
Random Access Memory (SRAM) and 1 KB of Electrically Erasable Programmable Read-Only
Memory (EEPROM) which can be read and written with the EEPROM library.
Each of the 14 digital pins on the Uno can be used as an input or output, using pin
Mode(), digital Write(), and digital Read() functions. They operate at 5 volts. Each pin can provide or
receive a maximum of 40 mA and has an internal pull-up resistor (disconnected by default) of 20-50 K
Ohms.
Serial: 0 (RX) and 1 (TX). Used to receive (RX) and transmit (TX) TTL serial data. These pins are
connected to the corresponding pins of the ATmega8U2 USB-to-TTL Serial chip.
External Interrupts: 2 and 3. These pins can be configured to trigger an interrupt on a low value, a
rising or falling edge, or a change in value. See the attachInterrupt () function for details.
PWM: 3, 5, 6, 9, 10, and 11. Provide 8-bit PWM output with the analogWrite() function.
SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). These pins support SPI communication using
the SPI library.
LED: 13. There is a built-in LED connected to digital pin 13. When the pin is HIGH value, the
LED is on, when the pin is LOW, it's off.
The Uno has 6 analog inputs, labelled A0 through A5, each of which provide 10 bits of
resolution (i.e. 1024 different values). By default they measure from ground to 5 volts, though is it
possible to change the upper end of their range using the AREF pin and the analogReference() function.
Additionally, some pins have specialized functionality:
TWI: A4 or SDA pin and A5 or SCL pin. Support TWI communication using the Wire library.
AREF. Reference voltage for the analog inputs. Used with analog Reference ().
Reset. Bring this line LOW to reset the microcontroller. Typically used to add a reset button to
shields which block the one on the board.
COMMUNICATION
The Arduino Uno has a number of facilities for communicating with a computer, another
Arduino, or other microcontrollers. The ATmega328 provides UART TTL (5V) serial communication,
which is available on digital pins 0 (RX) and 1 (TX). An ATmega16U2 on the board channels this serial
communication over USB and appears as a virtual com port to software on the computer. The '16U2
firmware uses the standard USB COM drivers, and no external driver is needed. However, on Windows,
a .inf file is required. The Arduino software includes a serial monitor which allows simple textual data
to be sent to and from the Arduino board. The RX and TX LEDs on the board will flash when data is
being transmitted via the USB-to-serial chip and USB connection to the computer (but not for serial
communication on pins 0 and 1).
A Software Serial library allows for serial communication on any of the Uno's digital pins.
The ATmega328 also supports I2C (TWI) and SPI communication. The Arduino software
includes a Wire library to simplify use of the I2C bus; see the documentation for details. For SPI
communication, use the SPI library.
PROGRAMMING
The Arduino Uno can be programmed with the Arduino software (download). Select "Arduino
Uno from the Tools > Board menu (according to the microcontroller on your board). For details, see
the reference and tutorials.
The ATmega328 on the Arduino Uno comes pre-burned with a bootloader that allows you to
upload new code to it without the use of an external hardware programmer. It communicates using the
original STK500 protocol (reference, C header files).
You can also bypass the bootloader and program the microcontroller through the ICSP (In-
Circuit Serial Programming) header; see these instructions for details.
The ATmega16U2 (or 8U2 in the rev1 and rev2 boards) firmware source code is available.
The ATmega16U2/8U2 is loaded with a DFU bootloader, which can be activated by:
On Rev1 boards: connecting the solder jumper on the back of the board (near the map of Italy) and
then resetting the 8U2.
On Rev2 or later boards: there is a resistor that pulling the 8U2/16U2 HWB line to ground, making
it easier to put into DFU mode.
You can then use Atmel's FLIP software (Windows) or the DFU programmer (Mac OS X and
Linux) to load a new firmware. Or you can use the ISP header with an external programmer (overwriting
the DFU bootloader). See this user-contributed tutorial for more information.
The module also has two auxiliary pins which can be used to interface external IIC modules like a
magnetometer, however it is optional. Since the IIC address of the module is configurable more than
one MPU6050 sensor can be interfaced to a Microcontroller using the AD0 pin. This module also has
well documented and revised libraries available hence it’s very easy to use with famous platforms like
Arduino.
3 Serial Clock (SCL) Used for providing clock pulse for I2C Communication
4 Serial Data (SDA) Used for transferring Data through I2C communication
5 Auxiliary Serial Data Can be used to interface other I2C modules with
(XDA) MPU6050. It is optional
7 AD0 If more than one MPU6050 is used a single MCU, then this
pin can be used to vary the address
8 Interrupt (INT) Interrupt pin to indicate that data is available for MCU to
read.
The OV7670 image sensor is controlled using Serial Camera Control Bus (SCCB) which is
an I2C interface (SIOC, SIOD) with a maximum clock frequency of 400KHz.
Talking about pins, as I have mentioned that a Micro SD Card supports only SPI
Communication, the SD Card Module has pins for SPI Communication. So, the pins on an
SD Card Module are as follows.
VCC – 5V
GND – GND
MOSI – Master OUT Slave IN (Input)
MISO – Master IN Slave OUT (Output)
SCK – SPI Clock (Input)
CS – Chip Select (Input)
RANGE TECHNOLOGY
The limit of range is normally where the receiver can no longer clearly hear what the
transmitter telling it and typically falls in the 1km range in normal conditions. Imagine trying
to talk to someone across a field. The range of your radio link will be dependent on a few
factors:
1. The output power of your transmitter - Many runs just below the legal maximum to be compliant
with international standards.
2. The sensitivity of the Receiver - A more sensitive receiver is like having better hearing, the signal
will travel further however it may pick up more noise in certain conditions
3. The quality of your antennas at both ends - Antennas could be an entire article on their own but
basically a larger antenna will send and receive a better signal. Often optimising your antenna
placement will make a huge difference to the performance to the system.
Although typical radio systems use the 2.4Ghz band, specialist long range systems such as the
TBS Crossfire can run on much lower frequencies which are able to travel much further at the same
power.
Transmitter
The transmitter used in the project is Fly Sky CT6B 2.4Ghz 6CH Transmitter
CT6B FLYSKY 2.4GHZ 6CH TRANSMITTER is an entry-level 2.4 GHz radio system offering the
reliability of 2.4 GHz signal.
CT6B FLYSKY 2.4GHZ 6CH TRANSMITTER radio is a value for money, entry level 6
channel transmitter, ideal for quadcopters and multicopper that require the 6ch operation.
This radio has two retract switches and proportional flap dials in easy reach for channels 5 and 6. It can
be powered by 8 x AA Size Batteries or a 12V Power Supply.
The T6 channel arrangement is:
CH 1 ailerons
CH 2 elevator
CH 3 throttle
CH 4 rudder
CH 5 aux
CH 6 aux
Specifications:
Specifications:
Channels: 6 Channels
Model type: heli/airplane
RF power: less than 20DBm
modulation: GFSK
Code type: PCM
Sensitivity: 1024
Low voltage warning: LED
Charger port: yes
ANT length: 26mm
Frequency: 2.4G
Power: 5V DC(1.5V AAA*4)
weight: 25g
size: 30*25*8mm
2.6.8 Frame
The frame of the drone should be rigid, as when we test the drone for flying it may fall from a
height and may break. The frame should also be light and can fly with the help for the propellers.
Specifications:
The frame is made up of quality glass fibre and polyamide nylon.
Integrated PCB connections for direct soldering of your esc's.
Pre-threaded brass sleeves for all of the frame bolts.
Coloured arms for orientation to keep you flying in the right direction.
Large mounting tabs on main frame bottom plate for easy camera mounting.
Fig. 9 Frame
2.6.9 Propellers
The purpose of your quadcopter propellers is to generate thrust and torque to keep your
drone flying, and to hover.
The upward thrust force generated by the propellers is usually measured in pounds or grams. To keep
your drone flying at a hover, the upward thrust needs to equal the weight of your drone. The thrust to
weight ratio TWR (thrust divided by weight), indicates how much thrust your drone generates relative
to its weight. A good rule of thumb is to design the TWR to be at least a value of two.
Typically, quadcopter propellers produce more thrust the faster they spin. They are also
influenced by the flight dynamics of your quadcopter. Some propellers produce much more thrust when
the drone is stationary, as opposed to when it is flying. Other props perform much better at higher
speeds.
Specification:
Made up of carbon nylon material which makes it strong.
Size: 1 x 4.5". Diameter of Shaft: 6.mm
Thickness of centre: 9.7mm
Fig. 10 Propellers
2.6.10 Battery
The community standard is the Lithium-Polymer or LiPo battery. These kinds of
batteries are light weight, compact and offer high discharge rates. These kinds of batteries are
made up of multiple cells. A single cell provides a nominal 3.5 Volts. To provide higher
voltages these cells are connected in series and have a “S” designation. A 3S battery holds 3.5
x 3 = 11.1 Volts. LiPo batteries also carry a “C” rating which indicates the maximum discharge
rate. The “C” stands for capacity. So, a 25C battery can discharge at 25 times its capacity. The
third important measurement for a battery is its capacity which is provided in milli-Amp hour
(mAh) values. A 2200 mAh battery with a 25C rating can discharge 25 x 2200 = 55000 mA or
55 Amperes. The discharge rate should be higher than the combined draw from your ESC’s
and motors.
The diode D1 protects the USB port of the computer when the Arduino is connected
to the computer. This diode has an important function and cannot be excluded.
The resistors divide the flight battery voltage by 2.5. This way it is possible to
measure the battery voltage during flight. The LED will light up when the battery voltage gets
to low and the motor rpm automatically increase to compensate the dropping battery voltage
during flight.
The 1kΩ and 1.5kΩ resistors need to be installed correctly otherwise the quadcopter
will not fly perfect.
The 10kΩ and 4.7kΩ resistors need to be installed correctly to the OV7670 module
to maintain the voltage of the module.
Fig. 13 Diode and Registers
The source code for the IDE is released under the GNU General Public License,
version The Arduino IDE supports the languages C and C++ using special rules of code
structuring. The Arduino IDE supplies a software library from the Wiring project, which
provides many common input and output procedures. User-written code only requires two basic
functions, for starting the sketch and the main program loop, that are compiled and linked with
a program stub main() into an executable cyclic executive program with the GNU toolchain,
also included with the IDE distribution. The Arduino IDE employs the program avrdude to
convert the executable code into a text file in hexadecimal encoding that is loaded into the
Arduino board by a loader program in the board's firmware.
2.6.14 C++
C++ was designed with a bias toward system programming and embedded, resource-
constrained software and large systems, with performance, efficiency and flexibility of use as
its design highlights. C++ has also been found useful in many other contexts, with key strengths
being software infrastructure and resource-constrained applications, including desktop
applications, servers (e.g. e-commerce, Web search or SQL servers), and performance-critical
applications (e.g. telephone switches or space probes).
Fig.15 C++
C++ is standardized by the International Organization for Standardization (ISO), with
the latest standard version ratified and published by ISO in December 2017 as ISO/IEC
14882:2017 (informally known as C++17). The C++ programming language was initially
standardized in 1998 as ISO/IEC 14882:1998, which was then amended by
the C++03, C++11 and C++14 standards. The current C++17 standard supersedes these with
new features and an enlarged standard library. Before the initial standardization in 1998, C++
was developed by Danish computer scientist Bjarne Stroustrup at Bell Labs since 1979 as an
extension of the C language; he wanted an efficient and flexible language similar to C that also
provided high-level features for program organization. C++20 is the next planned standard,
keeping with the current trend of a new version every three years.
2.6.15 MS Excel
Microsoft Excel has the basic features of all spreadsheets, using a grid of cells arranged
in numbered rows and letter-named columns to organize data manipulations like arithmetic
operations. It has a battery of supplied functions to answer statistical, engineering and financial
needs. In addition, it can display data as line graphs, histograms and charts, and with a very
limited three-dimensional graphical display. It allows sectioning of data to view its
dependencies on various factors for different perspectives (using pivot tables and the scenario
manager). It has a programming aspect, Visual Basic for Applications, allowing the user to
employ a wide variety of numerical methods, for example, for solving differential equations of
mathematical physics, and then reporting the results back to the spreadsheet. It also has a
variety of interactive features allowing user interfaces that can completely hide the spreadsheet
from the user, so the spreadsheet presents itself as a so-called application, or decision support
system (DSS), via a custom-designed user interface, for example, a stock analyser, or in
general, as a design tool that asks the user questions and provides answers and reports. In a
more elaborate realization, an Excel application can automatically poll external databases and
measuring instruments using an update schedule, analyse the results, make a Word report
or PowerPoint slide show, and e-mail these presentations on a regular basis to a list of
participants. Excel was not designed to be used as a database.
Microsoft allows for a number of optional command-line switches to control the manner
in which Excel starts.
Functions
Excel 2016 has 484 functions. Of these, 360 existed prior to Excel 2010. Microsoft
classifies these functions in 14 categories. Of the 484 current functions, 386 may be called
from VBA as methods of the object "Worksheet Function" and 44 have the same names as
VBA functions.
CHAPTER 3
SYSTEM DESIGN
3.1 Module Division
3. Arduino Uno R3
Arduino is a microcontroller which is programable using Arduino ide. Arduino is programmed
to send the signals of the transmitter to MPU 6050 for the movement of the drone.
4. MPU6050
The MPU6050 is a Micro Electro-Mechanical Systems (MEMS) which consists of a 3-axis
Accelerometer and 3-axis Gyroscope inside it. This helps us to measure acceleration, velocity,
orientation, displacement and many other motions related parameter of a system or object. It
measures the balancing of the drone and calibrates the ESCs of the drone. If the drone is not stable
then the signals are then sent to Arduino till the stability is maintained
5. ESCs
Electronic Speed Controllers (ESCs) gets the signals from the MPU 6050 to maintain the
rotation of the motor according to the angle of the drone.
3.2 Entity Relationship Diagram
//Setup routine
void setup(){
pinMode(12, OUTPUT);
//Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 (digital input 8) to trigger an interrupt on state change
PCMSK0 |= (1 << PCINT1); // set PCINT1 (digital input 9)to trigger an interrupt on state change
PCMSK0 |= (1 << PCINT2); // set PCINT2 (digital input 10)to trigger an interrupt on state change
PCMSK0 |= (1 << PCINT3); // set PCINT3 (digital input 11)to trigger an interrupt on state change
Wire.begin(); //Start the I2C as master
Serial.begin(57600); //Start the serial connetion @ 57600bps
delay(250); //Give the gyro time to start
}
//Main program
void loop(){
intro();
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("System check"));
Serial.println(F("==================================================="));
delay(1000);
Serial.println(F("Checking I2C clock speed."));
delay(1000);
#if F_CPU == 16000000L //If the clock speed is 16MHz include the next code line when
compiling
clockspeed_ok = 1; //Set clockspeed_ok to 1
#endif //End of if statement
if(error == 0){
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("Transmitter setup"));
Serial.println(F("==================================================="));
delay(1000);
Serial.print(F("Checking for valid receiver signals."));
//Wait 10 seconds until all receiver inputs are valid
wait_for_receiver();
Serial.println(F(""));
}
//Quit the program in case of an error
if(error == 0){
delay(2000);
Serial.println(F("Place all sticks and subtrims in the center position within 10 seconds."));
for(int i = 9;i > 0;i--){
delay(1000);
Serial.print(i);
Serial.print(" ");
}
Serial.println(" ");
//Store the central stick positions
center_channel_1 = receiver_input_channel_1;
center_channel_2 = receiver_input_channel_2;
center_channel_3 = receiver_input_channel_3;
center_channel_4 = receiver_input_channel_4;
Serial.println(F(""));
Serial.println(F("Center positions stored."));
Serial.print(F("Digital input 08 = "));
Serial.println(receiver_input_channel_1);
Serial.print(F("Digital input 09 = "));
Serial.println(receiver_input_channel_2);
Serial.print(F("Digital input 10 = "));
Serial.println(receiver_input_channel_3);
Serial.print(F("Digital input 11 = "));
Serial.println(receiver_input_channel_4);
Serial.println(F(""));
Serial.println(F(""));
}
if(error == 0){
Serial.println(F("Move the throttle stick to full throttle and back to center"));
//Check for throttle movement
check_receiver_inputs(1);
Serial.print(F("Throttle is connected to digital input "));
Serial.println((channel_3_assign & 0b00000111) + 7);
if(channel_3_assign & 0b10000000)Serial.println(F("Channel inverted = yes"));
else Serial.println(F("Channel inverted = no"));
wait_sticks_zero();
Serial.println(F(""));
Serial.println(F(""));
Serial.println(F("Move the roll stick to simulate left wing up and back to center"));
//Check for throttle movement
check_receiver_inputs(2);
Serial.print(F("Roll is connected to digital input "));
Serial.println((channel_1_assign & 0b00000111) + 7);
if(channel_1_assign & 0b10000000)Serial.println(F("Channel inverted = yes"));
else Serial.println(F("Channel inverted = no"));
wait_sticks_zero();
}
if(error == 0){
Serial.println(F(""));
Serial.println(F(""));
Serial.println(F("Move the pitch stick to simulate nose up and back to center"));
//Check for throttle movement
check_receiver_inputs(3);
Serial.print(F("Pitch is connected to digital input "));
Serial.println((channel_2_assign & 0b00000111) + 7);
if(channel_2_assign & 0b10000000)Serial.println(F("Channel inverted = yes"));
else Serial.println(F("Channel inverted = no"));
wait_sticks_zero();
}
if(error == 0){
Serial.println(F(""));
Serial.println(F(""));
Serial.println(F("Move the yaw stick to simulate nose right and back to center"));
//Check for throttle movement
check_receiver_inputs(4);
Serial.print(F("Yaw is connected to digital input "));
Serial.println((channel_4_assign & 0b00000111) + 7);
if(channel_4_assign & 0b10000000)Serial.println(F("Channel inverted = yes"));
else Serial.println(F("Channel inverted = no"));
wait_sticks_zero();
}
if(error == 0){
Serial.println(F(""));
Serial.println(F(""));
Serial.println(F("Gently move all the sticks simultaneously to their extends"));
Serial.println(F("When ready put the sticks back in their center positions"));
//Register the min and max values of the receiver channels
register_min_max();
Serial.println(F(""));
Serial.println(F(""));
Serial.println(F("High, low and center values found during setup"));
Serial.print(F("Digital input 08 values:"));
Serial.print(low_channel_1);
Serial.print(F(" - "));
Serial.print(center_channel_1);
Serial.print(F(" - "));
Serial.println(high_channel_1);
Serial.print(F("Digital input 09 values:"));
Serial.print(low_channel_2);
Serial.print(F(" - "));
Serial.print(center_channel_2);
Serial.print(F(" - "));
Serial.println(high_channel_2);
Serial.print(F("Digital input 10 values:"));
Serial.print(low_channel_3);
Serial.print(F(" - "));
Serial.print(center_channel_3);
Serial.print(F(" - "));
Serial.println(high_channel_3);
Serial.print(F("Digital input 11 values:"));
Serial.print(low_channel_4);
Serial.print(F(" - "));
Serial.print(center_channel_4);
Serial.print(F(" - "));
Serial.println(high_channel_4);
Serial.println(F("Move stick 'nose up' and back to center to continue"));
check_to_continue();
}
if(error == 0){
//What gyro is connected
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("Gyro search"));
Serial.println(F("==================================================="));
delay(2000);
if(type == 0){
Serial.println(F("Searching for MPU-6050 on address 0x69/105"));
delay(1000);
if(search_gyro(0x69, 0x75) == 0x68){
Serial.println(F("MPU-6050 found on address 0x69"));
type = 1;
gyro_address = 0x69;
}
}
if(type == 0){
Serial.println(F("No gyro device found!!! (ERROR 3)"));
error = 1;
}
else{
delay(3000);
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("Gyro register settings"));
Serial.println(F("==================================================="));
start_gyro(); //Setup the gyro for further use
}
}
//If the gyro is found we can setup the correct gyro axes.
if(error == 0){
delay(3000);
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("Gyro calibration"));
Serial.println(F("==================================================="));
Serial.println(F("Don't move the quadcopter!! Calibration starts in 3 seconds"));
delay(3000);
Serial.println(F("Calibrating the gyro, this will take +/- 8 seconds"));
Serial.print(F("Please wait"));
//Let's take multiple gyro data samples so we can determine the average gyro offset (calibration).
for (cal_int = 0; cal_int < 2000 ; cal_int ++){ //Take 2000 readings for calibration.
if(cal_int % 100 == 0)Serial.print(F(".")); //Print dot to indicate calibration.
gyro_signalen(); //Read the gyro output.
gyro_roll_cal += gyro_roll; //Ad roll value to gyro_roll_cal.
gyro_pitch_cal += gyro_pitch; //Ad pitch value to gyro_pitch_cal.
gyro_yaw_cal += gyro_yaw; //Ad yaw value to gyro_yaw_cal.
delay(4); //Wait 3 milliseconds before the next loop.
}
//Now that we have 2000 measures, we need to devide by 2000 to get the average gyro offset.
gyro_roll_cal /= 2000; //Divide the roll total by 2000.
gyro_pitch_cal /= 2000; //Divide the pitch total by 2000.
gyro_yaw_cal /= 2000; //Divide the yaw total by 2000.
Serial.println(F("==================================================="));
Serial.println(F("Gyro axes configuration"));
Serial.println(F("==================================================="));
Serial.println(F(""));
if(error == 0){
Serial.println(F("==================================================="));
Serial.println(F("Final setup check"));
Serial.println(F("==================================================="));
delay(1000);
if(receiver_check_byte == 0b00001111){
Serial.println(F("Receiver channels ok"));
}
else{
Serial.println(F("Receiver channel verification failed!!! (ERROR 6)"));
error = 1;
}
delay(1000);
if(gyro_check_byte == 0b00000111){
Serial.println(F("Gyro axes ok"));
}
else{
Serial.println(F("Gyro exes verification failed!!! (ERROR 7)"));
error = 1;
}
}
if(error == 0){
//If all is good, store the information in the EEPROM
Serial.println(F(""));
Serial.println(F("==================================================="));
Serial.println(F("Storing EEPROM information"));
Serial.println(F("==================================================="));
Serial.println(F("Writing EEPROM"));
delay(1000);
Serial.println(F("Done!"));
EEPROM.write(0, center_channel_1 & 0b11111111);
EEPROM.write(1, center_channel_1 >> 8);
EEPROM.write(2, center_channel_2 & 0b11111111);
EEPROM.write(3, center_channel_2 >> 8);
EEPROM.write(4, center_channel_3 & 0b11111111);
EEPROM.write(5, center_channel_3 >> 8);
EEPROM.write(6, center_channel_4 & 0b11111111);
EEPROM.write(7, center_channel_4 >> 8);
EEPROM.write(8, high_channel_1 & 0b11111111);
EEPROM.write(9, high_channel_1 >> 8);
EEPROM.write(10, high_channel_2 & 0b11111111);
EEPROM.write(11, high_channel_2 >> 8);
EEPROM.write(12, high_channel_3 & 0b11111111);
EEPROM.write(13, high_channel_3 >> 8);
EEPROM.write(14, high_channel_4 & 0b11111111);
EEPROM.write(15, high_channel_4 >> 8);
EEPROM.write(16, low_channel_1 & 0b11111111);
EEPROM.write(17, low_channel_1 >> 8);
EEPROM.write(18, low_channel_2 & 0b11111111);
EEPROM.write(19, low_channel_2 >> 8);
EEPROM.write(20, low_channel_3 & 0b11111111);
EEPROM.write(21, low_channel_3 >> 8);
EEPROM.write(22, low_channel_4 & 0b11111111);
EEPROM.write(23, low_channel_4 >> 8);
EEPROM.write(24, channel_1_assign);
EEPROM.write(25, channel_2_assign);
EEPROM.write(26, channel_3_assign);
EEPROM.write(27, channel_4_assign);
EEPROM.write(28, roll_axis);
EEPROM.write(29, pitch_axis);
EEPROM.write(30, yaw_axis);
EEPROM.write(31, type);
EEPROM.write(32, gyro_address);
//Write the EEPROM signature
EEPROM.write(33, 'J');
EEPROM.write(34, 'M');
EEPROM.write(35, 'B');
if(channel_1_assign != EEPROM.read(24))error = 1;
if(channel_2_assign != EEPROM.read(25))error = 1;
if(channel_3_assign != EEPROM.read(26))error = 1;
if(channel_4_assign != EEPROM.read(27))error = 1;
if(roll_axis != EEPROM.read(28))error = 1;
if(pitch_axis != EEPROM.read(29))error = 1;
if(yaw_axis != EEPROM.read(30))error = 1;
if(type != EEPROM.read(31))error = 1;
if(gyro_address != EEPROM.read(32))error = 1;
if('J' != EEPROM.read(33))error = 1;
if('M' != EEPROM.read(34))error = 1;
if('B' != EEPROM.read(35))error = 1;
if(error == 0){
Serial.println(F("Setup is finished."));
Serial.println(F("You can now calibrate the esc's and upload the YMFC-AL code."));
}
else{
Serial.println(F("The setup is aborted due to an error."));
}
while(1);
}
void start_gyro(){
//Setup the L3G4200D or L3GD20H
if(type == 2 || type == 3){
Wire.beginTransmission(address); //Start communication with the gyro with the
address found during search
Wire.write(0x20); //We want to write to register 1 (20 hex)
Wire.write(0x0F); //Set the register bits as 00001111 (Turn on the gyro
and enable all axis)
Wire.endTransmission(); //End the transmission with the gyro
}
//Setup the MPU-6050
if(type == 1){
}
}
void gyro_signalen(){
if(type == 2 || type == 3){
Wire.beginTransmission(address); //Start communication with the gyro
Wire.write(168); //Start reading @ register 28h and auto increment with
every read
Wire.endTransmission(); //End the transmission
Wire.requestFrom(address, 6); //Request 6 bytes from the gyro
while(Wire.available() < 6); //Wait until the 6 bytes are received
lowByte = Wire.read(); //First received byte is the low part of the angular
data
highByte = Wire.read(); //Second received byte is the high part of the angular
data
gyro_roll = ((highByte<<8)|lowByte); //Multiply highByte by 256 (shift left by 8)
and ad lowByte
if(cal_int == 2000)gyro_roll -= gyro_roll_cal; //Only compensate after the calibration
lowByte = Wire.read(); //First received byte is the low part of the angular
data
highByte = Wire.read(); //Second received byte is the high part of the angular
data
gyro_pitch = ((highByte<<8)|lowByte); //Multiply highByte by 256 (shift left by 8)
and ad lowByte
if(cal_int == 2000)gyro_pitch -= gyro_pitch_cal; //Only compensate after the calibration
lowByte = Wire.read(); //First received byte is the low part of the angular
data
highByte = Wire.read(); //Second received byte is the high part of the angular
data
gyro_yaw = ((highByte<<8)|lowByte); //Multiply highByte by 256 (shift left by 8)
and ad lowByte
if(cal_int == 2000)gyro_yaw -= gyro_yaw_cal; //Only compensate after the calibration
}
if(type == 1){
Wire.beginTransmission(address); //Start communication with the gyro
Wire.write(0x43); //Start reading @ register 43h and auto increment with
every read
Wire.endTransmission(); //End the transmission
Wire.requestFrom(address,6); //Request 6 bytes from the gyro
while(Wire.available() < 6); //Wait until the 6 bytes are received
gyro_roll=Wire.read()<<8|Wire.read(); //Read high and low part of the angular data
if(cal_int == 2000)gyro_roll -= gyro_roll_cal; //Only compensate after the calibration
gyro_pitch=Wire.read()<<8|Wire.read(); //Read high and low part of the angular data
if(cal_int == 2000)gyro_pitch -= gyro_pitch_cal; //Only compensate after the calibration
gyro_yaw=Wire.read()<<8|Wire.read(); //Read high and low part of the angular data
if(cal_int == 2000)gyro_yaw -= gyro_yaw_cal; //Only compensate after the calibration
}
}
void check_to_continue(){
byte continue_byte = 0;
while(continue_byte == 0){
if(channel_2_assign == 0b00000001 && receiver_input_channel_1 > center_channel_1 +
150)continue_byte = 1;
if(channel_2_assign == 0b10000001 && receiver_input_channel_1 < center_channel_1 -
150)continue_byte = 1;
if(channel_2_assign == 0b00000010 && receiver_input_channel_2 > center_channel_2 +
150)continue_byte = 1;
if(channel_2_assign == 0b10000010 && receiver_input_channel_2 < center_channel_2 -
150)continue_byte = 1;
if(channel_2_assign == 0b00000011 && receiver_input_channel_3 > center_channel_3 +
150)continue_byte = 1;
if(channel_2_assign == 0b10000011 && receiver_input_channel_3 < center_channel_3 -
150)continue_byte = 1;
if(channel_2_assign == 0b00000100 && receiver_input_channel_4 > center_channel_4 +
150)continue_byte = 1;
if(channel_2_assign == 0b10000100 && receiver_input_channel_4 < center_channel_4 -
150)continue_byte = 1;
delay(100);
}
wait_sticks_zero();
}
//Register the min and max receiver values and exit when the sticks are back in the neutral position
void register_min_max(){
byte zero = 0;
low_channel_1 = receiver_input_channel_1;
low_channel_2 = receiver_input_channel_2;
low_channel_3 = receiver_input_channel_3;
low_channel_4 = receiver_input_channel_4;
while(receiver_input_channel_1 < center_channel_1 + 20 && receiver_input_channel_1 >
center_channel_1 - 20)delay(250);
Serial.println(F("Measuring endpoints...."));
while(zero < 15){
if(receiver_input_channel_1 < center_channel_1 + 20 && receiver_input_channel_1 >
center_channel_1 - 20)zero |= 0b00000001;
if(receiver_input_channel_2 < center_channel_2 + 20 && receiver_input_channel_2 >
center_channel_2 - 20)zero |= 0b00000010;
if(receiver_input_channel_3 < center_channel_3 + 20 && receiver_input_channel_3 >
center_channel_3 - 20)zero |= 0b00000100;
if(receiver_input_channel_4 < center_channel_4 + 20 && receiver_input_channel_4 >
center_channel_4 - 20)zero |= 0b00001000;
if(receiver_input_channel_1 < low_channel_1)low_channel_1 = receiver_input_channel_1;
if(receiver_input_channel_2 < low_channel_2)low_channel_2 = receiver_input_channel_2;
if(receiver_input_channel_3 < low_channel_3)low_channel_3 = receiver_input_channel_3;
if(receiver_input_channel_4 < low_channel_4)low_channel_4 = receiver_input_channel_4;
if(receiver_input_channel_1 > high_channel_1)high_channel_1 = receiver_input_channel_1;
if(receiver_input_channel_2 > high_channel_2)high_channel_2 = receiver_input_channel_2;
if(receiver_input_channel_3 > high_channel_3)high_channel_3 = receiver_input_channel_3;
if(receiver_input_channel_4 > high_channel_4)high_channel_4 = receiver_input_channel_4;
delay(100);
}
}
if(trigger_axis == 0){
error = 1;
Serial.println(F("No angular motion is detected in the last 10 seconds!!! (ERROR 4)"));
}
else
if(movement == 1)roll_axis = trigger_axis;
if(movement == 2)pitch_axis = trigger_axis;
if(movement == 3)yaw_axis = trigger_axis;
}
//Channel 4=========================================
if(PINB & B00001000 ){ //Is input 11 high?
if(last_channel_4 == 0){ //Input 11 changed from 0 to 1
last_channel_4 = 1; //Remember current input state
timer_4 = current_time; //Set timer_4 to current_time
}
}
else if(last_channel_4 == 1){ //Input 11 is not high and changed from 1 to 0
last_channel_4 = 0; //Remember current input state
receiver_input_channel_4 = current_time - timer_4; //Channel 4 is current_time - timer_4
}
}
ESC_Calibration.cpp:-
#include <Wire.h> //Include the Wire.h library so we can communicate with the gyro.
#include <EEPROM.h> //Include the EEPROM.h library so we can store information onto the
EEPROM
//Declaring global variables
byte last_channel_1, last_channel_2, last_channel_3, last_channel_4;
byte eeprom_data[36], start, data;
boolean new_function_request,first_angle;
volatile int receiver_input_channel_1, receiver_input_channel_2, receiver_input_channel_3,
receiver_input_channel_4;
int esc_1, esc_2, esc_3, esc_4;
int counter_channel_1, counter_channel_2, counter_channel_3, counter_channel_4;
int receiver_input[5];
int loop_counter, gyro_address, vibration_counter;
int temperature;
long acc_x, acc_y, acc_z, acc_total_vector[20], acc_av_vector, vibration_total_result;
unsigned long timer_channel_1, timer_channel_2, timer_channel_3, timer_channel_4, esc_timer,
esc_loop_timer;
unsigned long zero_timer, timer_1, timer_2, timer_3, timer_4, current_time;
//Setup routine
void setup(){
Serial.begin(57600); //Start the serial port.
Wire.begin(); //Start the wire library as master
TWBR = 12; //Set the I2C clock speed to 400kHz.
//Arduino Uno pins default to inputs, so they don't need to be explicitly declared as inputs.
DDRD |= B11110000; //Configure digital poort 4, 5, 6 and 7
as output.
DDRB |= B00010000; //Configure digital poort 12 as output.
//Let's create a small delay so the message stays visible for 2.5 seconds.
//We don't want the ESC's to beep and have to send a 1000us pulse to the ESC's.
for(vibration_counter = 0; vibration_counter < 625; vibration_counter++){ //Do this loop 625
times
delay(3); //Wait 3000us.
esc_1 = 1000; //Set the pulse for ESC 1 to 1000us.
esc_2 = 1000; //Set the pulse for ESC 1 to 1000us.
esc_3 = 1000; //Set the pulse for ESC 1 to 1000us.
esc_4 = 1000; //Set the pulse for ESC 1 to 1000us.
esc_pulse_output(); //Send the ESC control pulses.
}
vibration_counter = 0; //Reset the vibration_counter variable.
}
////////////////////////////////////////////////////////////////////////////////////////////
//Run the ESC calibration program to start with.
////////////////////////////////////////////////////////////////////////////////////////////
if(data == 0 && new_function_request == false){ //Only start the calibration
mode at first start.
receiver_input_channel_3 = convert_receiver_channel(3); //Convert the actual receiver
signals for throttle to the standard 1000 - 2000us.
esc_1 = receiver_input_channel_3; //Set the pulse for motor 1 equal to
the throttle channel.
esc_2 = receiver_input_channel_3; //Set the pulse for motor 2 equal to
the throttle channel.
esc_3 = receiver_input_channel_3; //Set the pulse for motor 3 equal to
the throttle channel.
esc_4 = receiver_input_channel_3; //Set the pulse for motor 4 equal to
the throttle channel.
esc_pulse_output(); //Send the ESC control pulses.
}
////////////////////////////////////////////////////////////////////////////////////////////
// send 'r' print the receiver signals.
////////////////////////////////////////////////////////////////////////////////////////////
if(data == 'r'){
loop_counter ++; //Increase the loop_counter variable.
receiver_input_channel_1 = convert_receiver_channel(1); //Convert the actual receiver
signals for pitch to the standard 1000 - 2000us.
receiver_input_channel_2 = convert_receiver_channel(2); //Convert the actual receiver
signals for roll to the standard 1000 - 2000us.
receiver_input_channel_3 = convert_receiver_channel(3); //Convert the actual receiver
signals for throttle to the standard 1000 - 2000us.
receiver_input_channel_4 = convert_receiver_channel(4); //Convert the actual receiver
signals for yaw to the standard 1000 - 2000us.
//For starting the motors: throttle low and yaw left (step 1).
if(receiver_input_channel_3 < 1050 && receiver_input_channel_4 < 1050)start = 1;
//When yaw stick is back in the center position start the motors (step 2).
if(start == 1 && receiver_input_channel_3 < 1050 && receiver_input_channel_4 > 1450)start = 2;
//Stopping the motors: throttle low and yaw right.
if(start == 2 && receiver_input_channel_3 < 1050 && receiver_input_channel_4 > 1950)start = 0;
//For balancing the propellors it's possible to use the accelerometer to measure the vibrations.
if(eeprom_data[31] == 1){ //The MPU-6050 is installed
Wire.beginTransmission(gyro_address); //Start communication with the gyro.
Wire.write(0x3B); //Start reading @ register 43h and auto
increment with every read.
Wire.endTransmission(); //End the transmission.
Wire.requestFrom(gyro_address,6); //Request 6 bytes from the gyro.
while(Wire.available() < 6); //Wait until the 6 bytes are received.
acc_x = Wire.read()<<8|Wire.read(); //Add the low and high byte to the
acc_x variable.
acc_y = Wire.read()<<8|Wire.read(); //Add the low and high byte to the
acc_y variable.
acc_z = Wire.read()<<8|Wire.read(); //Add the low and high byte to the
acc_z variable.
for(start = 16; start > 0; start--){ //Do this loop 16 times to create an array of
accelrometer vectors.
acc_total_vector[start] = acc_total_vector[start - 1]; //Shift every variable one position
up in the array.
acc_av_vector += acc_total_vector[start]; //Add the array value to the acc_av_vector
variable.
}
if(cal_int != 2000){
Serial.print("Calibrating the gyro");
//Let's take multiple gyro data samples so we can determine the average gyro offset (calibration).
for (cal_int = 0; cal_int < 2000 ; cal_int ++){ //Take 2000 readings for calibration.
if(cal_int % 125 == 0){
digitalWrite(12, !digitalRead(12)); //Change the led status to indicate calibration.
Serial.print(".");
}
gyro_signalen(); //Read the gyro output.
gyro_axis_cal[1] += gyro_axis[1]; //Ad roll value to gyro_roll_cal.
gyro_axis_cal[2] += gyro_axis[2]; //Ad pitch value to gyro_pitch_cal.
gyro_axis_cal[3] += gyro_axis[3]; //Ad yaw value to gyro_yaw_cal.
//We don't want the esc's to be beeping annoyingly. So let's give them a 1000us puls while calibrating
the gyro.
PORTD |= B11110000; //Set digital poort 4, 5, 6 and 7 high.
delayMicroseconds(1000); //Wait 1000us.
PORTD &= B00001111; //Set digital poort 4, 5, 6 and 7 low.
delay(3); //Wait 3 milliseconds before the next loop.
}
Serial.println(".");
//Now that we have 2000 measures, we need to devide by 2000 to get the average gyro offset.
gyro_axis_cal[1] /= 2000; //Divide the roll total by 2000.
gyro_axis_cal[2] /= 2000; //Divide the pitch total by 2000.
gyro_axis_cal[3] /= 2000; //Divide the yaw total by 2000.
}
else{
///We don't want the esc's to be beeping annoyingly. So let's give them a 1000us puls while calibrating
the gyro.
PORTD |= B11110000; //Set digital poort 4, 5, 6 and 7 high.
delayMicroseconds(1000); //Wait 1000us.
PORTD &= B00001111; //Set digital poort 4, 5, 6 and 7 low.
if(!first_angle){
angle_pitch = angle_pitch_acc; //Set the pitch angle to the accelerometer
angle.
angle_roll = angle_roll_acc; //Set the roll angle to the accelerometer
angle.
first_angle = true;
}
else{
angle_pitch = angle_pitch * 0.9996 + angle_pitch_acc * 0.0004; //Correct the drift of the gyro
pitch angle with the accelerometer pitch angle.
angle_roll = angle_roll * 0.9996 + angle_roll_acc * 0.0004; //Correct the drift of the gyro
roll angle with the accelerometer roll angle.
}
//We can't print all the data at once. This takes to long and the angular readings will be off.
if(loop_counter == 0)Serial.print("Pitch: ");
if(loop_counter == 1)Serial.print(angle_pitch ,0);
if(loop_counter == 2)Serial.print(" Roll: ");
if(loop_counter == 3)Serial.print(angle_roll ,0);
if(loop_counter == 4)Serial.print(" Yaw: ");
if(loop_counter == 5)Serial.println(gyro_yaw / 65.5 ,0);
loop_counter ++;
if(loop_counter == 60)loop_counter = 0;
}
}
}
//This part converts the actual receiver signals to a standardized 1000 – 1500 – 2000 microsecond value.
//The stored data in the EEPROM is used.
int convert_receiver_channel(byte function){
byte channel, reverse; //First we declare some local variables
int low, center, high, actual;
int difference;
if(actual < center){ //The actual receiver value is lower than the
center value
if(actual < low)actual = low; //Limit the lowest value to the value that was
detected during setup
difference = ((long)(center - actual) * (long)500) / (center - low); //Calculate and scale the actual
value to a 1000 - 2000us value
if(reverse == 1)return 1500 + difference; //If the channel is reversed
else return 1500 - difference; //If the channel is not reversed
}
else if(actual > center){ //The actual receiver value is higher
than the center value
if(actual > high)actual = high; //Limit the lowest value to the value that was
detected during setup
difference = ((long)(actual - center) * (long)500) / (high - center); //Calculate and scale the actual
value to a 1000 - 2000us value
if(reverse == 1)return 1500 - difference; //If the channel is reversed
else return 1500 + difference; //If the channel is not reversed
}
else return 1500;
}
void print_signals(){
Serial.print("Start:");
Serial.print(start);
Serial.print(" Roll:");
if(receiver_input_channel_1 - 1480 < 0)Serial.print("<<<");
else if(receiver_input_channel_1 - 1520 > 0)Serial.print(">>>");
else Serial.print("-+-");
Serial.print(receiver_input_channel_1);
Serial.print(" Pitch:");
if(receiver_input_channel_2 - 1480 < 0)Serial.print("^^^");
else if(receiver_input_channel_2 - 1520 > 0)Serial.print("vvv");
else Serial.print("-+-");
Serial.print(receiver_input_channel_2);
Serial.print(" Throttle:");
if(receiver_input_channel_3 - 1480 < 0)Serial.print("vvv");
else if(receiver_input_channel_3 - 1520 > 0)Serial.print("^^^");
else Serial.print("-+-");
Serial.print(receiver_input_channel_3);
Serial.print(" Yaw:");
if(receiver_input_channel_4 - 1480 < 0)Serial.print("<<<");
else if(receiver_input_channel_4 - 1520 > 0)Serial.print(">>>");
else Serial.print("-+-");
Serial.println(receiver_input_channel_4);
}
void esc_pulse_output(){
zero_timer = micros();
PORTD |= B11110000; //Set port 4, 5, 6 and 7 high at once
timer_channel_1 = esc_1 + zero_timer; //Calculate the time when digital port 4 is set
low.
timer_channel_2 = esc_2 + zero_timer; //Calculate the time when digital port 5 is set
low.
timer_channel_3 = esc_3 + zero_timer; //Calculate the time when digital port 6 is set
low.
timer_channel_4 = esc_4 + zero_timer; //Calculate the time when digital port 7 is set
low.
while(PORTD >= 16){ //Execute the loop until digital port 4 to 7 is low.
esc_loop_timer = micros(); //Check the current time.
if(timer_channel_1 <= esc_loop_timer)PORTD &= B11101111; //When the delay time is expired,
digital port 4 is set low.
if(timer_channel_2 <= esc_loop_timer)PORTD &= B11011111; //When the delay time is expired,
digital port 5 is set low.
if(timer_channel_3 <= esc_loop_timer)PORTD &= B10111111; //When the delay time is expired,
digital port 6 is set low.
if(timer_channel_4 <= esc_loop_timer)PORTD &= B01111111; //When the delay time is expired,
digital port 7 is set low.
}
}
void set_gyro_registers(){
//Setup the MPU-6050
if(eeprom_data[31] == 1){
Wire.beginTransmission(gyro_address); //Start communication with the address found
during search.
Wire.write(0x6B); //We want to write to the PWR_MGMT_1 register (6B
hex)
Wire.write(0x00); //Set the register bits as 00000000 to activate the gyro
Wire.endTransmission(); //End the transmission with the gyro.
//Let's perform a random register check to see if the values are written correct
Wire.beginTransmission(gyro_address); //Start communication with the address found
during search
Wire.write(0x1B); //Start reading @ register 0x1B
Wire.endTransmission(); //End the transmission
Wire.requestFrom(gyro_address, 1); //Request 1 bytes from the gyro
while(Wire.available() < 1); //Wait until the 6 bytes are received
if(Wire.read() != 0x08){ //Check if the value is 0x08
digitalWrite(12,HIGH); //Turn on the warning led
while(1)delay(10); //Stay in this loop for ever
}
}
}
void gyro_signalen(){
//Read the MPU-6050
if(eeprom_data[31] == 1){
Wire.beginTransmission(gyro_address); //Start communication with the gyro.
Wire.write(0x3B); //Start reading @ register 43h and auto increment with
every read.
Wire.endTransmission(); //End the transmission.
Wire.requestFrom(gyro_address,14); //Request 14 bytes from the gyro.
while(Wire.available() < 14); //Wait until the 14 bytes are received.
acc_axis[1] = Wire.read()<<8|Wire.read(); //Add the low and high byte to the acc_x variable.
acc_axis[2] = Wire.read()<<8|Wire.read(); //Add the low and high byte to the acc_y variable.
acc_axis[3] = Wire.read()<<8|Wire.read(); //Add the low and high byte to the acc_z variable.
temperature = Wire.read()<<8|Wire.read(); //Add the low and high byte to the temperature
variable.
gyro_axis[1] = Wire.read()<<8|Wire.read(); //Read high and low part of the angular data.
gyro_axis[2] = Wire.read()<<8|Wire.read(); //Read high and low part of the angular data.
gyro_axis[3] = Wire.read()<<8|Wire.read(); //Read high and low part of the angular data.
}
if(cal_int == 2000){
gyro_axis[1] -= gyro_axis_cal[1]; //Only compensate after the calibration.
gyro_axis[2] -= gyro_axis_cal[2]; //Only compensate after the calibration.
gyro_axis[3] -= gyro_axis_cal[3]; //Only compensate after the calibration.
}
gyro_roll = gyro_axis[eeprom_data[28] & 0b00000011]; //Set gyro_roll to the correct axis that
was stored in the EEPROM.
if(eeprom_data[28] & 0b10000000)gyro_roll *= -1; //Invert gyro_roll if the MSB of EEPROM
bit 28 is set.
gyro_pitch = gyro_axis[eeprom_data[29] & 0b00000011]; //Set gyro_pitch to the correct axis that
was stored in the EEPROM.
if(eeprom_data[29] & 0b10000000)gyro_pitch *= -1; //Invert gyro_pitch if the MSB of EEPROM
bit 29 is set.
gyro_yaw = gyro_axis[eeprom_data[30] & 0b00000011]; //Set gyro_yaw to the correct axis that
was stored in the EEPROM.
if(eeprom_data[30] & 0b10000000)gyro_yaw *= -1; //Invert gyro_yaw if the MSB of EEPROM
bit 30 is set.
acc_x = acc_axis[eeprom_data[29] & 0b00000011]; //Set acc_x to the correct axis that was
stored in the EEPROM.
if(eeprom_data[29] & 0b10000000)acc_x *= -1; //Invert acc_x if the MSB of EEPROM bit
29 is set.
acc_y = acc_axis[eeprom_data[28] & 0b00000011]; //Set acc_y to the correct axis that was
stored in the EEPROM.
if(eeprom_data[28] & 0b10000000)acc_y *= -1; //Invert acc_y if the MSB of EEPROM bit
28 is set.
acc_z = acc_axis[eeprom_data[30] & 0b00000011]; //Set acc_z to the correct axis that was
stored in the EEPROM.
if(eeprom_data[30] & 0b10000000)acc_z *= -1; //Invert acc_z if the MSB of EEPROM bit
30 is set.
}
Flight_Control.cpp:-
#include <Wire.h> //Include the Wire.h library so we can communicate with the gyro.
#include <EEPROM.h> //Include the EEPROM.h library so we can store information
onto the EEPROM
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PID gain and limit settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float pid_p_gain_roll = 1.3; //Gain setting for the roll P-controller
float pid_i_gain_roll = 0.04; //Gain setting for the roll I-controller
float pid_d_gain_roll = 18.0; //Gain setting for the roll D-controller
int pid_max_roll = 400; //Maximum output of the PID-controller (+/-)
float pid_p_gain_yaw = 4.0; //Gain setting for the pitch P-controller. //4.0
float pid_i_gain_yaw = 0.02; //Gain setting for the pitch I-controller. //0.02
float pid_d_gain_yaw = 0.0; //Gain setting for the pitch D-controller.
int pid_max_yaw = 400; //Maximum output of the PID-controller (+/-)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Declaring global variables
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
byte last_channel_1, last_channel_2, last_channel_3, last_channel_4;
byte eeprom_data[36];
byte highByte, lowByte;
volatile int receiver_input_channel_1, receiver_input_channel_2, receiver_input_channel_3,
receiver_input_channel_4;
int counter_channel_1, counter_channel_2, counter_channel_3, counter_channel_4, loop_counter;
int esc_1, esc_2, esc_3, esc_4;
int throttle, battery_voltage;
int cal_int, start, gyro_address;
int receiver_input[5];
int temperature;
int acc_axis[4], gyro_axis[4];
float roll_level_adjust, pitch_level_adjust;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Setup routine
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
//Serial.begin(57600);
//Copy the EEPROM data for fast access data.
for(start = 0; start <= 35; start++)eeprom_data[start] = EEPROM.read(start);
start = 0; //Set start back to zero.
gyro_address = eeprom_data[32]; //Store the gyro address in the variable.
Wire.begin(); //Start the I2C as master.
//Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs.
DDRD |= B11110000; //Configure digital poort 4, 5, 6 and 7 as
output.
DDRB |= B00110000; //Configure digital poort 12 and 13 as output.
//Check the EEPROM signature to make sure that the setup program is executed.
while(eeprom_data[33] != 'J' || eeprom_data[34] != 'M' || eeprom_data[35] != 'B')delay(10);
//The flight controller needs the MPU-6050 with gyro and accelerometer
//If setup is completed without MPU-6050 stop the flight controller program
if(eeprom_data[31] == 2 || eeprom_data[31] == 3)delay(10);
for (cal_int = 0; cal_int < 1250 ; cal_int ++){ //Wait 5 seconds before continuing.
PORTD |= B11110000; //Set digital poort 4, 5, 6 and 7 high.
delayMicroseconds(1000); //Wait 1000us.
PORTD &= B00001111; //Set digital poort 4, 5, 6 and 7 low.
delayMicroseconds(3000); //Wait 3000us.
}
//Let's take multiple gyro data samples so we can determine the average gyro offset (calibration).
for (cal_int = 0; cal_int < 2000 ; cal_int ++){ //Take 2000 readings for calibration.
if(cal_int % 15 == 0)digitalWrite(12, !digitalRead(12)); //Change the led status to indicate
calibration.
gyro_signalen(); //Read the gyro output.
gyro_axis_cal[1] += gyro_axis[1]; //Ad roll value to gyro_roll_cal.
gyro_axis_cal[2] += gyro_axis[2]; //Ad pitch value to gyro_pitch_cal.
gyro_axis_cal[3] += gyro_axis[3]; //Ad yaw value to gyro_yaw_cal.
//We don't want the esc's to be beeping annoyingly. So let's give them a 1000us puls while calibrating
the gyro.
PORTD |= B11110000; //Set digital poort 4, 5, 6 and 7 high.
delayMicroseconds(1000); //Wait 1000us.
PORTD &= B00001111; //Set digital poort 4, 5, 6 and 7 low.
delay(3); //Wait 3 milliseconds before the next loop.
}
//Now that we have 2000 measures, we need to devide by 2000 to get the average gyro offset.
gyro_axis_cal[1] /= 2000; //Divide the roll total by 2000.
gyro_axis_cal[2] /= 2000; //Divide the pitch total by 2000.
gyro_axis_cal[3] /= 2000; //Divide the yaw total by 2000.
//Wait until the receiver is active and the throtle is set to the lower position.
while(receiver_input_channel_3 < 990 || receiver_input_channel_3 > 1020 || receiver_input_channel_4
< 1400){
receiver_input_channel_3 = convert_receiver_channel(3); //Convert the actual receiver signals
for throttle to the standard 1000 - 2000us
receiver_input_channel_4 = convert_receiver_channel(4); //Convert the actual receiver signals
for yaw to the standard 1000 - 2000us
start ++; //While waiting increment start whith every loop.
//We don't want the esc's to be beeping annoyingly. So let's give them a 1000us puls while waiting for
the receiver inputs.
PORTD |= B11110000; //Set digital poort 4, 5, 6 and 7 high.
delayMicroseconds(1000); //Wait 1000us.
PORTD &= B00001111; //Set digital poort 4, 5, 6 and 7 low.
delay(3); //Wait 3 milliseconds before the next loop.
if(start == 125){ //Every 125 loops (500ms).
digitalWrite(12, !digitalRead(12)); //Change the led status.
start = 0; //Start again at 0.
}
}
start = 0; //Set start back to 0.
//65.5 = 1 deg/sec (check the datasheet of the MPU-6050 for more information).
gyro_roll_input = (gyro_roll_input * 0.7) + ((gyro_roll / 65.5) * 0.3); //Gyro pid input is deg/sec.
gyro_pitch_input = (gyro_pitch_input * 0.7) + ((gyro_pitch / 65.5) * 0.3);//Gyro pid input is deg/sec.
gyro_yaw_input = (gyro_yaw_input * 0.7) + ((gyro_yaw / 65.5) * 0.3); //Gyro pid input is deg/sec.
//Place the MPU-6050 spirit level and note the values in the following two lines for calibration.
angle_pitch_acc -= 0.0; //Accelerometer calibration value for pitch.
angle_roll_acc -= 0.0; //Accelerometer calibration value for roll.
angle_pitch = angle_pitch * 0.9996 + angle_pitch_acc * 0.0004; //Correct the drift of the gyro
pitch angle with the accelerometer pitch angle.
angle_roll = angle_roll * 0.9996 + angle_roll_acc * 0.0004; //Correct the drift of the gyro roll
angle with the accelerometer roll angle.
//For starting the motors: throttle low and yaw left (step 1).
if(receiver_input_channel_3 < 1050 && receiver_input_channel_4 < 1050)start = 1;
//When yaw stick is back in the center position start the motors (step 2).
if(start == 1 && receiver_input_channel_3 < 1050 && receiver_input_channel_4 > 1450){
start = 2;
//The PID set point in degrees per second is determined by the roll receiver input.
//In the case of deviding by 3 the max roll rate is aprox 164 degrees per second ( (500-8)/3 = 164d/s ).
pid_roll_setpoint = 0;
//We need a little dead band of 16us for better results.
if(receiver_input_channel_1 > 1508)pid_roll_setpoint = receiver_input_channel_1 - 1508;
else if(receiver_input_channel_1 < 1492)pid_roll_setpoint = receiver_input_channel_1 - 1492;
//The PID set point in degrees per second is determined by the pitch receiver input.
//In the case of deviding by 3 the max pitch rate is aprox 164 degrees per second ( (500-8)/3 = 164d/s
).
pid_pitch_setpoint = 0;
//We need a little dead band of 16us for better results.
if(receiver_input_channel_2 > 1508)pid_pitch_setpoint = receiver_input_channel_2 - 1508;
else if(receiver_input_channel_2 < 1492)pid_pitch_setpoint = receiver_input_channel_2 - 1492;
//The PID set point in degrees per second is determined by the yaw receiver input.
//In the case of deviding by 3 the max yaw rate is aprox 164 degrees per second ( (500-8)/3 = 164d/s ).
pid_yaw_setpoint = 0;
//We need a little dead band of 16us for better results.
if(receiver_input_channel_3 > 1050){ //Do not yaw when turning off the motors.
if(receiver_input_channel_4 > 1508)pid_yaw_setpoint = (receiver_input_channel_4 - 1508)/3.0;
else if(receiver_input_channel_4 < 1492)pid_yaw_setpoint = (receiver_input_channel_4 - 1492)/3.0;
}
if (battery_voltage < 1240 && battery_voltage > 800){ //Is the battery connected?
esc_1 += esc_1 * ((1240 - battery_voltage)/(float)3500); //Compensate the esc-1 pulse for
voltage drop.
esc_2 += esc_2 * ((1240 - battery_voltage)/(float)3500); //Compensate the esc-2 pulse for
voltage drop.
esc_3 += esc_3 * ((1240 - battery_voltage)/(float)3500); //Compensate the esc-3 pulse for
voltage drop.
esc_4 += esc_4 * ((1240 - battery_voltage)/(float)3500); //Compensate the esc-4 pulse for
voltage drop.
}
else{
esc_1 = 1000; //If start is not 2 keep a 1000us pulse for ess-1.
esc_2 = 1000; //If start is not 2 keep a 1000us pulse for ess-2.
esc_3 = 1000; //If start is not 2 keep a 1000us pulse for ess-3.
esc_4 = 1000; //If start is not 2 keep a 1000us pulse for ess-4.
}
//! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
//Because of the angle calculation the loop time is getting very important. If the loop time is
//longer or shorter than 4000us the angle calculation is off. If you modify the code make sure
//that the loop time is still 4000us and no longer! More information can be found on
//the Q&A page:
//! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
if(micros() - loop_timer > 4050)digitalWrite(12, HIGH); //Turn on the LED if the loop time
exceeds 4050us.
//There is always 1000us of spare time. So let's do something usefull that is very time consuming.
//Get the current gyro and receiver data and scale it to degrees per second for the pid calculations.
gyro_signalen();
while(PORTD >= 16){ //Stay in this loop until output 4,5,6 and 7 are
low.
esc_loop_timer = micros(); //Read the current time.
if(timer_channel_1 <= esc_loop_timer)PORTD &= B11101111; //Set digital output 4 to low
if the time is expired.
if(timer_channel_2 <= esc_loop_timer)PORTD &= B11011111; //Set digital output 5 to low
if the time is expired.
if(timer_channel_3 <= esc_loop_timer)PORTD &= B10111111; //Set digital output 6 to low
if the time is expired.
if(timer_channel_4 <= esc_loop_timer)PORTD &= B01111111; //Set digital output 7 to low
if the time is expired.
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This routine is called every time input 8, 9, 10 or 11 changed state. This is used to read the receiver
signals.
//More information about this subroutine can be found in this video:
//https://youtu.be/bENjl1KQbvo
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ISR(PCINT0_vect){
current_time = micros();
//Channel 1=========================================
if(PINB & B00000001){ //Is input 8 high?
if(last_channel_1 == 0){ //Input 8 changed from 0 to 1.
last_channel_1 = 1; //Remember current input state.
timer_1 = current_time; //Set timer_1 to current_time.
}
}
else if(last_channel_1 == 1){ //Input 8 is not high and changed from 1 to 0.
last_channel_1 = 0; //Remember current input state.
receiver_input[1] = current_time - timer_1; //Channel 1 is current_time - timer_1.
}
//Channel 2=========================================
if(PINB & B00000010 ){ //Is input 9 high?
if(last_channel_2 == 0){ //Input 9 changed from 0 to 1.
last_channel_2 = 1; //Remember current input state.
timer_2 = current_time; //Set timer_2 to current_time.
}
}
else if(last_channel_2 == 1){ //Input 9 is not high and changed from 1 to 0.
last_channel_2 = 0; //Remember current input state.
receiver_input[2] = current_time - timer_2; //Channel 2 is current_time - timer_2.
}
//Channel 3=========================================
if(PINB & B00000100 ){ //Is input 10 high?
if(last_channel_3 == 0){ //Input 10 changed from 0 to 1.
last_channel_3 = 1; //Remember current input state.
timer_3 = current_time; //Set timer_3 to current_time.
}
}
else if(last_channel_3 == 1){ //Input 10 is not high and changed from 1 to
0.
last_channel_3 = 0; //Remember current input state.
receiver_input[3] = current_time - timer_3; //Channel 3 is current_time - timer_3.
}
//Channel 4=========================================
if(PINB & B00001000 ){ //Is input 11 high?
if(last_channel_4 == 0){ //Input 11 changed from 0 to 1.
last_channel_4 = 1; //Remember current input state.
timer_4 = current_time; //Set timer_4 to current_time.
}
}
else if(last_channel_4 == 1){ //Input 11 is not high and changed from 1 to
0.
last_channel_4 = 0; //Remember current input state.
receiver_input[4] = current_time - timer_4; //Channel 4 is current_time - timer_4.
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Subroutine for reading the gyro
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void gyro_signalen(){
//Read the MPU-6050
if(eeprom_data[31] == 1){
Wire.beginTransmission(gyro_address); //Start communication with the gyro.
Wire.write(0x3B); //Start reading @ register 43h and auto increment
with every read.
Wire.endTransmission(); //End the transmission.
Wire.requestFrom(gyro_address,14); //Request 14 bytes from the gyro.
if(cal_int == 2000){
gyro_axis[1] -= gyro_axis_cal[1]; //Only compensate after the calibration.
gyro_axis[2] -= gyro_axis_cal[2]; //Only compensate after the calibration.
gyro_axis[3] -= gyro_axis_cal[3]; //Only compensate after the calibration.
}
gyro_roll = gyro_axis[eeprom_data[28] & 0b00000011]; //Set gyro_roll to the correct axis
that was stored in the EEPROM.
if(eeprom_data[28] & 0b10000000)gyro_roll *= -1; //Invert gyro_roll if the MSB of
EEPROM bit 28 is set.
gyro_pitch = gyro_axis[eeprom_data[29] & 0b00000011]; //Set gyro_pitch to the correct
axis that was stored in the EEPROM.
if(eeprom_data[29] & 0b10000000)gyro_pitch *= -1; //Invert gyro_pitch if the MSB of
EEPROM bit 29 is set.
gyro_yaw = gyro_axis[eeprom_data[30] & 0b00000011]; //Set gyro_yaw to the correct
axis that was stored in the EEPROM.
if(eeprom_data[30] & 0b10000000)gyro_yaw *= -1; //Invert gyro_yaw if the MSB of
EEPROM bit 30 is set.
acc_x = acc_axis[eeprom_data[29] & 0b00000011]; //Set acc_x to the correct axis that
was stored in the EEPROM.
if(eeprom_data[29] & 0b10000000)acc_x *= -1; //Invert acc_x if the MSB of
EEPROM bit 29 is set.
acc_y = acc_axis[eeprom_data[28] & 0b00000011]; //Set acc_y to the correct axis that
was stored in the EEPROM.
if(eeprom_data[28] & 0b10000000)acc_y *= -1; //Invert acc_y if the MSB of
EEPROM bit 28 is set.
acc_z = acc_axis[eeprom_data[30] & 0b00000011]; //Set acc_z to the correct axis that
was stored in the EEPROM.
if(eeprom_data[30] & 0b10000000)acc_z *= -1; //Invert acc_z if the MSB of EEPROM
bit 30 is set.
}
void calculate_pid(){
//Roll calculations
pid_error_temp = gyro_roll_input - pid_roll_setpoint;
pid_i_mem_roll += pid_i_gain_roll * pid_error_temp;
if(pid_i_mem_roll > pid_max_roll)pid_i_mem_roll = pid_max_roll;
else if(pid_i_mem_roll < pid_max_roll * -1)pid_i_mem_roll = pid_max_roll * -1;
pid_last_roll_d_error = pid_error_temp;
//Pitch calculations
pid_error_temp = gyro_pitch_input - pid_pitch_setpoint;
pid_i_mem_pitch += pid_i_gain_pitch * pid_error_temp;
if(pid_i_mem_pitch > pid_max_pitch)pid_i_mem_pitch = pid_max_pitch;
else if(pid_i_mem_pitch < pid_max_pitch * -1)pid_i_mem_pitch = pid_max_pitch * -1;
pid_last_pitch_d_error = pid_error_temp;
//Yaw calculations
pid_error_temp = gyro_yaw_input - pid_yaw_setpoint;
pid_i_mem_yaw += pid_i_gain_yaw * pid_error_temp;
if(pid_i_mem_yaw > pid_max_yaw)pid_i_mem_yaw = pid_max_yaw;
else if(pid_i_mem_yaw < pid_max_yaw * -1)pid_i_mem_yaw = pid_max_yaw * -1;
pid_last_yaw_d_error = pid_error_temp;
}
//This part converts the actual receiver signals to a standardized 1000 – 1500 – 2000 microsecond value.
//The stored data in the EEPROM is used.
int convert_receiver_channel(byte function){
byte channel, reverse; //First we declare some local variables
int low, center, high, actual;
int difference;
void set_gyro_registers(){
//Setup the MPU-6050
if(eeprom_data[31] == 1){
Wire.beginTransmission(gyro_address); //Start communication with the address
found during search.
Wire.write(0x6B); //We want to write to the PWR_MGMT_1
register (6B hex)
Wire.write(0x00); //Set the register bits as 00000000 to activate the
gyro
Wire.endTransmission(); //End the transmission with the gyro.
//Let's perform a random register check to see if the values are written correct
Wire.beginTransmission(gyro_address); //Start communication with the address
found during search
Wire.write(0x1B); //Start reading @ register 0x1B
Wire.endTransmission(); //End the transmission
Wire.requestFrom(gyro_address, 1); //Request 1 bytes from the gyro
while(Wire.available() < 1); //Wait until the 6 bytes are received
if(Wire.read() != 0x08){ //Check if the value is 0x08
digitalWrite(12,HIGH); //Turn on the warning led
while(1)delay(10); //Stay in this loop for ever
}
}
}
4.2 Testing Approach
4 Receiver Check if its receives the Red Led lights when the PASS
signal from transmitter transmitter is turned on
3. PID Testing:
Once the stability of the drone was maintained the next phase was to apply the PID to the
quadcopter. The PID is used to make the drone move freely while flying and maintaining the stability
as it was stored while stabilization testing.
The PID consist of two factors
1. Gyroscope:
The gyroscope measures angular velocity, 𝜃̇, in radians per second or degrees per second.
Intuitively, by integrating the angular velocity the tilt angle can be calculated. Since the gyroscope
readings are taken at discrete time intervals, 𝑑𝑡, numerical integration is performed using the Euler
method.
The equation above assumes the sensor initial position is 0 degrees. If the starting position of
the sensor is non-zero, the angle has to be initialized to the value, possibly from another sensor i.e.
accelerometer.
A key element to observe was that the measurements were taken while the quadcopter was at
rest. So that if the quadcopter tilts to desire directions its can send signals to accelerometer.
2. Accelerometer:
The accelerometer measures the acceleration relative to free fall. The acceleration is often
measured in gs, which is based on earth’s gravitational pull (9.81m/s). To determine the orientation of
the accelerometer, it is assumed that the only force acting on the object is earth’s gravitation pull.
Gravity always acts ‘down’, thus when the object is tilted, the force is divided into components in the
x, y, and z directions of the object. Since the axes are orthogonal to one another, Pythagoras theorem
can be used to show the relationship between the forces.
The following equation is more useful as it calculates the angle relative to the z-axis (Roll)
𝑅𝑜𝑙𝑙 = 𝜙𝑥𝑦𝑧 = tan−1 ( 𝑦 /𝑧 )
With a similar approach, Pitch can also be calculated. However, Yaw cannot be determined
accurately, especially when the force in the z direction = 1g (assuming the accelerometer can only rotate
and not translate in any direction). In this case changing the yaw, will have impact on the components
of x and y, making yaw not constant.
6.1 CONCLUSION
Our research work yielded a successful development of Arduino Uno based Quadcopter at a
cheaper and affordable amount. Quadcopter which can be easily made from shelf components. It can
be used as a low-cost alternative to various applications which includes pesticide sprinkling, end to end
delivery within the transmitter’s RF range, surveillance in defence and other sensitive places like nation
border, mapping through remote sensing, and record the picture of places.
6.2 LIMITATION
The battery in the drone has a limited power of 10-15min of flight. The Camera used has a
very low resolution and the images are of low quality.
CHAPTER 7
BIBLIOGRAPHY
http://www.brokking.net/ymfc-al_main.html
(this link is used to make the quadcopter.)
https://www.instructables.com/id/How-to-Make-a-Drone-Using-Arduino-Make-a-Quadcopte/
(this link is used to build the quadcopter frame and other parts)
https://hkalasua.wordpress.com/2017/09/11/ov7670-arduino-sd/
(used to connect the camera module and sd card module to Arduino)
https://www.youtube.com/watch?v=2pHdO8m6T7c
(this video is used for the connection of the drone)
https://www.youtube.com/watch?v=DYpHB-LfloI&t=132s
(this video is used to write code to make quadcopter move according to the transmitter movement)
https://www.youtube.com/watch?v=nCPEJTUYch8&list=PL0K4VDicBzsibZqfa42DVxC8CGCMB7
G2G&index=5&t=377s
(used to set the gyro and accelerometer to the drone)