it's me, the millis moron

Good Morning (here anyhow)!

I don't know why I am having so much difficulty with this :-[

I don't want this done for me

I will include code that I hoped will turn a servo 0,90,180 degrees and back to 0 again. The servo hosts a ping ultrasound sensor that I query for distance info. All works splendidly when I use the irksome delay command. However when I try to implement millis timing I have problems.

Perhaps if someone could look at this they would see where my logic fails. I am trying to follow advice I've been given but I just don't seem to understand how to implement it.

In the example, the code for the 0 degree position is what I would like to do (millis timing?). The next sections of code (for 90,180) have been left the way I originally wrote it (meaning copied and pasted) to help explain what I am trying to accomplish.

#include <Servo.h> 
#include <Ping.h>

Ping ping = Ping(8,74,19);
Servo myservo;  // create servo object to control a servo 

unsigned long currentTime = 0;
unsigned long previousTime = 0;
int pos = (0);    // variable to store the servo position 
int outputPin = 12;
int outputPin2 = 13;
int outputPin3 = 11;

void setup() 
{
Serial.begin(9600);  
myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
pinMode(outputPin, OUTPUT);
pinMode(outputPin2, OUTPUT);
pinMode(outputPin3, OUTPUT);
} 

void loop() 
{ 
  
  currentTime = millis(); //get current time?
  unsigned long millisPassed = currentTime-previousTime; 

  //declare a variable = current time - previous
  
  ping.fire();
  Serial.print("Microseconds: ");
  Serial.print(ping.microseconds());
  Serial.print(" | Inches ");
  Serial.print(ping.inches());
  Serial.println();

         
    myservo.write(0); //turn servo to 0 degrees 
    Serial.print(0);  //print 0 
    Serial.println(" "); //print space
    if (millisPassed >= previousTime +1500) 

//if time passed is greater than or equal to
//previous time plus 1500 milsec then...
   
    digitalWrite(outputPin2, HIGH);  // turn on light at pin2
    if (millisPassed >= previousTime +35) 

 //if time passed is greater than or equal to
 //previous time plus 35 milsec then...
    
digitalWrite(outputPin2, LOW);  // turn off light pin2
     
                                  
    myservo.write(90);              
    Serial.print(90);
    Serial.println(" ");                         //the next examples work 
    digitalWrite(outputPin3, HIGH);     //as written
    delay(1000);
    digitalWrite(outputPin3, LOW); 
    delay(35);                        
                                 
    myservo.write(180);               
    Serial.print(180);
    Serial.println(" ");
    digitalWrite(outputPin, HIGH); 
    delay(1000);
    digitalWrite(outputPin, LOW); 
    delay(35);
                                 
    myservo.write(90);              
    Serial.print(90);
    Serial.println(" ");
    digitalWrite(outputPin3, HIGH); 
    delay(1000);
    digitalWrite(outputPin3, LOW); 
    delay(35);                        
  
}

You never update "previousTime", so it will always be zero - could this be part of your problem?

Hi, on this line you calculate the difference in time:
unsigned long millisPassed = currentTime-previousTime;

then you go and use it here:
if (millisPassed >= previousTime +1500)
"previousTime" is not needed again, you have already subtracted it.

for me, I draw myself a timeline diagram...

previousTime
--------------->
currentTime
----------------------------->
millisPassed
<------------>
1500
<----------------------->

get the picture :wink:
(then I think you have more to do)

Maybe this will help. millis() returns the number of milliseconds since the Arduino was reset.

So, on the first pass through loop, currentTime will have a very small value. Let's say that it is 25. (It might be smaller or larger, but since the times are all relative, the absolute value doesn't really matter.)

millisPassed will be set to currentTime minus previousTime (currently 0), so let's says it gets 25.

You get the ping thing to do its thing. The, you set the servo to position 0. Should this be done every time?

Next, you test whether millisPassed is greater than previousTime + 1500. millisPassed is 25. previousTime is still 0. 25 is not not greater than 1500, so the output pin is not turned on.

Next, you test whether millisPassed is greater than previousTime + 35. millisPassed is 25. previousTime is still 0. 25 is not not greater than 35, so the output pin is not turned off.

The other servo moves occur, along with the delays, and loop ends.

It's called again. millis is called again, and the results stored in currentTime. There were 4,005 milliseconds of delays, along with the time taken to execute the instructions in the previous pass through loop. So, lets say that the previous pass took 4030 milliseconds to execute. currentTime now contains 4055.

previousTime hasn't changed, so millisPassed is set to 4055.

The ping thing again does its thing, and the servo is positioned at 0.

The value in millisPassed (4055) is compared to previousTime (still 0) + 1500. This time, millisPassed is greater, so the digital pin is turned on.

The value in millisPassed (4055) is compared to previousTime (still 0) + 35. It should be obvious that this is true, so the digital pin is turned off.

The rest of loop executes, and loop ends. It's called again and again and again. The value in currentMillis keeps incrementing, by 4,000+ each pass, but previousTime never changes, so the digital pin will be turned on and (nearly) immediately turned back off on every pass.

This is clearly not what you want to have happening. What is less clear is what you do want to have happen.

For instance, what is the purpose of moving the servo? What is connected to the output pins? When happens when the output pins are set high for one second? What do you intend to do with the ping sensor output?

I'm sure we can help you with your understanding of millis, and it's applicability to your situation, if we understand what you are trying to do.

Thank you! You have all added enough for me to go back and try again. However, I haven't made my goals well understood and I can add that before I go back to beating my head against the bench.

This is all aimed at obstacle avoidance for my living room bot.

  1. I want the servo to move 0,90,180, and back to 0 degrees

  2. I want to take a distance measurement at each point and I understand that the way it's written I will only get ping info once (instead of at each of the positions) I was going to approach that after I got the timing thing worked out.

  3. The distance information from each position will be compared to determine if I am 12 inches or closer to an object? If yes move in the direction that will allow the most unobstructed movement (compare the three and take the largest distance ping).

I will be back to let you know how I did with your current suggestions. Thanks again!

As said, you never set the previousTime variable, should be handy to give it the value of currentTime when you are done getting millisPassed (since you won't need previousTime anymore, you allready know the time that has passed since the previous call).

If you want to go from 0 to 90 to 180, you might have to use a contraption called a 'state machine'.
Simply put... a single variable that holds a value.
Lets say, an int.
If the state is 0, the sensor is at 0 degrees, perform the ping, set the servo to 90 degrees and set the state to 1, make it wait to ensure the servo is at 90 degrees before it is allowed to enter the state machine again.
If the state is 1, the sensor is at 90 degrees, perform the ping, set the servo to 180 degrees and set the state to 2, make it wait to ensure the servo is at 180 degrees before it is allowed to enter the state machine again.
If the state is 2, the sensor is at 180 degrees, perform the ping, set the servo to 0 degrees and set the state to 0, add logic based on the three measurements and you should be ready to go.

Keep in mind that this 'state machine' (leaving it up to you to implement code-wise) shouldn't be accessed continuesly, only if it detects that an object is too close.
I'm assuming for the moment you don't have issues constructing something to handle that.

The 'make it wait' can be done in many ways... my favourite:
wait = 500; //500 milliseconds is half a second, should be plenty for 90 degrees of servo movement.
If it is in the state machine part, subtract millisPassed from wait, if it is equal to or less than 0, the wait is over, and you can continue into the actual state machine.

PS: these sort of constructs are obviously a lot more complex than generic messing with millis() ::slight_smile:

Good morning again,

Yes, Groove and Grumpy Mike helped me with 'machine state' and I managed to extend some of what they taught me. I had hoped to continue to add states and call them when needed but after a time I seem to have lost track of my own progress. I know, not too impressive.

A personal tragedy is effecting my ability to concentrate at the moment. I hope we will be able to pick up where we left off in a day or two. You have been very helpful and when I return I hope to have some examples of what I've learned with your help.

Thanks again and sorry for the interruption.

No worries, I (since I can't speak for others :wink: ) will still be here another while, at the least.
Feel free to take a break, forum posts don't run away, not unless the moderators or admins do so........
nah, I'm sure they'll behave ;D

hi im strugaling to get my arduino to type a key on the computer. i am new at using arduinos and i hear there are multaple steps involved but i dont have the slightest idea how to go about doing this. any code, info, tips would be helpfull. thanks.

@jbbiz
How does your issue relate to millis? That's the topic of this thread. If you have a related comment, problem, or solution, then add it to the thread.

If you have some completely different problem, start your own thread. You are much more likely to get relevant answers.