pulseIn for detecting CO2 laser status

Hello,
I'm trying to use pulseIn to determine if my CO2 laser is firing (aka cutting material) or if it's off. I realize it's a pulse timer but I was hoping to leverage it in a function to determine an on/off state. The code I currently have is below. It currently outputs "laser on" for every pulse received, which turns out to be allot. When pulses are not received its says "laser off" or after the pulseIn timer times out, which is 3 seconds, but then it repeats "laser off" every 3 seconds which I don't want. I only need it to serial print when the laser goes "on" or the goes "off" once.

Ideally I would like the code to function like this-

A) Serial print "laser off" when the Arduino initially boots up - as a default status outside of the main loop.
B) Main loop, function#1 - If a pulse is received (aka the laser starts firing), serial print once "laser on" until pulses cannot be detected. I'm fine with a 3 second timeout, if pulses are not being sent.
C) Main loop, function#2 - If no laser is detected, serial print once "laser off" and wait for another pulse to be detected.

Any and all help is greatly appreciated!


byte PWM_PIN = 3;
 
int pwm_value;
int x;
 
void setup() {
  pinMode(PWM_PIN, INPUT);
  Serial.begin(115200);
}
 
void loop() {
  {
  pwm_value = pulseIn(PWM_PIN, HIGH);
  //Serial.println(pwm_value);
  x = pwm_value;
}

if(x > 0) //if pwm_value (time) is larger than 0 consider it on.
    Serial.println("LASER ON");
  else{ 
    Serial.println("LASER OFF"); //if no pulse is received or times out print laser off.
  }
}

Hi @the-dude
try this sketch:

byte PWM_PIN = 3;

int pwm_value;
int x;
bool flagOn = false;
bool flagOff = false;


void setup() {
  pinMode(PWM_PIN, INPUT);
  Serial.begin(115200);
}

void loop() {
  {
    pwm_value = pulseIn(PWM_PIN, HIGH);
    x = pwm_value;
  }

  if (x > 0) //if pwm_value (time) is larger than 0 consider it on.
  {
    if (flagOn == false)
    {
      Serial.println("LASER ON");
      flagOn = true;
      flagOff = false;
    }
  }

  else
  {
    if (flagOff == false)
    {
      Serial.println("LASER OFF"); //if no pulse is received or times out print laser off.
      flagOff = true;
      flagOn = false;
    }
  }
}
}

Nice, clever simple use of a blowtorch to cut butter.

Srsly, I love it.

Check this out:

Give it a try and come back for help if you need to, you probably got this…

a7

Or just let someone else write the whole thing for you!

a7

Hi @ruilviana,
Thank you for offering to help. I tested the code you suggested. It works but only addressed half of the challenge I am facing. My laser sends pulses rapidly so the serial print repeats "laser on" and "laser off" after every pulse. Is there a way to add in additional functionality that only displays "laser on" at the start of a pulse and waits until no other pulses are detected (perhaps a 3 second window) before triggering the "laser off" serial print?
Thanks again for all your help!
-Ry

alto, I haven't dabbled in arduino coding for some time. The person who answered the "how to print serial only once in a loop" didn't really explain the solution and I'm having a hard time deciphering the suggested code. Can you explain or provide me with the example integrated into my code? My original code should work with his proposed solution, I'm just having trouble understanding it. Thanks a bunch.

I can try but TBF I am confused by the signals from the laser.

  1. When the laser is ON, what is the frequency and duty cycle of the pulse you are exploiting for you monitoring program? If it is variable, state the range for both parameters.

  2. The default time out of pulseIn is 1000 mS, 1 second, so where is the 3 seconds coming from?

  3. I assume when the laser is OFF there are no pulses.

  4. How long should a period of no pulses last before we find that it is time to say "LASER OFF"?

  5. I assume the return of any pulse would merit the immediate announcement of "LASER ON".

Give the best answers to those questions; it will help us help you or fix the code already provided you or write it from scratch.

It is a reasonably trivial program, but as you can see the real issue is being thorough in your description and circumstances. So true always.

Sry if it could all be gleaned/guessed/assumed from what you have already written. I don't think what you have said matches what you want or what the two sketches currently provide, so basically I asking you to clean slate this and start from scratch with 1-5 above.

And be patient. There are hungry sharks who will love to write this now;, I do have a life and generally do not write code for anyone, so it may be a minute before you have something to think about or test!

a7

You need State Change Detection, like in the example sketch File->Examples->02.Digital->StateChangeDetection

@alto777 The function of pulsein waits for the pin to go from LOW to HIGH , starts timing, then waits for the pin to go LOW and stops timing - the result is time in mirco seconds. If it has not detected a pulse after 3 seconds it displays a "0". My original code, stripped down to it's basic functionality (pulseIn(PWM_PIN, HIGH), serial prints this-

0
0
0
23
26
27
28
0
0
0

Now, based on what I've just outlined, 0 equals off and anything greater than zero equals on. I added the formula if(x > 0) to to display serial print "laser on" and anything equaling zero is off. It works but it repeats "laser on" for every pulse time detected. I've tried a number of things, like State Change Detection in the example scripts and ruilviana's example but the outputs don't alingn with the 0,0,0,23,26,27,28,0,0,0 (aka off,off,off, laser on, laser on, laser on, laser on, off, off, off) output I was originally getting with just serial printing the results of pulseIn(PWM_PIN, HIGH).

The outputs from state change detection and ruilviana looks like this- laser off, laser on, laser off, laser on, laser off, etc... after every pulse it says laser off. It should be considered consitantly on if a pulse is received within a 3 second window and those code examples aren't behaving like my original code. Here's the state change code I used-


byte PWM_PIN = 3;
 
int pwm_value;
//int x;
int statenow = 0;
int laststate = 0;
 
void setup() {
  pinMode(PWM_PIN, INPUT);
  Serial.begin(115200);
}
 
void loop() {
  {
  //pwm_value = pulseIn(PWM_PIN, HIGH);
  //Serial.println(pwm_value);
  //x = pwm_value;
  statenow = pulseIn(PWM_PIN, HIGH);
}

if (statenow != laststate) {
      Serial.println("LASER ON");
}else{ 
    Serial.println("LASER OFF");
  }
laststate = statenow;
}

I feel like the @ruilviana suggestion would be ideal but it displays a "laser off" after every pulse which I don't want. I just want a single serial print "laser on" and if another pulse is detected within the 3 second window, don't do anything. If a laser pulse is not detected after 3 seconds consider the laser off. If another 3 seconds goes by and there is no pulse, don't do anything since the last "laser off" is still valid.

Your sketch reports "LASER ON" when the pulse time changes and "LASER OFF" when the pulse time stays the same. You want to detect a state change between the OFF state (0) and the ON state (>0) and then report "LASER ON" if the change was from OFF to ON and report "LASER OFF" if the change was from ON to OFF.

Try this:

const byte PWM_PIN = 3;

boolean WasOn = false;

void setup()
{
  pinMode(PWM_PIN, INPUT);
  Serial.begin(115200);
}

void loop()
{
  boolean isOn = pulseIn(PWM_PIN, HIGH) > 0;

  if (isOn != WasOn)
  {
    // State change detected
    WasOn = isOn;

    if (isOn)
      Serial.println("LASER ON");
    else
      Serial.println("LASER OFF");
  }
}

Hi @johnwasser, your code works great when I'm test firing my laser because it's sending one pulse at a time. When I go to run the machine, it sends multiple pulses rapidly, so your codes output is on,off,off,on,off, etc... and I'm talking in less than a second it spits out tons of on and off's. How would I go about enhancing the code to say only display "laser on" if pulses are being sent... if 3 seconds goes by and no pulses are received serial print "laser off" and wait until another pulse is recieved before displaying "laser on" again.

void loop()
{
  unsigned long currentTime = millis();
  static unsigned long lastChangeTime = 0;
  boolean isOn = pulseIn(PWM_PIN, HIGH) > 0;

  // Only change state if the last state change was
  // more than 3 seconds ago
  if (isOn != WasOn && 
      currentTime - lastChangeTime > 3000)
  {
    // State change detected
    lastChangeTime = currentTime;
    WasOn = isOn;

    if (isOn)
      Serial.println("LASER ON");
    else
      Serial.println("LASER OFF");
  }
}

@johnwasser thank you so much for the continued help. I just tested it. Is there any way, after 3 seconds, to avoid it printing "laser off" just because the 3 seconds has passed? The laser is still firing and it sends a "laser off" serial print just because the timer has ended. Maybe a pulse counter could get me where I need to be, something like... count the number of pulses in 3 seconds, if the number of pulses equals zero, then serial print "laser off". If the number of pulses is greater than zero serial print "laser on" BUT if the last serial print was "laser on" do nothing and restart the counter/timer. That way "laser on" isn't being published after every 3 second check.

Maybe this will work. It will wait for up to three seconds for a pulse before declaring the laser as 'off':

const byte PWM_PIN = 3;

boolean WasOn = false;

void setup()
{
  pinMode(PWM_PIN, INPUT);
  Serial.begin(115200);
}

void loop()
{
  // If there is any pulse in the next three seconds, the laser is ON
  boolean isOn = pulseIn(PWM_PIN, HIGH, 3000000UL) > 0;

  if (isOn != WasOn)
  {
    // State change detected
    WasOn = isOn;

    if (isOn)
      Serial.println("LASER ON");
    else
      Serial.println("LASER OFF");
  }
}

Strange... It works great for single pulse test firing but when I go to run a job it rapidly displays on/off/on/off/etc...

When you 'run a job' is the laser ever off for more than three seconds? Is the laser ever on 100%? If the laser is at 100% (never off) the pulseIn() will time out after 3 seconds and will return 0.

No, the laser is never off for more than 3 seconds. It technically never even goes off for 2 seconds. I put a 50 milasecond delay in the loop and so far it's working correctly. I think we were getting some false positives because the laser is firing so fast. The delay seems to have fixed it though. I'm going to test it out a few times before calling it done but THANK YOU so MUCH for all your help.

Nice work.

 'm going to test it out a few times before calling it done

Good idea. When you have it perfect, please post the entire sketch as you guys came up with, TIA.

I'm still trying to figure out the default timeout of pulseIn(), which should be 1 second.

Adding the timeout parameter, I found it to be, well, wrong. In order to get the sketch below to print 60 lines in a minute, I had to us 1400000 us.

What are these, metric system microseconds?

The default (here) times out in ~700 ms, consistent with the factor by which the parameter was incorrect in the sketch I used to test. Measured by the clock on the wall.

So if the 3000000 constant is meant to yield 3 seconds, you should check that. It, too, will neither give you the actual clock on the wall time you think, however well it works in the solution. Because the 3 seconds part is really just "some longish time".

In a critical application, it probably shouldn't be built around pulseIn() at all.

void setup() {
  Serial.begin(115200);
  pinMode(11, INPUT_PULLUP);
}

unsigned int loopCounter;

void loop() {
  unsigned long width = pulseIn(11, HIGH, 1400000UL);
  unsigned long temp;

  Serial.print(loopCounter);
  Serial.print(" "); 

  Serial.println(width);

  loopCounter++;
}

a7

Ick! I tried it with a 2-seconds timeout and the pulseIn() timed out in 1.38326 seconds. The pulseIn() function calculates timing loop iterations based on 16 instruction cycles per loop. It looks like the timing loop is taking only 11 instruction cycles! Multiplying the 2-second timeout value by 16/11ths gets the timeout within 1%.

The pulseInLong() function uses micros() and times out at a hair over 2 seconds. Switching to pulseInLong() should provide a sufficiently accurate 3-second timeout.

@johnwasser Yes, that’s consistently consistent and wildly wrong.

What a PITA it is to test this kind of thing, real time be so slow...

pulseInLong() works. I got a little mixed around and didn’t care enough to take away from my researches which does better at what, nor the impact of interrupts happening or being enabled/disables might be in either.

pulseIn either variety is just not something I think I’d ever use; here it works nicely, though.

a7