Trouble with delay in code.

I am creating a drawing machine that uses two continuous rotation servos and an arduino.

I simply want the motors to run the code below for each motor, but there should be a “random” time offset.

To be more specific: There are two “loops” that should be completed separated, but with overlap allowed to occur. After each loop there is a different random pause (between 2 and 10 seconds).

Cycle One

_Motor spins a string with pen attached out 2 foot.
_delay for the amount of time it takes to go 2 feet.
_Motor reverses and brings string back to starting position.
_Random Pause before beginning cycle again. I think I need to use Millis here, as not to disturb Cycle Two, which can be happening simultaneously.

Cycle Two
_Same as cycle one, but on a separate motor.

Here is the code that I have completed, but the delay(randNumber) is stopping the movement of the other motor. The point of my drawing machine is to see how the two motors react to each other, while pulling a pen.

Any ideas? THANKS!!!

#include <Servo.h>

long randNumber;
long randNumber2;

 
Servo myservo; 
Servo myservo2;              
 

 
void setup()
{
  myservo.attach(9); 
  myservo2.attach(10);  
}
 
 
void loop() {
 
  randNumber = random(2000,20000);
  randNumber2 = random(1000,4500);
   
   
   
    myservo.write(50);        // Begin spinning the string out.
    delay(6500);              // Delay needed to reach 2 feet.
    myservo.write(130);       // Begin retrieving the string.
    delay(6500);              // Delay needed to retrieve the string.
    myservo.write(90);        // stop Servo 1.
   
   
    delay(randNumber);        // Servo 1 does nothing for a random amount of time, between 1 and 5 seconds.
   
   
   
    myservo2.write(50);       // Meanwhile, Servo 2 is completing the same 'loop' as servo 1. Independently. Causing some overlap, and interesting patterns to be drawn on the wall.
    delay(6500);
    myservo2.write(130);
    delay(6500);
    myservo2.write(90);
    
    
    delay(randNumber2);
   
   


   
 
}

I think I need to use Millis here

You think correctly. The delay()s have got to go.

Start the motor spinning and record the time. Periodically (every pass through loop), see if it is time to stop the motor. If it is, stop it, and record the stop time.

Periodically (every pass through loop), see if it is time to restart the motor. If it is, start it, and record the start time.

Do the same for the other motor.

Thank you, Paul.

I tried that. It sort of works except I am having two new problems.

  1. I need to reset the millis() counter after each cycle. Is this possible?

  2. The motors have begun to twitch slightly with the new coding.

Is this the best way to use the millis(); ?

Thanks very much

#include <Servo.h>

Servo myservo;
Servo myservo2;

long currentmillis = 0;
long randNumber;
int extend = 5000;
int retract = 10000;
int wait1 = 15000;


void setup() {
  
  myservo.attach(2);
  myservo2.attach(10);
  Serial.begin(9600);
  myservo.write(90);
  myservo2.write(90);
  
  
}


 void loop() {
   
 
 randNumber = random(20000,30000);
 currentmillis = millis(); 
 Serial.println(currentmillis);
 

 if (currentmillis > extend) {
   
   myservo.write(50);

 } 
 
 if (currentmillis > retract) {
   
   myservo.write(130);
 }
 
 
 if (currentmillis > wait1) {
   
   myservo.write(90);

   
 }
 

 
 if (currentmillis > randNumber) {
  
   
   currentmillis = 0;
   
  
 }
 
  
}

Actually, I got it working! Thanks all.

void loop() {
 
 

 
  randNumber = random(200,400);

 
     x = x+1;
     y = y+1;
  //Serial.println(y);
   
    if (y >= randNumber){
      
   
   
    if (x >= 500){
      myservo.write(50);
      //x = 0;
    }
   
     if (x >= 1500){
      myservo.write(130);
      //x = 0;
    }
   
   
      if (x >= 2000){
      myservo.write(90);
       x = 0;
      
    }
   
   
       y = 0;
  
    }

You can't just compare currentmillis, that's the same as comparing millis.

You should calc the time since the last time something was done and compare against that, somethign like this

timeSinceLastAction = millis() - lastAction;

if (timeSinceLastAction > extend) {
   myservo.write(50);
   lastAction = millis();
} 

if (timeSinceLastAction > retract) {
   myservo.write(130);
    lastAction = millis();
}

if (timeSinceLastAction > wait1) {
   myservo.write(90);
   lastAction = millis();  
}

if (timeSinceLastAction > randNumber) {
   lastAction = millis();
}

Rob

Rob, thank you very much.

It seems to be not working. Maybe I have something out of place?

#include <Servo.h> 

long randNumber; 
long timeSinceLastAction;
long lastAction;
int extend;
int retract;
int wait;



 
Servo myservo;  
Servo myservo2;            
 

 
void setup() 
{ 
    myservo.attach(10);  
    myservo2.attach(11);  
    Serial.begin(9600);
    myservo.write(90);
    myservo2.write(90);
} 
 
 
void loop() {
  
extend = 5000;
retract = 10000;
wait = 15000;
  
  randNumber = random(2000,20000);
    
timeSinceLastAction = millis() - lastAction;


if (timeSinceLastAction > extend) {
   myservo.write(50);
   lastAction = millis();
} 
 
if (timeSinceLastAction > retract) {
   myservo.write(130);
    lastAction = millis();
}
 
if (timeSinceLastAction > wait) {
   myservo.write(90);
   lastAction = millis();  
}
 
if (timeSinceLastAction > randNumber) {
   lastAction = millis();
} 
 

 
}
int extend;
int retract;
int wait;

<snip>

extend = 5000;
retract = 10000;
wait = 15000;

Why not combine these?

int extend = 5000;
int retract = 10000;
int wait = 15000;

If these are (going to be) constants, they should be declared as such.

timeSinceLastAction = millis() - lastAction;


if (timeSinceLastAction > extend) {
   myservo.write(50);
   lastAction = millis();
} 
 
if (timeSinceLastAction > retract) {
   myservo.write(130);
    lastAction = millis();
}
 
if (timeSinceLastAction > wait) {
   myservo.write(90);
   lastAction = millis();  
}

If you change the value in lastAction, that has no affect on timeSinceLastAction until the next pass through loop.

You really need to define a state variable, something like action. You are either extending, retracting, or waiting. You don’t want to do all three things at the same time. In each if block, set action correctly. In the if test, determine whether you should do something based on time AND state.

Something like:
if(action == extendAction && timeSinceLastAction > extend)
{
// Extend
action = waitAction;
lastAction = millis();
}

if(action == waitAction && timeSinceLastAction > wait)
{
// Wait
action = retractAction;
lastAction = millis();
}

Paul, thank you for the help. I'm still trying to wrap my head around the millis() timing.

So, I have the constants clarified now (thank you).

long randNumber;
long timeSinceLastAction;
long lastAction;
long action; 

const int extendAction = 5000;
const int retractAction = 5000;
long waitActionServo1;  // This should be random
long waitActionServo2; // This will be random

But i'm still having trouble with the main code. I can't wrap my head around the millis()!

So, the motors should extend for 5000 ms and then retract for 5000 ms, and have different random pauses (between 2 and 20 seconds), causing them to be running offset but still maintaining the 5000 ms extend and retract ( although each will be offset).

I've given the code a shot, but I must say I don't think it's correct. Could you give me another example of how to set the action for each state (retracting, extending, waiting).

Thanks so much. I will figure this out! Thank you for your help.