CNC Laser support

I’ve been testing Klipper and I am impressed of how quiet and fast it is. I would like to have support for CNC machines as also for Lasers. The actual state is not far from it.
First of all, it requires implementing a Hold/Continue and stop functionality that has immediate response. This is the only and most basic difference between Grbl and Marlin (Yet Marlin has it, because I coded it and made the PR, new bugfix versions include it).
GRBL Realtime commands:
Realtime commands are single control characters that may be sent to Grbl to
command and perform an action in real-time. This means that they can be sent at
anytime, anywhere, and Grbl will immediately respond, regardless of what it is doing
at the time. These commands include a reset, feed hold, resume, status report query,
and overrides (in v1.1).
-reset is already implemented as M112.
-feed hold should stop the machine with the maximum deceleration and turn off laser / spindle and temperatures optionally. In pause state it can be then reset, stopped or resumed.
-stop should just stop (but no reset or halting the machine as M112 does)
-resume should turn laser / spindle wait until is fully up to speed and proceed with the movement as originally planned . Finally, allow some macros to be executed as clean nozzle or park.

Notice these features not only add safety to the machine but allows you to restore the prints when the failures are not in the end-of a code.

Additionally, Laser etching change power inline as an extruder will extrude filament synchronized to the movement. It would be awesome to add this PWM capability to the kinematics.

Interesting.

FYI, one challenge with using Klipper with lasers (and other devices) is that it doesn’t currently buffer rapid pwm/gpio changes in the micro-controller. For further info see: SET_PIN not usable for laser engraving · Issue #133 · KevinOConnor/klipper · GitHub and https://github.com/KevinOConnor/klipper/pull/4128 .

Realtime commands are single control characters that may be sent to Grbl to
command and perform an action in real-time.

FWIW, there isn’t much interest in supporting “w31rD G-c0d3” commands in Klipper. We’ve built an api server so that we can implement features like this (eg, taking asynchronous actions). It already has the ability to query state and make immediate changes to the machine outside of the normal command queue.

feed hold should stop the machine with the maximum deceleration and turn off laser / spindle and temperatures optionally.

FYI, this will be a challenge to implement in Klipper if the goal is to halt quickly (eg, in less than a second). Klipper buffers actions into the micro-controllers and there is currently no way to pause buffered actions. (It is possible to fully halt the actions via an “emergency stop” / M112 but that resets the buffers.)

Cheers,
-Kevin

Thank you Kevin for taking the time to respond. I was aware of the topic and the limitation of the set_pin. It has the issue because of the way the PWM objects are handled within Klipper, yet I believe you could treat a spindle/laser as a stepper. A spindle/laser has also direction, enable and step, and is already synchronized . The only difference is to control the Step signal PWM is through duty cycle instead of by number of steps (pulses).
There is even the option of using the same stepper function and having a logical output overlaid to it. Like for example the PWM to control this devices is only at 50Hz (20 ms). You could make an stepper function of 256 steps in 20ms and make the steps proportional to the Duty cycle required width, then is Set in a type of Flipflop gate output to get the output to a pin.
I am not sure if servos are synchronized within the kinematics, but a servo has already a PWM duty cycle control its only limited to a range and frequency.

It is possible to fully halt the actions via an “emergency stop” / M112 but that resets the buffers.

Exactly, the code is already there. You have to make a state machine in that point that sets the mcu to wait for the next instruction instead of deleting the block.

// This is on base ... is to make such functions as this one with stop, resume and hold
void
command_emergency_stop(uint32_t *args)
{
    shutdown("Command request");
}
DECL_COMMAND_FLAGS(command_emergency_stop, HF_IN_SHUTDOWN, "emergency_stop");
// and this is in stepper.c (stop is already there) 
stepper_stop(struct stepper *s)
{
    sched_del_timer(&s->time);
    s->next_step_time = 0;
    s->position = -stepper_get_position(s);
    s->count = 0;
    s->flags = (s->flags & SF_INVERT_STEP) | SF_NEED_RESET;
    gpio_out_write(s->dir_pin, 0);
    gpio_out_write(s->step_pin, s->flags & SF_INVERT_STEP);
    while (!move_queue_empty(&s->mq)) {
        struct move_node *mn = move_queue_pop(&s->mq);
        struct stepper_move *m = container_of(mn, struct stepper_move, node);
        move_free(m);
    }
}

void
stepper_shutdown(void)
{
    uint8_t i;
    struct stepper *s;
    foreach_oid(i, s, command_config_stepper) {
        move_queue_clear(&s->mq);
        stepper_stop(s);
    }
}
DECL_SHUTDOWN(stepper_shutdown);

hold would be something like this:

stepper_hold(struct stepper *s)
{
    while (state_hold) {
   ->turn laser/spindle off
   ->check for M112
   ->check for resume
  if resurme hold state off and return 
   if m112-> stepper_stop, hold state off
   if stop
    sched_del_timer(&s->time);
    s->next_step_time = 0;
    s->position = -stepper_get_position(s);
    s->count = 0;
    //no reset
    //s->flags = (s->flags & SF_INVERT_STEP) | SF_NEED_RESET;
    gpio_out_write(s->dir_pin, 0);
    gpio_out_write(s->step_pin, s->flags & SF_INVERT_STEP);
    while (!move_queue_empty(&s->mq)) {
        struct move_node *mn = move_queue_pop(&s->mq);
        struct stepper_move *m = container_of(mn, struct stepper_move, node);
        move_free(m);
    }
  hold state->off
}

Sorry but I have not studied in depth your code to know how to add the proper names… I hope I am clear. I have been looking at it and testing with a device only for 2 days, yet I see so much potential in it I would like to contribute to it.

I’m currently attempting to set up Klipper for a CO2 laser. I have little need for modulated engraving, so quick changes to PWM duty cycle aren’t important for me in at least the near future. (Ultimately, I think that I’m likely either to use Klipper or LinuxCNC with Remora in the end; both have this split architecture between planning and real-time control that I’m looking for.)

So thanks, and I plan to follow this topic with interest!