Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

MEM 380/800:  Autonomous Vehicle Control I 

Project Summary – December 4, 2008 
Jason Collins, Ted Bieniosek, Jessica Snyder
Abstract 
  An  all‐terrain  radio  operated  vehicle  was  modified  both  mechanically  and  electronically  in  order  to  perform  the 
required task: travel autonomously through an unknown environment until an obstacle is encountered, then stop.  
To  permit  autonomous  control,  the  vehicle’s  radio  link  was  disabled,  a  microcontroller  was  installed,  and  the 
vehicle’s  steering  servos  and  speed  controller  were  placed  under  the  microcontroller’s  command.    The 
microcontroller  was  programmed  by  an  external  microcomputer  and  permitted  to  communicate  with  the 
microcomputer via wireless Bluetooth® connection to allow for microcontroller program start and termination.  The 
programming and electrical and mechanical modifications resulted in successful completion of the assigned task as 
well as early success in the secondary task of incorporating computer vision as a means of navigation. 
Vehicle  Microcontroller and Electronics 
  The  team  was  supplied  with  an  E‐Maxx  (Traxxas,    In addition to the vehicle and aftermarket replacement 
Model  3906)  electric  all‐terrain  truck.    The  stock  truck  parts,  the  team  was  supplied  with  the  following 
includes the following features:  electronic devices: 

• Four‐wheel drive  • Propeller Starter Kit (Parallax, Model 32300) 
• Two Titan 550 brushless, fan cooled motors  o Propeller microcontroller unit (Parallax, 
• EVX‐2 speed controller(forward/reverse/brake)  Model P8X32A‐Q44) 
• Two 7.2 V rechargeable batteries  • Bluetooth®  transceiver  (Embedded  Blue,  Model 
• Dual servo steering system  500‐SER) 
• Drive gear ratio:  18.67 : 1; Top speed:  30 M.P.H.  • Servo controller (Parallax, Model 28823) 
• Overall length:  518 mm; Overall width:  417 mm  • Servo (Hitec, Model HS‐5645MG) 
• Wheelbase:  335 mm;  Overall height:  248 mm  • “PING)))”  Ultrasonic  sensor  (Parallax,  Model 
28015) (5 units) 
Mechanical Modifications  • CMUcam2+ Vision sensor 
  To make the truck less of a high‐speed racing machine  • Spare 7.2 V rechargeable battery (2 units) 
and  more  stable,  predictable  and  controllable,  the  • 7.2 V battery charger 
following mechanical modifications were completed:  • 4 × “AA” battery holder (2 units) 
• “AA” size batteries 
• Stock  (red)  springs  were  replaced  with  higher  • Various lengths of wire 
stiffness  (orange)  springs.    This  modification 
stabilized the chassis and body, permitting more  Electronic Modifications 
stable  sensor  range  measurements  during 
  To allow the truck to be placed under the autonomous 
acceleration. 
control  of  a  program  in  operation  on  the  Propeller 
• Drive  gear  was  replaced;  gear  ratio  increased.   microcontroller,  the  following  modifications  were  made 
Lowering  the  gear  ratio  had  the  effect  of  to the vehicle: 
lowering  the  truck’s  top  speed,  decreasing  the 
stopping  distance,  and  providing  smoother  • The  stock  radio  receiver  was  disconnected  and 
acceleration  removed.    The  ability  of  the  truck  to  receive 
• Body was raised to maximum level.  The higher  signals from the stock radio control unit served 
vantage  point  solved  the  problem  of  the  range  no purpose in this project. 
sensors  detecting  erroneous  distance  values  • Four  of  the  “PING”  sensors  were  mounted  on 
(registering the floor).  the  plastic  body  of  the  truck;  three  forward 
facing  and  one  rear  facing.    The  sensors  were  board  image  microprocessor,  capable  of  tracking  color 
wired directly to the Propeller prototype board.  and other objects in multiple modes.  The team was able 
• The  servo  controller  was  wired  to  one  PS/2  to  program  the  CMUcam2+  to  track  colored  objects  in 
connector on the prototype board.  its  most  basic  mode.    The  heuristics  are  again  updated, 
• The  speed  controller  input  and  steering  servos  becoming still more complicated: 
were  wired  to  the  servo  controller  output 
channels.  • Check the camera. 
• The  Bluetooth®  transceiver  was  wired  to  the  • If  the  camera  does  not  see  the  desired  color, 
second PS/2 connector on the prototype board.  rotate servo until color is found. 
• The  CMUcam2+  was  mounted  on  the  spare  • Check the range sensors. 
servo  and  output  color  tracking  data  to  the  • If all sensors indicate a clear path, drive ahead. 
Propeller microcontroller.  • If  none  of  the  rules  below  are  broken,  steer 
• The fifth “PING” sensor was mounted alongside  towards the direction that the camera is facing. 
the camera and wired to the Propeller board.  • If  the  center  forward  sensor  shows  something 
• An additional 7.2  V battery was mounted on the  ahead, slow proportional to distance indicated. 
chassis to provide power for the CMUcam2+ and  • If  the  right  (left)  front  sensor  shows  something 
Propeller  chip.    A  4  ×  “AA”  battery  holder  was  in  that  direction,  steer  the  opposite  direction 
added to supply power to the servo controller.  proportional to the range to that object. 
• If  the  center  forward  sensor  shows  something 
Programming Strategy  very close, stop and turn around.  
  To  accomplish  the  goal  of  moving,  identifying  an  • If  the  range  sensor  mounted  on  the  camera 
obstacle,  and  halting  in  its  proximity,  simple  heuristics  indicates  something  very  close,  and  the  camera 
were  programmed  on  the  Propeller  chip  to  allow  for  confirms the color, halt. 
autonomous control: 
Conclusion 
• Check the range sensors.    At  the  conclusion  of  the  ten  week  quarter,  the  team’s 
• If all sensors indicate a clear path, drive ahead.  truck was able to complete a demonstration of the initial 
• If a forward sensor indicates something at close  objective, as well as operate in more sophisticated modes 
range, halt.  of travel.  With the implementation of the CMUcam2+, a 
variety  of  challenges  can  be  completed  and  algorithms 
  Successful  implementation  of  these  three  steps  was  explored.    In  upcoming  academic  quarters,  this  team 
sufficient to complete the first task.  In search of a better  hopes  to  implement  a  better  method  of  searching  for 
challenge, the team decided to explore the possibility of  colored  objects  rather  than  moving  and  looking 
avoiding  obstacles  rather  than  simply  stopping  in  front  randomly  throughout  the  environment.    Perhaps  some 
of them.  The heuristics change to the following:  methods of path planning and following can be explored.  
The  success  of  the  team  can  be  largely  attributed  to  an 
• Check the range sensors. 
organized  team  effort,  focus  and  time  management 
• If all sensors indicate a clear path, drive ahead. 
during class time, setting and meeting small daily goals, 
• If  the  center  forward  sensor  shows  something 
and prior experience. 
ahead, slow proportional to distance indicated. 
• If the  right (left)  front sensor shows something 
in  that  direction,  steer  the  opposite  direction 
proportional to the range to that object. 
• If  the  center  forward  sensor  shows  something 
very close, stop and turn around. 
• Repeat indefinitely. 

  Lastly, the team explored the CMUcam2+ and potential 
implementation  strategies.    The  CMUcam2+  has  an  on 
Appendix A:  Spin Code Listing
{{Truck.spin}}
{{
11-25-08
Control E-MAXX truck equiped with 5 Ping))) sensors and a CMUcam2+
}}
Con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
Th_Channel = 12 'servo control settings
St_Channel = 7
Cam_Channel = 1
Rate = 1
MaxDist = 100 'ping range settings
NeutralDist = 40
MinDist = 1
MaxForward = 135 'speed controller settings
MinForward = 131
Neutral = 125
MinReverse = 122
MaxReverse = 115
ExtLeft = 190 'steering settings
ExtRight = 40
MaxSteer = 50
Center = (ExtLeft + ExtRight) / 2
SensLim = 100
SteeringProportionalGain = 1
ConfidenceThreshold = 75
OBJ
Servo : "PWM"
Serial_PC : "FullDuplexSerial"
Serial_CAM : "FullDuplexSerial"
Num : "Numbers"
Distance : "Ping"
VAR
Byte Throttle 'display values
Byte Steering
Byte Cam_angle
Word D0
Word D1
Word D2
Word D3
Word D4
Byte mx 'camera values
Byte my
Byte x1
Byte y1
Byte x2
Byte y2
Byte pixels
Byte confidence
Byte r1
Byte r2
Byte TargetAquired
Byte CrMean
Byte YMean
Byte CbMean
Byte CrDeviation
Byte YDeviation
Byte CbDeviation
PUB Main
BTSetup 'setup bluetooth connection
CAM_init 'setup camera
Throttle := Neutral
Steering := 115
Cam_Angle := 125
r1 := 0
r2 := 0
repeat 'main loop
UserIn
UserOut
if Cam_Angle > 230
CAM_Angle := 230
elseif Cam_Angle < 35
CAM_Angle := 35
Servo.Send(Th_Channel, Rate, Throttle)
Servo.Send(St_Channel, Rate, Steering)
Servo.Send(Cam_Channel, Rate, Cam_Angle)
PUB Track | center2

CAM_Get
if Confidence > ConfidenceThreshold
TargetAquired := 1
if my < center2 'center2 has no initial value... is it required at all?
Cam_Angle := Cam_Angle + (75-my)/3
elseif my > center2
Cam_Angle := Cam_Angle - (my-75)/3

else
TargetAquired := 0
Cam_Angle := Cam_Angle + 50

PUB UserOut
serial_PC.tx(13)
if Throttle
serial_PC.str(string("Throttle:"))
serial_PC.str(Num.ToStr(Throttle, Num#DDEC))
if Steering
serial_PC.str(string(" Steering:"))
serial_PC.str(Num.ToStr(Steering, Num#DDEC))
if Cam_angle
serial_PC.str(string(" CAM:"))
serial_PC.str(Num.ToStr(Cam_angle, Num#DDEC))
if D0
serial_PC.str(string(" D0:"))
serial_PC.str(Num.ToStr(D0, Num#DDEC))
if D1
serial_PC.str(string(" D1:"))
serial_PC.str(Num.ToStr(D1, Num#DDEC))
if D2
serial_PC.str(string(" D2:"))
serial_PC.str(Num.ToStr(D2, Num#DDEC))
if D3
serial_PC.str(string(" D3:"))
serial_PC.str(Num.ToStr(D3, Num#DDEC))
if D4
serial_PC.str(string(" D4:"))
serial_PC.str(Num.ToStr(D4, Num#DDEC))
serial_PC.tx(13)
PUB UserIn | input
input := serial_PC.rx

Sample
if input == "w" 'forward
Throttle := Throttle + 3
elseif input == "s" 'reverse
Throttle := Throttle - 3
elseif input == "a" 'turn wheels left
Steering := Steering + 10
elseif input == "d" 'turn wheels right
Steering := Steering - 10
elseif input == "q" 'turn camera left
Cam_angle := Cam_angle - 5
elseif input == "e" 'turn camera right
Cam_angle := Cam_angle + 5
elseif input == "t" 'run the tracking code
Track
elseif input == "i" 'get tracking sample
CAM_Set
elseif input == "u" 'PC-CAM serial pass thru mode
PCtoCAM
elseif input == " " 'all stop
Throttle := Neutral
Steering := 115
Cam_angle := 125
elseif input == "c" 'start both controllers
serial_PC.rxflush
repeat
if serial_PC.rxcheck <> -1
quit
ThrottleController
SteeringController
UserOut 'temp added for loop
Servo.Send(Th_Channel, Rate, Throttle)
Servo.Send(St_Channel, Rate, Steering)
Servo.Send(Cam_Channel, Rate, Cam_Angle)
sample
if D4 < 5
quit
throttle := Neutral
Steering := 115
Cam_angle := 125
elseif input == "x" 'start the Throttle controller
ThrottleController
elseif input == "f" 'start the Steering controller
SteeringController
else
serial_PC.tx(13)
serial_PC.str(string("unknown"))

PUB ThrottleController
if D1 > MaxDist 'D1 = the forward ping sensor
Throttle := MaxForward
Serial_PC.str(string("Max"))
elseif D1 > NeutralDist
Throttle := MinForward + (D1 - NeutralDist) * (MaxForward - MinForward)/ (MaxDist - NeutralDist)
Serial_PC.str(string("Forward"))
elseif D3 > NeutralDist
Throttle := MinReverse - (NeutralDist - D1) * (MinReverse - MaxReverse)/ (NeutralDist - MinDist)
Serial_PC.str(string("Reverse"))

if r1 == D1
if r2 == D1
Throttle := Neutral
Servo.Send(Th_Channel, Rate, Throttle)
r1 := 0
r2 := 0
waitcnt(clkfreq/10 + cnt)
return
else
r2 := D1
else
r1 := D1
else
Throttle := Neutral
Serial_PC.str(string("Stop"))

PUB SteeringController
track

'limit sensor readings to SensLim constant


if D0 > SensLim
D0 := SensLim
if D2 > SensLim
D2 := SensLim

serial_PC.str(Num.ToStr((D2 - D0), Num#DDEC))


if Throttle > 124
if D0 + D2 == SensLim * 2 'sensors see nothing in range
steering := 250 - Cam_Angle
if TargetAquired == 0
Steering := Center 'add drive search here if desired
elseif(D2>D0+5) 'object on ritght
Steering := Center-(D2^2-D0^2)^0.5*SteeringProportionalGain
elseif(D0>D2+5) 'object of left
Steering := Center-(D2^2-D0^2)^0.5*SteeringProportionalGain
else 'objects at aproximately equal distances
Steering := Center
if(Steering > ExtLeft)
Steering := ExtLeft
'serial_PC.str(Num.ToStr(Steering, Num#DDEC))
if(Steering < ExtRight)
Steering := ExtRight
'serial_PC.str(Num.ToStr(Steering, Num#DDEC))
else
if(D2>D0+5)
Steering := Center+(D2^2-D0^2)^0.5*SteeringProportionalGain
if(Steering > ExtLeft)
Steering := ExtLeft
'serial_PC.str(Num.ToStr(Steering, Num#DDEC))
elseif(D0>D2+5)
Steering := Center+(D2^2-D0^2)^0.5*SteeringProportionalGain
if(Steering < ExtRight)
Steering := ExtRight
'serial_PC.str(Num.ToStr(Steering, Num#DDEC))
else
Steering := Center + 30
PUB Sample

D0 := Distance.Centimeters(0) 'only enable pins with a ping attached or code will hang
waitcnt(clkfreq/1000 + cnt)
D1 := Distance.Centimeters(1)
waitcnt(clkfreq/1000 + cnt)
D2 := Distance.Centimeters(2)
waitcnt(clkfreq/1000 + cnt)
D3 := Distance.Centimeters(3)
waitcnt(clkfreq/1000 + cnt)
D4 := Distance.Centimeters(4)
waitcnt(clkfreq/1000 + cnt)
PUB BTSetup
Serial_PC.start(24, 25, 0, 9600) 'if bluetooth card is in 9600 mode change it to 115200
Serial_PC.str(string("set baud 115200 *", 13))
waitcnt(clkfreq/10 + cnt)
Serial_PC.start(24, 25, 0, 115200) 'talk to bt card at 115200
serial_PC.str(string("con 00:22:69:D0:72:70", 13)) 'start bt connection with class dell laptop
waitcnt(clkfreq/10 + cnt)
PUB PCtoCAM | ToCAM, ToPC
Serial_CAM.tx(13)
Serial_PC.tx(13)
'Serial_PC.str(":")

repeat 'relay from PC to CAM


ToCAM := Serial_PC.rx
Serial_CAM.tx(ToCAM)
while ToCAM <> 13 'not equal
repeat 'relay from CAM to PC
ToPC := Serial_CAM.rx
Serial_PC.tx(ToPC)
while ToPC <> ":" 'not equal
PUB CAM_init
Serial_CAM.start(5, 6, 0, 115200) 'set camera serial settings
waitcnt(clkfreq/10 + cnt)
Serial_CAM.tx(13) 'new line
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("rs", 13)) 'reset
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("cr 18 36 19 33", 13)) 'set camera register: white balance on, auto gain on
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("pm 1", 13)) 'enable ping mode
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("tw", 13)) 'sample and set auto threshold
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("l1 1", 13)) 'LED
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("rm 1", 13)) 'set output to raw mode (butes instead of strings)
waitcnt(clkfreq/10 + cnt)
PUB CAM_Set
Serial_CAM.str(string("cr 18 32 19 32", 13)) 'set camera register: white balance off, auto gain off
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("VW 35 65 45 75", 13)) 'set virtual window to central portion of screen
waitcnt(clkfreq/10 + cnt)
Serial_CAM.rxflush
Serial_CAM.str(string("GM", 13)) 'get average color
'repeat
'Serial_PC.tx(Serial_CAM.rx) 'read values returned
CrMean := Serial_CAM.rx
YMean := Serial_CAM.rx
CbMean := Serial_CAM.rx
CrDeviation := Serial_CAM.rx
YDeviation := Serial_CAM.rx
CbDeviation := Serial_CAM.rx
Serial_PC.str(Num.ToStr(CrMean, Num#DDEC)) 'use .dec insetead of .str(num...
Serial_PC.str(Num.ToStr(YMean, Num#DDEC))
Serial_PC.str(Num.ToStr(CbMean, Num#DDEC))
Serial_PC.str(Num.ToStr(CrDeviation, Num#DDEC))
Serial_PC.str(Num.ToStr(YDeviation, Num#DDEC)) 'contirnue changing after test
Serial_PC.str(Num.ToStr(CbDeviation, Num#DDEC))
Serial_CAM.str(string("VW", 13)) 'set virtual window to full size
waitcnt(clkfreq/10 + cnt)
Serial_CAM.str(string("ST ")) 'send tracking parameters
Serial_CAM.dec(CrMean - 2 * CrDeviation)
Serial_CAM.str(string(" "))
Serial_CAM.dec(CrMean + 2 * CrDeviation)
Serial_CAM.str(string(" "))
Serial_CAM.dec(YMean - 5 * YDeviation)
Serial_CAM.str(string(" "))
Serial_CAM.dec(YMean + 5 * YDeviation)
Serial_CAM.str(string(" "))
Serial_CAM.dec(CbMean - 2 * CbDeviation)
Serial_CAM.str(string(" "))
Serial_CAM.dec(CbMean + 2 * CbDeviation)
Serial_CAM.tx(13)
waitcnt(clkfreq/10 + cnt)
PUB CAM_Get
Serial_CAM.rxflush
Serial_CAM.str(string("tc", 13))
repeat 6
Serial_PC.tx(Serial_CAM.rx) 'use rxtime(ms) later
mx := Serial_CAM.rx
my := Serial_CAM.rx
x1 := Serial_CAM.rx
y1 := Serial_CAM.rx
x2 := Serial_CAM.rx
y2 := Serial_CAM.rx
pixels := Serial_CAM.rx
confidence := Serial_CAM.rx
Serial_PC.str(Num.ToStr(mx, Num#DDEC)) 'use .dec insetead of .str(num...
Serial_PC.str(Num.ToStr(my, Num#DDEC))
Serial_PC.str(Num.ToStr(x1, Num#DDEC))
Serial_PC.str(Num.ToStr(y1, Num#DDEC))
Serial_PC.str(Num.ToStr(x2, Num#DDEC))
Serial_PC.str(Num.ToStr(y2, Num#DDEC))
Serial_PC.str(Num.ToStr(pixels, Num#DDEC))
Serial_PC.str(Num.ToStr(confidence, Num#DDEC))
Serial_PC.str(string(13, ":"))

waitcnt(clkfreq/100 + cnt)
   
Appendix B:  Vehicle Photos 
 

 
 

 
 
 
 
 

 
 
   
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Appendix C:  Daily Log 

You might also like