PWM Scaled to Toolhead Speed

I’m working on a project that requires a PWM pin to be scaled up and down with the tool head speed as it accelerates and decelerates.

Basically it is a CNC machine running Klipper and I want the spindle to slow down as the tool head goes into corners and speed up as it accelerates out of them. Just like klippper currently does with extruders, just with a PWM controlled device instead

Conceptually it seems quite straightforward. Basically instead of Klipper outputting a motion planner and look-ahead que modified signal to an extruder stepper motor, I want it to output a PWM signal to a PWM pin. Same trapezoidal acceleration planner and everything.

I see a module called PWM_tool in Klipper, but also see that it does not scale PWM duty cycle with tool head speed. At least not yet

Hi Braff,

I hope you’re successful by starting a new CNC initiative with Klipper. There was https://klipper.discourse.group/t/klipper-for-cnc-initiatives-and-projects-list, but that thread is death. I believe Klipper is the right FW for CNC, but nobody pushed it further on. Just look at China. If Klipper would be used for CNC machines, you would find a lot of machines using Klipper @Ali.

Unless you have a need for a feature set that is only found in Klipper, I’d suggest moving away, even for 3D-printing.

Very interesting established and new CNC firmware projects exist. Share your requirements if you would like more help.

Indeed. I have stopped merging upstream, at least until their own multi-axis implementation is finished.

As you’ve indicated, changing PWM speed during acceleration and deceleration isn’t currently supported. I’m sure it could be implemented, but I think it would need code changes.

The closest approximate I can think of would be to use the existing [pwm_tool] system and issue SET_PIN changes between each G1 move.

If changing the code is something you are comfortable with and you are okay with PWM changes no more frequent than every 10ms or so, then I suspect one could implement a Klipper host module that automatically issues periodic PWM mcu commands synchronized with toolhead motion.

If you need PWM updates more than every 10ms or so, then I suspect it would require micro-controller code changes. Those types of changes tend to be more work.

Cheers,
-Kevin

1 Like

Thanks Kevin,

Every 10ms should be OK. I think it will take 50ms for my toolhead to accelerate from 0 to full speed, so that would be 4 or 5 updates in that period. It would be better it if was continuous, but 4 or 5 steps in there is better than 0, and should work OK.

Is your thought to do this as a klippy/extra.py file? I am, somewhat, comfortable creating and modifying a klippy/extra file, and tried going down that path previously, but had a hard time getting the current speed of the toolhead and issuing the PWM updates at the right times. I am not at all a programmer so it was becoming a pretty convoluted exercise for me and I was getting afraid that I was not going down the right path, or that it would not be stable. It seems like something a programmer would be able to do pretty quickly and reliably, but I was not at all confident that was me.

Brian

1 Like

Hi naikymen,

No thank you. I like Klipper and its community. People are friendly and nice in the forum. I started with another firmware beginning 3d printing and I have to say, I didn’t like the atmosphere (don’t know the best words) in the forum.

I’ don’t know, if you would call this CNC machine :wink: I’m looking for a budget laser cutter and engraver for up to 150 bucks from China, which is able to run with open source firmware and a cool community, similar to Klipper.

I’m a fan of the safety importance regarding Klipper. I live in a 650 square feet flat with many other people above me. I couldn’t live anymore, if I hurt them with my hobby! I’m so afraid, I even build an automatic fire extinguisher for the printer Heater Bed Temperature is increasing without heating - #20 by hcet14. I don’t understand people using Kalico!

Hopefully someone starts a new initiative for CNC based on Klipper. I’m sure this community will support.

Thanks Kevin

Yeah, this PWM Speed scaling capability is especially critical with laser engraving or laser cutting, So it would be a valuable thing to figure out how to implement

1 Like

In my experience, being a programmer, I stopped saying “quickly” and “reliably” together like that :smiley:
Understanding that part of the code took a longer time for me, and this is highly critical code that really needs to work, as it affects nearly all klipper users.

This was on my roadmap while building `PWM_Tool`, but that being a hobby, and it working for my small setup, I did not come to it.

I did manage to have more frequent updates with my low-end AtMega board and a OrangePi Zero (first gen), so I am positive that much more frequent updates are doable given enough bandwidth. At the end, this will need to be tested and tried. With the current PWM_Tool, I was able to do raster engraving with a resolution of about 5 pixels per mm, with a speed of around 30mm/s.

In the limit, every Step-Sequence sent to the Microcontroller could be accompanied by a separate PWM update, which would be as linear as we could get.

My draft Idea from back then was to modify the toolhead.move() / process_moves() / move queue.[1]

The move queue after being cut down in the trapezoidal components contains the crutial acceleration / deceleration and “cruise” information. There, only during acceleration or deceleration the high number of updates is needed.
So I think my first experiment would add a list of “synchronous” PWM pins / Tools to the `Toolhead` class that convert the ramping times into separate PWM updates (move-like. It also uses the Stepcompress-Queue.)
For a more clean code, the trapezoid-generation of the PWM values should probably go into a separate “kinematic” class, in the klippy/kinematics/ folder.

I would really like trying this out, but sadly I am really busy for the forseeable future.
However, I still like to help with Code Reviews or sharing thoughts.

On another note: Some Laser engraving programs can cut the moves themselves and emit some estimated trapezoidal moves based on pre-defined accelerations. This is dirty, but might do the trick for some of your workloads.


  1. Originally I wanted to calculate the precise ratio of wanted / current speed in the iterative solver, but I think it would be better if it would be generated more similar to how the extruder moves are generated. ↩︎

I think for now if I could get klipper to send an updated duty cycle based on planned/actual tool head speed every 10 milliseconds that would be a good start. Definitely overkill during Cruise and maybe underkill during acceleration or deceleration but would be a decent starting point for now.

Is there a fairly straightforward/noob friendly way of creating a klippy/extras.py file that would do this? I’m not exactly sure how klipper works on the back end. Does it ultimately assign a time to everything and then execute that thing when that time comes along so that everything is synchronized?

Basically if I can get klipper to update the pwm duty cycle of a pin based on duty cycle = planned speed divided by cruise speed and execute it in time with the tool head speed every 10 milliseconds that would be a good enough starting point for now

It should be possible to do that. In brief, I think one could create a new klippy/extras/myextra.py file that does:

  • Creates a new printer object class (see klippy/extras/servo.py for an example).
  • Registers itself with the motion flush system (motion_queuing.register_flush_callback()). See klippy/extras/pwm_tool.py as an example.
  • On each flush callback, query the speeds of the main trapq (via ffi_lib.trapq_extract_old() - see klippy/extras/motion_report.py for example code). And then issue PWM updates as desired (see klippy/extras/pwm_tool.py for an example).

So, in brief, as Klipper flushes out each batch of movements (every 250ms), the new module could query those recent movements, and then create the appropriate PWM updates to go along with that movement.

The above wouldn’t be super CPU efficient but I’d guess it could be a good starting point. Alas, I don’t think I’d be able to provide much hands on development help.

Maybe that helps a little,
-Kevin

Thank you Kevin, I really appreciate it. I will give it a shot

Okay, I think I’m making progress on this. I’ve got it to the point where my pwm signal does scale with speed as the tool head accelerates and decelerates and runs it full constant speed during the cruise phase of motion.

However, this only seems to work at low speeds. As speed/acceleration is increased, the pwm updates start getting issued at times that no longer correspond to the motion. My intuition is telling me that it probably has something to do with the pwm update being placed into a different queue and not actually fully synchronized with the motion queue or something. Or, maybe the pwm updates are being applied to motions that were already flushed due to that 250 millisecond flush So the updates end up being sent at the wrong time not corresponding to emotions they were supposed to be sent along with.

Maybe I’ve got the wrong approach to sending pwm updates at times corresponding to motion, but at slow speeds it does seem work. Unfortunately those speeds are too slow for my application.

Is there a reason it might work at slow speeds but not it higher speeds?

Synchronisation might be an issue. Do you explicitly set the set-pin-times according to the time of the motion items?

If you have a fork, I could take a look at the code and see whether I can find a reason?

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.