Laser power scaling based on speed and direction

More
09 Oct 2024 22:49 #311680 by iforce2d
Recently I have been playing around with a cheap laser module, and found myself wanting to scale the power based on speed and direction. The reason for scaling with speed should be obvious. The reason for scaling with direction is that the laser beam is kinda rectangular and therefore cuts more effectively along one axis than the other - seems to be common with these cheap diode lasers.

I know there is already a component to handle some of these requirements, but I wanted to try making my own. Here is what I came up with:
component laserreg "";

pin in   float inpower    "Desired laser power at constant speed";
pin in   float reqspd    "Requested speed, connect to motion.requested-vel";
pin in   float curspd    "Current speed, connect to motion.current-vel";
pin in   float velx    "Current speed x component, connect to joint.0.vel-cmd";
pin in   float vely    "Current speed y component, connect to joint.1.vel-cmd";
pin in   float share    "Fraction of power given to pure Y movement, eg. 0.6";
pin out  float outpower "Scaled output laser power";

function _ fp "Update the laser power";

license "GPL";

;;

#include <math.h>

FUNCTION(_) {

    outpower = inpower * (curspd / reqspd);
    
    float angle = atan2(fabs(velx), fabs(vely));  // angle away from y in radians
    float horz = angle / (0.5*M_PI);          // 1 when moving perfectly along x axis
    outpower *= share + (1-share) * horz;

    if ( outpower > inpower )
        outpower = inpower;        
    if ( outpower > 100 )
        outpower = 100;        
    if ( outpower < 0 )
        outpower = 0;

}

One nice side effect is that I can now pause the job at any point and the laser will turn off, and resuming from the middle of a cut works nicely too. Previously I had to be careful to only pause between cuts, otherwise the laser would stay on!

Here is an example .hal file to use the component. This assumes that laser power is controlled by setting spindle speed, and is expressed in gcode as a value between 0 and 100 (eg. M3 S95). For my machine the desired final output is a value between 0 and 65535 so I'm using a lincurve to map to that range, you can remove or change that as appropriate for your case. This example also assumes that joint0 and joint1 have a trivkins type relation to movement in the X and Y axes respectively.

The current speed in each axis is obtained from joint.N.vel-cmd which might not be the actual speed, but it doesn't matter because all we need is the ratio between x/y to know the direction. My laser cuts more effectively in Y than X, so this configuration will scale the power down for Y movements. Swap the X and Y vel-cmd if your laser is the other way around. The value of 0.75 for 'share' comes from some experimentation to see how much a cut with pure Y movement needed to be scaled down to give the same cut effectiveness as a pure X movement. A value of 1 will result in no scaling.
loadrt lincurve personality=2
loadrt laserreg

addf lincurve.0 servo-thread
addf laserreg.0    servo-thread


# Laser power mapping (0-100 -> 0-65535)
setp lincurve.0.x-val-00 0
setp lincurve.0.y-val-00 0

setp lincurve.0.x-val-01 100
setp lincurve.0.y-val-01 65535

net laser-requested-speed    motion.requested-vel    => laserreg.0.reqspd
net laser-current-speed        motion.current-vel    => laserreg.0.curspd
net laser-velx            joint.0.vel-cmd        => laserreg.0.velx
net laser-vely            joint.1.vel-cmd        => laserreg.0.vely
setp                laserreg.0.share    0.75

net laser-percent        spindle.0.speed-out    => laserreg.0.inpower
net laser-regulated-percent    laserreg.0.outpower    => lincurve.0.in
net laser-65535                lincurve.0.out          => weeny.spindle.set-speed

Some examples of the outcome. First, the result without using any power compensation:
 

With speed compensation only:
 

With speed and direction compensation (could still use a little less power in Y moves):
 
Attachments:

Please Log in or Create an account to join the conversation.

More
09 Oct 2024 23:04 #311681 by iforce2d
btw here is the program I used to cut those test squares with various speeds and laser powers. Change the first four lines as required. Note that the comparisons in the loop are 'less than' and 'greater than', not 'greater than or equal', the power loop increments and the speed loop decrements, so the result of the settings as shown will be powers from 10 - 90, and speeds from 800 - 400. The line immediately before each 'endwhile' can be changed to increment by different amounts. 'Size' and 'margin' can be changed to alter the size of the cut squares.
#<minpwr>=10
#<maxpwr>=91
#<maxspd>=800
#<minspd>=399

#<size>=6
#<margin>=2
#<stride>=[#<size>+#<margin>]

g21

#<x>=0
#<y>=0
#<pwr>=#<minpwr>
#<spd>=#<maxspd>

o101 while [#<pwr> LT #<maxpwr>]
  #<y> = 0
  #<spd>=#<maxspd>
  o110 while [#<spd> GT #<minspd>]
    g0 x#<x> y#<y>
    m3 s[#<pwr>]            
    g1 y[#<y> + #<size>] f#<spd>
    g1 x[#<x> +#<size>]
    g1 y#<y>
    g1 x#<x>
    m5
    #<y> = [#<y> + #<stride>]
    #<spd> = [#<spd> - 100]
  o110 endwhile
  #<x> = [#<x> + #<stride>]
  #<pwr> = [#<pwr> + 10]
o101 endwhile

m2
The following user(s) said Thank You: tommylight

Please Log in or Create an account to join the conversation.

More
09 Oct 2024 23:25 #311684 by tommylight
Nicely done, thank you.

Please Log in or Create an account to join the conversation.

Time to create page: 0.281 seconds
Powered by Kunena Forum