Complete parts list:
- Sharp GP2D12 Infrared Ranger (x3)
- Embmega32 Development Board from Futurlec (with programming cable).
- Pololu Dual Serial Motor Controller
- Solarbotics GM7 Motor (x2) with wheels (x2)
- Acrylic sheet from TAP Plastics.
- Solderless breadboard from Radio Shack.
- Screws and spacers from Ace Hardware.
- 2 CDS cells, two resistors (around 4.7kΩ), wire.
- 6 NiMh AA batteries with connectors.
- Tamiya ball caster.
- 7845 5V regulator
The base is built from acrylic sheet. $1/lb from the scrap bin. Cut to shape by scoring the plastic and snapping it. I used a drill (Dremel) to make holes for screws. To hold everything together I used screws, and hot glue. This means that StirFry can be mostly diassembled if needed. However one or two parts needed to be held in place securely and for that I used Gorilla Glue.
My goal was to make a light seeking obstacle avoiding robot. After playing with many fairly complex algorithms I eventually found an simple algorithm in the style of Braitenberg's that behaves remarkably intelligently. Consider the input values from the ADCs to be in the range [0,1] and the motor output to be in the range [-1,1]. Then define
which is a measure of preference for turning right or left. The basic method is to drive the motors by
preference = 3*(leftRanger-rightRanger)-3*(leftEye-rightEye)
With these simple rules the robot is pretty smart. Some extra details are required to make things work well: I filter the inputs from all of the analogue-to-digital converters to eliminate spurious spikes. I used a very simply filter: at each step the output is the average of its previous value and the current input. So if adc(n) reads the input from ADC n and output is the filtered output then the algorithm is simply:
leftMotor = 0.5+0.5*preference
rightMotor = 0.5-0.5*preference
I also applied a threshold to the input from the infrared rangers. If the input is less than 0.15 it is set to zero. Without this it is sensitive to obstacles that are far enough away they are safe enough to ignore. I also clamped things to sensible ranges to make sure the robot didn't travel backwards. One extra thing needed to be added: this doesn't deal with head on collisions. If the front infrared sensor shows that something is within range the robot simply backs up and turns a bit. The direction of turn comes from the preference variable. the preference variable can be viewed like a 4 input neuron in a neural network with weights 3,-3,3,-3. With those weights this robot can seek out a light source even when its path is littered with objects. It seems to intelligently work its way around and between them.
output = 0.5*(adc(n)+output)
/* * Main loop */ float ldist = 0,cdist = 0,rdist = 0; float leye = 0,reye = 0; for (;;) { ldelay(100); ldist = (ldist+adc(LEFT))*0.5f; cdist = (cdist+adc(CENTRE))*0.5f; rdist = (rdist+adc(RIGHT))*0.5f; leye = (leye+adc(LEYE))*0.5f; reye = (leye+adc(REYE))*0.5f; float l = threshold(0.15f,ldist); float r = threshold(0.15f,rdist); float pref = 3*(l-r)-3*(leye-reye); if (cdist>0.2) { set_motor(0,0); ldelay(500); if (pref>0) { set_motor(-0.5f,-1.0f); } else { set_motor(-1.0f,-0.5f); } ldelay(400); } else { set_motor( 0.5f+sigma(pref,0.5f), 0.5f+sigma(-pref,0.5f) ); } }