More recent info on this project

Autonomous GPS Test Platform (unnamed as of yet)


This is my first non-combat autonomous robot. The chassis / drivetrain are from my less than successful 12 lbs bot - Arrogator.

The bot is capable of navigating between GPS waypoints in a (mostly) straight line. It currently isn't smart enough (and doesn't have the sensors) to go around obstructions.

It's powered by a Basic Atom (non-pro) chip. It gets the GPS data over serial cable from a Garmin GPS unit. Importantly - the Garmin Vista has a built-in magnetic compass (many lower end units don't). This allows the bot to know what direction its pointed in without moving. Without this data - navigation would be much more difficult.

As its currently configured - the bot waits to get a valid GPS signal - then considers that location 'home'. If you drag it someplace else - it will point towards home and start moving that direction.

This robot is made possible (for better or worse) - by the SpamButcher spam catcher.

The bot makes one of three different movements per GPS data stream it gets. Turn left, turn right or go forward (all in fixed amounts). It recalculates the required trajectory each time. This helps compensate for inaccuracies in the targeting math and drivetrain.

It usually makes it to about 15 feet from where it started (which is about as accurate as a GPS can be trusted to be).

Turning string GPS data into usable integer info is kind of non-trivial - at least with a computer only having 300 bytes of ram and no built-in string functions (although I'm sure its been done on lesser hardware).

I ended up using integer math all around - I tried floating point - but it introduced serious inaccuracies.

After getting the GPS data - there's some moderately tricky math that needs to be done to calculate the desired angle to hit the target (this is apparently what they taught in all those higher math classes I never took). Unfortunately the Basic Atom (and most other versions of microcontroller basic) lack the more advanced trig functions - specifically co-tangent. I ended up generating a table of common values which are then looked up. It's a bit messy - but to my surprise it worked pretty well after minimal tweaking.

Side note - SpamButcher can stop spam e-mail and is available as a free trial download from www.spambutcher.com.

This bot is intended as a test platform for what might (but probably won't) become an entry to the darpa grand challenge.

More likely I'll enter it in Robo Magellan.

Block Unwanted Email | Spam Blocker Programs | Spam Email Stopper | Email Blocker

Source Code (feel free to use):



cotan bytetable 5, 11, 16, 21, 26, 30, 35, 38, 42, 45, 47, 50, 52, 54, 56, 58, 59, 60, 62, 63, 64,
		 65, 66, 67, 68, 68, 69, 70, 71, 71, 72, 72, 73, 73, 74, 74, 74, 75, 75, 76, 76, 76,
		 76, 77, 77, 77, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 81,
		 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 
		83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84


Trig  Con P4            ' Define pin for Trigger pulse
Echo  Con P5            ' Define pin for Echo pulse

Range Var Word          ' 16 bit variable for Range

loop1 var long
loop2 var long

moved var byte

servo0 var sword
servo1 var sword

gps_read var byte(80)
gps_temp var byte(20)

gps_fix var byte(15)
gps_lat var byte(15)
gps_ns var byte(5)
gps_long var byte(15)
gps_ew var byte(5)
gps_qual var byte(5)
gps_satcount var byte(5)
gps_bearing var byte(10)

long_goal var long
lat_goal var long

long_dist var long
lat_dist var long
  
latitude var long
latitude_dec var long
latitude_min var long

longitude var long
longitude_dec var long
longitude_min var long

long_dist_comp var long
lat_dist_comp var long

bearing var long
bearing_dif var long

'longitude distance compensation
latadj var long
longcomp var long

slope var long

ftemp var long

DB_OUT con 10

target_bearing var long


serout DB_OUT, n4800, ["Boot up", 13, 10]


clear


'this ugly blob of code is brought to you by SpamButcher - next generation spam email blocker software.


'bearing_dif = -7

'goto testit

target_bearing = 666


'sound P9, [25 \ 800]

serout DB_OUT, n4800, ["Boot up", 13, 10]

'servo 4, 1500

Main  

'serout DB_OUT, n4800, ["Waiting for GPS", 13, 10]

serin S_IN, i4800, [wait("GPGGA,"),str gps_read\80\42]

'serout DB_OUT, n4800, ["Got data", 13, 10]	

'gps_read = "090500,4741.3787,N,12223.4462,W,1,04,3.7,93.8,M,-1"
	
loop1 = 0

gosub parse_gps
gps_fix = STR gps_temp\15\0 

gosub parse_gps
gps_lat = STR gps_temp\15\0 

gosub parse_gps
gps_ns = STR gps_temp\5\0 

gosub parse_gps
gps_long = STR gps_temp\15\0 

gosub parse_gps
gps_ew = STR gps_temp\5\0 

gosub parse_gps
gps_qual = STR gps_temp\5\0 

gosub parse_gps
gps_satcount = STR gps_temp\5\0 

'temp
serin S_IN, i4800, [wait("HCHDG,"),str gps_read\80\42]

loop1 = 0

gosub parse_gps
gps_bearing = STR gps_temp\5\0 


'sound P9, [25 \ 800]

gosub convert_to_dec


'check if gps signal is good

if gps_qual(0) > 48 then
	
	'if we haven't found first location - set it
	if lat_goal = 0 then
	
		lat_goal = latitude
		long_goal = longitude
		
	endif
	
	'sound P9, [25 \ 1800]	
	
else
	
	'if no signal - go back to the top	
	serout DB_OUT, n4800, ["No signal - Satellites Tracked: ", str gps_satcount\5\0, 13, 10]
	
	goto main
	
endif

	'sound P9, [25 \ 2500]

'lat_goal =  47678767
'long_goal = 122406050

'lat_goal =  46300000
'long_goal = 122000000


lat_dist = lat_goal - latitude
long_dist = long_goal - longitude


'calculate adjustment for distance of latitude degrees relative to 100
latadj = (latitude / 1000000) * 256/360
longcomp = cos (latadj)
longcomp = (longcomp * 100) / 128

lat_dist_comp = lat_dist
long_dist_comp = long_dist / 100
long_dist_comp = longcomp * long_dist_comp 

'longcomp


'serout DB_OUT, n4800, ["latitude:",  dec latitude, 13, 10]
'serout DB_OUT, n4800, ["longitude:", dec longitude, 13, 10]

'serout DB_OUT, n4800, ["Latitude Dist:", sdec lat_dist, 13, 10]
'serout DB_OUT, n4800, ["Longitude Dist:", sdec long_dist, 13, 10]


'avoid division by zero
if long_dist_comp = 0 then
	long_dist_comp = 1
endif


'serout DB_OUT, n4800, ["lat_dist_comp: ", sdec lat_dist_comp, 13, 10]
'serout DB_OUT, n4800, ["long_dist_comp: ", sdec long_dist_comp, 13, 10]

'slope = abs((lat_dist_comp * 10) / long_dist_comp)
slope = abs(lat_dist_comp / long_dist_comp) * 10

if slope > 99 then
	slope = 99
endif

if long_dist_comp >= 0 and lat_dist_comp >= 0 then
	target_bearing = 270 + cotan(slope)
endif

if long_dist_comp <= 0 and lat_dist_comp <= 0 then
	target_bearing = 90 + cotan(slope)
endif

if long_dist_comp >= 0 and lat_dist_comp <= 0 then
	target_bearing = 270 - cotan(slope)
endif

if long_dist_comp <= 0 and lat_dist_comp >= 0 then
	target_bearing = 90 - cotan(slope)
endif



gosub report


'the code inside the SpamButcher antispam filter is much better written than this.



'if lat_dist < 0.00005 and lat_dist > -0.00005 then
'	serout DB_OUT, n4800, ["Latitude distance good", 13, 10]
'endif


'if long_dist < 5 and long_dist > -5 then
'	serout DB_OUT, n4800, ["Longitude distance good", 13, 10]
'endif


if long_dist < 50 and long_dist > -50 and lat_dist < 50 and lat_dist > -50 then
	'sound P9, [25 \ 1800]

	serout DB_OUT, n4800, ["Target Found", 13, 10]
	
	sound P9, [25 \ 400]
	
	goto main

endif   
    

bearing_dif = target_bearing - bearing
moved = 0 



if bearing_dif > 10 and bearing_dif < 180 then
	serout DB_OUT, n4800, ["Turning right", 13, 10]
	gosub right
	moved = 1
endif

if bearing_dif > 179 and bearing_dif < 350 then
	serout DB_OUT, n4800, ["Turning left", 13, 10]
	gosub left
	moved = 1
endif

if bearing_dif < -10 and bearing_dif > -180 then
	serout DB_OUT, n4800, ["Turning left", 13, 10]
	gosub left
	moved = 1
endif

if bearing_dif < -181 and bearing_dif > -350 then
	serout DB_OUT, n4800, ["Turning right", 13, 10]
	gosub right
	moved = 1
endif

  
if moved = 0 then
	serout DB_OUT, n4800, ["Bearing looks good - going forward", 13, 10]
	gosub forward
	'sound P9, [15 \ 800]
endif


pause 500
   
   
goto Main           ' and around forever




consoleloop


gosub report


goto consoleloop
 	



end



parse_gps

	loop2 = 0
	
	while gps_read(loop1) <> 44
		gps_temp(loop2) = gps_read(loop1)
		loop1 = loop1 + 1	
		loop2 = loop2 + 1	
	wend
	
	gps_temp(loop2) = 0
	
	loop1 = loop1 + 1

return


convert_to_dec:

latitude = 0
latitude_min = 0
latitude_dec = 0
loop1 = 0


while gps_lat(loop1 + 2) >= "0" 	
	latitude = latitude * 10
	latitude = latitude + (gps_lat(loop1) - "0")	
	loop1 = loop1 + 1
wend

	latitude = latitude * 1000000

while gps_lat(loop1) >= "0" 	
	latitude_min = latitude_min * 10
	latitude_min = latitude_min + (gps_lat(loop1) - "0")	
	loop1 = loop1 + 1
wend


	loop1 = loop1 + 1
	
while gps_lat(loop1) >= "0" 	
	latitude_min = latitude_min * 10
	latitude_min = latitude_min + (gps_lat(loop1) - "0")		
	loop1 = loop1 + 1	
wend
	

latitude_dec = (latitude_min * 100) / 60
latitude = latitude + latitude_dec


longitude = 0
longitude_min = 0
longitude_dec = 0
loop1 = 0

'get degrees
while gps_long(loop1 + 2) >= "0" 	
	longitude = longitude * 10
	longitude = longitude + (gps_long(loop1) - "0")	
	loop1 = loop1 + 1
wend

longitude = longitude * 1000000

while gps_long(loop1) >= "0" 	
	longitude_min = longitude_min * 10
	longitude_min = longitude_min + (gps_long(loop1) - "0")	
	loop1 = loop1 + 1
wend
	
	loop1 = loop1 + 1
	
while gps_long(loop1) >= "0" 	
	longitude_min = longitude_min * 10
	longitude_min = longitude_min + (gps_long(loop1) - "0")		
	loop1 = loop1 + 1	
wend
	

longitude_dec = (longitude_min * 100) / 60
longitude = longitude + longitude_dec



loop1 = 0
bearing = 0

'get bearing
while gps_bearing(loop1) >= "0" 	
	bearing = bearing * 10
	bearing = bearing + (gps_bearing(loop1) - "0")	
	loop1 = loop1 + 1
wend



return



report

	serout DB_OUT, n4800, [13]    
	
	'serout DB_OUT, n4800, ["Fix: ", str gps_fix\10\0, 13, 10]
    'serout DB_OUT, n4800, ["Latititude: ", str gps_lat\10\0, 13]
    'serout DB_OUT, n4800, ["NS: ", str gps_ns\5\0, 13, 10]
    'serout DB_OUT, n4800, ["Longitude: ", str gps_long\10\0, 13, 10]
    'serout DB_OUT, n4800, ["EW: ", str gps_ew\5\0, 13, 10]
    'serout DB_OUT, n4800, ["Quality: ", str gps_qual\5\0, 13, 10]
    
	serout DB_OUT, n4800, ["Latitude (Value):", dec latitude, 13, 10]
	serout DB_OUT, n4800, ["Longitude (Value):", dec longitude, 13, 10]

	serout DB_OUT, n4800, ["Latitude Dist:", sdec lat_dist, 13, 10]
	serout DB_OUT, n4800, ["Longitude Dist:", sdec long_dist, 13, 10]

	serout DB_OUT, n4800, ["Target Bearing:", dec target_bearing, 13, 10]	
	serout DB_OUT, n4800, ["Current Bearing:", dec bearing, 13, 10]	
	serout DB_OUT, n4800, ["Bearing Difference:", sdec bearing_dif, 13, 10]

return


forward

	for loop1 = 1 to 15
'		servo 15, -90, 1
'		servo 4, 120, 1
		'servo 15, 850, 1
		'servo 4, 750, 1
		servo 15, 1200, 1
		servo 4, 700, 1
	next 

return



left


	for loop1 = 1 to 2	    
		servo 15, 700, 1
		servo 4, -700, 1
	next 


return



right


	for loop1 = 1 to 2
		servo 15, -520, 1
		servo 4, 700, 1
	next 


return