Non-blocking code help - timeline is attached

in the void startSequence() function?

void startSequence()
{
  unsigned long currentMillis = millis();
  
  for(uint8_t x = 0; x < 9; x++)
  {
    // Is this solenoid active
    if (mySolenoids[x].startTime < currentMillis && mySolenoids[x].stopTime > currentMillis)
    {
      // Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        // Turn off solenoid
        // Calculate nextPulseStart & nextPulseStop
      }

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
         // Turn on solenoid           
      }
    }
  }

Yes.

What should it be? I can't figure it out

I've given you 90% of the solution... surely you can do some work yourself and figure out the rest?

You are right.
How is my try:

void startSequence()
{
  unsigned long currentMillis = millis();
  
  for(uint8_t x = 0; x < 9; x++)
  {
    // Is this solenoid active
    if (mySolenoids[x].startTime < currentMillis && mySolenoids[x].stopTime > currentMillis)
    {
      // Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        digitalWrite(mySolenoids[x].pin, HIGH);
      }
      if((mySolenoids[x].pin == HIGH) && ((currentMillis + PULSE_LENGTH) >  mySolenoids[x].startTime))
      {
        digitalWrite(mySolenoids[x].pin, LOW);
      }

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
         // Turn on solenoid           
      }
    }

edit: I try the following code with LED (for the moment speaking as I don't have the solenoids yet) and not led is lashing

#define NUM_SOLENOIDS 2
uint8_t const PULSE_LENGTH = 50;

struct Solenoid
{
  unsigned long startTime;       // The time this solenoid is first active
  unsigned long stopTime;        // The time this solenoid becomes inactive
  unsigned long minPulse;        // The minimum time the next pulse is generated
  unsigned long maxPulse;        // The maximum time the next pulse is generated
  unsigned long nextPulseStart;  // The time of the next pulse starts 
  unsigned long nextPulseStop;   // The time of the next pulse  stops
  uint8_t pin;
};

Solenoid mySolenoids[NUM_SOLENOIDS]= { 50000,  600000, 5000, 10000, 0, 0, 2,
                           90000, 1200000, 9000, 25000, 0, 0, 3};



void setup()
{
   for (uint8_t i=0; i < NUM_SOLENOIDS; i++)
  { 
    pinMode(mySolenoids[i].pin,OUTPUT);

  }
  
}

void loop()
{
  startSequence();
}


void startSequence()
{
  unsigned long currentMillis = millis();
  
  for(uint8_t x = 0; x < 9; x++)
  {
    // Is this solenoid active
    if (mySolenoids[x].startTime < currentMillis && mySolenoids[x].stopTime > currentMillis)
    {
      // Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        digitalWrite(mySolenoids[x].pin, HIGH);
      }
      if((mySolenoids[x].pin == HIGH) && ((currentMillis + PULSE_LENGTH) >  mySolenoids[x].startTime))
      {
        digitalWrite(mySolenoids[x].pin, LOW);
      }

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
         // Turn on solenoid           
      }
    }
  }
}

What do you think this comment means?

Each solenoid has 2 variables (nextPulseStart & nextPulseStop) that determine the timing of the next pulse.

You need to calculate these based on the current time and a random number based on minPulse & maxPulse.

STOP AND THINK FOR A MINUTE!

// Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        
        // Turn off solenoid
        digitalWrite(mySolenoids[x].pin,LOW);
        
        // Calculate nextPulseStart & nextPulseStop
        mySolenoids[x].nextPulseStart = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse) + currentMillis;
      }
      

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
        //turn on solenoid
         digitalWrite(mySolenoids[x].pin, HIGH);           
      }

can't figure what I'm doing wrong

Better. Don't forget to calculate nextPulseStop as well.

For testing I would be writing everything out to the Serial Monitor.

if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        
        // Turn off solenoid
        digitalWrite(mySolenoids[x].pin,LOW);
        
        // Calculate nextPulseStart & nextPulseStop
        mySolenoids[x].nextPulseStart = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse) + currentMillis;
        mySolenoids[x].nextPulseStop = currentMillis - (mySolenoids[x].nextPulseStart + PULSE_LENGTH);
      }
      

Nope. Think about it. When does the pulse stop? You have just calculated nextPulseStart.

mySolenoids[x].nextPulseStop = currentMillis - PULSE_LENGTH;

This?

Come on... you are really not helping yourself here.

The pulse starts at nextPulseStart. It runs for PULSE_LENGTH.

Finish = Start + duration.

make sense.

 if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        
        // Turn off solenoid
        digitalWrite(mySolenoids[x].pin,LOW);
        
        // Calculate nextPulseStart & nextPulseStop
        mySolenoids[x].nextPulseStart = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse) + currentMillis;
        mySolenoids[x].nextPulseStop = mySolenoids[x].nextPulseStart + PULSE_LENGTH;
      }
      

edit: the above code is not working. where my mistake is at?

How can I print the time to the Serial Monitor at a specific intervals?
I did the following that seems not to work:

 unsigned long currentMillis = millis();
  unsigned long preMillis = 0;
  unsigned long interval = 1000;
  
  if((currentMillis - preMillis) >= interval)
  {
  preMillis = currentMillis;
  Serial.println(currentMillis);
  }

I have a detail question:

As far as I understand the timeline in post one it describes a sequence

For example after 1:30 of solenoid 1 doing pulsing
solenoid 2 is joining doing pulsing too
after 3:00 of solenoid1 doing pulsing
solenoid 3 is joining doing pulsing too

This means it must be 101% sure that solenoid2 starts only its own pulsing when solenoid1 has been pulsing for 1:30.

Does your code make sure that this is happening this way?
With having a quick look this seems to be not really sure.
It should work as long as none of the timing-values is set to a false value
but if one of the timing values is assigned a wrong value things start to drift apart.

So IMHO a step-chain (a state-machine) would be better suited to ensure that things stay coupled to each other

And what shall happen if the button is pressed after 1:00 or after 8:00 which means somewhere in the middle of the sequence?

Shall the code stop all pulsing
or shall the code go on and not react on the button-press?

best regards Stefan

one way of doing this is using this macro

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a 
// Serial.print is executed

if your original code works or not depends on where have you inserted this code
so post the complete sketch
best regards Stefan

What does that mean?

Why so you want to do that?

You should be printing out things that help you figure out why it is not working as you expect.

I'm almost done on this one... you don't seem to grasp any of the concepts being explained.

1 Like

It is working!!

for debug: how can I print the random number generated in this line of code:
but only to print the random number between the min and the max without the currentMillis offset?

mySolenoids[x].nextPulseStart = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse) + currentMillis;
long  startOffset = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse);
Serial.println(startOffset);
mySolenoids[x].nextPulseStart = startOffset + currentMillis;

How can I print the solenoid number that is associate with the 'startOffset' random number that been generated?

I try the following:

long  startOffset = random(mySolenoids[x].minPulse,mySolenoids[x].maxPulse);
        Serial.print("solenoid: ");
        Serial.print(mySolenoids[x].pin);
        Serial.println(startOffset);