You are on page 1of 59

Research Experience for Undergraduates:

Unmanned Aerial Vehicle Design, Phase I

By:
Sylvester Meighan
Damon Cardenas
Mark Finch
Laurissa Wilson

The University of Texas at San Antonio

August 10, 2007

This work was supported in part by the National Science Foundation, Grant Number: NSF
0649172
Table of Contents
________________________________________________________________________

Title page
1.0 Abstract p. 1
2.0 Introduction p. 1
3.0 Overview p. 2
4.0 Attitude Heading Reference System p. 3
4.1 Microcontroller p. 3
4.2 Accelerometer p. 5
4.3 Gyro p. 7
4.4 Pressure Sensor and Pitot tube p. 8
4.5 Sonar p. 9
4.6 Single Poll Double Throw Analog Switch p. 10
4.7 Magnetometer p. 11
4.8 Pulse Width Measurements p. 12
4.9 Liquid Crystal Display (LCD) p. 13
4.10 Serial Communication p. 14
4.11 Wireless Communication p. 14
4.12 Sensor Data Storage p. 14
5.0 GUI p. 17
6.0 Conclusion p. 20

Appendix
A. Code p.22
B. CIFER installation on the Ubuntu 7.04 distribution of Linux p.55

References p.56
1.0 Abstract

Modeling of nonlinear systems in aeronautics can be a difficult task to achieve by using


physics alone. This is due to the fact that textbook physics uses equations derived in an
undisturbed and restricted environment. In order to create a more accurate and precise
mathematical model, a different approach can be taken. Rather than using purely math and
physics to derive models that account for environmental disturbances, there are modern day
computational tools that allow us to use reverse engineering to achieve realistic and accurate
results. It may be more efficient to measure the response of a system to known inputs and use the
obtained data to predict future responses of the same system. The most important aspect to this
approach is the collection of time history data. To achieve this task the ATmega128
microcontroller was used as the main computer for the inertial measurement unit for data
collection. The MMA7260Q 3-axis accelerometer measured the pitch, roll, and yaw angles of the
aircraft while two IDG300 gyros where used to measure the pitch, roll, and yaw rates. Two
pressure sensors were used to measure the barometric pressure and the airspeed. Finally, an
ultrasonic ranger was implemented for low altitude measurements.

2.0 Introduction

Since the first deployment of Unmanned Aerial Vehicles (UAVs) in the military,
continuous research and development efforts have been focused on enhancing UAV technology.
Militarily, the usefulness and importance of UAVs cannot be underestimated, and their use in the
civilian sector shows promise as well. Two very important advantages of employing UAVs are
that human lives aren’t unnecessarily endangered, and tasks or objectives that were previously
considered impossible are made possible. Reconnaissance can be carried out and hostile targets
can be assessed and eliminated without sending one soldier across enemy lines. The potential
capabilities of UAVs would also be particularly advantageous to law enforcement agencies. For
example, a single, small UAV could be used by police officers to assess a situation beyond a
building that is obstructing their view, or perhaps serve as a delivery system to emplace chemical
sensors [1].
A less obvious but equally useful function that could be performed by one or more UAVs
is that of establishing an extended network for military communications. When missions must
be carried out across rugged or mountainous terrain, terrestrial communication capabilities can
be reduced. In such a situation, a team of UAVs could be strategically placed to relay signals
between distant ground locations. This type of system would give commanders a distinct
advantage in ground-based operations. Limitations of current UAV technology, however, have
prevented this system from reaching its full potential. Since the range of wireless transceivers on
UAVs is limited, as many UAVs as possible would be needed to maintain a satisfactory
communication link. Unfortunately, the cost of UAVs designed for military use is high, so
research has been conducted to implement a UAV-based communication network with a minimal
number of aircraft [2].
In fact, although companies like Aerovironment have already built and sold fully-
functional autonomous UAVs such as the Dragon Eye, there are many aspects of UAV
functionality and implementation that are still being researched [3]. An example is the prospect
of utilizing multiple UAVs operating autonomously to carry out missions while communicating
and coordinating with each other. Disregarding the ambiguity surrounding the term
“autonomous,” which could refer to varying levels of self-directed flight, using a system of
multiple UAVs to carry out a mission could be implemented with a central control station. The
problem facing researchers, however, is that using a central control station that must
communicate with every aircraft creates data bandwidth limitations. Thus, the current research
in this area involves designing autonomous UAVs to communicate directly between each other
to coordinate tasks, instead of relying upon a central control station [4].
The ultimate goal of this research project is to not only develop a fully autonomous UAV,
but also to integrate an autonomous UAV into a system of autonomous Unmanned Ground
Vehicles (UGVs). Ideally, the UAV would serve as both a relay for UGV communications and
as a target acquisition and reconnaissance vehicle. If successfully implemented, such a network
of vehicles would be very useful for performing critical missions such as search and rescue.
Obviously, the initial requirement is to design and build an autonomous flight control system for
the aircraft. This is quite an involved task in itself, as autonomous flight requires the use of
several sophisticated sensors and a robust control system. As an example of the degree of
complexity involved, the U.S. Army’s SOAR (Silent Operating Aerial Reconnaissance) UAV
uses 12 sensors, a GPS receiver, and a microcontroller to fly autonomously [5].
The goal of the initial phase of this project was to design and build an Attitude and
Heading Reference System (AHRS) consisting of several microelectromechanical system
(MEMS) sensors, a microcontroller, and a data logging system, as well as a graphical user
interface (GUI) to monitor sensor data from a ground station. The sensor data will be used in
future phases of the project to create a model of the aircraft, and, ultimately, an autonomous
control system.

3.0 Overview

The Research Experience for Undergraduates program at the University of Texas at San
Antonio will consist of three summers of work. Phase one of the research for the unmanned
aerial vehicle group consists of laying the foundation for the next two summers’ research
endeavors. This encompasses design of the aviation electronic systems (avionics) to be used to
monitor the flight dynamics of an aircraft. These electronic systems will have sensors for data
collection, an LCD display and push buttons on the unit for user interaction, wireless transmitters
for data transmission, an SD card for memory storage, along with control software on a base
station computer for aircraft monitoring and control. Phase two of the research will consist of
two parts. Modeling of the aircraft to be used and control system design. The modeling will use
the hardware previously developed to gather test flight data for use in system identification of the
aircraft. Then the developed model will be tested with simulations and implemented in
autonomous flight stability and navigation control algorithms. Finally, phase three will expand
upon the autonomous flight capabilities and wireless communication schemes previously
developed to achieve more intelligent path planning strategies, collision avoidance schemes, and
communication with unmanned ground vehicles for collaborative mission execution.

This summer marked phase one (hardware and software ground work) in the three part
plan. The first major hurdle in designing control algorithms for aerial vehicles involves the
calculating of a mathematical model. This model will be used in simulations to understand the
dynamics of the aircraft and in matlab and simulink for control system design. Developing a
model can be achieved by two different methods. A physics based approach requires
aerodynamic, mechanical, and atmospheric condition modeling. Because of the nonlinearity of
aircraft systems, this method can be tedious and result in less than desirable approximations
inherit in math and physics based modeling. The alternative approach is called system
identification. System Identification or System ID, requires the collection of sampled time
history data from test flights which is then conditioned and used to calculate the mathematical
model of a system. Using real-world measurements of an aircraft’s response to pilot control
inputs reduces the time required to develop a model and can produce highly accurate
representations because of the inclusion of real-world disturbances that would have been difficult
or impossible to account for using physics alone
.

4.0 Attitude Heading Reference System

4.1 Microcontroller

The collection of accurate time history data serves a pinnacle role in the system
identification process. Sensors are required for perception of forces and moments about
translational and rotational axes and a microcontroller is used to coordinate these actions along
with data logging and wireless communication. The ATmega128 8-bit microcontroller was
chosen as the main computer processor in this system. This processor was chosen for the
following reasons.

• RISC architecture - provides for more efficient and compact code.


• Code portability – this feature is very useful when development requires more resources
than available in the current microprocessor and an upgrade is necessary. Code
portability removes the need for unnecessary rewriting of code in these and similar
instances.
• User community – the atmel avr user community proves to be a very helpful resource
which can be found through websites like avrfreaks.net or other user forums. The wealth
of code found online also aided in the early phases of the development process.

The AVR-MT-128 development board was utilized for its pre-configured hardware
peripherals. As illustrated in Figure 4.1 below, the power, system clock, LCD, and serial port and
other connections are already in place on the microprocessor. This saved time soldering
components necessary to initially get started. The AVR-MT-128 also provides two external pin
headers for utilizing the remaining I/O pins of the ATmega128 and also one six pin header to
access the 10-bit analog to digital converter of the microcontroller. A JTAG connection was
utilized during the design process to download code to the flash memory and perform in circuit
debugging. The AVR-MT-128 board came with demo software that allowed printing of ASCII
text to the LCD screen, transmission of ASCII text through the serial port, and responses to
button push events. This code was modified to form the basic framework for the attitude heading
reference system.
AVR Studio 4 is an integrated development environment specifically made to write
assembly code for Atmel computer processors. It can be downloaded from Atmel’s main website
for free. In order to write C language code, winavr: avr-gcc has to be installed and used as a
plug-in to the latest version of AVR Studio 4. Winavr is a Microsoft Windows port of the Linux
gcc compiler tool chain and Libc a standard avr C library for Atmel microcontrollers. AVR
Studio provided a strong set of tools for code development and debugging. The compiler allows
a programmer to monitor variables in memory, register values, and port states in debug mode. It
also allows the user to step through the code or blocks of code. All of these features created a
productive environment for code development and debugging.

Figure 4.1 – AVR-MT-128 Development Board Schematic


4.2 Accelerometer

Some characteristics of interest in system identification and control are pitch, roll, and
yaw angles and rates of rotations (the aircraft attitude). An accelerometer is a device that
measures the force of gravity exerted along an axis. This measured force may be used to
calculate the angle of the axis with respect to gravity. The MMA7260Q is a three-axis micro-
electromechanical (MEMS) accelerometer. Sparkfun.com provided a convenient header board
that had this surface mount sensor mounted on a larger dip breakout board for prototyping. Of
the following features, the selectable sensitivity and low power consumption made this unit an
excellent option for uav applications.

Features:
• Selectable Sensitivity (1.5g/2g/4g/6g)
• Low Current Consumption: 500 μA
• Sleep Mode: 3 μA
• Low Voltage Operation: 2.2 V ñ 3.6 V
• 6mm x 6mm x 1.45mm QFN
• High Sensitivity (800 mV/g @1.5 g)
• Fast Turn On Time
• High Sensitivity (1.5 g)
• Integral Signal Conditioning with Low Pass Filter
• Robust Design, High Shocks Survivability
• Pb-Free Terminations
• Environmentally Preferred Package
• Low Cost
• 16 LEAD QFN

This accelerometer provides three analog voltage outputs that are proportional to the
force of gravity exerted along the x, y, and z axis of the device. Below in Figure 4.2 is a
representation of the inside of the accelerometer. There are two fixed metal surfaces with a third
surface in between that is free to move closer or farther from either of the fixed surfaces. The
center surface is flexed in either direction, closer to one of the fixed surfaces and further from the
other, by and acceleration (gravity). The distances between the center surface and side surfaces
create two variable capacitances that are proportional to the force of gravity.
Figure 4.2 - Simplified Accelerometer Model

The sensitivity selection pins (gs1 and gs2) were both connected to 3.3V to set the sensor
to measure accelerations of +/- 6 g’s with a sensitivity of 200mV/g. The three output pins of the
accelerometer where then connected to three different analog to digital converter pins on the
ATmega128 for measurement. The code found in the appendix was written to read each analog
to digital converter pin and convert the 10-bit number into a voltage value to be stored in
memory and used in the attitude calculations. The following values where measured to use in the
attitude calculation process. The maximum voltages (i.e. the voltage when gravity is acting
parallel to the measured axis) where measured and saved in memory for each accelerometer axis.
The voltages present when each axis was perpendicular to gravity where also measured and
stored in memory. The linear relation between the angles the board made with respect to gravity
and the voltage measured at that angle, for two different positions (perpendicular and parallel to
gravity) where used to predict the unknown angle of the sensor board for a given measured
voltage.

(y2 - y1)
m = ----------- newY2 = m*(newX2 - x1) + y1
(x2 - x1)

The voltage from the z-axis output of the accelerometer was also measured when the z-
axis was perpendicular to gravity but was used differently. Instead of finding an angle, the z-axis
was used to tell if the board was upside down or right side up. When the z-axis is less than the
perpendicular voltage, the sensor is upside down and vice versa. In code, this allowed
determining the quadrant that the other two axes are in. When the sensor is upside down the
measured angle must be in quadrant I or III and inversely when the sensor is right side up the
other measured angle are in quadrant II or IV. This scheme was used to determine the orientation
of the sensor board (and attitude of the aircraft).

4.3 Gyro

Similar to the accelerometer, Sparkfun.com provided a breakout board of the IDG-3000


rate gyro used in the inertial measurement unit. As illustrated in Figure 4.3 below, a rate gyro
measures the rate of rotation about a given axis.
Figure 4.3 - Rotational Axes of Gyro

The IDG-300 is also an analog device and provides output voltages that are proportional to the
rate of rotation. This gyro provides 2mV per degree of rotational rate. The gyro rates coupled
with the accelerometer angles can be used as feedback in a stability and navigation control
system.

4.4 Pressure Sensor and Pitot tube

The pressure sensors are used mainly to find the airspeed of the plane. The pressure
sensors measure the dynamic and static pressure of the air around the plane. The equation for
finding the velocity from the pressure sensors is shown below:

2[PD (kPa)]
2 2 2
V (m /s ) = --------------
R (kg/m3)

In the above equation, PD is the dynamic pressure and R is density of the surrounding air.
Velocity is denoted with the character V. The density of air is typically around 12kg/m3, and the
range of dynamic pressure for the pressure sensor is between 0 and 3.92kPa (kN/m2) or 0 – 400
mmH20.
The pinout for the MPXV5004 pressure sensor that we used is shown below in Figure4.4:

Figure 4.4 – Pressure Sensor Pinout

The first pin is marked with a notch on the lead. The output voltage of the pressure
sensor ranges from 1 to 4.9V. The Vout of the chip must be used for analog to digital conversion.
For this project, the pressure sensors were attached to NC4 and NO4 of the analog switch. This
switch is then connected to the ADC3 pin of the ATmega128. The equation for analog to digital
conversion is shown below:

adcRead 1024 bits 500 mmH2O


mmH2O = (---------- __ ------------) X --------------- .
1 4.9 1024 bits .
1 mmH2O / 102.0408 = 1 kPa

The equation above compensates for the fact that the pressure sensors only output
voltages from 1V to 4.9V.

4.5 Sonar

Another important device for this project is the sonar. The sonar is used to find the low
altitude of the plane. The basis of the sonar is using sound to approximate distance from an
object ahead of the device. A sound wave is sent from the face of the sonar, and a short time
later, the same sound is reflected off of an object and received by the sonar. The time between
the transmission and the reception of the sound wave, multiplied by the speed of sound in air
(≈344 m/s), gives the distance of the plane from an object.
The specifications for the LV MaxSonar (Figure 4.5 below) that was used for this project are:

• Locates distances from 6 inches to 255 inches


• Low Voltage Operation: 2.5 V – 5.5 V
• Pulse Width Modulation (PWM) capabilities
• High Sensitivity (800 mV/g @1.5 g)
• Serial Communication
• Readings can occur every 50 ms
• Low Cost

Figure 4.5 – Sonar Sensor

For this project, we did not make use of the PWM capabilities. To make sure the sonar
does not stop ranging data, the RX pin should (as a safety precaution) be pulled high. The TX
pin is used only for serial connections, thus, can be left without connections. The BW pin may
also be unconnected. The +5 pin is the supply voltage pin and can be connected to anywhere
from in the specified range for input voltage (2.5 – 5.5V). The GND pin must be connected to
the ground. Finally, the AN pin must be connected to one of the analog to digital ports on your
microprocessor.
When referring to the reading from the analog to digital port, the following conversion
equation must be used:

adcRead bits 5 volts 1000 mV 1 inches .


-------------- X ---------- X ----------- X ------------ = Distance in inches .
1 1024 bits 1 Volts 7.23 mV .

The 1024 bits is obtained from the 10-bit resolution ADC. The 5V is the maximum
voltage obtained from the ADC on the ATmega128 processor. The .00723V is obtained by
dividing the supply voltage by 512, which is used for the SonarMax chip.

4.6 Single Pole Double-Throw Analog Switch

A fundamental device when working with the ATmega128 microprocessor is the single
pole double-throw analog switch. The analog switch is capable of interchanging between two
channels of input with eight possible inputs. The schematic in Figure 4.6 below shows each of
these channels:

Figure 4.6 – Analog Switch

The eight input signals go into either the NC or NO channels, and are output from one of
the COM pins. Using the IN pin to switch between whether NC or NO is selected, you can use 8
input channels for four analog to digital ports while acquiring the appropriate data when
necessary. Thus the reason for why this device is important is simple; as can be seen from the
processors’ schematic, there are not enough analog to digital ports to support the analog devices
we are using. There are a total of eight analog to digital ports in the ATmega128
microprocessor, and since we will be using the following: 3-axis accelerometer (using 3 ADC
ports), 3 axes for the gyroscope (3 ADC ports), two pressure sensors (2 ADC ports), and a sonar
(1 ADC port) we will need a total of nine analog to digital ports. Clearly a method to help lower
the amount of necessary analog to digital ports is necessary.
To fully utilize the potential of the switch, one must make the proper connections. The
first step in doing so is connecting the V+ pin 16, to the proper supply voltage of 3.3V. Next,
attach the GND pin 8 and the EN pin 15 to the ground. The EN pin needs to be grounded for the
switch to be enabled. Now attach a set of inputs to the all the NC lines. All the NC lines will be
on or off at the same time, so plan to read all of those inputs together. Attach the remaining
input lines to the NO channels. For this specific task, the accelerometer inputs and one pressure
sensor input were assigned to the NC channels, and all the gyroscope inputs as well as one
pressure sensor were assigned to the NO channels. Attach all the COM channels to the
coordinating analog to digital (ADC) ports. Finally, attach the IN pin 1 of the chip onto any
available output port from the microprocessor chip. By changing the status of the output port
from low to high, the chip then switches from the NC channels the NO channels.

4.7 Magnetometer

Magnetometers can be used in flight to determine the magnetic heading of an object. The
earth has a magnetic field encompassing it due a multitude of factors. Magnetometers can sense
the subtle changes in the magnetic field of the earth to determine a heading. These readings can
be affected by different devices that may possess their own relatively strong magnetic field (for
instance function generators).
The magnetometer is probably the most difficult piece of equipment to set up for this
project. This project does not currently incorporate the magnetometer coding in the main
program for the simple reason that the code is not fully functional due to time constraints. The
magnetometer is not currently hardwired to the present board for the project either. The known
information about the magnetometer, however, is cited.
The magnetometer, unlike the other sensors, uses a method known as serial peripheral
interface (SPI) to communicate with the ATmega128 processor. The idea is that the ATmega128
sends one byte of data to the MicroMag 3 (magnetometer) to be processed by the chip. The
MicroMag 3 acts as a mini-microprocessor and performs certain operations based on what data is
sent to it. The magnetometer in turn transmits two bytes of information that describe the
magnetic heading.
The SPI protocol is simply a method for a microcontroller to communicate with another
device that acts much like a mini-microcontroller. With SPI, there are 4 lines which must be
connected for communication to occur successfully: Master-Out Slave-In line (MOSI), Master-In
Slave-Out line (MISO), Slave-Select line (SS), and the S-Clock (SCLK) line. The MOSI and
MISO lines are used to determine which processor is carrying out the main functions. For this
project, the ATmega128 is known as the “master,” and the MicroMag 3 is the “slave.” Since the
ATmega128 is the master, the MOSI line (Port B pin 2 (PB2)) must be set as an output, and the
MISO line (PB3) must be set as an input. The SS line is located on the PB0 pin of the
ATmega128 microprocessor board. This should be an output from the ATmega128 and should
be set low. Finally, the SCLK line of the ATmega128 is located at pin PB1, and should be set as
an output. **Note: For the SPI to work, the SPI enable bit in the sixth bit of the control register
must be set high, and the SPI flag in the seventh bit of the status register must be set low.
The MicroMag 3 magnetometer needs two more connections before wiring is completed.
A reset connection with one of the open ports on the ATmega128 (set as an output) is necessary
as well as a port for the data ready (DRDY) line (set as an input). The pinout, as well as a
picture of the magnetometer can be seen below in figure x:
Figure 4.7 - Magnetometer

Before any reception, computing or transmission of data can occur in the magnetometer,
the reset line must be pulsed from low to high to low. After the reset line is pulsed the
magnetometer can receive a command byte from the ATmega128. This is completed by writing
to the SPI data register (SPDR) in your main AVR program. The magnetometer then computes
the magnetic heading and sets the DRDY line high. When the DRDY line is set high, the
magnetic heading can then be retrieved by the magnetometer by reading from the SPDR in your
main program.

4.8 Pulse Width Measurements

Pulse width is important for this project because it helps to determine the amount of
power that the servos are using which in turn describes the response of the aircraft to a
command. When the ailerons or the elevators are turned by a user, a pulse goes to each of the
corresponding servos, alerting the servos to move an aileron or an elevator in a specific manner.
An example of how this system works can be seen below in Figure 4.8:
Figure 4.8 – Servo Pulse Width

In Figure 4.8, we can see that the length of a pulse changes the position of a servo. After
the remote control sends the signal to the servos, the servos react in a certain fashion, and that
data can be recorded to find the servo reaction. In the future, when the plane is more ready to be
made autonomous, this information can help the plane figure out on its own how much power to
send to each servo when it is ready to turn.
To acquire this data, the pulse output of the servos must be connected to an input capture
of the microprocessor. For this project, the IC1 pin (which can be located in
Port D bit 4 (PD4)) was used. The output signal lines from the servos also need to be attached to
the voltage supply and the ground of the microprocessor.
In the main AVR program for the project, an interrupt for the pulse readings must be set
up. The interrupt must begin a counter on the rising edge of a pulse and stop the counter on the
falling edge. The counter tells the length of the pulse in clock cycles. Using the amount of clock
cycles and the speed of the clock, the length of the pulse in time can be obtained. The equation
is:

(number of clock cycles) / (clock speed in MHz) = time in μs.

The time received from the servos should be in the range of 1.25 to 1.75 ms, as shown in
Figure 4.8 above.

4.9 Liquid Crystal Display (LCD)

The LCD screen is used in the final project only to display the status of the SD card,
which is the device that stores the sensor data. It is, however, also a very useful tool in the
debugging of a program. It provides a means to quickly see any particular bytes that you are
working with while a program is running. The LCD is connected to Port C of the ATmega128
processor and is very easy to implement into a program.
4.10 Serial Communication

Serial communication is one of the simpler techniques to use with the ATmega128
microprocessor board. The board used in this project has a female serial connection attached to
it. Using a serial cable you can attach the ATmega128 board to a computer and use programs
such as hyper terminal or X-CTU to obtain information (X-CTU is a program similar to hyper
terminal with options geared towards using wireless modules). Only a few command lines in the
main AVR program are necessary to send information through the serial port.

4.11 Wireless Communication

Wireless communication is one of the possible methods for obtaining data. If a storage
device (SD) card is not used, data can be streamed wirelessly from the sensors on the plane to a
bay station. This bay station can be a computer with either the hyper terminal or the X-CTU
program, with the X-CTU program being the preferred method. The wireless communication in
this project was completed using MaxStream’s XTend OEM RF module. The module is
described as a plug and play device, which means no special programming is necessary. Two
MaxStream Wireless modules are necessary. One module connects to the bay station (using the
X-CTU program) with a serial cable and the other connects to the ATmega128 board, also using
a serial cable.

4.12 Sensor Data Storage

To facilitate the development of a more accurate system model, and thus controller, of the
aircraft, sufficient sensor data needs to be recorded during flight. Sufficiency in this case refers
not only to the length of time the data is recorded, but also to the rate at which the data is
recorded. The determination of the frequency response of the aircraft in relation to servo inputs
is particularly important to the development of an accurate model, so a data storage method
needs to be able to record data fast enough to track high frequency responses of the aircraft. In
addition, a satisfactory model cannot be obtained without measuring responses of the aircraft to
all possible stimuli. This inherently involves flying the plane through all possible maneuvers
during a single flight, which, depending on the pilot’s capabilities, could take a few minutes.
Therefore, a data storage method capable of storing large amounts of data is also necessary.
In regards to possible future upgrades, high capacity data storage could prove to be very
useful. Once the aircraft enters its full operational stage, reconnaissance missions would
generate large amounts of data in the form of images and/or video that would need to be stored.
Additionally, as technology advances, higher-resolution sensors might be implemented that
would transfer larger amounts of data at higher rates, requiring greater data storage capability.
An example of such a sensor already in use by certain military aircraft is the Advanced
Helicopter Pilotage infrared sensor, which has a data transfer rate of 1.2 Gigabits per second [6].
Many different types of memory products are available, but most are either insufficient or
impractical for our purposes. Magnetic storage devices such as hard disk drives are available in
huge capacities and support high data transfer rates, but their size, weight and power
requirements are unreasonable for small UAVs. Erasable Programmable Read-only Memory
(EPROM) is extremely small, lightweight and fast, but the erase sequence is inconvenient and
current capacities are limited to a few megabytes. Electrically-erasable Programmable ROM
(EEPROM) is more convenient to erase than EPROM, but current capacities are also limited.
Flash memory, such as the Compact Flash card and the Secure Digital (SD) card, is available in
large capacities, and is very economical. It also supports fast data transfer rates, has a very small
footprint, requires little power, and is versatile [7].
Compact Flash cards, while boasting high capacity and fast data transfer rates, utilize a
50-pin interface, which would require too many precious I/O pins on the ATmega128
microcontroller. Also, the Compact Flash data transfer protocol is not supported in hardware by
the ATmega128. SD cards, on the other hand, utilize only a 9-pin interface, of which only 4 are
required to be connected to the microcontroller. As an added convenience, the SD card is
capable of communicating via the Serial Peripheral Interface (SPI) bus, which is supported in
hardware by the ATmega128 microcontroller. Not surprisingly, our choice for data storage was
the SD card, specifically a Kingston 512MB SD card.
The hardware interface for the SD card is shown below in Figure 4.12.1 and consists of a
SD/MMC breakout board, obtained from SparkFun Electronics, and a resistive voltage divider
network. The breakout board is simply a custom printed circuit board (PCB) with a spring-
loaded metal slot in which the SD card is inserted, and a pre-soldered pin header which provides
easy connections to the SD card’s nine pins. As previously mentioned, only four wires are
required to connect the SD card to the microcontroller, and they constitute the SPI interface:
SCLK, MOSI, MISO, and SS. The resistive voltage divider network was required to step down
the 5 volt signal levels coming from the ATmega128 to the 3.3 volt level required by the SD
card. The 3.3 volt signal levels coming from the SD card did not need to be altered in order to be
properly recognized by the ATmega128. Power was provided to the SD card by a 3.3 volt
regulator, and to establish a common signal ground reference, the ground pin of the SD card was
connected to a ground pin of the microcontroller.
Figure 4.12.1 – SD Card Interface Schematic

The SD card utilizes its own built-in controller to communicate with the host
(ATMega128), and an extensive command set is defined by the SD protocol for all actions to be
performed by the card. In addition to supporting SPI bus communications, the SD card also
supports a proprietary SD bus data transfer protocol, so the card must be initialized to establish
which protocol will be used. The SD card command set includes commands to write single or
multiple sectors, read single or multiple sectors, erase specific sectors, change certain operating
parameters, and check status bits. Software functions were written to implement most of these
commands, and they were integrated into the AHRS program. Using a menu-driven system on
the AVR-MT-128 development board’s LCD, the program is capable of writing sensor data to
the card, reading sensor data from the card and transmitting it through the ATmega128’s UART
port, and erasing sensor data from the card. A program was also implemented on a Windows PC
to capture sensor data sent from the ATmega128’s UART port and save the data to a text file for
later use. Figure 4.12.2 below shows a flowchart for the AHRS program.
Figure 4.12.2– AHRS Program Flowchart

Initial testing resulted in a data logging rate of approximately 2.7 kilobytes per second,
corresponding to a sensor data capture rate of 75Hz. Based on this rate, the 512MB SD card
would be capable of logging data for approximately 52 hours, which would allow for logging
multiple sessions of flight data. A file system (such as FAT16) was not implemented on the SD
card due to time constraints, thus requiring the use of the ATmega128’s UART port to transmit
sensor data to the PC’s RS232 serial port. Future work will likely include the development of a
file system for the SD card to allow more convenient transfer of data from the card to a PC.

5.0 GUI

The text-based graphical user interface (GUI) was developed using the C++
programming language and the Allegro gaming library. The purpose of this first GUI is to access
data retrieved from the UAV and UGV which has been stored in a text file. The GUI reads the
data and displays it in an easy to read format. The second graphics-based GUI was developed
using the OpenGL specification as well as the C++ programming language. This GUI also reads
data sent from the UAV and then graphically interprets the information. Specifically, this GUI
translates the speed, altitude, yaw, pitch, roll, and magnetic heading of the UAV. The decision to
use Allegro and OpenGL allows for the two separate programs to be integrated in the future, as
Allegro is able to support the OpenGL specifications with its own version, AllegroGL. OpenGL
can be used to draw two- or three-dimensional images to the display window while Allegro
handles other functions such as collecting input, handling timers, and loading data files (Foot and
Ohannessian).
Originally developed by Shawn Hargreaves, the open source Allegro programming
library now features updates and extensions from many users around the world. The benefits
provided by this library are numerous. It allows for cross-platform compatibility on OS X,
Windows, Linux, and UNIX. Also, source files can be viewed and edited on many different
compilers. Dev-C++ was used in this project; as a bonus this compiler features automatic
installation. Allegro can also be installed manually if necessary. Low level routines such as
mouse movement, screen resolution, graphics modes, and timers can be easily manipulated.
Additionally, Allegro is a well-documented library containing examples for most of the pre-
defined functions to illustrate how they are used within a program. Further help is readily
available on various internet forums; most notably the forums on the Allegro.cc web site were
most useful (Allegro).
When coding using the Allegro library, there are several important steps that need to be
remembered. When starting a new project in Dev-C++, first select ‘Windows Application’ under
the ‘Basics’ tab. Next, click on the ‘Multimedia’ tab and select ‘Allegro Application’. This links
the library to the project. Then, there must be an include line for the library itself within the
source file (i.e., #include <allegro.h>). Next, the Allegro library and all I/O components need to
be initialized in order to be used with the program. This can include the mouse, keyboard, and
timer. The screen resolution and graphics mode need to be set as well. An example initialization
function follows:

void init()
{
int depth, res;
if (allegro_init() != 0)
{
allegro_message("Unable to intialize allegro!\n%s\n", allegro_error);
exit(-1);
}
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);

if (install_keyboard()!= 0)
{
allegro_message("Unable to install keyboard!\n%s\n", allegro_error);
exit(-2);
}
if (install_mouse()== -1)
{
allegro_message("Unable to install mouse!\n%s\n", allegro_error);
exit(-3);
}
if (install_timer()!= 0)
{
allegro_message("Unable to install timer!\n%s\n", allegro_error);
exit(-4);
}
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0,
0);
if (res != 0)
{
allegro_message("Unable to set any graphic mode!\n%s\n",
allegro_error);
exit(-5);
}
set_window_title("UAV Sensor Data");

}//end init

The driver that controls the Allegro GUI is called a dialog struct. The dialog is a
description of the GUI. Allegro dialogs consist of fourteen elements: 1.) an integer pointer to
dialog procedure, integers specifying 2.) X-position, 3.) Y-position, 4.) Width of dialog object,
5.) height of dialog object, 6.) foreground color, 7.) background color, 8.) ASCII keyboard
shortcut, and 9.) flags (status indicators for dialog objects). The last two integer elements can be
used as the programmer wishes. The same applies to the last three elements (*dp, *dp2, *dp3),
except that these fields defined as type void*. Generally, a function of any type can be used here
as long as it is typecasted to a void* when it is called from within the dialog (Leverton). Both
Allegro.cc and the Allegro GUI Clinic provide excellent references for an in-depth description of
these fourteen dialog elements. Also note that in addition to the built-in dialog procedures, the
programmer is free to define their own processes or to even derive procedures from the existing
library for greater control. Below is an example dialog definition which allows user to input a
file name for illustration:

DIALOG user_input_dialog [ ] =
{
/* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)
*/
{ d_box_proc, 0, 0, 400, 40, 0, 0, 0, 0, 0, 0, NULL, NULL,
NULL },
{ d_text_proc, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, heading, NULL,
NULL },
{ d_edit_proc, 10, 0, 350, 10, 0, 0, 0, 0, 255, 0, input, NULL,
NULL },
{ d_keyboard_proc, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, (void*)exit_callback,
NULL,
NULL}
{ d_idle_proc, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, NULL, NULL,
NULL },
{ NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL,
NULL }
};

Utilizing the dialog struct allows for a compact, more efficient GUI design.
In conclusion, these two GUIs make it easier to view and interpret the sensor data at a
glance. In the future, it would be advantageous to this project to increase the functionality of the
GUIs to retrieve and display data in real time. The features supplied by Allegro and the OpenGL
specification will allow this and other additional features to be added to the GUI as the REU
UAV and UGV research project further develops.

6.0 Conclusion

Our research and design efforts during phase one of the UAV project yielded a nearly
operational Attitude and Heading Reference System. While we fell slightly short of our goal, the
progress made was significant and should provide an excellent starting point for students in
phase two of the REU UAV program. The integration of the accelerometer, rate gyro, pressure
sensors, sonar sensor, analog switch, pulse-width measurement function and data storage system
represented the majority of the AHRS’s complexity. Our difficulties experienced with the
magnetometer were minor, and resulted from a lack of familiarity with the proprietary SPI
interface used by the sensor. Continued work with the magnetometer should yield successful
results and bring the AHRS into a fully operational stage.
The current state of the AHRS and its associated hardware could benefit from a few
additional improvements. Possible wiring issues on the AHRS board led to difficulty while
troubleshooting faults, so a custom printed circuit board was deemed necessary for future
development. Further refinements could also be incorporated, such as a smaller, lighter-weight
battery system. The batteries used during our phase of the project were bulky and heavy, adding
unnecessary weight to the aircraft and potentially severely affecting the plane’s center of gravity.
One option would be to use a single, high-current rechargeable battery to power both the AHRS
board and the servos in the aircraft. Additionally, a custom mount will need to be fabricated to
secure the AHRS board inside the aircraft.
As mentioned previously, a FAT-based file system would significantly speed up the
process of transferring sensor data from the SD card to a Windows PC. Using the ATmega128’s
UART port to transfer sensor data to the PC’s serial port was relatively inefficient and could
impede the system identification process. With a FAT-based file system, the sensor data would
be written to the SD card in a file format, such as a text file, which could then be recognized and
quickly downloaded by a PC upon inserting the SD card into a standard USB card reader. This
would certainly be a convenience, but it is not a necessity.
The completion of phase one of the REU UAV research project represents a significant
step towards the goal of implementing a fully autonomous unmanned aerial vehicle. The AHRS
system we developed should provide the students participating in phase two of the project with
an excellent opportunity to complete the system identification process, as well as to develop a
robust controller for the UAV.
Appendix A. AHRS Code

/******************************************************************
* AHRS Code
*
* Authors:
* Sylvester Meighan
* Damon Cardenas
* Mark Finch
*******************************************************************/

//------------------------------------------------------------------
// Includes *******************************************************
//------------------------------------------------------------------
#include <stdio.h>
#include <avr/io.h>
// #include <avr/iom128.h>
#include "system.h"
#include "bits.h"
#include "lcd.h"
#include <math.h>
#include <util/delay.h>
#include "delay.h"
#include <string.h>
#include <avr/interrupt.h>
#include "sd_card.h"

//------------------------------------------------------------------
// Defines and Variables ******************************************
//------------------------------------------------------------------
#define B1 (PINA&BIT0)
#define B2 (PINA&BIT1)
#define B3 (PINA&BIT2)
#define B4 (PINA&BIT3)
#define B5 (PINA&BIT4)

#define RELAY_HIGH PORTA |= BIT6


#define RELAY_LOW PORTA &= ~BIT6

#define TXD (PIND&BIT3)


#define RXD (PIND&BIT2)
#define DALLAS (PINA&BIT5)

#define X_ACCEL 0
#define Y_ACCEL 1
#define Z_ACCEL 2

#define X_GYRO 3
#define Y_GYRO 4
#define Z_GYRO 5

#define CARRIAGE_RETURN 0x0D


#define LINE_FEED 0x0A
#define polldelay 2000

unsigned char ch;


unsigned short sensorData[100]; // variable to store Sensor Data
int mode; // variable to hold which mode to
stay in

uint8_t sreg; // need this to store the special function register values before
// disabling interrupts
unsigned char ovCounter; // counter for timer 1 overflow
unsigned int risingEdge, fallingEdge; // storage for times
unsigned long pulseClocks; // storage actual clock counts the
pulse
unsigned long pulseLength;

//------------------------------------------------------------------
// Function Definitions *******************************************
//------------------------------------------------------------------

// Initialize Accelerometer ---------------


void initSensors(void);

// Read Sensor ----------------------------


void readSensors(void);

// Print Accelerometer --------------------


void printAccel(void);

// Print Gyro -----------------------------


void printGyro(void);

// Check button input ---------------------


void buttonScan(void);

// Pulsin Function ------------------------


float pulsin();

//-----------------------------------------------------------------------
// Main Function *******************************************************
//-----------------------------------------------------------------------
int main(void){
// Initialize Stuff *************************************************
initPorts();
initUart1(); //Init Uart1
initUart0(); //Init Uart0
lcdIni(); //LCD initialisation
adcInit(); // initialize the adc
SPIinit();
SD_init();
DDRA |= 0b10000000;
// Disable interrupts.
//sreg = SREG;
//cli();

sendCmd(DISP_ON);
sendCmd(CLR_DISP);
sendStr("IMU board v1.0 Sylvester M");
delay_ms(200);

unsigned short temp;


initSensors();
DDRB |= 0b00000001;
sendCmd(CLR_DISP);

uint32_t i,j,k;
char SD_data[512];
i = 0;
int *a = &i;
mode = 1;

while(1){
sendCmd(CLR_DISP);
sendStr("B1:Read B2:WriteB3:Erase");
buttonScan();

if(mode == 1){
readSD(0,SD_data);
k = 0;
for(i=0;i<4;i++){
k += (uint32_t)SD_data[i] << (i*8);
}
sendCmd(CLR_DISP);
sendStr("Reading... Hold B1 to quit");
for(i=1;i<=k;i+=5){
readmultSD(i,i+5);
if(B1 == 0) break;
}
sendCmd(CLR_DISP);
sendStr("Reading finished");
delay_ms(400);
}

if(mode == 2){
sendCmd(CLR_DISP);
sendStr("Writing... Press B1 to quit");
for(i=0;i<512;i++)SD_data[i] = 0;
for(k=1;k<500000;k++){
for(j=0;j<11;j++) storeTelemetry(SD_data,a);
writeSD(k,SD_data);
for(i=0;i<512;i++)SD_data[i] = 0;
i = 0;
if(B1 == 0) break;
}
for(i=0;i<4;i++){
SD_data[i] = (k >> (i*8));
}
writeSD(0,SD_data);
sendCmd(CLR_DISP);
sendStr("Writing finished");
delay_ms(300);
}

if(mode == 3){
sendCmd(CLR_DISP);
sendStr("Erasing...");
eraseSD();
for(i=0;i<512;i++)SD_data[i] = 0;
writeSD(0,SD_data);
sendCmd(CLR_DISP);
sendStr("Erasing finished");
delay_ms(300);
}
}

return 0;
}//end main()
//-----------------------------------------------------------------------
// Initialize Sensors **************************************************
//-----------------------------------------------------------------------
void initSensors(void)
{
/*
GS1(PG1) GS2(PG1) G-range Sensitivity
GND GND 1.5g 800mV/g
GND 3.3V 2g 600mV/g
3.3V GND 4g 300mV/g
3.3V 3.3V 6g 200mV/g
*/

// The following line is in adc.h adcInit()


// DDRF &= 0b11100000; // configure adc0-4(x,y,z,p,s) as input to
receive analog input
DDRG |= 0b00000111; // set PG0-PG2 as output (sleep, gs1,
gs2)
PORTG &= 0b11111000; // set sensitivity to 1.5g
PORTG |= 0b00000001; // wake up the accelerometer
}

//-----------------------------------------------------------------------
// Read All Sensors ****************************************************
//-----------------------------------------------------------------------
void readSensors(void)
{
int channel,i;
float tempVolt, tempAngle, m;
for(i=0;i<100;i++) sensorData[i] = 0;
float sensor;

// Accelerometer Stuff **********************************************


//
// (y2 - y1)
// m = --------- newY2 = m*(newX2 - x1) + y1
// (x2 - x1)
// ******************************************************************

PORTA &= 01111111;


_delay_ms(5);
float xMax = 430.08;
float xLevel = 309.248;
float yMax = 497.664;
float yLevel = 376.832;
float zMax = 0;
float zLevel = 333.824; // 10-bit voltage with z-level to ground

// Z Accelerometer **********************************************

// get z - accelerometer voltage


channel = 2;
adcInit(channel);
tempVolt = adcRead();
sensorData[4] = tempVolt;

// Is the board right-side-up or up-side-down?


// z neg. flag: upside down = 1, rightside up = 0
if (tempVolt < zLevel)
{
sensorData[5] = 1;
}
else
{
sensorData[5] = 0;
}

// X Accelerometer *********************************************

// get x - accelerometer voltage


channel = 0;
adcInit(channel);
tempVolt = adcRead();

// calculate x-angle
m = (0 + 90)/(xLevel - xMax);
tempAngle = m*(tempVolt-xLevel) + 0;

if(tempAngle < 0)
{
sensorData[1] = 1; //set the neg flag
}
else
{
sensorData[1] = 0;
}
// correct if tempAngle > |90|
if(sensorData[5]==1) // if upside down
{
if(sensorData[1]) // and x is negitive
{
tempAngle = -180 - tempAngle; // shift appropriately
}
else // or x is positive
{
tempAngle = 180 - tempAngle; // shift appropriately
}
}

sensorData[0] = sqrt(square(tempAngle));

// Y Accelerometer *********************************************

// get y - accelerometer voltage


channel = 1;
adcInit(channel);
tempVolt = adcRead();

// calculate y-angle
m = (0 + 90)/(yLevel - yMax);

tempAngle = m*(tempVolt-yLevel) + 0;
if (tempAngle < 0)
{
sensorData[3] = 1;
}
else
{
sensorData[3] = 0;
}

// correct if tempAngle > |90|


if(sensorData[5]==1) // if upside down
{
if(sensorData[3]) // and y is negitive
{
tempAngle = -180 - tempAngle; // shift appropriately
}
else // or y is positive
{
tempAngle = 180 - tempAngle; // shift appropriately
}
}
sensorData[2] = sqrt(square(tempAngle));

// GYRO STUFF
*************************************************************
// accel. already uses ch 0 - 2 so
// the gyro is using these channels right now
// for testing purposes (change them later)
//
// adc bits 5 volts 1000 mV 1 deg/s
// --------- X --------- X ------- X ------- = (adc bits)*2.44140625 deg/s
// 1024 bits 1 volts 2 mV
//
************************************************************************

float xGyroStill = 313.334; // adc value for gyro at rest


float yGyroStill = 286.72; // adc value for gyro at rest
float zGyroStill = 321.7408;
PORTA |= 10000000;
_delay_ms(5);

// get x - gyro voltage


channel = 0;
adcInit(channel);
tempVolt = adcRead();
//sensorData[6] = tempVolt;

if (tempVolt < xGyroStill) // set the


negative flag
{
sensorData[7] = 1;
}
else
{
sensorData[7] = 0;
}

tempVolt = (tempVolt - xGyroStill)*2.44140625; // convert from 'bits'

// to 'deg/s'

sensorData[6] = sqrt(square(tempVolt));

// get y - gyro voltage


channel = 1;
adcInit(channel);
tempVolt = adcRead();
sensorData[8] = tempVolt;

if (tempVolt < yGyroStill) // set the


negative flag
{
sensorData[9] = 1;
}
else
{
sensorData[9] = 0;
}

tempVolt = (tempVolt - yGyroStill)*2.44140625; // convert from 'bits'

// to 'deg/s'

sensorData[8] = sqrt(square(tempVolt)); // save the abs. val of the


voltage

// get z - gyro voltage


channel = 2;
adcInit(channel);
tempVolt = adcRead();
sensorData[10] = tempVolt;

if (tempVolt < zGyroStill) // set the


negative flag
{
sensorData[11] = 1;
}
else
{
sensorData[11] = 0;
}

tempVolt = (tempVolt - zGyroStill)*2.44140625; // convert from 'bits'

// to 'deg/s'

sensorData[10] = sqrt(square(tempVolt)); // save the abs. val of the


voltage

//SONAR STUFF************************************************************
//-----------------------------------------------------------------------
// This is where we read data from the sonar. The data is found in inches.
// This data is used to find the elevation of the plane.
// The equation is:
// adc bits 5 volts 1000 mV 1 inches
// --------- X --------- X ------- X ------- = (adc bits)*.675354426
// 1024 bits 1 Volts 7.23 mV
// 1024 is from the 10-bit res. The 5 is standard for ADC read max. The
// .00723 is obtained by dividing the supply voltage by 512, which is
// used for the SonarMax chip.
//-----------------------------------------------------------------------

channel = 6;
adcInit(channel);
tempVolt = adcRead();
//sensorData[15] = tempVolt;

tempVolt = tempVolt*.675354426;
sensorData[15] = tempVolt;

//PRESSURE STUFF*********************************************************
//-----------------------------------------------------------------------
// This is the data from the MPXV5004G pressure Barometric sensor

PORTA &= 01111111;


channel = 3;
adcInit(channel);
tempVolt = adcRead();
//sensorData[12] = tempVolt;
tempVolt = (tempVolt-202)*.48828125;
//tempVolt = tempVolt*.675354426;
sensorData[16] = tempVolt;

//PRESSURE STUFF*********************************************************
//-----------------------------------------------------------------------
// This is the data from the MPXV5004G pressure Pitotstatic sensor

PORTA |= 10000000;
channel = 3;
adcInit(channel);
tempVolt = adcRead();
//sensorData[12] = tempVolt;
tempVolt = (tempVolt-202)*.48828125;
//tempVolt = tempVolt*.675354426;
sensorData[17] = tempVolt;
}
//-----------------------------------------------------------------------
// print Accelerometer *************************************************
//-----------------------------------------------------------------------
void printAccel(void)
{
sendStr("Accelerometer! ");
// X-Accelerometer
//readSensors();
unsigned short temp = sensorData[0]; // grab accel. value

if (sensorData[1]) // if value is negative then


{ // print a negative sign
sendChar(45);
}
//sendShortAsString(temp,1);
sendChar(' ');

// Y-Accelerometer
temp = sensorData[2]; // grab accel. value
if (sensorData[3]) // if value is negative then
{ // print a negative sign
sendChar(45);
}
//sendShortAsString(temp,1);
sendChar(' ');

// Z-Accelerometer
temp = sensorData[4]; // grab accel. value
if (sensorData[5]) // check upside down flag
{
sendChar(45);
}
else
{
sendChar(43);
}
//sendShortAsString(temp,1);
sendChar(' ');
}
//-----------------------------------------------------------------------
// print Gyro **********************************************************
//-----------------------------------------------------------------------
void printGyro(void)
{
//readSensors();
unsigned short temp;
PORTA |= 10000000;

sendStr("Gyro Readings...");
// X-Gyro
temp = sensorData[6]; // grab gyro value

if (sensorData[7]) // if value is negative then


{ // print a negative sign
sendChar(45);
}
//sendShortAsString(temp,1);
sendChar(' ');

// Y-Gyro
temp = sensorData[8]; // grab gyro value

if (sensorData[9]) // if value is negative then


{ // print a negative sign
sendChar(45);
}
//sendShortAsString(temp,1);
sendChar(' ');

// Z-Gyro
temp = sensorData[10]; // grab gyro value

if (sensorData[11]) // if value is negative then


{ // print a negative sign
sendChar(45);
}
//sendShortAsString(temp,1);
sendChar(' ');

}
//-----------------------------------------------------------------------
// Button Scan *********************************************************
//-----------------------------------------------------------------------
void buttonScan(){
mode = 0;
while(!mode){
// Button 1
if (B1==0){
mode = 1;
}

// Button 2
if (B2==0){
mode = 2;
}

// Button 3
if (B3==0){
mode = 3;
}

// Button 4
if (B4==0){
mode = 4;
}

// Button 5
if (B5==0){
mode = 5;
}
}
}

/*
ISR(TIMER1_OVF_vect)
{
ovCounter++;
}

ISR(TIMER1_CAPT_vect) // Timer 1 overflow ISR


{
PORTA = 0xFF;

//Check for rising or falling edge by checking the


//level on ICP. If high, the interrupt must have
//triggered by a rising edge and if not, the trigger
//must have been a falling edge.

if(PIND & 0b00010000)


{
risingEdge = ICR1; // save start time for pulse
TCCR1B = TCCR1B & 0xBF; // set to trigger on falling edge next
ovCounter = 0; //clear overlfow counter for this measurement
}
else
{
fallingEdge = ICR1; //save falling edge time
TCCR1B = TCCR1B | 0x40; //set for rising edge trigger next
pulseClocks = (unsigned long)fallingEdge - (unsigned long)risingEdge +
(unsigned long)ovCounter*0x10000; //calculation
pulseLength = pulseClocks*0.5;
}
}*/

//-----------------------------------------------------------------------
// Pulsin **************************************************************
//-----------------------------------------------------------------------
float pulsin()
{
TCCR1B=0xC2; //timer 1 input to clock/8, enable
input
//capture on rising edge and
noise canceller
TIMSK=0x24; //unmask timer 1 overflow and
capture interrupts
sei(); //enable global interrupt bit
}

//-----------------------------------------------------------------------
// send Telemetry *************************************************
//-----------------------------------------------------------------------
void storeTelemetry(char SD_data[],int *a)
{
readSensors();

int i = *a;
int *b = &i;

//Telemetry Header ------------------------------------------------


SD_data[i] = '$';
i++;
SD_data[i] = 'S';
i++;
SD_data[i] = 'D';
i++;
SD_data[i] = ',';
i++;

//Accelerometer DATA-----------------------------------------------
// X-Accelerometer

unsigned short temp = sensorData[0]; // grab accel. value

if (sensorData[1]) // if value is negative


then
{ // print
a negative sign
SD_data[i] = '-';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

// Y-Accelerometer
temp = sensorData[2]; // grab accel. value
if (sensorData[3]) // if value is negative
then
{ // print
a negative sign
SD_data[i] = '-';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

// Z-Accelerometer
temp = sensorData[4]; // grab accel. value
if (sensorData[5]) // check upside down flag
{
SD_data[i] = '-';
i++;
}
else
{
SD_data[i] = '+';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

//GYRO DATA--------------------------------------------------

// X-Gyro
temp = sensorData[6]; // grab gyro value

if (sensorData[7]) // if value is negative then


{ // print a negative sign
SD_data[i] = '-';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

// Y-Gyro
temp = sensorData[8]; // grab gyro value

if (sensorData[9]) // if value is negative then


{ // print a negative sign
SD_data[i] = '-';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

// Z-Gyro
temp = sensorData[10]; // grab gyro value

if (sensorData[11]) // if value is negative then


{ // print a negative sign
SD_data[i] = '-';
i++;
}
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

//Pulse length ------------------------------------------------------------


/*SREG = sreg;
convLongString(SD_data,b,pulseLength,0); //output milliseconds to Port C
SD_data[i] = ',';
i++;
sreg = SREG;
cli();*/

//Sonar Distance ----------------------------------------------------------


temp = sensorData[15];
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

//Pressure Data -----------------------------------------------------------


temp = sensorData[16];
convLongString(SD_data,b,temp,1);
SD_data[i] = ',';
i++;

//Pressure Data -----------------------------------------------------------


temp = sensorData[17];
convLongString(SD_data,b,temp,1);

//Include newline and carriage return at end of each data string-----------


SD_data[i] = 10;
i++;

*a = i;
}

//-----------------------------------------------------------------------
// get GPS data ********************************************************
//-----------------------------------------------------------------------
void getGps(void)
{
const unsigned short statusPoll[]= {0xB5, 0x62, 0x01, 0x03, 0x00, 0x00, 0x04, 0x0D};
//Status Poll
const unsigned short posllhPoll[]= {0xB5, 0x62, 0x01, 0x02, 0x00, 0x00, 0x03, 0x0A};
//Position Poll
const unsigned short velnedPoll[]= {0xB5, 0x62, 0x01, 0x12, 0x00, 0x00, 0x13, 0x3A};
//Velocity Poll

unsigned short i, j, k,gdata, navStat[24], navPos[36],navVelo[44];


int iChar ;

gdata = 0;
i = 0;
while(gdata==0)
{

/***********************************************************************
*******
// Poll and read Nav Pos...

************************************************************************
*******/
for(i = 0; i<8;i++)
{
sendDigitUart1(posllhPoll[i]); // Send poll command to the GPS via
USART
}
sendCharUart1(LINE_FEED);
sendCharUart1(CARRIAGE_RETURN);

i=0;

ch = receiveCharUart1();
/*
while (ch)
{
navPos[i] = ch;
i++;
}

gdata = checkPos(navPos);
*/
_delay_ms(240);
_delay_ms(240);
_delay_ms(240);
_delay_ms(240);
}
sendStr("Done");

/*****************************************************************************
*
// Check Sum Routine for NavPos Poll
******************************************************************************
*/

int checkPos(unsigned short* navPos)


{
int ch_a = 0;
int ch_b = 0;
int j = 0;

for (j=2;j<34;j++)
{
ch_a = ch_a + navPos[j];
ch_b = ch_b + ch_a;
}

ch_a &= 0xFF;


ch_b &= 0xFF;

if((navPos[34] == ch_a)&&(navPos[35] == ch_b))


{
return 1;
}
else
{
return 0;
}
}

/*****************************************************************************
*
* Convert long to string
******************************************************************************
*/
void convLongString(char SD_data[],int *b,unsigned short x,int y){
if(x!=0){
unsigned short digit=x%10;
convLongString(SD_data,b,x/10,0);
SD_data[*b] = digit+48;
(*b)++;
}
else if((x==0)&(y==1)){
SD_data[*b] = 48;
(*b)++;
}
}
/***************************************************************************
* sd_card.c
*
* Source code for SD commands
*
****************************************************************************/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <inttypes.h>
#include <avr/iom128.h>
#include "sd_card.h"

#define SPIDI 3 // Port B bit 3 (pin4): data in (data from SD card)


#define SPIDO 2 // Port B bit 2 (pin3): data out (data to SD card)
#define SPICLK 1 // Port B bit 1 (pin2): clock
#define SPICS 0 // Port B bit 0 (pin1): chip select for SD card

char sector[512];

void SPIinit(void) {
DDRB &= ~(1 << SPIDI); // set port B SPI data input to input
DDRB |= (1 << SPICLK); // set port B SPI clock to output
DDRB |= (1 << SPIDO); // set port B SPI data out to output
DDRB |= (1 << SPICS); // set port B SPI chip select to output
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
PORTB &= ~(1 << SPICS); // set chip select to low (SD card is selected)
}

char SPI(char d) { // send character over SPI


char received = 0;
SPDR = d;
while(!(SPSR & (1<<SPIF)));
received = SPDR;
return (received);
}

char Command(char befF, uint32_t address, char befH )


{ // sends a command to the SD card
SPI(0xFF);
SPI(befF);
SPI((uint8_t)(address >> 24));
SPI((uint8_t)(address >> 16));
SPI((uint8_t)(address >> 8));
SPI((uint8_t)address);
SPI(befH);
SPI(0xFF);
return SPI(0xFF); // return the last received character
}

int SD_init(void) { // init SPI


char i;
PORTB |= (1 << SPICS); // disable SD card
// start SD card in SPI mode
for(i=0; i < 10; i++) SPI(0xFF); // send 10*8=80 clock pulses
PORTB &= ~(1 << SPICS); // enable SD card
Command(0x40,0,0x95);
if (Command(0x40,0,0x95) != 1) goto sderror; // reset SD card

st: // if there is no SD card, prg. loops here


if (Command(0x41,0,0xFF) != 0) goto st;
return 1;
sderror:
return 0;
}

int readSD(uint32_t j, char SD_data[]) { // read and send 512 bytes from the SD card via the
serial port
int i;
// 512 byte-read-mode
uint16_t ix;
char r1 = Command(0x51,j,0xFF);
for (ix = 0; ix < 50000; ix++) {
if (r1 == (char)0x00) break;
r1 = SPI(0xFF);
}
if (r1 != (char)0x00) { //read error
return 1;
}

// wait for 0xFE - start of any transmission


// ATT: typecast (char)0xFE is a must!
while(SPI(0xFF) != (char)0xFE);

for(i=0;i<512;i++){
SD_data[i] = SPI(0xFF);
}

// at the end, send 2 dummy bytes


SPI(0xFF); // actually this returns the CRC/checksum byte
SPI(0xFF);
return 0;
}

int readmultSD(uint32_t n,int k) { // read and send multiple data blocks from the SD card via the
serial port
int i,j;
char c = Command(0x52,n*512,0xFF);
for (i=0;i<50000;i++){
if(c == (char)0x00) break;
c = SPI(0xFF);
}
if(c != (char)0x00){
//uart_puts("SD card: read error 1 ");
return 1;
}

// wait for 0xFE - start of any transmission


// ATT: typecast (char)0xFE is a must!
for(i=0;i<k;i++){
while(SPI(0xFF) != (char)0xFE);
for(j=0;j<512;j++){
while(!(UCSR1A & (1 << UDRE1))); // wait for serial port
UDR1 = SPI(0xFF);
//c = SPI(0xFF);
//convLongString((uint8_t)c,1);
}
SPI(0xFF);
SPI(0xFF);
}

c = Command(0x4C,0,0xFF);
for(i=0;i<50000;i++){
if(c == (char)0) break;
c = SPI(0xFF);
}
if(c != (char)0) goto stoperror;

while(SPI(0xFF) == (char)0);
return 1;

stoperror:
//uart_puts("Stop transmission error");
//serialterminate();
return 0;
}

int writeSD(uint32_t j,char SD_data[]) { // write RAM sector to SD card


int i;
uint8_t c;
// 512 byte-write-mode
uint16_t ix;

char r1 = Command(0x58,j*512,0xFF);
for (ix = 0; ix < 50000; ix++) {
if (r1 == (char)0x00) break;
r1 = SPI(0xFF);
}
if (r1 != (char)0x00) {
return 1;
}

SPI(0xFF);
SPI(0xFF);
SPI(0xFE);
// write ram sectors to SD card
for (i=0;i<512;i++) {
SPI(SD_data[i]);
}
// at the end, send 2 dummy bytes
SPI(0xFF);
SPI(0xFF);

c = SPI(0xFF);
c &= 0x1F; // 0x1F = 0b.0001.1111;
if (c != 0x05) { // 0x05 = 0b.0000.0101
return 1;
}
// wait until SD card is not busy anymore
while(SPI(0xFF) != (char)0xFF);
return 0;
}

void eraseSD(void){
int i;

char a = Command(0x60,0,0xFF);
//if(a != 0x00) uart_puts("Erase start address error");
a = Command(0x61,500000000,0xFF);
//if(a != 0x00) uart_puts("Erase end address error");

a = Command(0x66,0,0xFF);
for(i=0;i<50000;i++){
if(a != 0x00) break;
a = SPI(0xFF);
}

//if(a == 0x00) uart_puts("Erase failed!");


}
/****************************************************************
* system.c
*****************************************************************/

#include <stdio.h>
#include <avr/io.h>
//#include <avr/iom128.h>
#include "system.h"
#include "bits.h"
#include <util/delay.h>

#define BUZZ1_HIGH PORTE |= BIT4


#define BUZZ1_LOW PORTE &= ~BIT4

#define BUZZ2_HIGH PORTE |= BIT5


#define BUZZ2_LOW PORTE &= ~BIT5

//--------Init Ports --------------------


void initPorts(void) {

// Input/Output Ports initialization


// Port A initialization
PORTA=0x00;
DDRA=0x40;

// Port B initialization
PORTB=0x00;
DDRB=0x00;

// Port C initialization
PORTC=0x00;
DDRC=0xF7;

// Port D initialization
PORTD=0x00;
DDRD=0x08;

// Port E initialization
PORTE=0x00;
DDRE=0x30;

// Port F initialization
PORTF=0x00;
DDRF=0x00;
// Port G initialization
PORTG=0x00;
DDRG=0x00;

//--------Init Timers --------------------


void initTimers(void) {

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
///ASSR=0x00;
///TCCR0=0x00;
///TCNT0=0x00;
///OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: T1 pin Rising Edge
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Noise Canceler: Off
// Input Capture on Rising Edge
TCCR1A=0x00;
TCCR1B=0b01000001;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;

// Timer/Counter 2 initialization
// Clock source: T2 pin Rising Edge
// Mode: Normal top=FFh
// OC2 output: Disconnected
TCCR2=0x07;
TCNT2=0x00;
OCR2=0x00;
// Timer/Counter 3 initialization
// Clock source: System Clock
// Clock value: 2000,000 kHz
// Mode: Normal top=FFFFh
// OC3A output: Discon.
// OC3B output: Toggle
// OC3C output: Toggle
//TCCR3A=0x14;
//TCCR3B=0x02;
//TCNT3H=0x00;
//TCNT3L=0x00;
//OCR3AH=0x00;
//OCR3AL=0x00;
//OCR3BH=0x00;
//OCR3BL=0xFA;
//OCR3CH=0x00;
//OCR3CL=0xFA;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// INT2: Off
// INT3: Off
// INT4: Off
// INT5: Off
// INT6: Off
// INT7: Off
///EICRA=0x00;
///EICRB=0x00;
///EIMSK=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization


///TIMSK=0x00;
///ETIMSK=0x00;

//--------Init Uart interface --------------------


void initUart1(void) {

// USART1 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART1 Receiver: On
// USART1 Transmitter: On
// USART1 Mode: Asynchronous
// USART1 Baud rate: 9600
UCSR1A=0x00;
UCSR1B=0x18; //(00011000)
UCSR1C=0x06; //(00000110)
UBRR1H=0x00;
UBRR1L=0x67; //103 (0000 0110 0111)
//UBRR1L=0x06; //06 @ 1Mhz

void sendCharUart1(unsigned char ch) {

// wait for data to be received


while(!(UCSR1A & (1<<UDRE1)));
// send data
UDR1 = ch;

void sendDigitUart1(unsigned short num) {

// wait for data to be received


while(!(UCSR1A & (1<<UDRE1)));
// send data
UDR1 = num;

unsigned char receiveCharUart1(void) {

// wait for data to be received


while(!(UCSR1A & (1<<RXC1)));
// get and return received data from buffer
return UDR1;

unsigned char receiveCharUart1_nonstop(void) {

// wait for data to be received


if((UCSR1A & (1<<RXC1)))
// get and return received data from buffer
return UDR1;
else
// return 0
return 0;

//--------Send string to Uart-----------------------------


void sendStrUart1(unsigned char* str) {

unsigned int i=0;

// loop to the end of the string


while(str[i]!='\0')
{
sendCharUart1(str[i]);
i++;
}
}

//--------Send an unsigned short as a string to LCD-------


void sendLongAsStringUart1(unsigned long x,int y)
{
if(x!=0)
{
int digit=x%10;
sendLongAsStringUart1(x/10,0);
sendCharUart1(digit+48);
}
else if((x==0)&(y==1))
{
sendCharUart1(48);
}
}

//---------buzzer ---------------------------------
void buzzer(void) {

BUZZ1_LOW;
BUZZ2_HIGH;
_delay_us(125);
BUZZ2_LOW;
BUZZ1_HIGH;
_delay_us(125);

}
//--------Init Uart interface --------------------
void initUart0(void)
{

// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud rate: 9600
UCSR0A=0x00;
UCSR0B=0x18; //(00011000)
UCSR0C=0x06; //(00000110)
UBRR0H=0x00;
UBRR0L=0x67; //103 (0000 0110 0111)
}

void sendCharUart0(unsigned char ch) {

// wait for data to be received


while(!(UCSR0A & (1<<UDRE0)));
// send data
UDR0 = ch;

void sendDigitUart0(unsigned short num) {

// wait for data to be received


while(!(UCSR0A & (1<<UDRE0)));
// send data
UDR0 = num;

unsigned char receiveCharUart0(void) {

// wait for data to be received


while(!(UCSR0A & (1<<RXC0)));
// get and return received data from buffer
return UDR0;

unsigned char receiveCharUart0_nonstop(void) {


// wait for data to be received
if((UCSR0A & (1<<RXC0)))
// get and return received data from buffer
return UDR0;
else
// return 0
return 0;

//--------Send string to Uart-----------------------------


void sendStrUart0(unsigned char* str) {

unsigned int i=0;

// loop to the end of the string


while(str[i]!='\0')
{
sendCharUart0(str[i]);
i++;
}
}

//--------Send an unsigned short as a string to LCD-------


void sendLongAsStringUart0(unsigned long x,int y)
{
if(x!=0)
{
int digit=x%10;
sendLongAsStringUart0(x/10,0);
sendCharUart0(digit+48);
}
else if((x==0)&(y==1))
{
sendCharUart0(48);
}
}
/*
This is the code used for the Magnetometer. This code is
NOT COMPLETELY READY. IT IS ONLY CODE TO HELP SOMEONE
GET STARTED WITH THE MAGNETOMETER. The code is almost complete
in the sense that is retreives one byte from the magnetometer,
however, another byte must still be correctly obtained.
*/
//This first section shows the used header files
#include <AVR/io.h>
#include "system.h"
#include "bits.h"
#include "lcd.h"
#include "delay.h"
//Here is a list of used functions in the program
void SPI_MasterInit(void);
void SPI_Reset(void);
void SPI_MasterTransmit(unsigned char);
void tolcd(unsigned char);
void toUart1(unsigned char);
void sendStringUart1(unsigned char,int);
//this is the data that is to be transmitted and recived
unsigned char cdata = 0b00010001; //tells the micromag to send x-axis heading with sclk/64
unsigned char rdata; //first byte recieved by micromag
unsigned char rdata2; //second byte receieved by micromag

int main()
{
//Ports
InitPorts();
//Init Uart1
InitUart1();
//LCD initialisation
LCD_Ini();
// delay_ms(2);
SEND_CMD(DISP_ON);
// delay_ms(10);
SEND_CMD(CLR_DISP);
// write to lcd
SEND_STR("Magnetometer");

DDRB = 0b11010111; //set i/o ports for portb


DDRD = 0b11111111; //set i/o ports for portd
PORTD = 0x00; //set all ports low for portd
PORTB = 0x00; //set all ports low for portb
while (1)
{
int i = 16; //will be used for attempting to
SPI_MasterInit(); //used to initialize SPI
SPI_Reset(); //reset pulse necessary for micromag
SPI_MasterTransmit(cdata); //begin transmission to micromag
SPSR &= 0b01111111; //clear the SPI flag
SPCR |= 0b01000000; //enable SPI
while ((PINB & 0b01000000)); //wait for drdy from micromag

while (i > 8) //wait for 8 bits to be sent


{
i--;
}

rdata = SPDR; //retrieve first 8 bits


while (i > 0) //wait for next 8 bits to be sent

{
i--;
}

rdata2 = SPDR; //retrieve second 8 bits


SPCR |= 0b01000000;//re-enable SPI
SPSR &= 0b01111111; //clear SPI flag
SEND_CMD(DD_RAM_ADDR2); //go to second line of LCD screen
if (rdata != 0) //special case of zero, write 0 to LCD
{
tolcd(rdata);
SEND_CHAR(32);
}
toUart1(rdata);//write to serial port
if (rdata2 != 0)
{
tolcd(rdata2);
SEND_CHAR(32);
SEND_CHAR(32);
SEND_CHAR(32);
SEND_CHAR(32);
}
toUart1(rdata2); //write second byte to serial port
}
return 0;
}
/*The MasterInit and MasterTransmit code was code obtained
from the manual for the atmega128 microprocessor*/
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
PORTB = 0x06;
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = 0x52;
}
void SPI_MasterTransmit(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
}

void SPI_Reset(void)
{
PORTD &= 0b10111111; //The reset pin must be pulsed
PORTD |= 0b01000000; //for the magnetometer to read
PORTD &= 0b10111111; //to compute data
}
void tolcd(unsigned char x)
{
while(x >= 1)
{
unsigned char a = x%10;
tolcd(x/10);
SEND_CHAR(a+48);
if (1) break;
}
}

void toUart1(unsigned char mag)


{
sendStrUart1(mag,1);
}
Appendix B. CIFER installation on the Ubuntu 7.04 distribution of Linux

Install TexMaker
1. Click on Applications Æ Add/Remove…
2. under “Show:” pull down menu select “All Available Applications”
3. Type “Tex” in the search field
4. Under “Application” scroll to “TexMaker” and check the box next to it. Click OK and follow
the instructions to install.

Install CIFER
1. Download Cifer from aiaa.org
2. extract files and follow installation directions in “Getting_Started.pdf”
3. Create root by typing “sudo passwd”
4. create a password for the root user
5. login as root by typing “su” and entering a password
6. install “alien package converter app” to convert .rpm to .deb (ubuntu installer file)
7. type: sudo apt-get update
sudo apt-get install alien
sudo alien –k name-of-rpm-file.rpm
move to the desktop

8. run the “.deb” file to automatically install CIFER.

Before changing defaults (option 11) in CIFER, follow these instructions to avoid an error
message about missing a file named “libtermcap.so.2”. This file is an obsolete library and needs
to be installed separately.

Type: Sudo apt-get install gcc


Sudo apt-get install libgcc1
Sudo apt-get install g++
Sudo apt-get install cpp
Sudo apt-get install ncurses-base
Sudo apt-get install ncurses-bin
Sudo apt-get install-term
Sudo apt-get install libncurses5
Sudo apt-get install libncurses5-dev
Sudo ln –s /liblibncurses.so.5 /lib/libtermcap.so2

To run CIFER
1. goto the file menu “Applications Æ Accessories Æ Terminal”
2. type “xterm”
3. login as root
4. change to the c-shell by typing “csh”
5. type “source /usr/local/cifer/cifer_linux/cifrc”
6. type “cifer”
This launches cifer. Follow the onscreen directions to navigate the program.
References

[1] Murphy, Douglas, and James Cycon. “Applications for Mini VTOL UAV for Law
Enforcement.” Proceedings of the SPIE – The International Society for Optical
Engineering 1999: 35-43. Inspec. Engineering Village. UTSA Library, San Antonio, TX.
9 Aug. 2007 <http://www.engineeringvillage2.com>.

[2] Basu, Prithwish, Jason Redi, and Vladimir Shurbanov. “Coordinated Flocking of UAVs for
Improved Connectivity of Mobile Ground Nodes.” Military Communications
Conference, 2004. MILCOM 2004. IEEE Vol. 3, 31 Oct.-3 Nov. 2004: 1628 – 1634.
IEEE Xplore. UTSA Library, San Antonio, TX. 9 Aug. 2007
<http://ieeexplore.ieee.org>.

[3] “UAS: Dragon Eye.” Aerovironment. 9 Aug. 2007


<http://www.aerovironment.com/uas_product_details.asp?Prodid=2?>.

[4] Sujit, P.B., and Randy Beard. “Distributed Sequential Auctions for Multiple UAV Task
Allocation.” American Control Conference, 2007. 9-13 Jul. 2007: 3995-3960. IEEE
Xplore. UTSA Library, San Antonio, TX. 9 Aug. 2007 <http://ieeexplore.ieee.org>.

[5] Lyon, David H. “A Military Perspective on Small Unmanned Aerial Vehicles.” IEEE
Instrumentation & Measurement Magazine Sep. 2004: 27-31. IEEE Xplore. UTSA
Library, San Antonio, TX. 7 Aug. 2007 <http://ieeexplore.ieee.org>.

[6] Hall, W.J., Jr. “Recce and UAV: Mass Memory an Enabling Technology for Merger.”
Nonvolatile Memory Technology Conference 24-26 Jun. 1996: 132-137. IEEE Xplore.
UTSA Library, San Antonio, TX. 7 Aug. 2007 <http://ieeexplore.ieee.org>.

[7] Barr, Michael. “Memory Types.” Embedded Systems Programming May 2001: 103-104.

[8] Tischler, Mark B., and Robert K. Remple. Aircraft and Rotorcraft System Identification
Engineering Methods With Flight Test Examples. Reston, VA: American Institute of
Aeronautics and Astronautics, Inc., 2006.

[9] 31 June-July 2007 <http://atmel.com/>.

[10] 31 June-July 2007 <www.avrfreaks.net>.

[11] 31 June-July 2007 <http://www.olimex.com/>.

[12] Barnett, Cox , and O'cull . Embedded C Programming and the Atmel AVR. Clifton Park,
NY: Thomas Delmar Learning, 2003.

[13] Nimefurahi. "Re: MySQL 4.0.27 Won'T Compile -- Needs Termcap?" Ubuntu Forums. 19
Oct. 2006. 10 Aug. 2007
<http://ubuntuforums.org/showthread.php?t=241707&highlight=libtermcap.so.2>.
[14] Foot, George and Robert J. Ohannessian. “Allegro.cc.” Mar. 2002. Aug. 9 2007.
<http://www.allegro.cc/resource/Libraries/Graphics/AllegroGL>.

[15] Leverton, Matthew. “Allegro.cc.” Jan. 1999. Aug. 9 2007. < http://www.allegro.cc/>.

[16] "AVR Freaks." AVR Freaks. 24 July 2007 <http://www.avrfreaks.net/>.

[17] Maxbotix Home." MaxBotix. 24 July 2007 <http://www.maxbotix.com/>.

[18] "SmileyMicros." Atmel. 14 July 2007 <http://www.smileymicros.com/>.

[19] "SparkFun Electronics.“ Olimex. 14 July 2007


<http://www.sparkfun.com/commerce/categories.php>.

[20] "Pitot-Static (Prandtl) Tube." NASA. 10 Aug. 2007 <http://www.grc.nasa.gov/WWW/K-


12/airplane/pitot.html>.