robotlab_275_71.png home | robots | microflight | other projects

MicroRover

Introduction

rover.jpg
Fig 1: Rover in action (8.2Mb)
This small robot measures 75x38x50 mm, and is powered by two geared DC motors. Four NiMH cells, delivering 120mAh at 1.2 V each provide enough power for approximately 1 hour autonomy. The brains of the robot are made up of a AT90LS8535 running at 4MHz in a TQFP package. The motors are driven by a 74AC244, an octal buffer/line driver which I used to make 2 H-bridges.

The robot has 8 sensors; 4 touch sensors on each corner, two directional LDR light sensors, one IR sensor (TSOP1736, RC5 type) and one proprioceptive sensor indicating battery status. This sensor package seems to be enough to provide for rather intelligent behavior.

The robot has a tank like locomotion. I've grown fond of this type of locomotion as it provides traction on all wheels. Also, I really enjoy the skid steering.

The robot has 4 connectors; one to charge the batteries, another one to program the robot, a serial connector and one expansion bus, exposing 8 data lines, from which 4 our ADC capable. I've build a wireless module to put on top of the robot. More on that will follow, sufficient to say now that it uses a BIM2 transceiver from radiometrix. I've experienced some troubles getting the PCB ready for the PC host adapter, as I had to redo the PCB for a few times to get it right. Hence, I put the wireless module on a lower priority.

Schematic

microrover_small.gif

Images

SIMG0823_200x150.jpg SIMG0818_200x150.jpg
SIMG0822_200x150.jpg SIMG0816_200x150.jpg
SIMG0814_200x150.jpg

Example code

The next code is a small BASCOM program that can drive the MicroRover. It is a simple subsumption architecture, using 3 behaviors; photofobic, wandering and react to touch.

subsumption.gif
Fig 2: Subsumption layers
The most primitive behavior is reaction to touch, this behavior can subsume over all other tasks. Most of the time, the robot is in a photofobic state, it will wander of to a dark place by constantly steering in the most dark direction. Light values are measured by an ADC channel on the AVR MPU. Whenever the robot reads the light intensity on its two eyes, it'll power the LDRs for a short time and - enough time for the ADC to setlle - and then read out the intensities (lines 149-155). This intermittent powering of the LDRs prevent battery drain. When the light intensities falls below a certain treshhold, the robot will sit happy until light levels are up again.

Whenever an object hits one of the touch sensors, the robot will try to turn away from the obstacle by reversing its direction and turning towards the opposite site of the touched sensor. If both front or aft sensors are touched, the robot just reverses direction, no turn takes place (lines 250-302).

After a random time, the rover wants to wander around. This wandering behavior has priority over its photofobic state, but lower priority than the touch behavior. When in wandering state, the robot is attracted to light. It will run of as fast as it can to brightest spot it can detect. The time that the robot wanders around is determined by another random number. I've found that this wandering state is very usefull for the robot to roam the complete room. If the wandering behavior would not be included, the robot would simply drive to a dark spot and sit there until light intensities are high enough to get it moving again. With the wandering behavior, though, the robot can sit idle on a dark spot, come to life again and run straight into the light. When the wandering behavior shuts down, the robot gets a panic attack and hurries to the nearest dark spot it can find (lines 337-374).

Lines 171 to 190 implement code to steer the robot via a TV remote control. The remote control can steer the robot in all 4 directions. Moreover, it can let the robot dump its internal state to its serial port. This can come in handy when debugging.

Although the battery level is already measured (lines 157-161) , by comparing a constant voltage drop over 3 diodes against the battery voltage, nothing is done with it. The idea is to have a small hardware extension on the robot that allows it to charge automatically. This extension can be made of just two wires that can connect to a docking station, composed of two metal plates. The idea is to let the robot navigate to a charging station as soon as battery levels drop below a certain treshhold. Moreover, the idea is to use the LDRs to navigate to the charging station. A LED, pulsating at a low enough frequency cqn be easily detected by the LDRs. The LED would indicate the position of the charging station.

     1   '(
     2     r o v e r
     3     จจจจจจจจจ
     4     test code for rover based on 8535
     5   ')
     6   
     7   M1A alias portd.7
     8   M1B alias portd.6
     9   
    10   M2A alias portc.1
    11   M2B alias portc.0
    12   
    13   BAT_CONTROL alias portc.4
    14   const BAT_LEVEL = 5
    15   
    16   TOUCH_BACK_LEFT alias pinc.5
    17   TOUCH_BACK_RIGHT alias pinc.6
    18   TOUCH_FRONT_LEFT alias pind.4
    19   TOUCH_FRONT_RIGHT alias pind.5
    20   
    21   EYE_CONTROL alias portc.7
    22   const EYE_LEFT = 7
    23   const EYE_RIGHT = 6
    24   
    25   config Adc = Single , Prescaler = Auto
    26   config debounce = 10
    27   config Rc5 = pind.2
    28   enable interrupts
    29   
    30   ' -- subroutine declarations
    31   declare sub forward
    32   declare sub backward
    33   declare sub turn_left
    34   declare sub turn_right
    35   declare sub halt
    36   declare sub diagnostics
    37   
    38   declare sub motor
    39   
    40   declare sub touch
    41   declare sub photofoob
    42   declare sub wander
    43   
    44   ' -- variable declarations
    45   dim eye_l as  Word
    46   dim eye_r as  Word
    47   dim bat as Word
    48   dim tch_bl as bit
    49   dim tch_br as bit
    50   dim tch_fl as bit
    51   dim tch_fr as bit
    52   
    53   dim c as byte
    54   dim rc5_address as byte, rc5_command as byte
    55   dim temp as byte
    56   dim i as integer
    57   
    58   ' -- define behaviours
    59   
    60   '  . global settings
    61   const BEAT  = 50           ' -- unit of execution time
    62                              '  a behaviour will use this as a standard
    63                              '  time tick for action
    64   const BEAT2 = 100
    65   
    66   '  . touch
    67   dim touch_state as byte    ' - state of the 'touch' behaviour
    68   dim touch_dur as word      ' - duration
    69   dim touch_turn as byte
    70   dim touch_direction as byte
    71   
    72   '  . motor
    73   dim motor_vector as byte   ' - drive vector for motors
    74   const M_STOP = 0
    75   const M_FORWARD = 1
    76   const M_RIGHT = 2
    77   const M_BACK = 3
    78   const M_LEFT = 4
    79   
    80   ' . photofoob
    81   dim photofoob_state as byte
    82   dim photofoob_turn as byte
    83   dim photofoob_dur as word
    84   dim photofoob_offset as word
    85   
    86   '  . wander
    87   dim wander_state as byte
    88   dim wander_turnorgo as bit
    89   dim wander_dur as long
    90   const WANDER_RUN = 200*BEAT
    91   
    92   ' -- main
    93   DDRD = &B11001011
    94   DDRC = &B10011111
    95   
    96   start Adc
    97   
    98   set PORTC.6
    99   set PORTC.5
   100   set PORTD.5
   101   set PORTD.4
   102   
   103   wander_state = 0
   104   photofoob_state = 0
   105   photofoob_offset = 50
   106   touch_state = 0
   107   motor_vector = 0
   108   
   109   do
   110      ' pull in data from the sensors
   111      gosub latch_sensors
   112   
   113      ' behaviours
   114      photofoob
   115      wander
   116      touch
   117   
   118      ' override controls now with RC5 commands
   119      ' gosub remote
   120   
   121      ' motor control
   122      motor
   123   
   124      temp = inkey()
   125      if temp > 0 then
   126         call diagnostics
   127      end if
   128   
   129   loop
   130   
   131   ' -- control the engine
   132   sub motor
   133      select case motor_vector
   134         case M_STOP:
   135            call halt
   136         case M_FORWARD:
   137            call forward
   138         case M_BACK:
   139            call backward
   140         case M_LEFT:
   141            call turn_left
   142         case M_RIGHT:
   143            call turn_right
   144      end select
   145   end sub
   146   
   147   ' -- Pull the sensory data into globals
   148   latch_sensors:
   149      set EYE_CONTROL
   150      waitus 250
   151      c = EYE_LEFT
   152      eye_l = getadc(c)
   153      c = EYE_RIGHT
   154      eye_r = getadc(c)
   155      reset EYE_CONTROL
   156   
   157      set BAT_CONTROL
   158      waitus 250
   159      c = BAT_LEVEL
   160      bat = getadc(c)
   161      reset BAT_CONTROL
   162   
   163      tch_bl = TOUCH_BACK_LEFT
   164      tch_br = TOUCH_BACK_RIGHT
   165      tch_fl = TOUCH_FRONT_LEFT
   166      tch_fr = TOUCH_FRONT_RIGHT
   167   
   168      return
   169   
   170   ' --
   171   remote:
   172      getrc5( rc5_address, rc5_command)
   173      if rc5_address <> 255 then
   174         rc5_command = rc5_command and &B10111111
   175         select case rc5_command
   176            case 32:
   177               motor_vector = M_FORWARD
   178            case 33:
   179               motor_vector = M_BACK
   180            case 16:
   181               motor_vector = M_RIGHT
   182            case 17:
   183               motor_vector = M_LEFT
   184            case 12:
   185               motor_vector = M_STOP
   186            case 14:
   187               call diagnostics
   188         end select
   189      end if
   190      return
   191   
   192   ' -- print out some diagnostics
   193   sub diagnostics
   194     print "el  "; eye_l
   195     print "er  "; eye_r
   196     print "ba  "; bat
   197     print "wd  "; wander_dur
   198     print "bl "; tch_bl
   199     print "br "; tch_br
   200     print "fl "; tch_fl
   201     print "fr "; tch_fr
   202     print "vc "; motor_vector
   203   end sub
   204   
   205   ' -- move forward
   206   sub forward
   207      set M1A
   208      reset M1B
   209      set M2A
   210      reset M2B
   211   end sub
   212   
   213   ' -- move backward
   214   sub backward
   215      reset M1A
   216      set M1B
   217      reset M2A
   218      set M2B
   219   end sub
   220   
   221   ' -- turn right
   222   sub turn_right
   223      set M1A
   224      reset M1B
   225      reset M2A
   226      set M2B
   227   end sub
   228   
   229   ' -- turn left
   230   sub turn_left
   231      reset M1A
   232      set M1B
   233      set M2A
   234      reset M2B
   235   end sub
   236   
   237   ' -- stop rover
   238   sub halt
   239      reset M1A
   240      reset M1B
   241      reset M2A
   242      reset M2B
   243   end sub
   244   
   245   
   246   ' ------------------------------------------------------------------------
   247   ' --    B E H A V I O U R S
   248   ' ------------------------------------------------------------------------
   249   
   250   sub touch
   251      ' we always react to touch, even when processing a touch
   252      if tch_bl = 0 then
   253         touch_turn = M_RIGHT
   254         touch_direction = M_FORWARD
   255         touch_state = 1
   256         touch_dur = BEAT2
   257      end if
   258   
   259      if tch_br = 0 then
   260         touch_turn = M_LEFT
   261         touch_direction = M_FORWARD
   262         touch_state = 1
   263         touch_dur = BEAT2
   264      end if
   265   
   266      if tch_fl = 0 then
   267         touch_turn = M_RIGHT
   268         touch_direction = M_BACK
   269         touch_state = 1
   270         touch_dur = BEAT2
   271      end if
   272   
   273      if tch_fr = 0 then
   274         touch_turn = M_LEFT
   275         touch_direction = M_BACK
   276         touch_state = 1
   277         touch_dur = BEAT2
   278      end if
   279   
   280      select case touch_state
   281   
   282      case 0:
   283   
   284      case 1:
   285         motor_vector = touch_direction
   286         if touch_dur = 0 then
   287            touch_state = 2
   288            touch_dur = BEAT2
   289         end if
   290         decr touch_dur
   291   
   292      case 2:
   293         motor_vector = touch_turn
   294         if touch_dur = 0 then
   295            touch_state = 0
   296            touch_dur = 0
   297            motor_vector = M_STOP
   298         end if
   299         decr touch_dur
   300   
   301      end select
   302   end sub
   303   
   304   sub photofoob
   305      select case photofoob_state
   306   
   307      case 0:
   308         ' we kick into action when it is too light
   309         if eye_l > photofoob_offset or  eye_r > photofoob_offset then
   310            photofoob_turn = M_LEFT
   311            if eye_l > eye_r then
   312               photofoob_turn = M_RIGHT
   313            end if
   314            photofoob_dur = BEAT
   315            photofoob_state = 1
   316         end if
   317   
   318      case 1:
   319         motor_vector = photofoob_turn
   320         if photofoob_dur = 0 then
   321            photofoob_state = 2
   322            photofoob_dur = BEAT
   323         end if
   324         decr photofoob_dur
   325   
   326      case 2:
   327         motor_vector = M_FORWARD
   328         if photofoob_dur = 0 then
   329            photofoob_state = 0
   330            motor_vector = M_STOP
   331         end if
   332         decr photofoob_dur
   333   
   334      end select
   335   end sub
   336   
   337   sub wander
   338      select case wander_state
   339   
   340      case 0:
   341         i = rnd(100)
   342         i = i * 10
   343         wander_dur = i * BEAT
   344         wander_state = 1
   345   
   346      case 1:
   347         if wander_dur = 0 then
   348            wander_state = 2
   349            wander_turnorgo = 0
   350            wander_dur = WANDER_RUN
   351         end if
   352         decr wander_dur
   353   
   354      case 2:
   355         if wander_turnorgo = 0 then
   356            motor_vector = M_LEFT
   357            if eye_l < eye_r then
   358               motor_vector = M_RIGHT
   359            end if
   360         else
   361            motor_vector = M_FORWARD
   362         end if
   363         if wander_dur = 0 then
   364            wander_state = 0
   365            motor_vector = M_STOP
   366         end if
   367         decr wander_dur
   368         i = wander_dur mod BEAT2
   369         if i = 0 then
   370            toggle wander_turnorgo
   371         end if
   372   
   373      end select
   374   end sub

 

Print » Edit | Attach | Diff «