Marlin: [BUG] Laser turns off when there is no S?? parameter after G0/G1

Created on 9 Aug 2020  路  49Comments  路  Source: MarlinFirmware/Marlin

Bug Description

I am using inline laser control. The inline laser control works as expected, but the laser is turned off when I do a G1 or G0 movement without a S?? parameter. Is this normal? I attached a gcode file. On every M3 S60 command, the laser turns on, but it turns off directly after that on the next G1 movement. When I set the laser power with an inline command, it does stay on during the next move without a S?? parameter. For example:

G1 X5 S60 // laser turns on
G1 X50 // laser stays on

But:

M3 S60 // turns the laser on
G1 X50 // laser turns off

In configuration_adv.h, I have disabled #define LASER_MOVE_G0_OFF. From what I understand, In the second example the laser should stay on untill I use a M5 command or set it to another value.

My Configurations

Configurations.zip

Steps to Reproduce

  • Download Marlin 1.6
  • Configure to use laser control and inline laser control

Expected behavior:

From what I understand, In the second example the laser should stay on untill I use a M5 command or set it to another value.

Actual behavior:

The laser turns offon every G0/G1 movement without a S?? parameter

GCode Example

Example.zip

CNC / Laser

All 49 comments

Looking through the code LASER_POWER_INLINE is incompatible with the old M3 gcode
When LASER_POWER_INLINE you must use M3 I eg M3 S60 I and laser only comes on with first move.

Ahh that's a shame. Do you know which piece of code turns off the laser during the movement after a regular M3 command? I think when I remove that piece of code it will work for me. Thanks!

updated... description not quite accurate enough, not entirely incompatible

Thans for the clarification. Is the laser supposed to turn of after the first move?

So which of the following is right:

M3 S60 I // laser stays off
G1 X5 // laser turns on
G1 X50 // laser stays on

Or

M3 S60 I // laser stays off
G1 X5 // laser turns on
G1 X50 // laser turns off

If possible, I still would like to edit the code so that a regular M3 works and that it does not get turnt off on the next moves, since the software I use does use inline laser control for the infill, but does use the 'normal' (M3 / M5) laser control for the outline.

Thanks again

What software?

LaserGRBL

So basically it not any bug at all, you want a new feature, LaserGRBL compatibility

No, I thought it was a bug. I also tested it using the terminal. I thought the M3 and M5 were supposed to work normally when using inline laser control. That's why I Thought it was a bug. Do you know where in the code the laser gets turned off when moving after a regular M3?

Btw, I am using a slightly modified version of LaserGRBL to make it compatible with Marlin. The inline laser control works perfect, I only thought the normal control was supposed to work even with inline control enabled.

just a small comment, if not a bug but more a feature request then replace [BUG] with [FR] in the title and maybe rephrase the title

the program LaserGRBL does have a marlin mode. am attempting to ascertain what it really means by that..

I do think there are issue with laser support.

In the file M3-M5.cpp I found this block of code:
(Marlin/src/gcode/control/M3-M5.cpp, Line 81 - 99)

#if ENABLED(LASER_POWER_INLINE)
    if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) {
      // Laser power in inline mode
      cutter.inline_direction(is_M4); // Should always be unused
      #if ENABLED(SPINDLE_LASER_PWM)
        if (parser.seen('O')) {
          cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0);
          cutter.inline_ocr_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t)
        }
        else
          cutter.inline_power(cutter.upower_to_ocr(get_s_power()));
      #else
        cutter.set_inline_enabled(true);
      #endif
      return;
    }
    // Non-inline, standard case
    cutter.inline_disable(); // Prevent future blocks re-setting the power
  #endif 

If I understand it correctly, when a M3 command is sent without a 'I', it should go to non-inline mode. However, this does not happen for me and the laser gets turned off when I sent a regular movement.

the fuction inline_disable contains

    // Force disengage planner power control
    static inline void inline_disable() {
      isReady = false;
      unitPower = 0;
      planner.laser_inline.status.isPlanned = false;
      planner.laser_inline.status.isEnabled = false;
      planner.laser_inline.power = 0;
    }

looks good, but in the middle of planner.cpp with no way to avoid this code without disabling LASER_POWER_INLINE is

 // Update block laser power
  #if ENABLED(LASER_POWER_INLINE)
    laser_inline.status.isPlanned = true;
    block->laser.status = laser_inline.status;
    block->laser.power = laser_inline.power;
  #endif

And this is what turns M3 off

Its a right mess... trying to get me head around what the original intent was...

Thanks for the clarification.
I hope that in future updates regular laser control and inline laser control can both work!

can you provide example gcode that uses a mix of features. M3/M5 G1 with S 's etc

Here is an example gcode file
From line 0 to 3724 it creates the infill. This parts works as it should.
From line 3725 to 4256 it should create the outline, but this dos not work as expected.
For example, on line 3727 the laser turns on, but it directly turns off when on the next line when it starts moving.

smiley.zip

I think with LASER_POWER_INLINE enabled, this should happen:

M3 S60 I // laser turns on, inline power is active: planner expects power parameter with every G0/G1 code and adjusts power acoording to planned movement
G1 X5 // laser turns off, as no laser power is given
G1 X50 S50// laser turns on synchronized with movement to X50
M5 // laser off

M3 S60 // laser turns on, inline power is ignored
G1 X5   // laser keeps on at S60, moves to X5
G1 X50 S30  // laser keeps on at S60, ignoring S30 , moves to X50
M5  // laser off

So M3 S60 should disable planner laser power calculation, set laser_inline.power to 0 but should not set unitPower to 0, so in planner will be something like this

block->laser.power = laser_inline.status.isEnabled ? laser_inline.power : unitPower ;

I think with LASER_POWER_INLINE enabled, this should happen:

M3 S60 I // laser turns on, inline power is active: planner expects power parameter with every G0/G1 code and adjusts power acoording to planned movement

G1 X5 // laser turns off, as no laser power is given

G1 X50 S50// laser turns on synchronized with movement to X50

M5 // laser off



M3 S60 // laser turns on, inline power is ignored

G1 X5   // laser keeps on at S60, moves to X5

G1 X50 S30  // laser keeps on at S60, ignoring S30 , moves to X50

M5  // laser off

So M3 S60 should disable planner laser power calculation, set laser_inline.power to 0 but should not set unitPower to 0, so in planner will be something like this

block->laser.power = laser_inline.status.isEnabled ? laser_inline.power : unitPower ;

@chepo92 Thanks for your reply, thats what I thought too, but the last part doesn't work for me like that. During the moves after the regular M3 S60, the laser turns off.

@chepo92 Thanks for your reply, thats what I thought too, but the last part doesn't work for me like that. During the moves after the regular M3 S60, the laser turns off.

Yes, I can replicate it, try that change in the code

@chepo92
I just tried to compile the new firmware. I get an error: 'unitPower was not declared in this scope'. This is about line 1832 of the planner.cpp file right? What happens when you want to use inline control after a regular M3? Will that work?

@ryanaukes I think it should be:
block->laser.power = laser_inline.status.isEnabled ? laser_inline.power : cutter.power;
You have to make other changes (M3-M5.cpp, planner.cpp, spindle_laser.h), I'm working on it in:
https://github.com/chepo92/Marlin/tree/CR10S5-BL-laser-fs

I just tested it but still no luck, the planner is setting cutter.power= 0, somewhere, i'll try hardcode the power and disable trapezoid power to find out

What happens when you want to use inline control after a regular M3? Will that work?

What do you think? I believe after a regular M3 it should ignore any inline power change (as if LASER_POWER_INLINE was disabled):

M3 S60 // laser turns on, inline power is ignored
G1 X5   // laser keeps on at S60, moves to X5
G1 X50 S30  // laser keeps on at S60, ignoring S30 , moves to X50
M5  // laser off

I am not really used to GitHub yet. How can I see what you changed to try to fix this? I am not using trapezoid power.

I am not really used to GitHub yet. How can I see what you changed to try to fix this? I am not using trapezoid power.

follow this link: https://github.com/MarlinFirmware/Marlin/compare/bugfix-2.0.x...chepo92:CR10S5-BL-laser-fs
look at the changes in M3-M5.cpp, planner.cpp, spindle_laser.h,

Making many test,
All changes in planner.cpp line ~1835
0. Original block->laser.power = laser_inline.power ;
- M3 turns on, any following G0/G1 will turn off
- M3 I turns laser on after a G0/G1 is sent

  1. set block->laser.power = cutter.power ;
  2. after M3 turns on, but turns off after a G1/G0, I think cutter.power is not keeping previous power value
  3. after M3 I keeps always off for any G1/G0

  4. set block->laser.power = 10 ;

  5. sending M3 turns on but a G1/G0 turns it off.
  6. M3 I keeps laser at 10% for any G1/G0 for any in line power

  7. block->laser.power = laser_inline.status.isEnabled ? laser_inline.power : cutter.power;

  8. Similarly to a combination of 0 and 1,
  9. M3 turns on, any following G0/G1 will turn off
  10. M3 I keeps laser at the set inline power for any G1/G0 with inline power argument

So the problem should be when cutter.power is not keeping previous value or being set to 0 somewhere

@chepo92 Did you by any chance already find a solution or made some progress? I tried the changes you made, but for me it didn't work either.

@chepo92 Did you by any chance already find a solution or made some progress? I tried the changes you made, but for me it didn't work either.

No luck, I don't know where cutter.power is being changed in code

A workaround for now is that you post process or change the config of your gcode generator, so it always outputs inline power, I think that is easier.

Thats a shame. What method do you use to change the normal code to inline code? I can do it manually but for some files that would take way too long. For example, how would you post process the example file I included in my post.

Thanks!

Thats a shame. What method do you use to change the normal code to inline code? I can do it manually but for some files that would take way too long.

You can do it with any text editor or with a search and replace post processing script (search for all M3 alone and add the power to the following G0/G1 lines until an M5 is found)

I have just spent some time being confused by this, I think its certainly a bug. The same file works fine with LASER_POWER_INLINE disabled does not work at LASER_POWER_INLINE enabled.

At least LASER_POWER_INLINE should be defaulted off until this is fixed.

Hi,

I was the original author of the laser power inline code (though it was completed by someone else as I didn't have access to a laser cutter for a while)

The reason for:

    // Force disengage planner power control
    static inline void inline_disable() {
      isReady = false;
      unitPower = 0;
      planner.laser_inline.status.isPlanned = false;
      planner.laser_inline.status.isEnabled = false;
      planner.laser_inline.power = 0;
    }

When I originally wrote it (as someone else ended up finishing off the code) was to ensure the laser could be fired without issuing a move order.

Suppose you wish to pulse the laser to check alignment (on a CO2 laser which is what I was prototyping the firmware on); what you would need to do is issue M3 S[power] M5, and it would pulse the laser on and off allowing you to do tape based alignment. Inlined power calls are tied to movement, so will not execute until another block of movement has occured.

This was done as otherwise you need to use planner.synchronize() to sync with the movement, but then you deplete the movement buffer and the laser head slows down and then speeds back up on every power change ; that's why there is a return at the end of the inlined power processing; to avoid ever hitting the synchronize call see here

If you want M3 to behave in the way originally suggested:

G1 X5 S60 // laser turns on
G1 X50 // laser stays on

Being equivelent to

M3 S60 // turns the laser on
G1 X50 // laser turns off

You either A: Make the M3 call be inlined by adding I to the end OR toggle LASER_POWER_INLINE_INVERT in your config, making all calls behave inlined unless stated otherwise. The latter would likely be the best option for longer term use; as if you want to do temporary firing you can just use M3 S[power] I M5 I to create a pulse for alignment

@jediminer543 Thank you for the full explanation.

It is helpful to understand the reasons of why this is the way it is!

@jediminer543 so in your view do we have a bug here? not sure myself

I think it would be more of an flawed design than a bug; What I should really have done is move the entire power config into planner controlled sections to completely eliminate the planner.synchronise() call in power setting; then the M3 I mode would become the same as M3 and the entire behaviour would be simplifed.

I didn't do that originally as both I ran out of time, and also wasn't certain the planner had any design built in to support what would basicly be a zero length meta-block

This issue has had no activity in the last 30 days. Please add a reply if you want to keep this issue active, otherwise it will be automatically closed within 7 days.

bump, still a bug IMHO. A change of defaults this setting to off would fix.

submitting a PR with the change will make that happen a lot faster

@ryanaukes do you know whether the pull request from @IamPete1 has resolved your issue?

@ryanaukes do you know whether the pull request from @IamPete1 has resolved your issue?

Disabling inline laser control won't solve my problem, since my problem is that I want to be able to use both inline laser control and regular laser control.

OK, I didn't actually read through every detail. I just saw the PR referenced at the end of the comments and thought maybe it had been resolved.

@shitcreek I just saw your reply to my other post where you explained how the inline laser is supposed to work, but I cannot respond there anymore. I do understand how it is supposed to work. On this page you can see the problem I am having and why this suboptimal behaviour of Marlin is the way it is.

The problem is that I can use either inline laser control or regular laser control. As soon as I enable inline laser control, regular laser control doesn't work anymore. Whenever I use a regular G1 or G0 without a Sxxx parameter it turns off the laser, while it is supposed to stay on.

I now have a better setup so I'll spin up the linux test build of marlin and see what I can do

@ryanaukes I just took a look at your config_adv file and I think I see your problem.
Your SPEED_POWER_STARTUP is set to 1
With LASER_MOVE_POWER, the laser will default to SPEED_POWER_STARTUP if no S parameter is included.

When you say the laser turns off, do you mean completely and on the display as well or just that it is effectively off?

@ryanaukes I just took a look at your config_adv file and I think I see your problem.

Your SPEED_POWER_STARTUP is set to 1

With LASER_MOVE_POWER, the laser will default to SPEED_POWER_STARTUP if no S parameter is included.

When you say the laser turns off, do you mean completely and on the display as well or just that it is effectively off?

Thanks for your reply! It has been a while since I tested it, so I honestly don't know right now. I will try it again soon and let you know (hopefully during this weekend)!

Isn't the laser supposed to stay at the same value when using a G1 after turning the laser on with a regular M3 (so no inline laser command), instead of turning to the default value? Because if it sets it to the default on every move without a parameter, regular laser commands would be really unpractical to use when also using inline laser commands.

My bad. I meant with M3.
G1 shouldn't turn the laser off unless it has S0

in gcode.cpp:

#if ENABLED(LASER_MOVE_POWER)
    // Set the laser power in the planner to configure this move
    if (parser.seen('S')) {
      const float spwr = parser.value_float();
      cutter.inline_power(TERN(SPINDLE_LASER_PWM, cutter.power_to_range(cutter_power_t(round(spwr))), spwr > 0 ? 255 : 0));
    }
    else if (ENABLED(LASER_MOVE_G0_OFF) && parser.codenum == 0) // G0
      cutter.set_inline_enabled(false);
  #endif

As you can see, only G0 is targeted.

When you say the laser turns off, do you mean completely and on the display as well or just that it is effectively off?

I just tested it again. When I do the following:

M3 S60
G1 X50

The laser turns on after the M3 command. After the G1 command, the laser turns off, but the value (60 in this case) keeps set. So the power is nit set to 0, but the laser gets disabled.

Is your fan pin assigned to a different pin?

FAN_PIN is set to pin 9,
FAN1_PIN is set to pin 8,
SPINDLE_LASER_PWM_PIN is set to pin 44

Check out that PR of mine, I try to fix this issue, with some success. Still need more testing and how it will behave with certain features turned off.

Check out that PR of mine, I try to fix this issue, with some success. Still need more testing and how it will behave with certain features turned off.

Thanks, I will definitely check it out!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ShadowOfTheDamn picture ShadowOfTheDamn  路  3Comments

otisczech picture otisczech  路  3Comments

ceturan picture ceturan  路  4Comments

ahsnuet09 picture ahsnuet09  路  3Comments

StefanBruens picture StefanBruens  路  4Comments