A lonely clock that speeds up its ticking when it detects an approaching object. Might it be a friend?! The clock can’t tell, it doesn’t get out much.

The build uses a stepper motor controlled by an A4988 tied to the ultrasonic sensor. The speed is determined dynamically by subtracting the distance of the sonar ping from 1000. When the sensor doesn’t see anything within 100 cm of its range, it sets itself to the minimum speed of 100.

This project was inspired in part by the rapidly wagging tail off my dog when I come home.

 

#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 speed = min(100 + distance*5, 900);
rotate_stepper( 100, 1000 - speed);
rotate_stepper(-100, 1000 - speed);
} else {
Serial.println("No ping.");
}

delay(30);
}