You are on page 1of 54

GPS Homing Robot

Final Report

Team Members:
Zachary Chaves (CMPE)
Phillip Johnson (EE)
Gregory Wilkosz (EE)

Advisor:
Dr. John E. Ayers

January 6, 2004
ECE 292
Table of Contents

Abstract................................................................................................................................3
Objective..............................................................................................................................3
Design..................................................................................................................................3
Compass...........................................................................................................................3
Preliminary Design......................................................................................................3
Problems Encountered.................................................................................................4
Final Design.................................................................................................................4
Drive System....................................................................................................................5
Preliminary Design......................................................................................................5
Problems Encountered.................................................................................................6
Final Design.................................................................................................................8
Vehicle Speed Reduction...............................................................................................10
Preliminary Design....................................................................................................10
Problems Encountered...............................................................................................10
Final Design...............................................................................................................11
Collision Avoidance.......................................................................................................12
Preliminary Design....................................................................................................12
Problems Encountered...............................................................................................12
Final Design...............................................................................................................12
GPS System...................................................................................................................14
Preliminary Design....................................................................................................14
Problems Encountered...............................................................................................16
Final Design...............................................................................................................18
Alternative Designs............................................................................................................18
LCD / Keypad User Interface Module...........................................................................18
Preliminary Design....................................................................................................18
Problems Encountered...............................................................................................20
Final Design...............................................................................................................20
Budget/Parts.......................................................................................................................21
Timelines............................................................................................................................22
Conclusion.........................................................................................................................24
Appendix A........................................................................................................................25
Abstract
Every possible location on the Earth’s surface has been mapped by coordinates,
which makes it possible to express any location accurately. Satellites broadcast to these
locations so that any receiver may realize its location. This is the theory behind the
Global Positioning System (GPS). The purpose of this project is to build a robot that is
capable of navigating itself by taking full advantage of this technology.

Objective
In order to fulfill the objectives of this project, certain requirements must be
outlined. These parameters will shape the way this project is carried out, from design
decisions to economic constraints. The most crucial objective will allow an operating
vehicle to navigate from one point to another using an onboard GPS navigation system.
The vehicle should not get stuck or turn over easily. The destination and any needed
initializing inputs should be the only data input into the system. The vehicle should be
able to traverse multiple types of terrains and navigate the entire course (point A to point
B) that has been input by the operator. Simple obstacles in the vehicle's path should be
navigable. The overall weight of the vehicle, with all components applied, should weigh
less than 10kg (22 lbs.). The overall cost of the project, which includes testing and other
incidental costs, should not cost more than one thousand dollars.

Design
Compass
Preliminary Design

Since the Garmin GPS-LVS16 only provides a calculated compass heading output
when the unit is moving, a stand-alone compass is needed in order to determine the
direction that the vehicle is facing. The initial design involved a PNI V2Xe 2-axis 360
degree resolution digital compass. This compass required a 3VDC input which would
have been easily pulled from the Zilog microcontroller board. The means by which it
output data to communicate with microcontrollers is SPI communication protocol.
Problems Encountered

Due to the lack of turning precision of our vehicle, a digital compass with great
precision was not necessary. The PNI V2Xe’s output using SPI communication protocol
was also determined to involve too much work with software.

Final Design

We chose to use the Dinsmore 1490 digital compass with 45 degree resolution (8-
directional). The 8-directional compass provided enough resolution to indicate to the
software which direction the vehicle was traveling to assist in navigation. This compass
outputs to four general purpose I/O pins of our microcontroller. These bits determine the
directional orientation of the compass. This was much easier to implement than the PNI
V2Xe digital compass. Figure 2 shows the schematic for interfacing the Dinsmore 1490
digital compass to the Zilog Z8 Encore! microcontroller. The following Figure 1 shows
the digital compass mounted to the top of the vehicle without the white plastic enclosure.

Figure 1: Dinsmore 1490 Digital Compass mounted on top of vehicle.


Figure 2: Dinsmore 1490 Digital Compass / Zilog Z8 Encore! MCU Interface
Schematic

Drive System
Our requirement for the drive system was to be able to move a vehicle or robot in
a desired direction depending on the information obtained from the GPS. Another
requirement is that the vehicle would need to carry all the required hardware, weigh less
than 10 kg, and able to move over many different terrains.

Preliminary Design
Our first job was to find a vehicle that would cover many different terrains. We
decided that a vehicle which uses tracks, similar to a military tank, would achieve this
goal. We also found a vehicle that would be able to cross water obstacles because the
tracks are able to paddle through the water. The vehicle we found, produced by TYCO
Industries, is called The Landshark, which is a radio controlled (R/C) vehicle that has a
six volt battery. The overall weight of the vehicle is less than seven pounds, which
should allow us to add the necessary components and not go over our weight limit of 22
kg.
Once the vehicle was determined to be suitable for our needs, we needed to learn
how to control the vehicle with a microcontroller. We began by disassembling the
vehicle so we could look at the drive system already inside the vehicle. We found that the
vehicle has two direct current (DC) motors and a motor controller board. Examining the
motor controller board, we noticed that there was a decoder chip that helps drive the
motors. After finding the data sheet for the PT8A978P decoder chip, we determined that
we would be able to use the existing motor controller board to control the vehicle. Using
an oscilloscope, we found that the incoming signal from the R/C unit was a frequency-
shift keyed (FSK) square wave signal, as shown in Figure 3. We noticed that the signal
has two distinct sections: information and end sections. The information section has a
frequency of 1.64 kHz, while the end section has a frequency of 820 Hz. The end section
only supplies four pulses to the entire control stream, while the information section will
vary depending upon the desired function. Once we determined the proper sequencing of
the input signal we would be able to duplicate these signals to control the vehicle.

Figure 3: FSK Input Signal to Motor Control Board Decoder

Problems Encountered
The first problem that we encountered in the design of the drive system was the
combination of the information and end sections of the signal. We determined that a 2:1
multiplexer (MUX) would be able to combine the two signals properly. However, we
would need to design a control signal that would allow the switching of the MUX. This
signal would also vary according to the drive function that we desired. Since the Zilog
microcontroller that we were using has four timers, we would be able to use one timer in
its pulse width modulation (PWM) function. This allowed us to switch from the 820Hz
to 1.64 kHz signal and output a similar drive signal that the R/C remote supplies.
Another problem was the type of MUX that we would use in our system.
Originally we found an Analog Device 8180 switching MUX. This item would switch
from one input to another with only a 10ns delay, which would not interfere with our
desired output signal. However, this device requires a negative voltage for proper
operation. Our Zilog Development Kit does not have the negative supply voltage for this
device. We also determined that to create the negative voltage would be an added cost
that would not be necessary. Therefore we searched the internet and found Texas
Instrument’s SN54AHC157 Quadruple 2:1 MUX. This device would work with an
operating voltage of -0.5V to 7V and therefore would be able to be attached to the Zilog
Development board with no problems. This is possible because there is a prototype area
on the Development board that will accept two 16-pin SOIC devices, allowing us to
attach the device to the development board and not create another circuit board to insert
into the vehicle.
Another aspect of the drive system is the ability for the user to use the R/C remote
to control the vehicle whenever they feel it is necessary. An interrupt signal would be
required to turn the microcontroller’s drive system off and allow the remote’s signal to
take over. We first thought that the output signal form the remote could be used to create
the interrupt. This option would not work properly. The remote signal would always
interrupt the system because when there was no incoming signal an interrupt would still
be noticed. This was due to the average output voltage with no signal applied was greater
than 0.5V. The average output voltage was around 1.3V, therefore some signal
conditioning was required to accomplish this task. We were able to obtain a KIA 393P
Comparator from the lab and create the circuit shown in Figure 4. This comparator
would allow the remote signal to activate the interrupt, but not when there was an average
output voltage.

+6V
from Battery Pack

R 1
10K
U 1A
D 1
8

1 2 3 +
1 Interrupt Signal
Drive Signal From 1N 448 2 - to Microcontroller
R/C Remote C 1
.1 u F
K IA 3 9 3
0
4

+3.3V
0
Reference Voltage

Figure 4: Comparator Circuit

Once the interrupt was working properly, we noticed that the Texas Instrument’s
MUX would not allow us to switch another set of input signals to the second set of inputs
on the MUX. We found that the control signal operates all four selectors on the device,
not a control signal for every two inputs. Therefore we needed another MUX device on
the board to allow us to complete this operation. This was not a big problem because the
Zilog Development board has two locations for 16-pin SOIC devices in the prototype
area. We attached another MUX to the second location and made the selector input the
output of the interrupt signal. Figure 5 shows the connection of the two MUX’s that
combine the drive signal and switches from the microcontroller to the remote signal.
U 1 Controller Generated U 2
820 Hz Drive Signal
Signal 2 4 2 4 Drive Signal to
5 1 A 1 Y 7 5 1 A 1 Y 7
2 A 2 Y 2 A 2 Y Vehicle Drive Board
11 9 11 9
14 3 A 3 Y 12 14 3 A 3 Y 12
4 A 4 Y 4 A 4 Y
1.64 kHz 3 3
6 1 B 6 1 B
Signal 2 B 2 B
10 10
13 3 B 13 3 B
4 B 4 B
1 1
15 A /B 15 A /B
G G

PWM 74AH C 157 Drive Interrupt 0 74AH C 157


0
Signal Signal Signal
from
R/C
Remote

Figure 5: MUX Schematic

After all the components were applied to the vehicle and testing commenced, we
found that the vehicle moved in a pulsing motion. We found that by applying the
vehicle’s battery to the Zilog Development board for power, we would lose power every
time the motors were engaged. This alerted us to the fact that the supply voltage of the
6V battery would drop below 3V and cause the Zilog board to reset. We were able to
overcome this problem by inserting a battery pack specifically for the microcontroller.
This battery pack holds four AAA batteries and supplies enough power (6V) to energize
the Zilog Development board.

Final Design
The final design of the drive system first required the programming of the Zilog
microcontroller to output the proper timing signals. This was accomplished by using the
onboard timers. One timer (TMR0) was initialized to output a continuous 820 Hz square
wave, while another timer (TMR1) was initialized to output a continuous 1.64 kHz
square wave. Once this was accomplished, a third timer (TMR2) was required to output
a varying PWM signal. This varying signal would control a MUX that would combine
the output of the other two timers. However, this PWM signal would change depending
upon the function that was required. So if the program wanted the vehicle to move
forward, a certain PWM would be required. To determine the proper PWM signal, we
found that the end code, which is four pulses at 820 Hz, lasted for only 4.878 ms. Then,
looking at the data sheet for the decoder device on the motor controller board, we
determined the appropriate times for each movement function of the vehicle. These times
are shown in Table 1. With these times determined, the PWM signal would be designed
to produce a low for 4.878ms and then go high for a given time, depending on the drive
function.

Drive Function Required Pulses Time


Forward 22 13.414 ms
Reverse 40 24.39 ms
Turn_Left 58 35.366 ms
Turn_Right 64 39.024 ms
Table 1: PWM Signal for Certain Drive Functions
Now that the function times were determined, we could design the proper code to
accomplish these tasks. We created a drive class in our program so we could use the
functions wherever they are required. One function, Forward, would begin by initializing
TMR0 and TMR1. Then we initialized TMR2 to run in PWM mode. Now we need to
determine the proper code to make the signal at the times required. First we need to find
the desired time-out period (TOP) by adding the end code time and the information code
time. For the Forward function we used 18.292 ms to achieve proper operation. This
value will be used to help determine the proper reload values (RV), which are required in
programming TMR2. The reload values are determined by using the equation below:

( TOP )( SC ) = RV
P

The system clock (SC) for the Zilog Development board runs at 18.432 MHz,
while we determined that the prescale (P) value to be 16. Now that the reload value was
obtained, we converted this value to a hexadecimal (hex) value. The highest two values
of this number will be applied to T2RH, while the lowest go to T2RL. Now we can
determine the pulse width modulation value (PWMV). First, we must find the high time
ratio (HTR). We can achieve this value by using the end code time (ECT) and the
information code time (ICT) and using the equation below:

ECT
×100 = HTR
ICT

Once the high time ratio is found, we can find the PWMV by using the following
equation:

  HTR  
PWMV = RV 1 −   
  100  

Now that the PWMV was obtained, we can convert this value to a hex value. The
highest two values of this number will be applied to T2PWMH, while the lowest go to
T2PWML. This completes the initialization of TMR2, which will vary for each drive
function. Now we could attach the SN54AHC157 MUX to the Zilog Development board
and attach the appropriate outputs to the MUX. The proper connections can be seen in
the first MUX shown in Figure 4. Once these connections were completed, we tested the
final output signal from the MUX with an oscilloscope. We found that the signal was not
perfect. There was more end code pulses than were desired, so we modified the
T2PWML and T2PWMH values to ensure the proper output from the MUX. The output
of the MUX would be considered the completed drive signal, which we could take and
input into the decoder chip on the vehicle’s drive board and would be able to control the
vehicle.
Since the Forward and Reverse functions of the drive system will be used to
control for extended periods, these functions will run the three timers continuously.
However, the Turn_Left and Turn_Right functions will only apply their output drive
signal for a certain amount of time. This was achieved by using two simple for loops that
will provide delay. This delay was determined by testing and allows the vehicle to turn
approximately 45 degreed in either direction. The final function designed was Stop. This
function is accomplished by turning all timers off and allowing no signal to the vehicle’s
drive board. The entire drive program can be seen in Appendix A.
Now that the microcontroller can control the vehicle, we looked into allowing the
user to override the system and take control using the R/C remote. We proceeded by
noticing where the drive signal on the vehicle’s drive board is applied to the decoder chip
and removed a section of the trace on the board to not allow the signal to connect. We
then attached a wire to either side of the broken connection and attached a connector to
the opposite end. This connector will allow us to connect to the Zilog Development
board. The drive signal from the vehicle was then attached comparator, as seen in Figure
5. The output of the second MUX will then be attached to the wire that connects to the
decoder’s input pin on the vehicle’s drive board.
Next, we inserted a quad AAA battery pack into the vehicle’s interior case to
power the Zilog board. We then attached a single-pole single-throw (SPST) switch to the
exterior of the vehicle to allow us to turn the Zilog Development board on or off. We
also found that the Zilog board fit inside the vehicle’s case with a few modifications. The
modifications included attaching a slim board to the Zilog Development board and
removing some ribbing from the vehicle’s interior case. Now the Zilog board will not
slide around and dislodge its connections.

Vehicle Speed Reduction


Preliminary Design
Once testing commenced with the compass and drive system enabled, we found
that the vehicle moves quickly along the ground. We decided that if the vehicle were to
reduce its speed, then we would be able to control the vehicle’s progress and allow the
avoidance detection system to handle obstacles more efficiently.

Problems Encountered
Our first problem was to determine how to slow the vehicle down. We began by
trying to use the drive system program. We found that the program was using its Turbo
mode for forward progress. So we determined that by changing the information code to
change the mode to just Forward, we could possibly slow the vehicle. This was not the
case. The current vehicle’s motor control board was designed to only allow Turbo mode
by placing a ground at one of the control pins on the decoder device.
Our next idea was to reduce the amount of voltage to the motor control board in
an attempt to slow the vehicle. We tested this by using a variable DC power supply and
attached it to the input power on the motor control board. We found we could easily
reduce the speed of the vehicle using this method. However, we were still concerned
about being able to use the vehicle at higher speeds because the higher speed is required
when the vehicle maneuvers through water. The vehicle already moves slowly in water at
its current speed, but if we were to slow it down, it would take forever to move across
water. So we decided that we should attach a relay to the vehicle and have the
microcontroller switch the relay from 3V to 6V when the GPS determined that the
vehicle was moving slower than normal.

Final Design

We designed a circuit that includes a voltage regulator, a LM317 Universal


Adjustable Regulator, and a relay that will reduce the input voltage to the vehicle’s motor
control board. The relay was implemented on the circuit board, but can not be activated.
It was intended to allow the program to increase speed when the GPS detects the vehicle
is moving slow, mainly when the vehicle is in the water this would occur. However, we
determined that a test in water was not going to be performed; therefore the relay routine
was not implemented. The speed reduction circuit is shown in Figure 6 below.

Speed Change
Input from
0 Microcontroller

LS1
2
1
4

5
3 Voltage Output
to Motor
U 1 R ELAY SPD T
Controller Board
Vehicle 3 2
Battery V IN VO U T

Input 1
AD J
C 1
0 .1 u F LM317
R 1

17k

R 2
10k

Figure 6: Vehicle Speed Reduction Circuit

0
Collision Avoidance
Preliminary Design

The purpose of the collision avoidance system is to allow the vehicle to move
around obstacles that impede its progress. The vehicle could both run into the obstacle
and move around them, or sense the oncoming object and make the vehicle move around
the obstacles. We have this option due to the GPS’s ability to sense the forward motion
of the vehicle and determine that it is not moving any farther and then have a routine that
would move the vehicle in a coordinated manner that could possible miss the obstacle.

Problems Encountered

We found a sensor that would allow us to recognize an object that is in front of us,
but the output would vary depending upon the distance the object is from the sensor. We
needed to determine the output voltage from the sensor for a desired distance. With the
proper output voltage of the sensor set at 1.2 volts, we needed a way to make an input to
he microcontroller to either be a high or low. We determined that a comparator with a
reference voltage of 1.2 volts would be adequate. After initial testing of the comparator
circuit with the microcontroller we found that the input capacitors would not discharge.
Therefore a resistor in parallel with the input capacitor would be required for proper
operation.

Final Design

We began by researching for sensors that would notice objects that are more than
8 inches from the sensor. We found that the Sharp GP2D12 sensors would detect objects
from 4 to 31 inches (10 to 80 cm) away from the sensor. The output of the sensor would
increase as the object became closer. Therefore we determined that a comparator circuit,
as shown in Figure 7, would allow us to detect objects that we about 10 inches from the
vehicle. We also needed to detect objects directly in front of the vehicle and from either
the left or right sides. We found that using three sensors would give us enough coverage
to allow the vehicle to proceed without missing any medium size objects. We then
proceeded with the programming of the microcontroller to allow these sensors to
interrupt the system when an obstacle is detected. Then, depending upon which sensor is
active, the program will turn the vehicle in the appropriate direction and move forward
for a short amount of time. Then the interrupt routine will end and proceed with the main
portion of the routine.
H I
U 1A R 5
Left D 2 10k

8
3 Port D3
Sensor +
1
Output
D 1N 4448
2 -
Interrupt
LM 393
R 1 C 1
9 .6 M .0 1 u F

4
0

H I
0
U 1B R 6
Center D 3
5
10k

Sensor +
7
Port D4
Output
D 1N 4448
6 -
Interrupt
LM 393
R 2 C 2
9 .6 M .0 1 u F

H I
0 U 2A R 7
Right D 4 10k

8
3 Port D5
Sensor +
1
Output
D 1N 4448
2 -
Interrupt
LM 393
R 3 C 3
9 .6 M .0 1 u F

4
0

U 3
H I

6V 3 2
Battery V IN VO U T

Input C 4
1
AD J
.1 u F R 4
LM 317 10k

Figure 7: Collision Avoidance Circuit


GPS System

Preliminary Design

For finding out where the vehicle is and where it needs to go a global position
system (GPS) is a perfect choice. Not only is it universal but it keeps its precision.
This vehicle requires a compact GPS unit that is affordable, does not use a lot of power,
and updates fast enough to work in real time. This is necessary because the vehicle is
expected to travel efficiently, as if a human were operating the vehicle. The GPS we
chose to use is the Garmin GPS 16-LVS. This device weighs 6.4 oz and can fit right on
top of our vehicle. It also has brackets to mount it to the head of the vehicle. The
electrical characteristics are also reasonable in that they will use less than 25% of the
vehicles power and are shown below Table 2.

Table 2: GPS Electrical Characteristics

The acquisition times of the GPS are shown below in Table 3. While this is a bit
sluggish, the receiver has such a wide range of accuracy that a more frequent update
would be redundant.

Table 3: GPS Update Speeds


The GPS 16-LVS also has a UART port which can interface directly with the
microcontroller board. Because the GPS needs to transmit lots of information about
where it is it is best that such hard wiring be avoided.
Another huge convenience to this is that the details of timing and receiving data
are already defined for the UART port. The work is only in setting up the devices to
work with each other in software.
Other models considered were usually more expensive, too big, or too confusing
to use. However one board by Zilog was designed specifically for a GPS, as shown
below in Figure 8. This would have been extremely easy to implement. The
disadvantages to this board would be the size and that it would be easily breakable. A
picture is shown below. Note how much room the LCD screen and the keypad would
have taken up.

Figure 8: Zilog Designed GPS Board

Compare this board with the board we decided to use for this project shown below
in Figure 9. This board has everything needed with the disadvantage being in challenge
to implement. This board also fits snugly inside our vehicle. These pictures are sized
relative to each other.
Figure 9: Zilog Z8 Encore!® MCU

Problems Encountered

The GPS sends out its data on a simple comma delimited code scheme. We tested
this on a computer and were able to see this information directly. The information
sequence we are looking at is defined as shown below in Table 4.

Table 4: GPS Output Data


The main problem was in not being able to read anything from the GPS. We
were struggling with this for some time. The GPS worked fine with a laptop computer
and it was hooked up to the board exactly the same way. It turned out that the RS-232
connector was set up differently, the receive and transmit ports were reversed in the order
Garmin determined to be correct.

In Figure 10 below, the latitude and longitude variables are filling up with values.
These are the expected numbers for:

Latitude: 41 48.4280
Longitude: 072 15.1543

Figure 10: Latitude and Longitude Values


Final Design

The GPS was wired to the board as shown below in Figure 11.

Figure 11: GPS Wiring Diagram

It was then mounted to the front of the vehicle by making use of the brackets on
the bottom of the device. The cord was then cut and a new RJ-45 connector was attached
to shorten the 16 foot cable. The new shortened cord was then plugged in to the
microcontroller using a RJ-45 to DB-9 adapter. Afterwards, the hardware was attached
and the programming of the microcontroller began. The completed program can be seen
in Appendix A.

Alternative Designs

LCD / Keypad User Interface Module


Preliminary Design

The purpose of the liquid crystal display (LCD) / keypad user interface module
was to enable a user to input destination coordinates to the vehicle. The vehicle would
then autonomously travel to the input destination coordinates. The LCD that was chosen
for this application was a 16 x 4 LCD parallel display. This particular LCD had an
onboard LSI HD4470 controller. The keypad that was chosen was a 16-button
indoor/outdoor keypad. These components were enclosed in a plastic housing. Windows
were cut in the plastic case to enable mounting of the components. The connections
between the LCD / keypad and the microcontroller board were accomplished by the use
of a DB-25 connector. The following Figure 12 is of the User Interface Module (UIM)
containing the LCD and keypad.
U 1

1
Vss 2
Vcc 3
LCD DISPLAY

Vee 4
R S 5
R /W 6 P1
E 7 1
D B0 8 14
D B1 9 2
D B2 1 0 15
D B3 1 1 3
D B4 1 2 16
D B5 1 3 4
D B6 1 4 17
D B7 5
18
6
21076 19
7
20
8
21
9
22
10
23
11
24
12
25
13
U 2
C O N N E C TO R D B 25

1
1 2
2 3
Keypad

3 4
4 5
5 6
6 7
7 8
8 9
9

152063

Figure 12: Schematic of User Interface Module


Problems Encountered

Approximately three weeks were spent working on the UIM. The software
initialization routine was what took up most of that time. Without any success, this
portion of the project was placed on the back burner until more important components of
the project were successful.

Final Design

Without any success implementing the UIM, the module was deemed unimportant
to the completion of the project. Focus was then returned to the implementation of the
GPS with the vehicle.
Budget/Parts
This section shows the parts that were ordered and whether they were used or not.
The overall project was well under the proposed budget of $1000. The detailed list of
purchased parts is shown in Appendix B. Chart 1 shows the distribution of funds and
how they were applied to this project.

Excess
307.02 Total Amount
Used on
Project
509.02

Total Amount
Spent 183.96

Chart 1: Distribution of Funds


Timelines
The following timeline shows the progression of our project through the first semester:

Jan 2004 Feb 2004 Mar 2004 Apr 2004


ID Task Name Start Finish Duration
25/1 1/2 8/2 15/2 22/2 29/2 7/3 14/3 21/3 28/3 4/4 11/4 18/4 25/4

1 Formed Teams 1/20/2004 2/2/2004 2w

2 Project Statement 1/30/2004 2/10/2004 1.5w

3 Project Specifications 2/6/2004 2/19/2004 2w

4 Research Possible Components 2/18/2004 4/13/2004 8w

5 Design 2/18/2004 5/4/2004 11w

6 Purchase Components 3/8/2004 5/14/2004 10w

7 Project Broken Down Into Sections 4/1/2004 5/5/2004 5w

8 290 Presentation 4/30/2004 4/30/2004 .2w

ECE 290 Timeline


The following timeline shows the progression of our project through the second semester:

Sep 2004 Oct 2004 Nov 2004


ID Task Name Start Finish Duration
29/8 5/9 12/9 19/9 26/9 3/10 10/10 17/10 24/10 31/10 7/11 14/11 21/11 28/11 5/12

1 Build Sections 8/30/2004 12/10/2004 15w

2 Drive System 9/23/2004 10/29/2004 5.4w

3 Digital Compass 9/13/2004 10/29/2004 7w

4 GPS 9/23/2004 12/10/2004 11.4w

5 Debugging 9/13/2004 12/10/2004 13w

6 291 Presentation 12/10/2004 12/10/2004 .2w

ECE 291 Timeline


Conclusion
In final tests, the GPS Homing Robot would unreliably progress towards its preprogrammed destination.
Since the vehicle relied so heavily on the 8-directional compass, it did not have that great of accuracy as far as
heading direction. The vehicle was programmed to travel forwards for three heading directions to reduce
abruptness of driving towards its destination. Say if the desired heading was north, the vehicle would travel
forwards for north, northwest, and northeast.
Without hazard avoidance implemented, the vehicle could not avoid any hazards and the user would have
to follow the vehicle closely and pick it up if collision with an obstacle was imminent. All of the hardware
aspects of the project were completed well before the Senior Design Day deadline. The software bugs which
needed to be worked out were the most time consuming of any problems encountered. Testing for the project was
a difficult and lengthy process. Since the GPS only provided valid outputs while outdoors, the only way we could
test and debug was through trial and error outdoors. Not only did it take upwards of 5 minutes for each test (GPS
acquire time and setup), but the vehicle motor and compass batteries would run out of energy quickly. For the
project to successfully fulfill all of its specifications, more software work would need to be done and tested.
Appendix A
#include "compass_main.h"
#include "Timer.h"
#include "Drive.h"
#include <ez8.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

unsigned char current_ms;


static int timer_2sec;

main()
{

int i,c;
unsigned char direction,update_direction;

//destlat1 = 41.48428; //these are our default values


//destlon1 = -72.151543; //change one to north, the debugger goes north
DI();
destlat1 = 41.48436; //these coordinates are middle of campus
destlon1 = -72.15148;

////////////// begin normalize destination ///////////////////


while (destlat1<0)
{destlat1 = 360+destlat1;}
while (destlon1<0)
{destlon1 = 360+destlon1;}

destlat1 = destlat1*(3.14159/180);
destlon1 = destlon1*(3.14159/180);
////////////// end normalize destination ///////////////////

////////////// begin initializations ///////////////////


//init_delay();
//init_portF_gpio();
initialize_compass();
EI();
////////////// end initializations ///////////////////

////////////// start mainloop ///////////////////


while(1)
{
timer_2sec ++;
if (timer_2sec == 10000)
{
update_direction = TRUE; // Indicate main routine to read sensor
timer_2sec = 0;
}

if (update_direction == TRUE) //if it is time to update direction


{

encode_direction((PEIN & READ_SENSOR),destlat1,destlon1);


update_direction = FALSE;

for (i=0; i < 400; i++) // delay a bit, prevents spinning


{
for (c=0; c < 3000; c++)
{
;
}
}

}
////////////// end mainloop ///////////////////

}
/*
void init_portF_gpio(void)
{
PFADDR = 0x01; // PA Data Dir = output: updated
PFCTL = 0x04; // PA Out Ctrl = push-pull
PFHDE = 0x00; // OUTPUT : updated
PFOUT = 0x00;
}

void delayms (unsigned int milliseconds)


{
current_ms = 0;
T3CTL &= 0x7F; // Disable T3
T3H = 0x00 ; // Restart from 0
T3L = 0x00 ;
T3CTL |= 0x80 ; // Turn On T3
while (current_ms < milliseconds)
; // Delay loop
T3CTL &= 0x7F; // Stop T3
}

void init_delay(void) // timer initialization module


{
SET_VECTOR(TIMER3,isr_timer3);
T3H = 0x00; // Start value = 0
T3L = 0x00;
T3CPH = 0x48; // 1ms reload counter
T3CPL = 0x00;
T3CTL = 0x01; // Continuous mode; clock divide by 1
IRQ2E0 &= 0x7F;
IRQ2E1 |= 0x80; // T3 has lowest priority
}

#pragma interrupt // interupt service routine


void isr_timer3(void)
{
current_ms++ ; // Increment count
}

void isr_Timers(void)
{
int i;
int c;
SET_VECTOR(P7AD,isr_Timers); //Setup the vector for PORTD2 interrupt ,HIGH priority
T0CTL &= 0x7F;
T1CTL &= 0x7F;
T2CTL &= 0x7F;

PFOUT = 0x01;
delayms(5000);
/*for(i=0;i<500;i++) // First loop to turn timer on
{
for(c=0;c<6000;c++) // Second loop to turn timer on for 5 secs
{
;
//PEOUT |= 0x80; // Output to MUX to disable signal from timers
// and enable signal from hand held controller
}
}
T0CTL |= 0x80;
T1CTL |= 0x80;
T2CTL |= 0x80;
PFOUT = 0x00;
}
*/

////////////////////////////////////////////////////////

void initialize_compass(void)
{
// Set up the hardware for reading the Sensor
// Port B pins 0-3 are all inputs, Port B pin 4 for INTR generation
PEADDR = 0x01; // Select Data direction sub register
PECTL = 0x0F; // Lower Nibble Input; Higher Nibble Output
}

unsigned char encode_direction(unsigned char dir,double numlat,double numlon) //sent go


direction
{
unsigned char heading_direction;

getdir(destlat1,destlon1); //this fuction updates "course"; the nessasary direction to take

switch ((PEIN & READ_SENSOR))


//encode direction
{
case 0x03: // North East
diren = 1;
break;

case 0x06: // North West


diren = 7;
break;

case 0x07: // North


diren = 0;
break;
case 0x09: // South East
diren = 3;
break;
case 0x0B: // East
diren = 2;
break;
case 0x0C: // South West
diren = 5;
break;
case 0x0D: // South
diren = 4;
break;
case 0x0E: // West
diren = 6;
break;
case 0x00: case 0x01:
case 0x02: case 0x04:
case 0x05: case 0x08:
case 0x0A: case 0x0F:
default : //should
not get here, fix compass if so
diren = 8; //north is
default
break;

// 7nw 0n 1ne
// 6w 2e
// 5sw 4s 3se
//course(direction I need to go)
//dir(direction I am going)
//if -1<=course-dir<=1, forward
//if 1<course-dir<=4, turn left
//if 4<course-dir turn right
//if 1<dir-course<4, turn right
//if 4<dir-course turn left

////////////// begin see if there ///////////////////


getdist(destlat1,destlon1); //feet away
if (dist < 50)
{
Stop();
}
////////////// end see if there ///////////////////
////////////// begin 'necessary turn?' ///////////////////
if (diren<8)
{
if ((-1<=course-diren)&&(course-diren<=1))
Forward();
else if (((1<course-diren) && (course-diren<=4))||(4<diren-course))
Turn_Left();
else
Turn_Right();
}
////////////// end 'necessary turn?' ///////////////////

///////////////////////////
void getgps(void) //set up to return the north pole
{

inituart0(); // initialize UART


stage = 0x00;

while(readit){
if(stage && new_byte){

////////////// start find correct starting sequence ///////////////////


if( stage == 0x01 && x=='G')
stage = 2;

else if(stage == 0x02 && x=='P')


stage = 3;

else if(stage == 0x03 && x=='R')


stage = 4;
////////////// end find correct starting sequence ///////////////////

else if(stage == 0x04 && x!=',') //get to first comma


stage = 4;
else if(stage == 0x04 && x==',') //get past comma
stage = 5;

else if(stage == 0x05 && x!=',') { //utc data


stage = 5;
// if (x=='V')
// stage = 0x00; //reset if data not valid
//this functions
to loop until signal
}
else if(stage == 0x05 && x==','){ //pass comma
stage = 6;
}

else if(stage == 0x06 && x!=',') //status data


stage = 6;
else if(stage == 0x06 && x==','){ //pass comma
stage = 7;
loopmode = 0; //[0] for sign
}

////////////// start get latitude string ///////////////////


else if(stage == 0x07 && x!=','){ //latitude data
latch[loopmode] = x;
loopmode++;
}

else if(stage == 0x07 && x==','){ //pass comma


stage = 8;
latch[loopmode]=0x00; //NULL last value
}
////////////// end get latitude string ///////////////////

else if(stage == 0x08 && x!=',') //lat hemisphere


latsig = x;
else if(stage == 0x08 && x==','){ //pass comma
stage = 9;
loopmode = 0; //[0] for sign
}

////////////// start get longitude string ////////////////


else if(stage == 0x09 && x!=','){ //longitude data
lonch[loopmode] = x;
loopmode++;
}
else if(stage == 0x09 && x==','){ //pass comma
stage = 10;
lonch[loopmode]=0x00; //NULL last value
}
////////////// end get longitude string ////////////////

else if(stage == 0x0A && x!=','){ //lon hemisphere


lonsig = x;
readit = 0;
}
else //
stage = 0x00;

new_byte = 0x00;

} //end if statement
} //end while loop

////////////// start string to double ////////////////


ch = latch;
numlatu = strtod(ch,0x00);
ch = lonch;
numlonu = strtod(ch,NULL);
////////////// end string to double ////////////////

////////////// start string fixings ////////////////


if (latsig=='S' || latsig=='s')
numlatu = (-1)*(numlatu);
if (lonsig=='W' || lonsig=='w')
numlonu = (-1)*(numlonu);
////////////// end string fixings ////////////////

////////////// start 'here' manipulation ////////////////


numlatu = numlatu/100;
numlonu = numlonu/100;
numlatu = floor(numlatu) + (numlatu-floor(numlatu))/.6; //decimal is in minutes
numlonu = floor(numlonu) + (numlonu-floor(numlonu))/.6;

while (numlatu<0) //normalize


numlatu = 360+numlatu;
while (numlonu<0)
numlonu = 360+numlonu;

numlatu = numlatu*(3.14159/180); //put in radians


numlonu = numlonu*(3.14159/180);
////////////// end 'here' manipulation ////////////////

int getdir(double latdes, double londes)


{

getgps(); //get 'here'

latc=numlatu; // range (-2pi,2pi)


lonc=numlonu; // range (-2pi,2pi)

getd(latc,lonc,destlat1,destlon1); //update the global 'd'; a measure of distance

gettc();

////////////// start course find ////////////////


tc1 = tc1*(180/3.14159); // turn radians to angle

while (tc1>=360){ //make sure angle is between 0 and 360


tc1=tc1-360;}
while (tc1<0){
tc1=tc1+360;}

if (tc1<23) { //n
course1 = 0;}
else if (tc1<68) { //ne
course1 = 1;}
else if (tc1<113) { //e
course1 = 2;}
else if (tc1<158) { //se
course1 = 3;}
else if (tc1<203) { //s
course1 = 4;}
else if (tc1<248) { //sw
course1 = 5;}
else if (tc1<292) { //w
course1 = 6;}
else if (tc1<338) { //nw
course1 = 7;}
else { //n
course1 = 0;}
course = course1;
////////////// end course find ////////////////

return course1;
}

double gettc()
{
//does the equivilent of the function below
/* acos(
(
sin(destlat1)-sin(latc)*cos(d)
)/
(
sin(d)*cos(latc)
)
);
*/

////////////// begin get tcl ////////////////


if ((destlat1>=0)&&(destlat1<3.14159))
temp1 = sqrt(1/(1+(1/(tan(destlat1)*tan(destlat1)))));
else
temp1 = -sqrt(1/(1+(1/(tan(destlat1)*tan(destlat1)))));

if ((latc>=0)&&(latc<3.14159))
temp2 = sqrt(1/(1+(1/(tan(latc)*tan(latc)))));
else
temp2 = -sqrt(1/(1+(1/(tan(latc)*tan(latc)))));

while (d>=6.28319){ //make sure angle is between 0 and 2pi


d=d-6.28319;}
while (d<0){
d=d+6.28319;}

if ((d<1.5708)||(d>4.7124))
temp2 = temp2*sqrt(1/(1+tan(d)*tan(d)));
else
temp2 = temp2*(-sqrt(1/(1+tan(d)*tan(d))));

temp1 = temp1-temp2;

if ((d>=0)&&(d<3.14159))
temp2 = sqrt(1/(1+(1/(tan(d)*tan(d)))));
else
temp2 = -sqrt(1/(1+(1/(tan(d)*tan(d)))));

if ((latc<1.5708)||(latc>4.7124))
temp2 = temp2*sqrt(1/(1+tan(latc)*tan(latc)));
else
temp2 = temp2*(-sqrt(1/(1+tan(latc)*tan(latc))));

if (((temp1-temp2)>-.0001)&&((temp1-temp2)<.0001)) //catch rounding errors


tc1 = 0;
else
tc1 = acos(temp1/temp2);
////////////// end get tcl ////////////////

////////////// begin fixtcl ////////////////


temp3=destlon1-lonc;
while (temp3>=6.28319){ //make sure angle is between 0 and 2pi
temp3=temp3-6.28319;}
while (temp3<0){
temp3=temp3+6.28319;}

if ((temp3>=0)&&(temp3<3.14159))
tc1 = 2*3.14159-tc1; //tcl >0
else
tc1 = tc1; //tcl <0
////////////// end fixtcl ////////////////

return acos(temp1/temp2);

double cos(double cx)


{

while (cx>=6.28319){ //make sure angle is between 0 and 2pi


cx=cx-6.28319;}
while (cx<0){
cx=cx+6.28319;}

if ((cx<1.5708)||(cx>4.7124))
return sqrt(1/(1+tan(cx)*tan(cx)));
else
return (-sqrt(1/(1+tan(cx)*tan(cx))));
}

double sin(double cx)


{
while (cx>=6.28319){ //make sure angle is between 0 and 2pi
cx=cx-6.28319;}
while (cx<0){
cx=cx+6.28319;}

if ((cx>=0)&&(cx<3.14159))
return sqrt(1/(1+(1/(tan(cx)*tan(cx)))));
else
return -sqrt(1/(1+(1/(tan(cx)*tan(cx)))));
}

double getd(double lat1d,double lon1d,double lat2d,double lon2d)


{
//this fuction does the equivilent of below function
//acos(
// sin(lat1d)*sin(lat2d)+cos(lat1d)*cos(lat2d)*cos(lon1d-lon2d)
// );
while (latc>=6.28319){ //make sure angle is between 0 and 2pi
latc=latc-6.28319;}
while (latc<0){
latc=latc+6.28319;}
while (lonc>=6.28319){ //make sure angle is between 0 and 2pi
lonc=lonc-6.28319;}
while (lonc<0){
lonc=lonc+6.28319;}

if ((latc>=0)&&(latc<3.14159))
temp1 = sqrt(1/(1+(1/(tan(latc)*tan(latc)))));
else
temp1 = -sqrt(1/(1+(1/(tan(latc)*tan(latc)))));
if ((destlat1>=0)&&(destlat1<3.14159))
temp1 = temp1*sqrt(1/(1+(1/(tan(destlat1)*tan(destlat1)))));
else
temp1 = temp1*(-1)*sqrt(1/(1+(1/(tan(destlat1)*tan(destlat1)))));

if ((latc<1.5708)||(latc>4.7124))
temp2 = sqrt(1/(1+tan(latc)*tan(latc)));
else
temp2 = (-sqrt(1/(1+tan(latc)*tan(latc))));
if ((destlat1<1.5708)||(destlat1>4.7124))
temp2 = temp2*sqrt(1/(1+tan(destlat1)*tan(destlat1)));
else
temp2 = temp2*(-sqrt(1/(1+tan(destlat1)*tan(destlat1))));

temp3 = lonc - destlon1;


while (temp3>=6.28319){ //make sure angle is between 0 and 2pi
temp3=temp3-6.28319;}
while (temp3<0){
temp3=temp3+6.28319;}
if ((temp3<1.5708)||(temp3>4.7124))
temp2 = temp2*sqrt(1/(1+tan(temp3)*tan(temp3)));
else
temp2 = temp2*(-sqrt(1/(1+tan(temp3)*tan(temp3))));
d=acos(temp1+temp2);
//temp1 = (latc)(destlat1)(latc)(destlat1)(lonc - destlon1)
//return acos(sin(lat1d)*sin(lat2d)+cos(lat1d)*cos(lat2d)*cos(lon1d-lon2d));
return d;
}

int getdist(double latdes, double londes)


{
getd(latc,lonc,latdes,londes); //get d
dist = floor(20884586*d); //convert d to feet 20884586
return dist; //and put in 'dist': distance in feet
}

void inituart0(void)
{
DI();
PAADDR = ALT_FUN; // Configure for alternate function
PACTL |= PORTA_UART_TXD | PORTA_UART_RXD; // Enable UART0 TxD0/RxD0 pins
SET_VECTOR(UART0_RX, isr_uart_rec_0); // Update ISR TABLE (occurs during compiling not run
time)
SET_VECTOR(UART0_TX,isr_tr); // Update ISR TABLE (occurs during compiling not run time)

U0BRH = (char)(BRG0 >> 8); // Baud Rate High


U0BRL = (char)(BRG0 & 0xff); // Baud Rate Low

IRQ0ENH |= 0x18; // Highest Priority


IRQ0ENL |= 0x18; // Highest priority

U0CTL0 = UART_RXD_EN | UART_TXD_EN; // Transmit enable, Receive Enable, No Parity, 1 Stop


IRQ0 = 0x00;
EI(); // Enable global interrupt
}

#pragma interrupt // interupt service routine


void isr_uart_rec_0(void)
{
x = U0D; // get value
if(stage==0x00){
stage = 0x01;
new_byte = 0x01;
}
else new_byte = 0x01;

#pragma interrupt
void isr_tr(void){

/*************************************************/
/*****************************************************************************
* File: Drive.c
* Description: This code will initiate timer 2 in PWM and for a certain amount
* of ON/OFF timer that will control the AD8081. The AD8081 will
* all the 820 and 1640 Hz signals to be combined. The output of
* the AD8081 will be input into the vehicle decoder and drive the
* vehicle in the appropriate direction.
*
*******************************************************************************/

#include <eZ8.h>
#include "Timer.h"
#include "Drive.h"

void Forward(void)
{

init_820Hz();
init_1640Hz();

T2CTL &= 0x7F; // disable timer


T2CTL |= 0x23; // set mode to PWM and prescalar to 16
T2H = 0x00; // Start value = 00 don't change
T2L = 0x01; // Start value = 01 don't change
T2PWMH = 0x4B; // change these 4 values for different duty cycle
T2PWML = 0x67; // this routine is now for 50% duty cycle
T2RH = 0x62; // The two registers T2CPH and T2CPL together
T2RL = 0x6E; // dictate the period of the rectangular waveform
// T2PWMH and T2PWML dictate the duty cycle of the
// rectangular pulses

/* IRQPS |= 0x80;
SET_VECTOR(P7AD, isr_Timers); // initialization of TIMER2 vector
IRQ1ENL |= 0x80; // sets priority IRQ1ENL &= 0x08
IRQ1ENH |= 0x80; // sets priority IRQ1ENH |= 0x08*/

PCADDR = 0x02; // setting Port C7 as alternate function


PCCTL |= 0x80; // setting Port C7 as alternate function
T2CTL |= 0x80; // enable timer
}

void Reverse(void)
{
init_820Hz();
init_1640Hz();

T2CTL &= 0x7F; // disable timer


T2CTL |= 0x23; // set mode to PWM and prescalar to 16
T2H = 0x00; // Start value = 01 don't change
T2L = 0x01; // Start value = 01 don't change
T2PWMH = 0x7C; // change these 4 values for different duty cycle
T2PWML = 0xFF; // this routine is now for 50% duty cycle
T2RH = 0x93; // The two registers T2CPH and T2CPL together
T2RL = 0xED; // dictate the period of the rectangular waveform
// T2PWMH and T2PWML dictate the duty cycle of the
// rectangular pulses

/*IRQPS |= 0x80;
SET_VECTOR(P7AD, isr_Timers); // initialization of TIMER2 vector
IRQ1ENL |= 0x80; // sets priority IRQ1ENL &= 0x08
IRQ1ENH |= 0x80; // sets priority IRQ1ENH |= 0x08*/

PCADDR = 0x02; // setting Port C7 as alternate function


PCCTL |= 0x80; // setting Port C7 as alternate function
T2CTL |= 0x80; // enable timer

void Turn_Left(void)
{
int i;
int c;
init_820Hz();
init_1640Hz();

T2CTL &= 0x7F; // disable timer


T2CTL |= 0x23; // set mode to PWM and prescalar to 16
T2H = 0x00; // Start value = 01 don't change
T2L = 0x01; // Start value = 01 don't change
T2PWMH = 0x8C; // change these 4 values for different duty cycle
T2PWML = 0xC4; // this routine is now for 50% duty cycle
T2RH = 0xA3; // The two registers T2CPH and T2CPL together
T2RL = 0xAD; // dictate the period of the rectangular waveform
// T2PWMH and T2PWML dictate the duty cycle of the
// rectangular pulses

PCADDR = 0x02; // setting Port C7 as alternate function


PCCTL |= 0x80; // setting Port C7 as alternate function

for(i=0;i<68;i++) // First loop to turn timer on


{
for(c=0;c<3000;c++) // Second loop to turn timer on for .5 secs
{
T2CTL |= 0x80; // enable timer
}
}

T2CTL &= 0x7F; //disable timer 2


T1CTL &= 0x7F; //disable timer 1
T0CTL &= 0x7F; //disable timer 0
}

void Turn_Right(void)
{
int i;
int c;
init_820Hz();
init_1640Hz();

T2CTL &= 0x7F; // disable timer


T2CTL |= 0x23; // set mode to PWM and prescalar to 16
T2H = 0x00; // Start value = 01 don't change
T2L = 0x01; // Start value = 01 don't change
T2PWMH = 0x5D; // change these 4 values for different duty cycle
T2PWML = 0x7C; // this routine is now for 50% duty cycle
T2RH = 0x74; // The two registers T2CPH and T2CPL together
T2RL = 0x6D; // dictate the period of the rectangular waveform
// T2PWMH and T2PWML dictate the duty cycle of the
// rectangular pulses

PCADDR = 0x02; // setting Port C7 as alternate function


PCCTL |= 0x80; // setting Port C7 as alternate function

for(i=0;i<60;i++) // First loop to turn timer on


{
for(c=0;c<3000;c++) // Second loop to turn timer on for .5 secs
{
T2CTL |= 0x80; // enable timer
}
}

T2CTL &= 0x7F; //disable timer 2


T1CTL &= 0x7F; //disable timer 1
T0CTL &= 0x7F; //disable timer 0
}

void Stop(void)
{
T0CTL &= 0x7F; // disable timer0
T1CTL &= 0x7F; // disable timer1
T2CTL &= 0x7F; // disable timer2

#include <ez8.h>
#include "compass_main.h"

// Extern for LED/ Timer0 ISR


unsigned char update_flag;
extern unsigned char update_direction;
//extern int digit;
unsigned char digit;
//int timer_2sec;

// Extern for UART/ I2C ISRs


//extern char compass_control_register;
//extern char compass_status_register;

// *************************************************
//* This Timer ISR get called every 1ms.
//**************************************************
/*#pragma interrupt
void isr_timer3(void)
{
static int timer_2sec;
if(digit == 3)
{
// Port E6
PEOUT &= 0xBF; // PEO &= 0xBF; For older ZDS
PEOUT |= 0x40;
PEOUT &= 0xBF;
}
else if (digit == 2)
{
// Port E5
PEOUT &= 0xDF;
PEOUT |= 0x20;
PEOUT &= 0xDF;
}
else if (digit == 1)
{
// Port G7
PGOUT &= 0x7F;
PGOUT |= 0x80;
PGOUT &= 0x7F;
}
else if (digit == 0)
{
// Port E7
PEOUT &= 0x7F;
PEOUT |= 0x80;
PEOUT &= 0x7F;
}

update_flag = 1; // Indicate the main routine to update data

timer_2sec ++;
if (timer_2sec == 2000)
{
update_direction = TRUE; // Indicate main routine to read sensor
timer_2sec = 0;
}
}

/*****************************************************************************
* File: Timer.c
* Description: This code will initiate the two timers which are constantly
* used within the Drive System program to the proper settings.
*
*******************************************************************************/

#include <eZ8.h>
#include "Timer.h"
void init_820Hz(void) // timer initialization module
{
T0CTL &= 0x7F; // disable timer
T0CTL |= 0x21; // set prescalar to 16 and mode to Continuous
T0H = 0x00; // Start value = 01
T0L = 0x01; // Start value = 01
T0RH = 0x02; // The two registers TOCPH and TOCPL together
T0RL = 0xBE; // dictate the period of the rectangular waveform

/* IRQPS |= 0x80;
SET_VECTOR(P7AD, isr_Timers); // initialization of TIMER2 vector
IRQ1ENL &= 0x80; // sets priority
IRQ1ENH |= 0x80; // sets priority*/

PAADDR = 0x02; // setting Port A1 as alternate function


PACTL |= 0x02; // setting Port A1 as alternate function
T0CTL |= 0x80; // enable timer
}

void init_1640Hz(void) // timer initialization module


{
T1CTL &= 0x7F; // disable timer
T1CTL |= 0x21; // set prescalar to 16 and mode to continuous
T1H = 0x00; // Start value = 01
T1L = 0x01; // Start value = 01

T1RH = 0x01; // The two registers TOCPH and TOCPL together


T1RL = 0x5F; // dictate the period of the rectangular waveform

/*IRQPS |= 0x80;
SET_VECTOR(P7AD, isr_Timers); // initialization of TIMER2 vector
IRQ1ENL &= 0x80; // sets priority
IRQ1ENH |= 0x80; // sets priority*/

PCADDR = 0x02; // setting Port C1 as alternate function


PCCTL = 0x82; // setting Port C1 as alternate function
T1CTL |= 0x80; // enable timer
}

#define FREQ 18432000 // 18.432MHz


#define BAUD0 4800 // 9.6K baud for UART0
#define BRG0 FREQ/(BAUD0*16L) // NOTE THE TYPECAST HERE

#define UART0
#define PORTA_UART_RXD 0x10
#define PORTA_UART_TXD 0x20
#define UART_TXD_EN 0x80
#define UART_RXD_EN 0x40

#define DATA_DIR 0x01 // Data Direction


#define ALT_FUN 0x02 // Alternate Function
#define OUT_CTL 0x03

void inituart0(void);
void getgps(void); //updates gps
double getlat(void); //returns latitude
double getlon(void); //returns longitude
int getdir(double, double); //returns int direction, getdir(lat,lon)
double gettc(void);
double cos(double);
double sin(double);
double getd(double,double,double,double);
int getdist(double, double);
void isr_uart_rec_0(void);
void isr_tr(void);

unsigned char x='0'; // UART receive data variable


unsigned char stage=0,new_byte=0;
double numlatu,numlonu;
double latc,lonc,d,tc1,temp1,temp2,temp3,temp4;
int course1;

char latch[12];
char lonch[12];
char latsig,lonsig;
char *ch;

int loopmode;
int readit=1;

double destlat1,destlon1;
int diren, course;
unsigned int dist;

void initialize_compass(void);
void read_sensor(void);
void update_status(void);
void select_intr_port(void);
void isr_Timers(void);
void init_portF_gpio(void);
void init_delay(void);
unsigned char encode_direction(unsigned char,double,double);
void isr_timer3(void);
void delayms (unsigned int milliseconds);

#define TRUE 1
#define FALSE 0

#define UPDATE_INTERVAL 1000 // 1000 milliseconds or 1 second


#define READ_SENSOR 0x0F
#define SET_ERROR_BIT 0x08
#define CHK_ERR_BIT_SET 0x08

/* FROM Z8ENCORE.H */
#define DATA_DIR 0x01 // Data Direction
#define ALT_FUN 0x02 // Alternate Function
#define OUT_CTL 0x03 // Output Control (Open-Drain)
#define HDR_EN 0x04 // High Drive Enable
#define SMRS_EN 0x05 // Stop Mode Recovery Source Enable

/*********************************************************
* File : Drive.h
* Description : prototype functions
*
************************************************************************/

void Forward(void);
void Reverse(void);
void Turn_Left(void);
void Turn_Right(void);
void Stop(void);

/*********************************************************
* File : Timer.h
* Description : prototype functions
*
************************************************************************/

void init_820Hz(void);
void init_1640Hz(void);
void isr_Timers(void);

/*!\file uart.h
* \brief Header file for Z8 Encore! UART Devices.
*
* This file contains header information required by UART driver
* implementations for Z8 Encore! microcontrollers.
*
* This source file uses Doxygen-style comments to generate documentation
* automatically.
*
* Copyright (C) 1999-2004 by ZiLOG, Inc.
* All Rights Reserved.
*/
#ifndef _UART_H_
#define _UART_H_

#include <defines.h>
#include <uartdefs.h>

/*! UART interrupt enable definitions used */


#define IRQ_U0RXI (BYTE)0x10
#define IRQ_U0TXI (BYTE)0x08

#ifdef EZ8_UART1
#define IRQ_U1RXI (BYTE)0x40
#define IRQ_U1TXI (BYTE)0x20
#endif

#define REGFILEADDR_U0TXD 0xF40


#define REGFILEADDR_U1TXD 0xF48

#define CLOCK_DIVISOR 16 //!< The default clock


divisor used.

#define BAUD_9600 9600UL //!< Baud rate 9600.


#define BAUD_19200 19200UL //!< Baud rate
19200.
#define BAUD_38400 38400UL //!< Baud rate
38400.
#define BAUD_57600 57600UL //!< Baud rate
57600.
#define BAUD_115200 115200UL //!< Baud rate 115200.
#define DATABITS_8 8 //!< 8-bit single
processor mode used with UARTs.
#define DATABITS_9 9 //!< 9-bit
multiprocessor mode used with UARTs (not supported in this release).

#define STOPBITS_1 1 //!< The number of stop


bits used in the driver.
#define STOPBITS_2 2

#define PAR_NOPARITY 0 //!< No parity.


#define PAR_ODPARITY 3 //!< Odd parity.
#define PAR_EVPARITY 2 //!< Even parity.

/*!
* The error codes consists of both the errors reported by the UART device
* (through status registers), and the errors that occur in the UART driver
* software.
*/
#define UART_ERR_NONE ((BYTE)0x00) //!< The error code for success.
#define UART_ERR_KBHIT ((BYTE)0x01) //!< The error code for
keyboard hit.
#define UART_ERR_FRAMINGERR ((BYTE)0x02) //!< The error code
returned when Framing error occurs in the character received.
#define UART_ERR_PARITYERR ((BYTE)0x03) //!< The error code returned
when Parity error occurs in the character received.
#define UART_ERR_OVERRUNERR ((BYTE)0x04) //!< The error code
returned when Overrun error occurs in the receive buffer register.
#define UART_ERR_BREAKINDICATIONERR ((BYTE)0x05) //!< The error code returned
when Break Indication Error occurs.
#define UART_ERR_INVBAUDRATE ((BYTE)0x06) //!< The error code returned
when baud rate specified is invalid.
#define UART_ERR_INVPARITY ((BYTE)0x07) //!< The error code returned
when parity option specified is invalid.
#define UART_ERR_INVSTOPBITS ((BYTE)0x08) //!< The error code returned
when stop bits specified is invalid.
#define UART_ERR_INVDATABITS ((BYTE)0x09) //!< The error code returned
when data bits per character specified is invalid.
#define UART_ERR_BUSY ((BYTE)0x0A) //!< Definition for
'UART busy'.
#define UART_ERR_NULLPOINTER ((BYTE)0x0B) //!< The error code
returned when a null pointer is passed by user application.

#define UART_ERR_FAILURE ((BYTE)-1) //!< The error code for failures.


#define UART_ERR_USERBASE ((BYTE)0xF0) //!< The error code base
value for user applications. Usable values 0xF0 to 0xFE

#define UART_IO_PENDING ((BYTE)1) //!< Definition for 'IO


Pending'.
#define UART_IO_COMPLETE ((BYTE)0) //!< Definition for 'IO
complete'.

/*!
* \brief The settings required to configure the UART driver.
*
* This structure will contain all the information required to
* configure the UART device. This structure is used for opening
* (initializing) the UART device as well as for re-configuring
* the UART device.
*/
typedef struct
{
INT32 baudRate ; //!< The baudrate.
BYTE stopBits ; //!< The number of stopbits.
BYTE parity ; //!< The parity bit option.

} UART ;

typedef UINT8 BUFFSIZE_T ;

/*!
* \brief The FIFO structure.
*
* This structure is used to hold information about the software
* transmit/receive FIFO buffers implemented in interrupt mode.
*/
typedef struct
{
UCHAR *pBuffer ; //!< The FIFO buffer
BUFFSIZE_T next_in ; //!< The in-pointer
BUFFSIZE_T next_out ; //!< The out-pointer
BUFFSIZE_T size ; //!< The FIFO buffer size

} FIFO ;

/*! Macro definitions */


#define SETBRK_UART0() U0CTL0 |= UART_CTL0_SBRK
#define RESETBRK_UART0() U0CTL0 &= ~UART_CTL0_SBRK
#define ENABLEPARITY_UART0() U0CTL0 |= UART_CTL0_PEN
#define DISABLEPARITY_UART0() U0CTL0 &= ~UART_CTL0_PEN
#define SETODDPARITY_UART0() U0CTL0 = (U0CTL0&~(UART_CTL0_PEN|
UART_CTL0_PSEL)) | (PAR_ODPARITY<<3)
#define SETEVENPARITY_UART0() U0CTL0 = (U0CTL0&~(UART_CTL0_PEN|
UART_CTL0_PSEL)) | (PAR_EVPARITY<<3)

#ifdef EZ8_UART1
#define SETBRK_UART1() U1CTL0 |= UART_CTL0_SBRK
#define RESETBRK_UART1() U1CTL0 &= ~UART_CTL0_SBRK
#define ENABLEPARITY_UART1() U1CTL0 |= UART_CTL0_PEN
#define DISABLEPARITY_UART1() U1CTL0 &= ~UART_CTL0_PEN
#define SETODDPARITY_UART1() U1CTL0 = (U1CTL0&~(UART_CTL0_PEN|
UART_CTL0_PSEL)) | (PAR_ODPARITY<<3)
#define SETEVENPARITY_UART1() U1CTL0 = (U1CTL0&~(UART_CTL0_PEN|
UART_CTL0_PSEL)) | (PAR_EVPARITY<<3)
#endif

/*!
* \brief Receive a character.
*/
INT getch( VOID ) ;

/*!
* \brief Detect any key strokes in the keyboard connected to the default UART device.
*/
UCHAR kbhit( VOID ) ;

/*!
* \brief Transmit a character.
*/
reentrant UCHAR putch( CHAR ) ;

/*!
* \brief Initialize the UART0 device.
*/
VOID open_UART0( VOID ) ;

/*!
* \brief Configure the UART0 device.
*/
UCHAR control_UART0( UART *pUART ) ;

/*!
* \brief Set baudrate for UART0 device.
*/
UCHAR setbaud_UART0( UINT32 baud ) ;

/*!
* \brief Set Parity for the UART0 device.
*/
UCHAR setparity_UART0( UCHAR parity ) ;

/*!
* \brief Set Stopbits for the UART0 device.
*/
UCHAR setstopbits_UART0( UCHAR stopbits ) ;

/*!
* \brief Write data bytes to the UART0 device.
*/
reentrant UCHAR write_UART0( CHAR *pData, UINT16 nbytes ) ;

/*!
* \brief Return transmitter status for UART0.
*/
UCHAR get_txstatus_UART0( VOID ) ;

/*!
* \brief Read data bytes from the UART0 device.
*/
UCHAR read_UART0( CHAR *pData, UINT16 *nbytes ) ;

/*!
* \brief Return receiver status for UART0.
*/
UCHAR get_rxstatus_UART0( VOID ) ;

/*!
* \brief Flush receiver for UART0.
*/
UCHAR flush_UART0( VOID ) ;

/*!
* \brief Close the UART0 device.
*/
VOID close_UART0( VOID ) ;

#ifdef EZ8_UART1
/*!
* \brief Initialize the UART1 device.
*/
VOID open_UART1( VOID ) ;

/*!
* \brief Configure the UART1 device.
*/
UCHAR control_UART1( UART *pUART ) ;

/*!
* \brief Set baudrate for UART1 device.
*/
UCHAR setbaud_UART1( UINT32 baud ) ;

/*!
* \brief Set Parity for the UART1 device.
*/
UCHAR setparity_UART1( UCHAR parity ) ;

/*!
* \brief Set Stopbits for the UART1 device.
*/
UCHAR setstopbits_UART1( UCHAR stopbits ) ;

/*!
* \brief Write data bytes to the UART1 device.
*/
reentrant UCHAR write_UART1( CHAR *pData, UINT16 nbytes ) ;

/*!
* \brief Return transmitter status for UART1.
*/
UCHAR get_txstatus_UART1( VOID ) ;

/*!
* \brief Read data bytes from the UART1 device.
*/
UCHAR read_UART1( CHAR *pData, UINT16 *nbytes ) ;

/*!
* \brief Return receiver status for UART1.
*/
UCHAR get_rxstatus_UART1( VOID ) ;

/*!
* \brief Flush receiver for UART1.
*/
UCHAR flush_UART1( VOID ) ;

/*!
* \brief Close the UART1 device.
*/
VOID close_UART1( VOID ) ;
#endif /*! EZ8_UART1 */

#endif /*! _UART_H_ */

/*! End of File */


Appendix B
Part Price Not
Mfr Qty Description Total Used
Number (ea.) Used
Newark
25B6465 1 Plastic Box 10.91 10.91 10.91
90F5336 4 8-pin IDC Connector 0.76 3.04 3.04
90F4263 4 8-pin Strain Relief Cover 0.98 3.92 3.92
90F5403 4 6-pin IDC Connector 0.37 1.48 1.48
90F5371 4 6-pin Dust Cover 0.28 1.12 1.12
23C1433 1 25-pin D-type Connector 6.16 6.16 6.16
91F5861 4 AD8180AR 2-1 Multiplexer 4.95 19.80 9.90 9.90
90F5302 4 Screwlock Kit 1.91 7.64 7.64
50F6398 1 25-pin D-type 6 ft. Cable 5.03 5.03 5.03
50F4687 2 9-volt Battery Cable 1.18 2.36 2.36
10N175 1 RJ45 Crimp Connectors, 10 ct. 17.34 17.34 17.34
Shipping and Sales Tax 50.92 50.92

Digikey
269-3249-ND 1 Zilog Microprocessor Educational Kit 39.95 39.95 39.95
296-12605-1- Quad 2-1 Data Selector
ND 5 SN74AHC157 0.40 2.00 1.20 0.80
A-25993-ND 100 Female Connectors, crimped 0.18 17.69 17.69
A-26967-ND 4 6-pin Connector,.1", 1RW 0.47 1.88 0.94 0.94
Shipping 17.00 17.00

Jameco
103190 3 10-pin connector, .1", 1RW 0.42 1.26 0.84 0.42
152063 1 Keypad 16 Buttons, 4x4 14.95 14.95 14.95
210761 1 16x4 LCD Display 22.95 22.95 22.95
100765 50 Female Connectors, crimped 0.11 5.50 5.50

Junun.org
GP2D12 7 Sharp Distanve Measuring Sensor 8.25 57.75 24.75 33.00
7 3-pin JST Cables for Sensor 1.10 7.70 3.30 4.40

Dinsmore
1490 2 Dinsmore 8-pos Digital Compass 13.00 26.00 26.00

PNI
11862 1 V2Xe 2-Axis Compass Module 55.00 55.00 55.00

Garmin
010-00258-02 1 GPS16-LVS Unit 141.00 141.00 141.00

TYCO R/C Tigershark w/ Battery


Misc. 1 Pack 90.00 90.00 90.00
1 Fast Lane 6V Battery and Charger 26.95 26.95 26.95
1 Thread Rod, 3/16" 0.45 0.45 0.45
1 Dremel Collet 3.49 3.49 3.49
1 Electrical Tape 2.49 2.49 2.49
1 Dremel Cutting Kit 15.99 15.99 15.99
1 9-volt Battery, 2 ct. 6.49 6.49 6.49
Misc. Hardware 4.75 4.75 4.75
Sales Tax 2.02 2.02 2.02
Totals 692.98 509.02 183.96

You might also like