I have many interests, but these projects are where they seem to meet. I have long been facinated with aircraft, and electronics. These are some of the things that I have experimented with in the past.
Here are a series of articles and projects based on the Atmel AVR series of microcontrollers. Here are some useful links.
Atmel 8 bit microcontrollers - Manufacturer Website
WinAVR - Open source C compiler tools for Windows
AVR LibC - C library documentation. This library comes with WinAVR.
AVR Freaks - Community website
Wikipedia Page - Online encyclopedia entry for the Atmel AVR
Some source code that I have loaded to the webiste is also available.
This will show how to setup a simple bread board for AVR development. This will also serve as my reference so I don't have to look things up every time. I have recently been using the ATmega168 microcontroller because it has lots of peripherals, comes in a relatively small PDIP package, and has lots of memory.
The first step for me is to look at the data sheet. I can never remember the pin out of anything without looking it up, and guessing wrong could have bad consequences. The Summary is an easy place to find this information.
I have pasted below a screen shot of the pin outs of the PDIP package from the datasheet.
The pins that look something like PC6 are the digital IO port pins. This means port C pin 6. When programming all the pins in the same port are controlled in the same register. The names in parenthesis are the special functions for the pins.
You don't need to be concerned with most of these pins right now. Below is a screen shot of a 4 axis stepper controller board from my senior design project. Ignore the pins numbers since they are for the surface mount package. The names are correct though.
The capacitors are good to have and keep the micro controller more stable and noise immune, but are not totally needed for the breadboard circuit.
Here is the bare minimum you need to get going.
I have so far only used In-System Programming (ISP) to download programs to the microcontroller. The connection is shown below. Sorry for the confusion with the labels. They do match the net labels on the AVR from above. There is also a 10 pin version that I don't really use.
This page documents getting a C development enviornment setup for the Atmel AVR Microcontrollers.
The math library is not used by default by the linker using this plugin. You can add this using the following steps.
Another nice thing to add is compiling using the C99 standard. This lets you initialize loop counter variables inside a for loop declaration.
There is a great video that shows debugging with the AVR JTAGICE MKii debugger at http://www.avrtv.com/2008/09/25/debugging-with-jtagicemkii/
To start a debug session while in a AVR Studio project select Debug. If using the debugWire interface, you will be prompted to enable the debugWire interface.
Once the session is started you can set break points, inspect variables, and hardware ports like you would expect.
To stop debugging while using debugWire interface select Debug > JTAGICE MK II Options > Disable debugWire.
This will give some basic information on how to compile a simple program, and download it to the breadboard circuit.
Start the Eclipse IDE. It should be setup as discribed in the IDE page.
Create a new C project type of AVR Cross Target Application using the AVR-GCC toolchain.
I leave both Debug and Release targets selected. The resease target is build to create the hex file loaded to the micro controller.
In my case I select the ATMega168 with a frequency of 20000000. I am running with a 20 MHz ceramic resonator.
If you have AVR Studio installed, then there is a good chance you already have the Jungo driver installed for your AVR ISP MKII programmer. If you keep that driver then you will have to load your hex file to the micro through AVR Studio. If you want to use the AVR Dude programming software that comes with WinAVR then change your driver to C:\WinAVR-20081205\utils\libusb\bin\avrisp2.inf.
Right click on the project in the project explorer and select properties. Now expand the AVR tab, and click on AVR Dude. Add a new programmer configuration, and select your programmer from the list.
Since I updated my programmer with the latest firmware from Atmel, it does not seem to work with AVR Dude anymore. I have just been loaded programs through AVR Studio.
Create a new source file, and copy the following code. This was adapted from the avr-libc example project. The _BV() you see in the code is a macro defined by avr-libc. It stands for "bit value". It is just a clean way of writing a bit shift.
_BV(3) => 1 << 3 => 0x08
This is used to set or clear different bits in a port. An example would be setting the PD7 pin as an output while not changing any other pins. This is done by OR'ing the port with 1<<7 or 0b0100 0000.
DDRD |= _BV(PD7);
Many port and pin names are defines in the <avr/io.h> file. These names match those given for the device in the data sheet.
Save the file and select the build option from the toolbar. The icon looks like a hammer. This is the output.
**** Build of configuration Release for project PWM **** make all Building file: ../main.c Invoking: AVR Compiler avr-gcc -Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atmega168 -DF_CPU=20000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c" Finished building: ../main.c Building target: PWM.elf Invoking: AVR C Linker avr-gcc -Wl,-Map,PWM.map -mmcu=atmega168 -o"PWM.elf" ./main.o Finished building target: PWM.elf Invoking: AVR Create Extended Listing avr-objdump -h -S PWM.elf >"PWM.lss" Finished building: PWM.lss Create Flash image (ihex format) avr-objcopy -R .eeprom -O ihex PWM.elf "PWM.hex" Finished building: PWM.hex Create eeprom image (ihex format) avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex PWM.elf "PWM.eep" Finished building: PWM.eep Invoking: Print Size avr-size --format=avr --mcu=atmega168 PWM.elf AVR Memory Usage ---------------- Device: atmega168 Program: 368 bytes (2.2% Full) (.text + .data + .bootloader) Data: 3 bytes (0.3% Full) (.data + .bss + .noinit) Finished building: sizedummy |
Next I am going to show how to set the fuses, and download the program on to the microcontroller.
Open AVR Studio, and hit cancel when prompted to open an existing project. Next click on the connect toolbar button at the top. Enter the connection information for the programmer. On the main tab select the device type, and click dead signature. This will verify you are communicating with the microcontroller.
On the Fuse tab make any required changes. Be very careful here since you can make a chip pretty much useless with bad choices. For example changing to an external oscillator if you don't have one installed on a board, or changing the clock to an external pin input when you don't have a clock source to drive it. Enabling the debug wire interface will also disable ISP programming mode which could be a problem if you only have an ISP programmer. Here is a screen shot of mine.
Now switch over to the program tab, and browse for the compiled .hex file. After programming the program should immediately start running.
The the video clip at the bottom of the page to see how it looks.
| Attachment | Size |
|---|---|
| avr_pwm.MOV | 922.12 KB |
This page will document some of my experiences with the ATAVRRZRAVEN 2.4 GHz Evaluation and Starter Kit. This kit includes a USB module and two Raven Boards. The USB stick contains a AT90USB1287 microcontroller and a AT86RF230 2.4 GHz tranceiver.
The image above shows the two Raven boards connected. Communication at the medium access control (MAC) layer is handles using a 64 bit MAC address. According to the IEEE 802.15.4 standard a 16 bit address is used at the network layer. This network address is shown below. The node addresses are 0x0002, and 0x0003. The coordinator node always takes the address 0x0000.
The temperatures were gathered by right clicking on the node and selecting "Read Temperature". You can also do several other things by right clicking on a node.
There are a few strange things with the kit, but overall it is pretty good. The kit comes with two LR44 batteries for each Raven board. The batteries were pretty much dead when I got my kit though.
The kit comes with the headers in a bag and not soldered to the board. The headers are very small and kind of tough to solder. I kept getting solder bridges. It comes with two JTAG connectors, and an expansion pin header. There are ISP connectors on the board, but it does not come with the headers and they are a non-standard size. You need to solder on the headers to program the parts, or have access to the expansion pins. This includes plugging in an external power source. There is a JTAG adapter included to convert the small pin header to the standard size 0.1" header.
In the documentation and online videos, the Raven boards play a raven sqwak sound when a message is received. I could not figure out why mine was not playing any sound. It turns out you have to download the sound file to the Raven board from AVR Wireless Studio.
The firmware shippen on the raven software has a few quirks. It implements software that implements part of the ZigBee standard. Only Star and Tree networking topologies are used. Mesh networking is not supported.
There are some items on the Raven boards that I could not figure out how to work. There is an Audio Menu where it appears that you can record sound, but it does not seem to work. One of the boards for some reason does not want to send a message anymore. It just seems to hang, and when you push the joystick again it say cancelled. This is even after reflashing the board with the binary files from the Atmel Website.
I am impresses with the radio performance. They seem to have a pretty good range.
The default firmware seems buggy to me.
The really small size of the headers is annoying. They are hard to solder, and no header is included for the ISP connector, only the JTAG. I am not sure of an easy way of connecting an ISP to the board.
Documentation seems vauge in areas.
There is a new fully compliant ZigBee stack that can be downloaded for these boards from the Atmel website called Bitcloud. I am planning on trying this out soon.
The serviece binds the USB stick to an IP address and Port number. This is cool since it allows acces from another computer. This disadvantage is that I was not able to figure out how the run the stick as a coordinator to start the network, and also to use the packet sniffer. This is because they are acting as two seperate applications trying to bind to the same port.
This is a collection of older projects I worked on before I began the electrical engineering program at Colorado State University.
Project from 2002
Airspeed is a very important part of aircraft operation. If the airspeed is too low then the aircraft can no longer generate enough lift to support flight, and may stall. This could result in destruction of the vehicle if the craft impacts the ground. If the airspeed is too great then the aircraft is overstressed and may come apart due to the excessive forces.
Airspeed also has a lot to do with efficiency. There is a certain airspeed that gives the best climb rate, and best cruise performance. If the aircraft is equipped with flaps, then there is generally a maximum airspeed for flap deployment, as well as landing gear. My point is that if you are going to fly, you better know the airspeed. I need a sensor to tell me this. For this project I have chosen to use the Motorola MPX5050 differential pressure sensor.
A regular aircraft uses what is basically a differential pressure gauge and then converts this pressure difference to an airspeed. It has a pitot tube pointed into the wind to collect the dynamic pressure, and a static pressure port to compare this absolute pressure with the impact or dynamic pressure.
The equation for converting the pressure difference to airspeed is Velocity = square root of {( 2 * Dynamic pressure ) / Density }. Velocity in Meters / Second. Dynamic pressure in Newton / Meters ^2 or Pascals. Density in Kg / Meter ^3. For my equation I will use the standard density of 1.225 Kg / M ^3
I am using a metric equation for this because the equation given on the data sheet for the pressure sensor converts voltage into Kilopascals. Since I am only really familiar with miles per hour I simply need to multiply the final value in meters per second by 2.237 to convert this to MPH.
I wanted better resolution from my first program. I wanted to stick with the 10 Bit ADC onboard the pic for now. I then decided to amplify the signal by a gain of +5. This means that the AD # will max out when the sensor is outputting +1 volt. This means that the sensor can not read past 270 mph. I wanted the resolution, and did not need a speed any greater than this.
The program appears to be working properly, and I am happy with the results for now. Time to move on to the next phase of the project!
The air density can change with weather, and altitude. Since I am assuming it remains constant, my sensor will not be reporting the exact airspeed. This is not really much of a problem however. If my aircraft stalls at 15 miles per hour in standard atmospheric conditions, then my sensor will always report exactly 15 MPH when the craft stalls. This is because density effects performance, exactly the same as it does my airspeed calculations. This is called indicated airspeed, and is the kind that certificated aircraft use, because it is of the most use to pilots. At higher altitudes your true airspeed will actually be higher, but so will your stall speed and other performance numbers.
The attached file below is the program I wrote. It is in the Pic Basic Pro language for the PIC microcintroller.
| Attachment | Size |
|---|---|
| Airspeed.bas | 4.05 KB |
Project from 2002
Pressure altimeters have been used in airplanes almost since their creation. They do however have their bad points. The ambient air pressure for a given altitude changes from day to day, or sometimes hour to hour. It is therefore necessary to adjust the altimeter before flight to either the current air pressure for your location, or to your current altitude if known. They can be very accurate if used correctly however. I think that I am going to be simple with my project and just use the International Standard Atmosphere pressure of 101.325 kPa. This means that my altimeter will always read what is called pressure altitude. This is what all aircraft operating over 18,000 feet are required to use. All this means is that my altitude readings on some days under certain conditions may be a little off. If this proves to be a bigger problem than anticipated then I may come back and rethink this. I would have to call the weather station and input the corrected atmospheric pressure before flight if I wanted true accuracy.
An equation for calculating altitude using standard atmospheric conditions is
alt = -26216 * LN (pressure / 101.304) Pressure is in kPa.
I have created a working altimeter using a PIC16F877 micro controller and a Motorola MPX4115AS www.phanderson.com. I used the PicBasic Pro compiler since I know very little about programming, and assembly language looked intimidating to me.
Standard atmosphere information can be found here. They list a standard pressure of 101.3 kPa, but I have found another site that listed it at 101.325 kPa. pressure sensor from
The full scale output of this sensor is 4.8 volt, but using the standard atmospheric pressure of 101.325 kPa for sea level altitude the output voltage is 4.084625 volts. This was calculated from the equation given in the Motorola MPX4115AS data sheet.
Vout = Vs x (0.009 x P - 0.095)
or rearranged to solve for pressure Pressure = {(Vout / Vd) + .095}/ .009
Vout is the output voltage form the sensor
Vs is the power supply voltage which is 5 volts
and P is the pressure in kPa (kilopascals)
At 2.5 volts the altitude according to my formula which uses
standard atmospheric pressure will be, 11,194 feet using a pressure of
66.111 kPa. I don't think that this project will ever go higher than this.
I have configured the PIC to use a V +ref on pin RA3 and a V - ref on pin RA2. Since I am looking to get a very good resolution, I have limited my altimeter's range to just over 10,000 feet. For V -ref I have used 2.5 volts coming from a voltage divider, and used 4.1 volts for the V +ref. All this means is that the PIC will only convert analog voltages between these two voltages to numbers. Since this is a 10 bit ADC (Analog to Digital converter) it has a total count number of 1024.
Resolution = Voltage Reference / Counts
Voltage Reference = V+ref - V-ref
Voltage Reference = 4.1 - 2.5 = 1.6 Volts
If I use the ADC on the PIC16f877 then it has a 10 bit resolution which
gives me 2 ^ 10 = 1024 counts.
Resolution = 1.6 / 1024
Resolution = 1.56 mV
This is a small voltage difference, and noise has been a problem.
A person name Ingvar Gillholm from the PicBasic list has been a big help to me. He has given me a basic routine for converting 10 bits to 12 bits that works well as long as there is a little noise in the signal which I have plenty of. Here is the routine.
for counter = 0 to 63 'no more than 64, then it can overflow
'There is a max value of 1024 for a 10 bit ADC, 1024 * 64 = 65536, the max variable size is a word 'variable which is 16 bits wide. 2^16 = 65536
ADCON0.2 = 1 ' Start Conversion
notdone: Pause 5
If ADCON0.2 = 1 Then notdone ' Wait for low on bit-2 of ADCON0, conversion finished
'Load Value into word variable ADvalue
ADvalue.highbyte = ADRESH ' Move HIGH byte of result to ADvalue
ADvalue.lowbyte = ADRESL ' Move LOW byte of result to ADvalue
NewADvalue = NewADvalue + ADvalue 'just keep adding them
next
ADvalue = NewADvalue / 16 'will produce 12bit from a 10bit AD converter
A 12 bit number gives a total of 4096 possibilities. Since I am using references of 2.5 volts, and 4.1 volts the effective resolution is
Resolution = Voltage Reference / Counts
Reference = 4.1 - 2.5 = 1.6 Volts
Resolution = 1.6 / 4096
Resolution = 0.3906 mV
The equation for converting the AD number to the voltage is
Voltage = ( AD# * Reference ) + V-ref
Voltage = ( AD# * 0.3906 mV ) + 2.5 volts
Getting rid of the decimal places and writing this in PicBasic Pro language this equation looks like this.
OutVolt = ADvalue */ 1000 + 25000 'ADvalue * 1000/256 + 25000 gives millivolt*10 if ADvalue is 12bit
Pressure = {(Vout / Vd) + .095}/ .009 rearranged from Motorola MPX4115AS the data sheet for pressure instead of Vout.
Here is a link to converting pressure in kPa to inches of mercury for comparing against a weather report.
I have been informed that an easy was of doing math on a microcontroller is to use linear approximation. This basically creates a series of linear equations for the data. The PicBasic Pro compiler has a lookup2 command that is used for this. A description of how approximation using a lookup table works is nicely done by Tracey Allen.
Here is some sample data of the above program that has been copied from HyperTerminal.
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
ADvalue = 3921 OutVolt = 40316 Pressure = 10014 Altitude = 00303
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
ADvalue = 3921 OutVolt = 40316 Pressure = 10014 Altitude = 00303
ADvalue = 3921 OutVolt = 40316 Pressure = 10014 Altitude = 00303
ADvalue = 3921 OutVolt = 40316 Pressure = 10014 Altitude = 00303
ADvalue = 3922 OutVolt = 40320 Pressure = 10015 Altitude = 00300
There is a little noise as you can see, but not too horrible. You have to consider to very tiny voltage differences we are dealing with here. It only fluctuates 0.0004 volts. I am pleased with the output of the sensor. A three foot resolution is just fine for my application.
Project from 2001
Raw string from GPS - The two sentences that I extracted data from.
$GPRMC,063242,A,3549.0260,N,08620.6226,W,0.0,54.8,210602,3.0,W,A*24
$GPGGA,063242,3549.0260,N,08620.6226,W,1,06,1.6,212.2,M,-31.4,M,,*7B
Data Output From PIC to Hyper Terminal
A,06,35,49.0246,N,086,20.6195,W,00679,000,000,3,W
A,7,35,49.0262,N,086,20.6223,W,696,0,54,3,W
Description Of My Protocol |
|
| A | Data Status Warning - A for good, V for bad |
| 7 | Number Of Satilites in Use |
| 35 | Degrees of Latitude |
| 49.0262 | Minutes of Latitude |
| N | North or South Lattitude |
| 086 | Degrees of Longitude |
| 20.6223 | Minutes of Longitude |
| W | West of East Longitude |
| 696 | Altitude in Feet |
| 0 | Groundspeed in MPH |
| 54 | True Heading |
| 3 | Magnetic Variation |
| W | Direction of Magnetic Variation |
Any GPS that has an NMEA 0183 output option can be very useful in many projects. These sentences have a certain structure, and are output at 4800 baud with 8 data bits no parity and one stop bit. They only output a string of data once per second however.
Another option for interface in using the Garmin Protocol, but it seems complicated to me. I really don't understand it yet. The above PDF if loaded onto my web as this file no longer seems to be avalible on the Garmin Web Site.
Here is a sample taken from my Garmin E-trex GPS using HyperTerminal.
$GPRMC,010214,A,3549.0189,N,08620.6280,W,0.0,0.0,130602,3.0,W,A*13
$GPRMB,A,0.01,L,,02,4000.888,N,08235.544,W,308.185,34.0,,V,A*51
$GPGGA,010214,3549.0189,N,08620.6280,W,1,03,2.8,220.4,M,-31.4,M,,*7B
$GPGSA,A,2,,,,,,,21,22,25,,,,3.0,2.8,1.0*3F
$GPGSV,3,1,10,02,48,163,00,05,05,037,00,06,02,095,00,11,16,267,00*78
$GPGSV,3,2,10,14,49,076,00,20,23,317,00,21,20,153,43,22,25,188,41*74
$GPGSV,3,3,10,25,77,330,47,30,27,051,00*7E
$GPGLL,3549.0189,N,08620.6280,W,010214,A,A*58
$GPBOD,34.0,T,37.1,M,02,*47
$PGRME,14.7,M,10.2,M,18.0,M*16
$PGRMZ,723,f,2*1C
$GPRTE,1,1,c,*37
Looks confusing doesn't it? Not to fear, the world wide web to the rescue again.
$GPRMC,hhmmss,A,ddmm.mmmm,N,dddmm.mmmm,W,x.x,x.x,ddmmyy,x.x,W*hh
1 = Time of fix in UTC
2 = Data status (A = OK V = navigation receiver warning)
3 = Latitude of fix
4 = N or S
5 = Longitude of fix
6 = E or W
7 = Speed over ground in knots
8 = Track made good in degrees True
9 = UT date
10 = Magnetic variation degrees (Easterly var. subtracts from true course)
11 = E or W
12 = Checksum
$GPRMC,010214,A,3549.0189,N,08620.6280,W,0.0,0.0,130602,3.0,W,A*13
| 010214 | 01:02:14 UTC Time of Fix |
| A | Receiver Warning OK |
| 3549.0189,N | Latitude 35 degrees, 49.0189 minutes North |
| 08620.6280,W | Longitude 086 degrees, 20.6280 minutes West |
| 0.0 | Speed of 0 Knots |
| 0.0 | True heading of 0 degrees (Only works when the GPS is moving) |
| 130602 | UT Date(Universal Time) is 13th of June, 2002 |
| 3.0,W | Magnetic variation from true heading is 3 degrees to the West |
| A*13 | Mandatory Checksum. http://www.garmin.com/support/faqs/40.html |
$GPGGA,hhmmss.ss,ddmmmm,N,dddmm.mmmm,W,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
1 = Time of fix in UTC
2 = Latitude of fix
3 = N or S
4 = Longitude of fix
5 = E or W
6 = Fix Quality Indicator (1 = GPS Fix, 2 = DGPS Fix)
7 = Number of Satellites In Use
8 = Horizontal Dilution Of Position (HDOP)
9 = Meters Above Mean Sea Level
10 = Height of geoid above WGS84 (Type of Earth Model) ellipsoid
11 = Time in seconds since last DGPS update
12 = DGPS Reference Station ID
$GPGGA,010214,3549.0189,N,08620.6280,W,1,03,2.8,220.4,M,-31.4,M,,*7B
| 010214 | 01:02:14 UTC Time Of Fix |
| 3549.0189,N | Latitude 35 degrees, 49.0189 minutes North |
| 08620.6280,W | Longitude 086 degrees, 20.6280 minutes West |
| 1 | GPS Mode |
| 03 | 3 Satellites in use |
| 2.8 | Horizontal Delution Of Position is 2.8 |
| 220.4,M | 220.4 Meters above mean sea level |
| -31.4,M | geoid height of 31.4 Meters below ellipsoid |
| *7B | Mandatory Checksum. http://www.garmin.com/support/faqs/40.html |
Description Of Other Sentence Types
From things I have read the GPS that I am using along with most on the marked are considered smart GPS units. The smart ones in my opinion are fairly stupid. Waypoints can be created on your computer and downloaded into the GPS. Then I could just read what course to fly from the sentence structure. These smart GPS units skip to the closest waypoint however. This means that if I programmed in a simple out and back route for my aircraft to fly, it would skip the out part and come back. I also desire to be able to change waypoints in flight. The Garmin protocol that allows communication with the unit is complex, and I have not figured it out yet.
The solution that I came up with is two get the info from the GPS, and then do my own waypoint calculations. I may have opened up a can of worms however as the math will be very difficult to implement using a microcontroller.
There are two different types of Navigation. Great Circle Navigation, and Rhumb Line Navigation. See http://pilotsweb.com/navigate/dis_dir.htm for a good description of the two. I will be using Great Circle Navigation since it is the shortest distance.
I am going to work an example of flying from my house to Nashville International Airport using Great Circle Navigation.
Coordinates of my house
Latitude and Longitude 35 deg 49.0189 min N 086 deg 20.6280 min W
Coordinates of Nashville International Airport (BNA)
Latitude and Longitude 36 deg 7.5961 min N 86 deg 40.9236 min W
Distance D = 60 ACOS [ SIN Lat1 SIN Lat2 + COS Lat1 COS Lat2 COS (Lon2 - Lon1)]
Where: D = Distance (in Nautical Miles)
Lat1 = Original Latitude in decimal degrees
Lat2 = Destination Latitude in decimal degrees
Lon1 = Original Longitude in decimal degrees
Lon2 = Destination Longitude in decimal degrees
First task is to convert degree minutes to decimal degrees by dividing minutes by 60 and adding to the degrees
Degrees Minutes.m to Decimal Degrees Decimal Degrees = Degrees + ( M.m / 60 )
Coordinates of my house
Latitude and Longitude 35 deg 49.0189 min N 086 deg 20.6280 min W
35.8169816 N 86.3438 W
Coordinates of Nashville International Airport (BNA)
Latitude and Longitude 36 deg 7.5961 min N 86 deg 40.9236 min W
36.1266016 N 86.68206 W
D = 60 ACOS [ SIN Lat1 SIN Lat2 + COS Lat1 COS Lat2 COS (Lon2 - Lon1)]
D = 60 ACOS [ SIN 35.8169816 SIN 36.1266016 + COS 35.8169816 COS 36.1266016 COS (86.68206 - 86.3438)]
D = 60 ACOS [ SIN 35.8169816 SIN 36.1266016 + COS 35.8169816 COS 36.1266016 COS (.33826)]
D = 60 ACOS [ .3450160442 + .6549579407]
D = 60 ACOS [ .9999739849]
D = 24.79721689 in nautical miles
D in statute miles = 24.79721689 * 1.151 = 28.54159664 statute miles
360 - cos C1 = (sin Lat2 - sin Lat1 * cos D ) / ( cos Lat1 * sin D )
C1 = course angle at point one.
D = the distance from point one to point two. (degrees)
D= 24.79721689 in nautical miles
Distance in degrees = Distance in Nautical Miles / 60
D in degrees = 24.79721689 / 60
D in degrees = .4132869482
All Units are in degrees
360 - cos C1 = ((sin Lar2 - (sin Lat1 * cos D) ) / ( cos Lat1 * sin D )
360 - cos C1 = (sin 36.1266016 - sin 35.8169816 * cos .4132869482 ) / ( cos 35.8169816 * sin .4132869482 )
360 - cos C1 = (.0043886195 ) / ( .0058490786 )
360 - cos C1 = (.7503095462 )
360 - C1 = 41.3828
C1 = 360 - 41.3828
C1 = 318.6
http://www.directionsmag.com/latlong.php
http://pilotsweb.com/navigate/dis_dir.htm
http://www.angelfire.com/nt/navtrig/
http://www.best.com/~williams/avform.htm
| Attachment | Size |
|---|---|
| gpsin.bas | 2.5 KB |
Project from 2004
This is the first robot that I built. I was happy with it since I was so new to electronics and programming. It uses my infrared collision avoidance sensor. Two Led's and two IR sensors are used to give it differential object detection.
The above picture is showing all of the necessary external components of a pic micro controller. Except for the 470 ohm resistor and the LED of course. The 4 Mhz crystal can be replaced with anything up to 20 Mhz, but it will mess up all the timing of the program. I use a 4 Mhz ceramic resonator with internal capacitors. It makes for a small package and cannot be damaged as easily as a crystal which is important for my robot. It is not as accurate, but that kind of precision is not necessary for this application.
I used a PIC 16F84 micro controller programmed in basic with the PIC Basic compiler. The program is attached at the bottom of this page.
Even though it looks complicated it is a fairly simple project. My messy wiring is mostly why it looks so intimidating. The whole thing was powered from a 7.2 volt nicad battery pack that can be seen in the above picture. I use a 5 volt IC (Integrated Circuit) voltage regulator to power the 555 timer used for the IR LED's, the H-bridge IC, and the PIC micro controller. The full battery power of 7.2 volts is used to power the motors. I used a twin motor gearbox assembly from Tamiya that is available at Tower Hobbies. The chassis that I used is also available from them. It worked well except for one very annoying problem. When traveling on carpet making sharp turns the track seems to come off quite often. Maybe a tracked vehicle was not the best choice. It does ride over quite high objects without getting stuck.
The microcontroller can only provide about 20 milliamps of current which is not very much. An H-Bridge IC was used to provide the current necissary to drive the motors.
After many frustrating hours trying to make a home made H-bridge drive with little success, I finally decided that my real focus should be elsewhere for the moment so I bought a kit that uses an H-bridge IC with protection diodes, filter capacitors, and very handy terminal blocks for the connections.
I was very happy with the H-bridge kit. It came with a very high quality printed circuit board. The IC did get quite hot though, so I decided to add a heat sink. It is available from HVW Tech.
Above is a top view showing the breadboard, and part of the H-bridge board. The IR LED's can be seen at the bottom sides. They are wrapped in electrical tape in an effort to make the light more dirctional. The detectors are just to the outside of the LED's. The IR oscillator circuit is on the left, and the micro controller and it's necessary external components are on the right. Note the filer capacitors at the top corners. They are used to filter the output of the detectors.
The robot seemed to work quite well. It was kind of a wall hugger since one of the motors turned a little faster than the other. This maked it curve to the right a little when it is supposed to be going straight.
I had a frustrating problem with false sensor triggers for quite a while. Placing a 1uf capacitor from the sensor output to ground seemed to have solved the problem.
Another problem it that one sensor appeared to trigger before the other. I tried a pot to adjust the brightness of the LED, but this did not seem to work very well.
The sensors also triggered a little further out than I would have liked. This distance was at about 4 feet away from an obstacle. When I lowered the brightness of the LED's the distance is reduced, but so is the effectiveness of the sensor. It had a very hard time detecting black or narrow objects.
| Attachment | Size |
|---|---|
| ir_robot.bas | 3.44 KB |
Project from 2003
Infrared light is invisible to the human eye. In this project I use IR light pulsed at 38 KHz to detect obsticles. When the pulsed light reflects back from an obstacle it is picked up by the detector. Filtering out all other frequencies helps to elliminate false detections from other light sources.
How does your TV remote work? It switches on and off the LED at a specific frequency. A detector then looks for signals at the desired frequency while ignoring all other noise. In my example I used 38 KHz. This means that the LED turns on and off at a rate of 38,000 times per second.
I found an IC (integrated circuit) at Digikey that did it all in one complete, small package. It's part number is PNA4602M-ND. The data sheet can be viewed here.
Here are where things get a little trickier. How does one turn on and off a light at 38,000 times per second? I chose to use a classic IC called the 555 timer.
I used an 8 pin dip package. It is available from Digikey. The part number I used was LMC555-CN. The datasheet is available here.
The circuit that I used is on the data sheet. Figure 12 shows a 50% duty cycle oscillator. This is exactly what I wanted. This means the LED will be on for half of the time, and off for half the time. The frequency of 38 KHz just means how fast it turns on and off.
The equation below if from the datasheet and will set the frequency.
F = 1/ (1.4 * R1,2 * C)
F is the frequency we want in Hz = 38,000
R1,2 is the sum of both resistors is ohms = ?
C is the value of the capacitor in farads = ?
The data sheet gives a chart estimating the capacitor and resistor values for a given frequency. The closest value is .001 uF.
R1,2 = 1 / (1.4CF)
R1,2 = 1 / 1.4(1 x 10 -9f) (38,000 Hz)
R1,2 = 1 / 5.32 x 10 -3
R1,2 = 18796 ohms or 18.8 K ohms (K = kilo or thousand)
I Measured the distance that the receiver will work at, and in it's current configuration it is about 4 to 5 feet. I was pleased with this since I am using a 120 ohm resistor for the LED that makes it much dimmer than it could be. I was happy, as it appears this will work well for it's intended purpose of object detection.
Right now if you stand over 5 feet away the sensor produces 5 volts as it should when it is not detecting anything. When you move closer to the sensor it reaches a point where the voltage goes low or 0 volts. The detector I am using is an IC that has a built in frequency discriminator, and comparator circuit.
Since the exact value needed for the resistor is not available and to account for part tolerances, a variable resistor is used. This means that it must be adjusted to the correct value for the frequency to be set where it needs to be. I just had to adjust it using the detector unit as my guide.
I did run into a problem with this however. There was a large area where I think it was adjusted right where it was triggered the whole time. The only time I could not get it to detect IR light was when I covered the lens of either the detector or the LED, or took out the LED. I had the LED totally wrapped in electrical tape except for the front which can be seen in the picture above. It was still picking up light however. When I had it adjusted close, but a little off, I could stand at the wall of my bedroom about 10 feet away and the detector would not react, but it would start to flicker when I was about 8 feet away.
Somehow I think that IR light is leaking to the sensor. It is possible I suppose that when the circuit is adjusted correctly that it works so well that light is being picked up that is reflecting off my wall about 10 feet away, and maybe many other objects that I am not thinking about.
I should also mention that during the above tests I had the R3 resistor set at 60 ohms which probably about doubled the brightness of the LED from the original 120 ohms used.
Sorry, It looks a little cluttered but I am sure you can see the general idea. An interesting side note is that the LED in the picture is an infrared LED, yet it is clearly seen lit up. Well it just so happens that CCD cameras like my computer camera I took this with can see infrared light. When I took this picture I could see nothing lit up at all with my own eyes. Pretty neat stuff.
Here is the wiring schematic of the circuit.
Q1 A general purpose small signal transistor is used to boost the current through the LED allowing it to be much brighter than is otherwise possible. It's data sheet is right here. The timer IC is not capable of sourcing much current but is used to turn on and off the transistor.
R1, and R2 Refer to the equation above to see where these values came from. These two resistors in series are used to set the oscillating frequency. See the equation above from the manufacturer's data sheets to determine the value of these as well as C1.
R3 This resistor is used to set the current going through the Infrared LED. It's value really could be much lower than the 120 ohms that I am using, if your LED is capable of handling that much current.
R4 This resistor is used to set the amount of current used to turn on the transistor and allow current to flow from the emitter to the collector. It's value should not be too low or you could burn up the control electronics. The 555 timer in this case. I am planning on my final version to drive maybe 4 led from this one circuit, so this resistor may need to be a lower value to allow more current to flow through the transistor.
R5 This resistor is used as a pull-up resistor. That means that the reset pin on the timer is going to be set to logic high (+5 volts). The timer can be disabled if this pin in grounded.
C1 This is a .001 uf capacitor that is used in conjunction with the total resistance of R1 and R2 to set the oscillating frequency.
C2 This is a power filter capacitor to smooth out the supply voltage. I tried the circuit without it, and it didn't work. Maybe my home made power supply does not supply as smooth of a voltage as I thought.
C3 Another filter capacitor used to smooth out the ground connection.
D1 The data sheet for the LED that I used can be found here. The Data sheet says that there is a voltage drop of 1.2 to 1.6 volts, and a max continuous current rating of 100ma. The measured current through the LED is 15.5 ma using a 120 resistor. Since it is oscillating with a 50% duty cycle this means that actually double that or 31 ma is flowing through the LED during it's on time. The range can probably be extended greatly by lowering the value of R1. Since the max continuous rating is 100ma and we do not have it continuously on, it should be possible to push even more current through it. How much more I don't know. It would make sense that since it is only on half the time we can have twice the current, but I do not believe this to be the case. The LED needs time to cool off. Ok, so now I have to figure out the resistor value that I need to get lets say 100ma (could go even higher). The voltage drop of the resistor is normally about 1.2 volts according to our data sheet. The voltage drop from the emitter to collector of the transistor is about 0.2 volts. Using ohms law we have
Current = Voltage / Resistance Rearranged this is
Resistance = Voltage / Current we started with 5 volts, the LED uses 1.2, and the transistor uses 0.2. This leaves 3.6 for the resistor to drop.
Resistance = 3.6 volts / 0.100 amps (0.100 amps is the same as 100 ma.
Resistance = 36 ohms.
Hopefully this value is correct, but I am not totally sure about the transistor voltage drop. I read it somewhere on the internet! We could go a little lower than this value, but not by much. As you can see this is quite a bit lower than the current value of 120 ohms. And I get a 5 foot range now. That means the light travels a total of 10 feet. Five feet to an object, then is reflected back 5 feet.
I am going to try adding a pot and a resistor in parallel for the LED the resistor will probably be somewhere around 36 ohms to safeguard against burning out the LED from too much current by having the pot turned down all the way. Then the Pot can be used to adjust the brightness of the LED to effectively set the range of the unit.
This is a listing of project completed during my courses at Colorado State University.
See the file attachments at the end
Colorado State University
Department of Electrical Engineering
Fort Collins, CO 80523
May 03, 2006
Lab 9 Competition:
UART (Universal Asynchronous Receiver Transmitter)
From: Steven Turner, Wednesday 2:10 Lab
The goal I have chosen for the lab competition project is to create a UART (Universal Asynchronous Receiver Transmitter). This design is able to send and receive a byte of data from a terminal program to the XRC board. This design will handle 8 data bits and can be configured for no parity, even parity, or odd parity.
This design requires a voltage level converter to convert the TTL voltage levels to the RS-232 levels of the computer serial port. A small board was assembled using a Sipex SP233ACP IC since it requires no external capacitors. Two male headers were soldered to the expansion port of the XCR board. This design requires ground, receive, and transmit wires coming from the expansion port. This setup is shown in the picture below.
The figures below show how the data is transmitted and received. The line idles high when no data is being transmitted. A start bit that is low for one bit period tells the receiver that the next 8 bit periods will contain the 8 data bits received least significant bit first. If parity is enabled, the parity bit will follow the last data bit. Then a stop bit is the last part of the transmission. Another start bit could immediately follow, or the line may remain in an idle state.
The final block diagram for my design is shown in figure 1. This shows how my design may be easily inserted into another project to provide communication functionality with a computer, microcontroller, or even another XCR board. The baud rate is easily adjusted. All that is required is to place a clock signal on the CLK_8X_BAUD pin that is eight times the required baud rate. The P_ENABLE pin when high will enable parity for both the transmitter and receiver. The P_ODD pin will tell the UART to use odd parity when high. TX_START when brought high will load the data currently on the TX_DATA bus into the transmitter shift register, and then begin the transmission. The RX_DATA bus contains the data that is currently stored in the receiver buffer. This data is valid during reception of the next byte since a separate register is used for shifting in the data. The UART implementation in figure 1 uses two flip flops to store the parity configuration is order to leave two more switches free for data transmission. I have the master clock on my board set to 2400 Hz, and use this as both the master clock and the 8X baud clock. This will produce a baud rate of 300 bits per second.
The design of the UART was broken down into the design of individual blocks. These blocks were then independently tested to ensure they worked correctly. Once these tests were complete, the block could be treated as a black box. These blocks were then connected as shown in figure 2. The blocks required for the receiver are shown on the left, while the transmitter blocks are shown on the right. This procedure greatly simplified the design process. The individual blocks are listed in the below tables.
|
Block Name |
Description |
Design Figure |
Schematic Figure |
|
RX_Control |
This block has inputs from various other blocks, and controls the main operation of the entire receiver. |
3A |
3 |
|
Clock_Generator |
A counter that counts from 000 to 111. The counter is reset to 000 by the RX_Control block at the end of every receive cycle in order to sync the clock to the data. The counter does not start to count until the RX_Control brings it’s receive output high. The Clk_Out pin pulses every time a bit should be shifted into the RX_Shift_Reg. This line is also used by the RX_Bit_Counter, and the Parity_Checker. |
4A |
4 |
|
Clock_Sync |
This is a simple state machine that will output a 0 until it receives a 0 for three consecutive clock cycles. Since the clock is set to 8 times the baud rate. The Start output will go high just before halfway through the start bit. The RX_Control will take one more clock cycle before the Receive line will go high. This should be very close to the center of the start bit depending on how close the 8X clock edge lines up with the edge of the start bit. |
5A |
5 |
|
RX_Bit_Counter |
A counter that counts from 0 to 9. The TC (Terminal Count) output will go high when the counter reaches 9. This will tell the RX_Control block when all 8 data bits, and the parity bit have been received. |
6A |
6 |
|
RX_Shift_Reg |
A shift register where the data is stored during reception. Stores 8 data bits and the parity bit. After the receive cycle is complete the data is loaded into an 8 bit buffer register by a load signal from the RX_Control. |
NA |
7 |
|
Parity_Checker |
After the receive cycle is complete, the error output is stored in a flip flop with the same load signal used to load the data into the buffer. The flip flops are then reset with a signal from the RX_Control block. |
8A |
8 |
|
Block Name |
Description |
Design Figure |
Schematic Figure |
|
TX_Control |
This block has inputs from various other blocks, and controls the main operation of the entire transmitter. |
9A |
9 |
|
Clock_Generator |
This is the same block as that described for the receiver. It is used again in order to make this a full duplex UART. This means it can receive and transmit data simultaneously. |
4A |
4 |
|
TX_Bit_Counter |
A counter that counts from 0 to 11. See the TX_Shift_Reg block for a description of why a count of 11 is necessary. The TC (Terminal Count) output will go high when the counter reaches 11. This will tell the TX_Control block when the transmission is complete. |
11A |
11 |
|
TX_Shift_Reg |
A shift register where the data is stored for transmission. Since the transmit line must idle high, the first bit stored is the idle state. The low start bit is stored next. After that are the 8 data bits. Next is the optional parity bit. Then the stop bit. |
NA |
12 |
|
Parity_Generator |
This block generates the parity bit to be transmitted if parity is enabled. If the parity is disabled the output will always be a high voltage. This means that if parity is disabled the stop bit will last for two bit periods. |
NA |
13 |
This design was eventually a success. Redesign of a few components was necessary during the testing phase since my logic had a few flaws. The first test of the hardware only resulted in the correct transmission of the data about half of the time. This was due to a design flaw in the Clock_Generator block. The problem was fixed by resetting the counter after every receive cycle. Another issue that required some though to overcome was the design of the Parity_Checker. The first design would output the error correctly only every other receive cycle, and only while data was not being currently received. This was fixed by storing the parity error bit in a flip flop at the end of the receive cycle, and resetting the Parity_Checker before the start of a new cycle.
I am very happy with the outcome of this project. I believe this design is very reusable, and could be useful for many future projects involving communications with other devices. The complete design shown in figure 1 does use 60 of 64 macro cells on the XCR board. This design would probably be more useful on a chip with more macro cells.
| Attachment | Size |
|---|---|
| State Diagram.xls | 78 KB |
| UART_Schematics.zip | 98.79 KB |