Programming a laser

Hello, I'm trying to trigger a laser from another program using the arduino.
Essentially, the arduino receives a pulse from this other program (from a TTL converter) and the arduino then executes some code, which triggers a laser every 10 minutes for 1 second at 10hz. I'm trying to write non-blocking code so I'm not using the delay function. I'm, however, having trouble triggering the laser. Here's the code:

//COM4


int switchState_Cue = 0;
int cueState_Retrieval = 0;
int reset_Millis_Stop = 0;
int reset_start_Laser = 0;
int reset_startoffperiod = 0;
int reset_realLaser = 0;

long sessiontime;
long sessiontimestart;
long sessiontimestop;
long totalsessiontime; 
long currentMillis;
long stopLaser;
long laserlimit;
               
long startoffperiod;               
long endoffperiod;              
long startLaser;           
long endLaser;
long realLaser;

unsigned long Millis_start = 0;
unsigned long Millis_stop = 0;

void setup() {
  
  // put your setup code here, to run once:
  
 
  pinMode(3, OUTPUT); //Laser output
  pinMode(2,OUTPUT); //LED output
  pinMode(12,INPUT);//Cue input
  pinMode(11,INPUT);//Second cue input from another program (TTL converter).
 
  
  laserlimit = 1000; //laser will stop after 1 second 
  sessiontime = 4200000; // 1hour 10min
  
  Serial.begin(9600);
  
  digitalWrite(2, HIGH);
  delay(2000); 
  digitalWrite(2, LOW);

   
  digitalWrite(3, LOW);
  delay(0);
}

void loop() {
       
  switchState_Cue = digitalRead(12); // First time cue goes off, that's when session begins.
  
  reset_Millis_stop = reset_Millis_stop +1; //resetting millis.
 
  if (switchState_Cue == HIGH) {
           sessiontimestart = millis();  //
           
          if (reset_Millis_stop> 0){
            Millis_stop =millis();
            x = x-1;
          }
           digitalWrite(2, HIGH); // this is just pulsing the LED, to make sure that the system is working still.
        
       while (currentMillis - sessiontimestart < sessiontime){
        
          if ((Millis_start - Millis_stop) >= 10000){   // Trying to pulse the laser every ten seconds.
              reset_realLaser = reset_realLaser+1;
              Millis_stop = Millis_start;
                 
                reset_start_Laser = reset_start_Laser+1;
                reset_startoffperiod = reset_startoffperiod+1;
               
                digitalWrite(2,LOW); //checking the code with LED.


 
                if (reset_realLaser>0){
                realLaser = millis();
                       reset_realLaser = reset_realLaser - 1;
                }
                
                      while ((byeLaser - realLaser) <= laserlimit){  // Every ten seconds, the laser should go off for 1 second (from laserlimit function).
                          if (reset_start_Laser>0){
                             startLaser = millis();
                             reset_start_Laser = reset_start_Laser-1;
                          }

                          while ((endLaser - startLaser) <= 10){ // Trying to write the laser on HIGH for 10 milliseconds.
                              digitalWrite(2,HIGH);
                              digitalWrite(3, HIGH); // 10hz laser ON
                              endLaser = millis();
                          }
                          
                                if (reset_startoffperiod>0){
                                   startoffperiod = millis();
                                  reset_startoffperiod = reset_startoffperiod-1;
                                  }
                                  
                              while(endoffperiod-startoffperiod <= 90){  // Trying to write the laser on LOW for 90 milliseconds. Combined with the above, for 1 seconds, the laser should be turned on.
                                  digitalWrite(2,LOW);
                                  digitalWrite(3,LOW);
                                   endoffperiod = millis();
                              }
                              
                     byeLaser = millis();
               
                      }  
             }
          Millis_start = millis();
        }
        
           

  }
  
        if (currentMillis - sessiontimestart >= sessiontime){  // Checking to see if session time is up, in which case, session ends.
           Stopsession();
        }
        
        cueState_Retrieval = digitalRead(11);  // This is relevant for another part of the project, where I'm getting an input from a TTL converter. I  need to know when that happens.
        
        if (cueState_Retrieval == HIGH){
          retrieved();
        }
          
    currentMillis = millis();
   
}

void retrieved() { // Again, just trying to write down when I'm getting a pulse from another program.
               
               Serial.print("Retrieved at time...");
               Serial.println((currentMillis+10000)-sessiontimestart);
               
                }
                   
void Stopsession() {
              
                  digitalWrite(2, LOW);
                    sessiontimestop = millis();
                    totalsessiontime = sessiontimestop - sessiontimestart;
       
                      Serial.print("Total Session Time...");
                      Serial.println(totalsessiontime);
                
                      Serial.end();
           }
      

Does this mean you already know how to trigger your laser and have thoroughly tested that code and it works as you want?

1 Like

it is not about delay(), it is about not using blocking constructions of any kind,

Your code is pretty cryptic.

If you were to choose informative names for variables (instead of "x") and add some comments to the code, you might be able to remember what you did and why, six months from now.

what? do you mean USB-to-UART converter?

is this one way program?

Apologies! I tried to annotate and explain some bits, hopefully makes it easier to read. Thanks for your help!

Ah, it's a simple output converter (kind of like an arduino actually, but can only send outputs). I work in a lab with behavior equipment so it's kind of a niche system.

Yeah, exactly, I'm trying to sync this code with the other program (the output converter). So I need to make sure timing is perfect.

So I sort of misspoke maybe. I already tested the code in a very basic sense with a delay function, and it works like a charm. As such:


  if (switchState_Cue == HIGH) {
     
           sessiontimestart = millis();
              digitalWrite(2, HIGH);
              
               while (currentMillis - sessiontimestart < sessiontime) {
                       
                       digitalWrite(3, HIGH); // 10hz laser ON 
                       delay(10);
                       digitalWrite(3, LOW);
                       delay(90);
                       
                      
                       currentMillis = millis();
               
        }
       digitalWrite(2, LOW);

so, why you think you must not using this working code?

Then what is the problem?

1 Like

Because the working code doesn't solve the issue. I need to have the code be non-blocking, so that it's precisely synced with the output converter. So when the session is pulsed to start from the output converter (as in, "if (switchState_Cue == HIGH) " from first line of code), the two programs are synced in time.

But, you only describe the initial conditions. What keeps the two in sync over time?

Non-blocking, every 10 minutes, pulse a LASER at 10hz for 1 second.

Here is a simulation using 3 seconds interval in place of 10 minutes interval and assumes 50% duty cycle for the 10Hz LASER pulses.

// https://wokwi.com/projects/368931699398868993
// https://forum.arduino.cc/t/programming-a-laser/1143111

// unsigned long interval[] = {600000, 100}; // [10 minutes, 100 millisecond frequency]
unsigned long interval[] = {3000, 100}; // for SIMULATION, interval is 3 seconds
unsigned long previousTime[] = {0, 0}; // clear two event timers
unsigned long currentTime; // use for all intervals
bool intervalOccurred[2]; // interval occurred flags

int LASERpin = 3;
int LASERstate = LOW; // LASER off
int pulseCount = 0; // count 10 LASER pulses

void setup() {
  Serial.begin(115200);
  welcome();
  pinMode(LASERpin, OUTPUT);
}

void loop() {
  unsigned long currentTime = millis(); // update "now" time for all intervals

  if (currentTime - previousTime[0] >= interval[0]) { // 10 minutes interval
    intervalOccurred[0] = true; // this interval occurred
    previousTime[0] = currentTime; // establish new start time for this interval
  }

  if (intervalOccurred[0]) { // at 10 minutes interval
    // Serial.print(LASERstate);
    if (currentTime - previousTime[1] >= interval[1] / 2) { // 50% duty cycle of 10hz/100ms
      previousTime[1] = currentTime; // interval occurred, establish new start time for this interval
      LASERstate = !LASERstate;
      digitalWrite(LASERpin, LASERstate); // turning LASER ON and OFF
      Serial.print(LASERstate); // printing LASER ON and OFF 
      if (pulseCount++ == 9) { // 10 pulses only
        Serial.println(" <-- 10Hz (50% duty) 1 = LASER ON 0 = LASER OFF");
        pulseCount = 0; // reset pulse count
        LASERstate = 0; // reset LASER state so first pulse is ON
        intervalOccurred[0] = 0; // clear 10 minutes interval flag after 10 LASER pulses 
      }
    }
  }
}

void welcome() {
  Serial.print("Every 10 minutes, pulse a LASER at 10hz for 1 second. ");
  Serial.print("For this simulation, interval is set to 3 seconds.");
  Serial.println();
}

Haha what I'm hoping for is that if i use non-blocking code, then it will be synced 'enough' that the code will be off only milliseconds worth. It doesn't have to be perfectly synced per se, as long as I can get an error of +/- 1 second. I'm a biologist by training so all of this is quite new to me.

Did you not have a physics class that dealt with pendulums and synchronizing them? Energy MUST be expended to keep one in time with the other. Same applies to ANY other system, including computer systems. There must be a master and a slave situation where something must be done to the slave to make it match the time of the master. Hope is not one of the options!

Thanks I appreciate this! So then, but how would you recommend me going about solving this issue of syncing both systems then.

Just continue with this scheme. The slave system will have to WAIT for the next sync pulse, just as it must wait for the begin pulse. The timing of the pulses will have to be determined by experimenting.

If I understood this, I could possibly help, but...