Millis() with for loops

So I’m trying to make an autonomous robot with a servo motor swerving with an ultrasonic sensor on it, determining if there’s any obstacles on it.
Upon getting weird glitches and inconsistencies, I researched and saw that the delays in my for loop may be causing unwanted side effects, since I want it to do multiple things at once(driving, swerving, getting distances, determining if there’s an obstacle etc)
I can’t find anything to help me using millis() with for loops.
I want to use this code{

for(i = 45; i < 165; i ++)
  {   
    servo.write(i);

    delay(2);
  }




  
    for(i ; i >= 45; i --)
  {
    servo.write(i);

    delay(2);
  }

but instead of delay(2), I want to use millis.

How would I go about doing this? Nothing I try seems to work! Im sure it’s a very simple solution.

When you want to do the movement, set an enableFlag and start a timer.
When going through a none blocking loop(), when you see the enableFlag set and the timer finished go to a function, make a servo movement, increment a counter, if the counter reaches maximum reset the enableFlag then leave, else restart the timer and leave.

Start by converting the for() into while(). This pulls apart the relevant pieces so we can work on them separately.

const int scanMax = 165;
const int scanMin = 45;
i=scanMin;
while(i<scanMax) {
  servo.write(i);
  delay(2);
  i++;
}

Then turn it into an if(). Remember this is inside loop() so it will get repeated. As I’m writing this step, I realize that I wrote “165” in two places. That makes it a candidate for a named constant.

const int scanMax = 165;
const int scanMin = 45;
if(i>=scanMax ) {
  i = scanMin;
}
if(i<scanMax) {
  servo.write(i);
  delay(2);
  i++;
}

Now we can remove that delay…

const int scanMax = 165;
const int scanMin = 45;
const unsigned long scanInterval = 2; //milliseconds, use a smaller number for a faster scan
static unsigned long lastScanTime;
if(i>=scanMax) {
  i = scanMin;
}
if(i<scanMax && millis() - lastScanTime >= scanInterval) {
  servo.write(i);
  lastScanTime = millis();
  i++;
}

This keeps it scanning “forever”. You may wish to do something different when it reaches the maximum value. Maybe that’s the time you do some calculations or movements and then some other trigger later sets it back to the starting value.

Also, pick a better name for i. That’s appropriate for small for() loop but now it’s vulnerable to mistakes like using i for some other small for() loop elsewhere in the code.

An alternative to using millis() is available depending on the hardware you’re using.

You can use the same timer millis() uses (Timer 0) and set up your own interrupt and handle things specific to your project without otherwise affecting the operation of timer 0 or millis() etc.

You can do this by using a timer 0 compare interrupt. All you need is a couple of lines in the setup() to establish a compare interrupt at some arbitrary value and to add a service handler.

For example, initialize the compare value and enable the interrupt:

void setup() 
{
  ...
  
  //setup a T0 compare interrupt that will happen each millisecond (or close to it...)
  OCR0A = 0xA0;
  TIMSK0 |= _BV( OCIE0A );

and a handler that will be called every time the compare happens (i.e. once every ~1mS):

SIGNAL(TIMER0_COMPA_vect) 
{
  //interrupt serviced once per mS

  ....
  
}//timer compare int

You can set up a timer variable and decrement it in the compare handler. When it reaches zero, set a flag and act on that flag in the main loop.

For example:

#include <Servo.h>

//
#define TIMER_INT         0b00000001
#define DIR_FLG           0b00000010
//
#define SERVO_INTERVAL    2
#define SERVO_POS_MIN     45
#define SERVO_POS_MAX     165
#define SERVO_INIT_DELAY  100

Servo
  servo;

uint16_t
  servo_timer;
uint8_t
  flags;
uint8_t
  servo_pos;

void setup() 
{
  servo.attach(9);  //use whichever pin works for you
  
  //setup a T0 compare interrupt that will happen each millisecond (or close to it...)
  OCR0A = 0xA0;
  TIMSK0 |= _BV( OCIE0A );
  
  servo_pos = SERVO_POS_MAX;
  servo.write(servo_pos);
  flags = 0x00;
  servo_timer = SERVO_INIT_DELAY;
  
}//setup

void loop() 
{
  ServiceServo();

  //do other stuff
  //...
  

}//loop

void ServiceServo( void )
{
  //only move servo when timer flag is set
  if( !(flags & TIMER_INT) )
    return;

  //update servo position
  servo.write(servo_pos);

  //halt ints while updating flags also changed in ISR
  noInterrupts();
  flags &= ~TIMER_INT;
  interrupts();

  //bump position variable up or down, depending on the direction flag
  //if flag is clr, counting down
  //if flag is set, counting up
  servo_pos = servo_pos + (flags & DIR_FLG)?+1:-1;

  //update direction flag at each end
  if((servo_pos == SERVO_POS_MIN) || (servo_pos == SERVO_POS_MAX) )
  {
    //again, halt ints when updating flags
    noInterrupts();
    flags ^= DIR_FLG; //just toggle flag bit with an xor
    interrupts();    
  }//if
    
}//ServiceServo

//Timer Compare interrupt handler
SIGNAL(TIMER0_COMPA_vect) 
{
  //interrupt serviced once per mS
  //decrement counter
  if( servo_timer )
  {
    servo_timer--;
    if( !servo_timer )
    {
      //when it hits zero, set flag
      flags |= TIMER_INT;

      //reset timer
      servo_timer = SERVO_INTERVAL;
    
    }//if
    
  }//if
  
}//timer compare int

In this example I use a flag to know if the count is moving up or down to simplify counting ticks and direction updates.

(Compiled for a Mega2560 but not tried. YMMV…)

MorganS:
Start by converting the for() into while(). This pulls apart the relevant pieces so we can work on them separately.

const int scanMax = 165;

const int scanMin = 45;
i=scanMin;
while(i<scanMax) {
  servo.write(i);
  delay(2);
  i++;
}




Then turn it into an if(). Remember this is inside loop() so it will get repeated. As I'm writing this step, I realize that I wrote "165" in two places. That makes it a candidate for a named constant.



const int scanMax = 165;
const int scanMin = 45;
if(i>=scanMax ) {
  i = scanMin;
}
if(i<scanMax) {
  servo.write(i);
  delay(2);
  i++;
}




Now we can remove that delay...



const int scanMax = 165;
const int scanMin = 45;
const unsigned long scanInterval = 2; //milliseconds, use a smaller number for a faster scan
static unsigned long lastScanTime;
if(i>=scanMax) {
  i = scanMin;
}
if(i<scanMax && millis() - lastScanTime >= scanInterval) {
  servo.write(i);
  lastScanTime = millis();
  i++;
}




This keeps it scanning "forever". You may wish to do something different when it reaches the maximum value. Maybe that's the time you do some calculations or movements and then some other trigger later sets it back to the starting value.

Also, pick a better name for i. That's appropriate for small for() loop but now it's vulnerable to mistakes like using i for some other small for() loop elsewhere in the code.

Thanks so much! The step by step really helped! In a bit, I’m going to try to get it to swerve back in the same way, but if I can’t manage, I’ll reply on here again… Thanks again!!