Stop motor after 3 seconds

I have a code to vibrate a motor when ultrasonic sensor having a object less than 10cm in front of it,
and the motor stops after it is removed.

Now, I want it to vibrate for 3 seconds only, even if the object is not removed, how should I modify my code?
Many thanks in advance!

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 3

int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup() {
 pinMode(motorPin, OUTPUT);
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
 
}

void loop() {
/* The following trigPin/echoPin cycle is used to determine the
 distance of the nearest object by bouncing soundwaves off of it. */ 
 digitalWrite(trigPin, LOW); 
 delayMicroseconds(2); 

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);
 
 //Calculate the distance (in cm) based on the speed of sound.
 distance = duration/58.2;
 
 if (distance >= maximumRange || distance <= minimumRange){
 /* Send a negative number to computer and Turn LED ON 
 to indicate "out of range" */
 Serial.println("-1");
 digitalWrite(LEDPin, HIGH); 
 }
 else {
 /* Send the distance to the computer using Serial protocol, and
 turn LED OFF to indicate successful reading. */
 Serial.println(distance);
 digitalWrite(LEDPin, LOW); 
 }
 if (distance < 10){
   analogWrite(motorPin, 25);
 }
 else {analogWrite(motorPin, 0);
 }
 //Delay 50ms before next reading.
 delay(50);
}

Look at the technique in the Blink Without Delay example sketch. And there is a longer demo in several things at a time.

Basically, record the time (millis() ) when the motor is turned on and switch it off then the later time exceeds the initial time by 3 seconds (3000 millisecs).

...R

You could try this..

Go here : https://github.com/leftCoast/Arduino/tree/master/libraries/LC_baseTools

Grab the bottom two source files timeObj.h & timeObj.ccp

You can put them in your sketches folder then restart your sketch.

On the top of your sketch add..

#include "timeObj.h"

Before your setup() we'll add a few bits.

timeObj motorTimer(3000);      // A 3 sec. timer for the motor
boolean weBeShakin = false;     // A boolean to keep track if the motor's running' or not. It aint.


// A routine to turn on the motor.
void motorOn(void) {
   
   // *** Do your stuff to turn on the motor ***
   motorTimer.start();   // Start the timer
   weBeShakin = true;   // Let the world know the motor is runnin'!
}


// A routine to turn the motor off.
void motorOff(void) {

   // *** Do your stuff to shut off the motor ***
   weBeShakin  = false;   // let the world know, de motor is off!
}


// Now the magic bit..
// Call this first in your loop() function.
void checkMotor(void) {   

   if (weBeShakin) {                     // IF the motor's running..
      if (motorTimer.ding()) {     // And IF the time has run out..
         motorOff();                         // Shut off the motor.
      }
   }
}


void setup() {

   // *** your stuff here ***
}


void loop() {

   checkMotor();

   // *** your stuff ***
}

Now, if you fill out and use the motor on and off routines, then make sure the checkMotor() is called in your loop. Your motors should never run longer than your 3 seconds.

Hope this helps!

-jim lee

Code Tags @jimLee Code Tags.

I have to confess I don't see any great advantage with your add-on compared to using millis() directly. See this essay.

And I think it is much better for beginners to learn the simple stuff rather than have it hidden from them in code that must surely be more verbose for no additional functionality.

Another factor is that anyone here can give advice about using millis() but you are the only person who can give advice about your code if the user has problems with it.

...R

Really?! Well that’s too be you feel that way.

-jim lee

jimLee:
Really?! Well that's too be you feel that way.

We can agree to differ in our philosophies about libraries - but that doesn't exempt you from the need to modify your earlier post to put your code within code tags.

...R

Better?

-jim lee

That’s twice today I’ve seen " " in includes not <>.

#include "timeObj.h"

The man page only shows <> so where does this " " come from? The other example I saw earlier didn’t compile until I changed to <>.

jimLee:
Better?

-jim lee

99/100 since you accidentally wrapped one of your text lines inside the tags... :stuck_out_tongue:

#include "timeObj.h"  // Find it in your sketch folder.
#include <timeObj.h>  // Look in your library folder.

I even wrapped it in code tags.

-jim lee

jimLee:

#include "timeObj.h"  // Find it in your sketch folder.

#include <timeObj.h>  // Look in your library folder.

Aha! We live and learn…

Many thanks for the inputs from both experts!

I am pretty new to the world of programming and from what I understand, C++ is not my school grades.

To my best guesswork, cutting and pasting codes into right places, I made a blinking motor without delay.
While it is not my intention, I consider it as a major step. XD

/*
 HC-SR04 Ping distance sensor:
 VCC to arduino 5v 
 GND to arduino GND
 Echo to Arduino pin 7 
 Trig to Arduino pin 8
 
 This sketch originates from Virtualmix: http://goo.gl/kJ8Gl
 Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html
 And modified further by ScottC here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html
 on 10 Nov 2012.
 */

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 3

int motorState = 0;             // motorState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;   

int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup() {
 pinMode(motorPin, OUTPUT);
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
 
}

void loop() {
/* The following trigPin/echoPin cycle is used to determine the
 distance of the nearest object by bouncing soundwaves off of it. */ 
 digitalWrite(trigPin, LOW); 
 delayMicroseconds(2); 

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);
 
 //Calculate the distance (in cm) based on the speed of sound.
 distance = duration/58.2;
 
 if (distance >= maximumRange || distance <= minimumRange){
 /* Send a negative number to computer and Turn LED ON 
 to indicate "out of range" */
 Serial.println("-1");
 digitalWrite(LEDPin, HIGH); 
 }
 else {
 /* Send the distance to the computer using Serial protocol, and
 turn LED OFF to indicate successful reading. */
 Serial.println(distance);
 digitalWrite(LEDPin, LOW); 
 }
 
 unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;  

    // if the LED is off turn it on and vice-versa:
    if (motorState == 0)
      motorState = 25;
    else
      motorState = 0;
  }
 
 
 if (distance < 10){
   analogWrite(motorPin, motorState);
 }
 else {analogWrite(motorPin, 0);
 }
  }

I am really new to programming, and I think if I somehow modify this part:

 unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;  

    // if the LED is off turn it on and vice-versa:
    if (motorState == 0)
      motorState = 25;
    else
      motorState = 0;
  }

I should be able to stop the motor after it runs for 3 seconds, until the ultrasonic sensor pick up something again.
BTW, is there any resources for newbies to understand programming quickly?

This isn’t tested but I wanted to show you how to run for 3 seconds; it is in the runMotor() fuction.

I broke out the too far and too close conditions to help you simplify and better understand.

if the motor is running, bringing an object out of range and then back into range will restart the 3 second trigger, extending its ‘on’ time

check it out and see if it does what you want.

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 3
//
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
long interval = 1000;
boolean lastTrip;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
int triggerDistance = 10;
//long duration, distance; // Duration used to calculate distance
//
void setup() 
{
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}
//
void loop() 
{
  long distance = getDistance();
  if (distance > maximumRange)
  {
    Serial.println(F("Too Far!!"));
    digitalWrite(LEDPin, HIGH); 
  }
  if (distance < minimumRange)
  {
    Serial.println(F("Too Close!!"));
    digitalWrite(LEDPin, LOW); 
  }
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
}
//
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//
void runMotor()
{
  if( millis() - startTime < 3000UL) // Three Second Interval
  {
    analogWrite(motorPin, 25);
    //or digitalWrite(motorPin, HIGH);
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}

BulldogLowell:
This isn’t tested but I wanted to show you how to run for 3 seconds; it is in the runMotor() fuction.

I broke out the too far and too close conditions to help you simplify and better understand.

if the motor is running, bringing an object out of range and then back into range will restart the 3 second trigger, extending its ‘on’ time

check it out and see if it does what you want.

Many thanks for your help!!

It fits my situation and I can stop the motor. XD

I did some modifications, so that motor stops immediately when SR04 is far enough.
Also, I added a delay function hoping to reduce the power consumption by SR04.

Please kindly refer to my revised code, I tried to break it into small bits and try to understand the logic behind:

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 3
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
long interval = 1000;
boolean lastTrip;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 10; // Minimum range needed
int triggerDistance = 10;
//long duration, distance; // Duration used to calculate distance
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//////////////////////////////////////////////////////////////////////////////////
void runMotor()
{
  if( millis() - startTime < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 25);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  long distance = getDistance();
  if (distance > minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, LOW); 
  }
  if (distance < minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, HIGH); 
  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
if (distance > triggerDistance)
{analogWrite(motorPin, 0);
motorState = 0;
}
delay (500);
}

I would like to add some more conditions, though.
I want the motor to vibrate more vigorously depending on the distance.

Say, using analogWrite function,
I want the motor to vibrate at 25 when distance is 20cm for 500ms.
Vibrate at 100 when distance is 10 cm for 2 seconds
Vibrate at 255 when distance is 5cm for 5 seconds

Many thanks in advance!

Regarding to power consumption, I have heard the power consumption for Arduino nano is 20mA, and SR04 is 15mA.
So, if I use a 5V 6000mAh power bank to power it, can I say it can run for 6000 / (20+15) = 171 hours, assuming the motor will not vibrate throughout the whole duration?

I am thinking a sleep mode and wake arduino via a tilt switch, I would like to know whether it is worthwhile...some commented it does not really save a lot of power. My device will be active only for 1~2 hours per day.

My device will be active only for 1~2 hours per day.

Why not turn it off when not in use?

No, a 6000 mAh battery will not last 171 hours. First, batteries tend to discharge on their own when not in use. Second, the voltage supplied by the battery will drop, too. At some point, before the 171 hours are up, the voltage will be too low to be usable.