last modified 27-APR-2000

Wouter van Ooijen (


I have build a number of stepbots: small PIC-controlled robot vehicles using stepper motors. The basic idea is to use two steppers which are directly connected to the front wheels, and a real wheel which can turn freely. The two steppers take care of the propulsion and steering. The steppers from old 5.25 disk drives are very practical, requiring 100 mA (per coil) at 12 Volt, which can be provided by 10 penlight NiCads. A 7805 regulator provides the 5 Volt required for the PIC 16f84 brain. A single ULN2803 interfaces the brain to the two stepper motors. I use either a 24 Volt wall wart to charge the NiCads and series resistor in the robot that selects the appropriate charge current, or a removeable NiCad pack.

stepper motors

5.25 inch diskdrives contain a number of different stepper motor types. You can find steppers with 4, 5 and 6 wires. The 4 wire types (often found in the more recent 5.25 drives) are bipolar and can not be used with the circuit described here. The 5 and 6 wire types are essentially the same. Use an multimeter to find the one (5 wire steppers) or two (6 wire steppers) common wire(s) that have a low resistance to other wires. For a 6 wire stepper connect the two commons together and you have a 5 wire stepper.

stepper diagrams

Now you must find out the stepping sequence. You can do this by hand, using a 12 V power supply (watch out for the spikes when you remove the power from a coil!), or by connecting the stepper to the robot circuit programmed for continous motion. In both cases you must find the correct sequence by trial and error, but you can keep one coil fixed, and from the remaining 8 possibilities two are OK (one for forward and one for backward motion).

stepper motors

The front wheels are taken from broken office chairs. These wheels are a bit difficult to take apart, but a combination of patience and some brute force will do the job. I drill a hole through the center of each half wheel which is a little bit smaller than the metal cylinder on the steppers' shaft and use some force to push it onto the shaft. A strip of self adhesive staircase grip paper around the wheels improves the grip on smooth undergrounds.

The real wheel is a swivel wheel, the kind used under office chairs and TV trolleys. It is important that the real wheel turns easily, which requires that it has a very small area of contact with the underground, and that this area is only a tiny bit (a few mm) behind its vertical axis. The wheel on the left picture is much better than the one on the right. An alternative real 'wheel' is a smooth sphere that simply sits beneath the real of the stepbot.

rear wheel 1 rear wheel 2

The brain of the robot is a Microchip PIC 16f84 microcontroller. This chip not very expensive, has enough horsepower for this simple control task and can be programmed quickly without removing it from its circuit. I use either a test clip directly on the chip, 2x3 pin header (one pin cut off as key) or a D15M connector as in-circuit programming interface. The electronics (16f84, crystal, 7805, ULN2803 and a few pin header connectors) can be build on a 2 x 3 cm breadboard.

circuit chip pinouts

Don't expect miracles from this simple hardware: it can crawl for an hour or so at its top speed of a few cm per second provided that the underground is smooth and level. The steppers deliver just enough power to move the vehicle, so it will not ride over any substantial obstacle. A toothpick in its path can be enough to block it.

The three stepbots shown below use essentially the same hardware. The first (left) one was build on a piece of wood using a solderless breadboard for easy modification. A battery pack can be put on its back. The middle one has its electronics (on a small PCB), the two steppers and a battery pack in a small gray case. Both use 12V steppers from 5.25 inch drives. The right one uses smaller 5V steppers from a small printer. It is not succesfull because the steppers do not deliver enough pull and I could not find a suitable rear wheel.

three stepbots

The essence of a simple Jal program to move the robot is shown below. The delay can be varied to find the minimal step interval which can start the robot. The library procedure stepper_motor_full_forward produces the sequence 0001, 0010, 0100, 1000. Similar procedures are available for half stepping and for stepping backward. The initial values can be changed to 0b_0011 to get a two coil sequence.

   -- a robot that just rides at a constant speed 
   include 16f84_10                         -- define target 
   include jlib                             -- standard libraries 
   var byte left    = 0b_0001               -- start of the stepper sequences 
   var byte right   = 0b_0001               -- " 
   port_b_direction = all_output            -- an input would not help us much 
   forever loop                             -- 
      stepper_motor_full_forward( left )    -- step both sides forward 
      stepper_motor_full_forward( right )   -- " 
      port_b_low  = left                    -- output the new steps 
      port_b_high = right                   -- " 
      delay_1mS( 25 )                       -- 25 mS delay between steps 
   end loop 

A more interesting but still very simple robot follows a line on a piece of paper. I use a black line on white paper. The line is approximately 5 mm wide. The robot is placed on the line before it is started. The main problem is to follow a line which bends abruptly. One sensor could be used, but this requires the robot to sweep left and right to keep locked onto the line. I used two (reflective) sensors.

   -- a robot that follows a line using two sensors 
   include 16f84_10                              -- define target 
   include jlib                                  -- standard libraries 
   var bit left dark at pin_a0                   -- define IO pins 
   var bit right_dark at pin_a1                  -- " 
   var byte left  = 0b_0001                      -- start of the stepper sequences 
   var byte right = 0b_0001                      -- " 
   port_b_direction = all_output                 -- IO direction 
   port_a_direction = all_input                  -- " 
   forever loop                                  -- 
      if ! left_dark then                        -- when left sensor sees white 
         stepper_motor_full_forward( left )      -- step left motor 
      end if                                     -- 
      if ! right_dark then                       -- when right sensor sees white 
         stepper_motor_full_forward( right )     -- step right motor 
      end if                                     -- 
      port_b_low = left                          -- output the new steps 
      port_b_high = right                        -- " 
      delay_1mS( 25 )                            -- 25 mS delay between steps 
   end loop 
line follower

Maze walking is more impressive than line following but also more difficult. (apart from the fact that you will also have to build a maze!). Any connected maze can be walked by following the wall with your left (or right) hand. Using switches to detect collision with a wall seems simple until you try it. A wall will always turn up at an unexpected angle, so a lot of switches are needed or a clever mechanism must allow a switch to be pushed from a wide range of angles. My robots do not have much power, so the switch must also be easy to push. I made a wide angle mechanism from a round piece of PCB material (I would have preferred a flippo but I could not find one). An obstacle in front or to the side of the robot will turn the circle around its axis, closing the switch. This works fine but the robot must keep close to the wall which makes a closed turn difficult and an irregular wall can lock the robot into a corner. A wire sensor like a cockroaches' antenna would probably not have these problems. The things on the picture below that look like Mickey Mouse ears are PCB pieces. The switches have been salvaged from an old VCR.


The most critical part of the software for my maze walker is the part which controls the turning, especially when it must turn left after it has hit its nose against a wall. The software uses feedback from the switches as often as possible to compensate for possible slip between the wheels and the surface. A turn right must not start too soon because the robot would get stuck against the edge of the maze (the sensor is in front of the turning axis of the robot). Apart from these two difficult turns the software just makes the robot follow the wall to its right side. When it senses the wall it steers away from the wall, when it does not sense the wall it steers (a little bit) to the right where it expects the wall. If the wall is lost for a significant time it turns to the right.

   -- a maze-walking robot that follows the wall to its right side
   include 16f84_10
   include jlib
   var volatile bit  right_free  is pin_a3
   var volatile bit  left_free   is pin_a4
   var volatile byte left_motor  is port_b_low
   var volatile byte right_motor is port_b_high
   const byte stepper_initial    = 0b_0011
   var byte left_value           = stepper_initial
   var byte right_value          = stepper_initial
   port_b_direction              = all_output 
   port_a_direction              = all_input

   procedure move( byte in left, byte in right ) is
      while ( left != 0 ) | ( right != 0 ) loop
         if  ( left != 0 ) then 
            if left < 128 then
               stepper_motor_full_forward( left_value )
               left = left - 1
               stepper_motor_full_backward( left_value )
               left = left + 1
            end if      
         end if
         if ( right != 0 ) then
            if right < 128 then
               stepper_motor_full_forward( right_value )
               right = right - 1
               stepper_motor_full_backward( right_value )
               right = right + 1
            end if      
         end if
         left_motor  = left_value
         right_motor = right_value
         delay_1mS( 25 )
      end loop
   end procedure

   var byte n     = 0
   forever loop
      -- frontal hit : turn left
      if ! left_free then
         -- move back to get free from the wall
         move( -100, -100 )
         -- turn a little bit left 
         move( 0, 30 )
         for 3 loop
            -- forward until right sensor hits 
            while right_free loop move( 1, 1 ) end loop
            -- a little bit back to get free from the wall
            move( -10, -10 )      
            -- turn right until left sensor hits
            while left_free loop
               move( 1, 0 )
               move( 1, -1 )
               move( 1, 0 )
            end loop
            -- retreat to make toom for the turn left
            move( -90, -90 )      
            -- turn left
            move( -30, 30 )
         end loop   
         -- retreat to make toom for the turn left
         move( -15, -15 )
         -- turn slowly left until right sensor hits   
         for 75 loop move( 1, 3 ) end loop           
      -- hit right wall
      elsif ! right_free then   
         -- remember & steer away
         n = 0
         move( 1, 2 )
      -- free on both sides
      elsif ( n < 120 ) then   
         -- turn a little to the right
         n = n + 1 
         if ( n & 3 ) == 0 then
            move( 1, 0 ) 
            move( 1, 1 )
         end if     
      -- definitely lost the wall
         -- turn right sharply
         move( 1, -1 )               
      end if
   end loop

The Mickey Mouse robot can walk a maze by following the wall to its right side, but it has its problems. It can get stuck in a corner, it sometimes thinks it must turn right when it actually just wandered a little bit from the wall, and it must make some strange moves to make a left turn (when runs into a wall). This is largely due to the relatively large distance between the front wheels and the real wheel. But it works! Below you can see it crawling its way through a maze. The cloth is needed because the wheels do not get enough grip on my wooden floor. My cats don't know what to think of this oversized mouse.