M42 using variable value is slow/not working well
-
Hello all. I have a custom built pen plotter (operates very similarly to a laser cutter/engraver in practice). The mechanism to raise/lower the pen is a voice coil driven by an external controller that takes a single-wire PWM signal (51% - 100% duty cycle moves the actuator up, and 49%-0% moves the pen down). This gives me a precise way to control the pressure of the pen on paper.
At any rate, the VCA controller is connected to OUT6 of my Duet Mini 5+. I'm using M42 commands to drive it. So after building my gcode files using Lightburn, I simply replace M3 commands with something like
M42 P0 S0.35
for example.
This works perfectly for static values of S. But if I try and use a variable for S, like the following:
var d = global.pressure32 (...) M42 P0 S{var.d}
The plotter no longer reliably moves the pen. Adding a 100msec dwell after moving the pen works better, but results in some slow/jerky motion and doesn't seem like a real fix.
I don't know if the issue lies with the motion planner somehow or if reading the variable repeatedly is just slow.
My config.g:
; Configuration file for Duet 3 Mini 5+ (firmware version 3.3) ; executed by the firmware on start-up ; ; generated by RepRapFirmware Configuration Tool v3.3.16 on Sat Jul 22 2023 22:18:39 GMT-0500 (Central Daylight Time) ; General preferences M453 ; CNC mode G90 ; send absolute coordinates M550 P"nPLT" ; set printer name ; Network M551 P"duet" ; set password M552 P192.168.1.14 S1 ; enable network and set IP address M553 P255.255.255.0 ; set netmask M554 P192.168.1.1 ; set gateway M586 P0 S1 ; enable HTTP M586 P1 S0 ; disable FTP M586 P2 S0 ; disable Telnet ; Drives M569 P0.0 S0 ; physical drive 0.0 goes forwards M569 P0.1 S1 ; physical drive 0.1 goes backwards M569 P0.2 S1 ; physical drive 0.2 goes forwards ;M569 P0.3 S1 ; physical drive 0.3 goes forwards M584 Y0.0:0.1 X0.2 P2 ; set drive mapping M350 X16 Y16 I1 ; configure microstepping with interpolation M92 X100 Y59.26 ; set steps per mm, shorter pulleys on X ;M92 X80 Y59.26 ; set steps per mm, longer pulleys on X M566 X500.00 Y500.00 ; set maximum instantaneous speed changes (mm/min) M203 X18000.00 Y18000.00 ; set maximum speeds (mm/min) M201 X500.00 Y500.00 ; set accelerations (mm/s^2) M906 X1800 Y1800 I30 ; set motor currents (mA) and motor idle factor in per cent M84 S1 ; Set idle timeout ; Axis Limits M208 X0 Y0 S1 ; set axis minima M208 X290 Y290 S0 ; set axis maxima ; Endstops M574 X1 S1 P"^io1.in" ; configure switch-type (e.g. microswitch) endstop for low end on X via pin !^io0.in M574 Y1 S1 P"^io0.in" ; configure switch-type (e.g. microswitch) endstop for low end on Y via pin !^io1.in ; Pen M950 P1 C"io4.out" ; allocate GPIO port 1 for the enable/disable of the voice coil amp M950 P0 C"out6" Q30000 ; allocate GPIO port 0 to out6 on expansion connector, 30kHz M42 P1 S0 ; disable motion of pen M42 P0 S0.6 ; pen up command M42 P1 S1 ; enable motion of pen G4 P500 M42 P0 S0.5 ; set to 50% (which is 0% output) M42 P1 S0 ; diable motion of pen ; Sensors M308 S0 P"io3.in" Y"linear-analog" A"Pen pressure" F0 B-8.5 C1160 ; Variables global pressure_on_pause=0.5 global pen_up_on_pause=0 global pen_is_up=1 global pen_is_on=0 global pressure32=0.38 global pressure85=0.36 global pressure105=0.32
And a snippet of a gcode file:
; Layer C02 M42 P0 S{global.pressure85} G1 Y250.831 M42 P0 S0.6 G0 X65.497Y250.831 M42 P0 S{global.pressure85} G1 Y56.831 M42 P0 S0.6 G0 X173.447Y56.831 M42 P0 S{global.pressure85} G1 Y250.831
The immediate fix I can think of simply hardcodes in all values into M42 commands before running the plot, but I wanted to see if there was a better/easier way of doing things. Thanks for any assistance.
-
@usinjin this is one for @dc42 to confirm but adding the delay (or M400) will almost certainly not be what you want as it means the following movement commands wont be handled until the delay/M400 completes. even without the delay using M42 in between the movement commands like that is probably sub optimal. The way this is handled for Laser cutters is with a S parameter of the G1 command. If that can be made to work with your VCA controller then that may be the better solution:
https://docs.duet3d.com/en/User_manual/Reference/Gcodes#m452-select-laser-device-mode
you can set the same pin you are using now for M42, but instead as a laser pin. I expect you will want S1 mode of M452 so there is a continuous output and then use commands of the form:
G1 Xxxx Yxxx Sx.xxWhat I don't know is if commands of this sort:
G1 Xxxx Yxxx S{<variable>}Will work better but its worth a shot.
-
@usinjin this is a known issue, see https://github.com/Duet3D/RepRapFirmware/issues/767. Meanwhile I suggest you either use a M400 command prior to each M42 command, or use laser mode and the G1 S parameter as @tony suggested.
-
Thanks to both for the help. I did forget to mention that I had tried M400 already, and seeing as it's the same as G4 P0 that's when I tried to increase the dwell time, neither of those work very well.
I avoided laser mode before because as I'm controlling an actuator and not a laser, the "pen down" time is dependent on the force being applied. I want to be able to add padding with G4 in the event that I use a very low pressure so that I can make sure the pen is touching the page before moving occurs. Using M42 allowed me to separate "pen moves" and "XY" moves. Is there still a way to do this with M452?
-
Actually, could I do this with M670?
-
@usinjin Never tried it, but it seems to hit the nail for your use case. From what I gathered, it will apply the advanced timing on both moves (up+down).
Is that a problem? -
@o_lampe I think it would work okay, there could be some wasted time if I set the timing to the worst-case for all pen movements. Not 100% sure.
I'm still not convinced that my hardware will support laser mode. I suspect the G1 commands will be fine, but the problem arises with G0 traversals when the pen needs to be "up"/"off". Won't G0 set the laser duty cycle to 0%? If so, that is actually pen "down" at full force on my hardware. Maybe I can turn the driver off first (also with M42, but hard coded value of 0 for off and 1 for on), so it won't matter what the duty cycle is?
I also figured out how I could turn this in my gcode files:
... M42 P0 S{var.pressure32} ...
Into this:
... M42 P0 S0.355 ...
Based off another file that has had pressure variables written to it:
M28 pressure_values.g set global.pressure32=0.355 ;calculated from a load cell input value ...
I did this with a Python program running on the host that transfers the files via FTP. It's a pretty ugly solution to basically just do a text substitution, but it does work...if anyone is interested in how I did that I can elaborate. I will also keep trying the laser mode option (which would be far nicer I think).
-
@usinjin said in M42 using variable value is slow/not working well:
Won't G0 set the laser duty cycle to 0%? If so, that is actually pen "down" at full force on my hardware
You could reverse the sense so that 0 means pen up and 1 means down, by inverting the control pin name in the M452 command.