A basic set of eight small gears orbiting one larger gear powered by a stepper motor and controlled by an ultrasonic sensor. As the range of the sonar pulse increases, so does the speed of the busy box.

Made for the Tech Demo 3 – Mechanics

Code as follows (Modified from my Tech Demo 2 code):

#define TRIG_PIN 8
#define ECHO_PIN 7
#define MAX_DISTANCE 450
#define SOUND_SPEED 34000
#define TIMEOUT (2 * MAX_DISTANCE * 1000000)/SOUND_SPEED
#define DIR_PIN 2 // The direction pin controls the direction of stepper motor rotation.
#define STEP_PIN 3 // Each pulse on the STEP pin moves the stepper motor one angular unit.
#define ENABLE_PIN 4 // Optional control of the driver power.

void setup()
{
pinMode(TRIG_PIN, OUTPUT);
digitalWrite(TRIG_PIN, LOW);
pinMode(ECHO_PIN, INPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN, LOW);
Serial.begin(9600);
}

long ping_sonar(void)
{
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
return pulseIn(ECHO_PIN, HIGH, TIMEOUT);
}

void rotate_stepper(int steps, float speed)
{
// Configure the direction pin on the stepper motor driver based on the sign
// of the displacement.
int dir = (steps > 0)? HIGH:LOW;
digitalWrite(DIR_PIN, dir);

// Find the positive number of steps pulses to emit.
int pulses = abs(steps);

// Compute a delay time in microseconds controlling the duration of each half
// of the step cycle.
// microseconds/half-step = (1000000 microseconds/second) * (1 step/2 half-steps) / (steps/second)
unsigned long wait_time = 500000/speed;

// The delayMicroseconds() function cannot wait more than 16.383ms, so the
// total delay is separated into millisecond and microsecond components. This
// increases the range of speeds this function can handle.
unsigned int msec = wait_time / 1000;
unsigned int usec = wait_time – (1000*msec);

// Print a status message to the console.
Serial.print(“Beginning rotation of “);
Serial.print(steps);
Serial.print(” steps with delay interval of “);
Serial.print(msec);
Serial.print(” milliseconds, “);
Serial.print(usec);
Serial.print(” microseconds.\n”);

// Loop for the given number of step cycles. The driver will change outputs
// on the rising edge of the step signal so short pulses would work fine, but
// this produces a square wave for easier visualization on a scope.
for(int i = 0; i < pulses; i++) { digitalWrite(STEP_PIN, HIGH); if (msec > 0) delay(msec);
if (usec > 0) delayMicroseconds(usec);

digitalWrite(STEP_PIN, LOW);
if (msec > 0) delay(msec);
if (usec > 0) delayMicroseconds(usec);
}
}

void loop()
{
long duration = ping_sonar();
if (duration > 0) {
float distance = (duration * 1e-6 * SOUND_SPEED) / 2;
Serial.print(“Ping: “);
Serial.print(duration);
Serial.print(” usec Distance: “);
Serial.print(distance);
Serial.println(” cm”);
int gearSpeed = min(300, max(distance*2, 100));
rotate_stepper(1000, gearSpeed);
} else {
Serial.println(“No ping.”);
}

delay(30);
}