How to report current/last position and move on event
-
@Triet
If you look for the M26 command in resurrect.g it gives you the offset in bytes that represents the file progress.
You can use Notepad ++ to find the line as shown below.
Not sure it will be the exact line where the driver error occurred, but it should be close.Go to SEARCH -> GOTO
-
@OwenD said in How to report current/last position and move on event:
If you look for the M26 command in resurrect.g it gives you the offset in bytes that represents the file progress.
Yeah, you saved my day!
After rethinking all this, I am even considering a restart operation after a motor stall event. Of course I need to re-home the Z axis (because the motors will be set idle when pausing) - I got an optical endstop to be used when the bed moves downwards (controlled by resurrect-prologue.g). It will be fixed at a known offset from the original zero Z position and I hope to be able to continue the print job after a motor skipping steps. I am becoming ambitious
I am tired of having to restart long running print jobs. Either the nozle rides against the infill, or some movement overburdens the motor torque. I am still tuning acceleration, speed, jerk and motor current.
The only case staying unsafe is when the layer shift is caused by belt slipping, as there is no way to detect that case without a toolhead tracking device. I hope to get that straight using this belt tension device:
https://www.amazon.de/Upgraded-Tensiometer-Synchronriemen-Detection-Measurement/dp/B0D1P56DMG/ref=sr_1_2?__mk_de_DE=ÅMÅŽÕÑ&crid=37GQBSJM9KDK6&dib=eyJ2IjoiMSJ9.mXBj72HLFHjcOC3RDhvS8Y15_iQNd8EgnovU69EzOscb1eA22Jf8tdIvMOD_i2C5teVoqLiVuJ_pbelIUdkLlcnaRlNRfAVI5G7azyWi8lY.h3k8C3RTL5nzn9OVaBCWPBzkGaJBf_zX6goq9ZPwsos&dib_tag=se&keywords=belt+tensiometer&qid=1714045886&sprefix=belt+tensiometer%2Caps%2C118&sr=8-2
or here even cheaper:
https://www.aliexpress.com/item/1005006699137801.html?spm=a2g0o.productlist.main.5.1139SdEHSdEHf2&algo_pvid=c901d3d3-fe59-42c0-bf7b-a34fcc5d9890&algo_exp_id=c901d3d3-fe59-42c0-bf7b-a34fcc5d9890-2&pdp_npi=4%40dis!EUR!10.28!10.28!!!10.75!10.75!%40211b600e17140459762522501e1063!12000038040401587!sea!DE!2262907766!&curPageLogUid=MUqEmGjmGE8j&utparam-url=scene%3Asearch|query_from%3AThanks again
-
@OwenD said in How to report current/last position and move on event:
Much of what you want is stored when a print is paused in resurrect.g, so you don't need to worry about it from a resume point of view
Wait... I confused myself.
resurrect.g has it, but I could not find any confirmation that it is created when pause.g runs. It is rather related to the power fail case.
I don't know what g-commands are executed when the pause button is pressed in PanelDue (allegedly, everything in RRF happens via g-commands). I looked at pause.g and it only does retracting and repositioning, that means it does not have any command to actually stop the print job or save any information.
In pause.g I read: "called when a print job is paused". That means that just calling pause.g is a step after actual pausing and will not by itself save the current position or anything else. So pausing a print job is one thing, running pause.g is another.
But looking at resume.g, I found following line:
G1 R1 X0 Y0 ; go back to the last print move
which means that at pausing a print job, the current position is stored to a restore point #n. And how does that position get stored there? Using "G60: Save current position to slot". I infer that G60 is used in some other macro file when the print job is paused.
In the description of G60 I read that
"When a print is paused the coordinates are saved to slot 1 automatically"
but I still don't know where this saving is disposed.My question is now, what is the g-command or macro file to run in order to pause a print job (the same way as pressing the pause button on the PanelDue)?
Of course I can do handycrafts to save the current position and take all necessary precautions when a motor skip steps, but I would prefer using proven "built-in" methods.
Your turn.
-
@Triet said in How to report current/last position and move on event:
My question is now, what is the g-command or macro file to run in order to pause a print job (the same way as pressing the pause button on the PanelDue)?
OK, I found it: M25 is the real pause command. The description does not explicitly say that the current position is saved in a slot, but it can be assumed, because the corresponding resume command M24 calls resume.g, and there a slot is read to reposition the nozzle.
Question solved I think. Whether anything is written to resurrect.g is still to be checked. The documentation seems to be incomplete in this point.
-
From the documentation I linked above
How it works
Any time you pause a print from SD card, the state of the print is saved to a special file on the SD card, sys/resurrect.gThe example I showed above is after a pause.
When I initially went to get a sample, resurrect.g didn't exist, so I had to start a print and pause it to create one.
As I said, I don't know if it will put you on the exact line that caused the driver error, but it's fairly easy to use the object model to get the machine position at the time to compare.
You could either write it to file or use G60 to save it to a slot.My own driver_stall.g re-homes after a stall rather than pauses so I use G60 but also write to a log file.
That's ok for a random stall but if there's a problem it'll keep stalling and re-homing.
I guess creating a "max stalls" variable would make sense.;0:/sys/driver-stall.g var yMotorTemp = {sensors.analog[5].lastReading * 1.00} var xMotorTemp = {sensors.analog[4].lastReading * 1.00} var xDriver = 4 var yDriver = 1 if (param.D = var.xDriver) || (param.D = var.yDriver) set var.yMotorTemp = sensors.analog[5].lastReading; get the current motor temp set var.xMotorTemp = sensors.analog[4].lastReading; get the current motor temp echo "X motor temp =", var.xMotorTemp ^ "C" , " : Y motor temp =", var.yMotorTemp ^ "C" echo " A driver stall has occured on driver " ^ param.D echo "Layer shifting may have occured at X:",move.axes[0].machinePosition, "Y:", move.axes[1].machinePosition, "Z:", move.axes[2].machinePosition echo "Requested speed is " , move.currentMove.requestedSpeed, "mm/sec. Top speed is", move.currentMove.topSpeed, "mm/sec" if (var.xMotorTemp !=0) || (var.yMotorTemp !=0) echo "X motor temp =", var.xMotorTemp ^ "C" , " : Y motor temp =", var.yMotorTemp ^ "C" echo >>"0:/sys/print_log.txt" "A driver stall has occured on driver " ^ param.D echo >>"0:/sys/print_log.txt" "Layer shifting may have occured at X:",move.axes[0].machinePosition, "Y:", move.axes[1].machinePosition, "Z:", move.axes[2].machinePosition echo >>"0:/sys/print_log.txt" "Requested speed is " , move.currentMove.requestedSpeed, "mm/sec. Top speed is", move.currentMove.topSpeed, "mm/sec" if (var.xMotorTemp !=0) || (var.yMotorTemp !=0) echo >>"0:/sys/print_log.txt" "X motor temp =", var.xMotorTemp ^ "C" , " : Y motor temp =", var.yMotorTemp ^ "C" echo >>"0:/sys/print_log.txt" "**********************************" ; check if a driver stall is already being acted on. if global.InMacro=true echo "Driver stall macro already running - no further action taken" M99 ; exit macro M400 if job.file.fileName!= null ; check if we are printing set global.InMacro=true ; stop the mcro being run multiple times G60 S3 ; save position to slot 3 echo "File position is ", job.filePosition, "bytes" echo "Physical position is X:",move.axes[0].machinePosition, "Y:", move.axes[1].machinePosition, "Z:", move.axes[2].machinePosition G4 P5 ; if a tool is selected and the heater is up to temp we'll retract if heat.heaters[tools[max(state.currentTool,0)].heaters[0]].current > heat.coldRetractTemperature G10 G1 F1800 ; reduce speed before homing G28 X Y ; home X & Y M400 M116 set global.InMacro = false ; unset the flag so it will start looking for stalls on the return G1 F1200 ; reduce speed when travelling back to saved slot G1 R3 X0 Y0 Z5; travel to 5mm above stall position G1 F60 ; reduce speed G1 R3 X0 Y0 Z0 ; move to stall position ; if a tool is selected and the heater is up to temp, we'll un-retract if required. if (heat.heaters[tools[max(state.currentTool,0)].heaters[0]].current > heat.coldExtrudeTemperature) && (tools[max(state.currentTool,0)].isRetracted) G11
-
@OwenD said in How to report current/last position and move on event:
From the documentation I linked above
I had already read that document but interpreted it solely in the context of power failure or power off (that is, configuring M911). Now I see that saving the position happens as a result of any pause of a print from SD card.
Anyway, all prerequisites are fulfilled to allow me to "catch" any layer shift due to stepper stalling and resume the print job, which is kind of cool. But I still need to learn that RRF scripting language (should not be a problem for me since it looks like a bash dialect).
Thanks for driving my RRF competence upwards - still learning (who doesn't?).
-
@OwenD said in How to report current/last position and move on event:
I went through your driver_stall.g and can only say:
I like that you gather diagnostic information allowing you to tackle the issue (it is a pity that the motor load e.g. voltage can't be reported, afaik). And I also understand why you do not pause, because you can continue the job without homing the Z axis (since steppers never were idle). Fine script!
-
I am wondering if it is possible to check if the stall event is a false positive case. In this case, the distance to the homing position would be unchanged. So it boils down to measuring the travel it takes to home and compare it to the saved position. If it is different than the saved position, a layer shift has occurred.
Do you know a way to do homing starting at some position and report the traveled distance?
One could move the nozzle using a high number of very small segments until the endstop triggers and then a count/sum over all moves would probably yield the result, but then the movement should be commanded stepwise for a good resolution and I don't know the implications of such a method. It seems to me that using this RRF "programming language" should allow to use a loop, iterating one move with one motor step at a time. What do you think?
-
@Triet said in How to report current/last position and move on event:
I am wondering if it is possible to check if the stall event is a false positive case. In this case, the distance to the homing position would be unchanged. So it boils down to measuring the travel it takes to home and compare it to the saved position. If it is different than the saved position, a layer shift has occurred.
Do you know a way to do homing starting at some position and report the traveled distance?
You can do that using G1 H3
The sequence (posted by @DC42 a ling time ago) would beG92 X0. ; Set current position to 0 G1 S3 X-300. ; Home to X minimum and set the axis limit M208 ; Report axis limits M208 S1 X0. ; Set axis limit back to 0 G92 X0. ; Set current position as 0
I thought about how to make that into a useful macro and came up with the following.
However I'm not really sure if it's of great benefit.
The driver won't report an error unless it thinks it's skipped a minimum of either 1 or 4 steps as I understand it.
A lot will depend on the repeatability of the end stop and whether the measured distance can be resolved to a meaningful number of steps difference.
It might help tuning for false positives.I've tested the macro,
but haven't introduced stalls or used it as part of an event.
I'd be interested to hear the results if you care to test it as such.; dist2home.g
; ASSUMES HOMING TO MINIMA!!
; only accepts X and Y axes
; assumes X is axes[0] and Y is axes[1]; send axis by using A parameter
; send threshold for number of steps to constitute false positive as D parameter
; e.g.
; M98 P"dist2home.g" A"Y" D"3"; adjust as required
var dist2move = -500 ; set greater than all axies length
var thisAxis = "X" ; default to x axis,but can be changed if parameter sent
var moveSpeed = 600; speed during homing moves
var homeOnError = true ; home axes is error found
var return = true ; return to start position
var logErrors = true
var logFile = "0:/sys/driver_stall_log.txt"
var maxErrorSteps = 3 ; can be overwritten by param.D
var zLift = 2 ; amount to lift Z before moving
;*****************************************; don't edit below here
var stepX = {1 / move.axes[0].stepsPerMm}
var stepY= {1 / move.axes[1].stepsPerMm}
var microStepsX = var.stepX / move.axes[0].microstepping.value
var microStepsY = var.stepY / move.axes[1].microstepping.value
var currentXlimit = move.axes[0].min
var currentYlimit = move.axes[1].min
var currentX = move.axes[0].machinePosition
var currentY = move.axes[1].machinePosition
var currentZ = move.axes[2].machinePosition
var xMove = var.dist2move ; will be reset as needed
var yMove = var.dist2move ; will be reset as needed
var searchPosX = move.axes[0].machinePosition
var searchPosY = move.axes[1].machinePosition
var hasErrorX = false;
var hasErrorY = false;
var measuredError = 0
var filePos = 0
if exists(param.A)
set var.thisAxis = param.A
if exists(param.S)
set var.maxErrorSteps = max(1,floor(param.S)) ; set max error steps to not oess than one, or param.D
if exists(param.R)
set var.filePos = param.R
var maxErrorX = var.maxErrorSteps * var.stepX
var maxErrorY = var.maxErrorSteps * var.stepYif !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
echo "Machine not homed"
M99M400 ; wait for any moves to stop
G60 S5 ; save position to slot 5echo "selected axis is " ^ var.thisAxis
echo "start position X" ^ var.currentX ^ " Y" ^ var.currentY
if var.thisAxis = "X"
set var.yMove = 0
echo "Move amount is " ^ var.xMove
G92 X0 ; Set current X position to 0
G4 P100
G91
G1 Z{var.zLift} F120; raise Z
M400
G1 H3 X{var.xMove} F{var.moveSpeed}; Home to selected axis to minimum and set the axis limit
M400
set var.searchPosX = move.axes[0].min - var.currentXlimit
echo "Dist: " ^ abs(var.searchPosX) ^ " Start: " ^ var.currentX
set var.measuredError = abs(var.currentX - abs(var.searchPosX))
if var.measuredError <= var.maxErrorX
set var.hasErrorX = false
echo "Error amount on X ("^ var.measuredError ^ "mm) is less than or equal to " ^ var.maxErrorSteps ^ " steps " ^ "(" ^ var.maxErrorX ^ "mm)"
else
set var.hasErrorX = true
echo "Measured error on X is : " ^ var.measuredError ^ " mm"
echo "Full steps : " ^ floor(var.measuredError/var.stepX) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepX)/var.microStepsX)
M208 S1 X{var.currentXlimit} Y{var.currentYlimit} ; Set axis limit back to original
M208 ; report axis setting
G90 ; absolute moves
G92 X{var.currentXlimit}elif var.thisAxis = "Y"
set var.xMove = 0
G92 Y0 ; Set current position to 0
G91 ; set relative moves
G1 H3 Y{var.yMove} F{var.moveSpeed}; Home to selected axis to minimum and set the axis limit
M400
echo "Dist: " ^ abs(var.searchPosY) ^ " Start: " ^ var.currentY
set var.measuredError = abs(var.currentY - abs(var.searchPosY))
if var.measuredError <= var.maxErrorY
set var.hasErrorY = false
echo "Error amount on Y ("^ var.measuredError ^ "mm) is less than or equal to " ^ var.maxErrorSteps ^ " steps " ^ "(" ^ var.maxErrorY ^ "mm)"else set var.hasErrorY = true echo "Measured error on Y is : " ^ var.measuredError ^ " mm : Steps = " ^ var.measuredError / var.stepY echo "Full steps : " ^ floor(var.measuredError/var.stepY) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepY)/var.microStepsY) M208 S1 X{var.currentXlimit} Y{var.currentYlimit} ; Set axis limit back to original M208 ; report axis settings G90 ; absolute moves G92 Y{var.currentYlimit}
else
echo "Undefined axis sent: " ^ param.A
echo "Exiting macro with no action"
G90 ; absolute moves
M99 ; exit macroG90 ; absolute moves
if var.homeOnError
if var.hasErrorX
echo "homing X"
G28 X
if var.hasErrorY
echo "homing Y"
G28 Y
G1 R5 Z0 ; restore Z position
M400if var.return
G1 R5 Z{var.zLift} F60
G1 R5 X0 Y0 Z{var.zLift} F3600; move back to original position
G1 R5 Z0 F60 ; lower Z to original
M400
echo "Position restored"
;G92 Y{var.currentYlimit}. X{var.currentX} Z{var.currentZ}; Set current position as originalif var.hasErrorX || var.hasErrorY
if var.logErrors
if !fileexists(var.logFile)
echo >{var.logFile} "Driver stall log"
echo >>{var.logFile} ""
echo >>{var.logFile} state.time
echo >>{var.logFile} "Print job: " ^ job.file.fileName ^ ""
echo >>{var.logFile} "File position: " ^ job.filePosition ^ " : First report @ " ^ var.filePos
if var.hasErrorX
echo >>{var.logFile} "Error amount X:" ^ var.currentX - abs(var.searchPosX) ^ " mm"
echo >>{var.logFile} "Full steps : " ^ floor(var.measuredError/var.stepX) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepX)/var.microStepsX)
if var.hasErrorY
echo >>{var.logFile} "Error amount Y:" ^ var.currentY - abs(var.searchPosY) ^ " mm - Steps = " ^ abs(var.currentY - abs(var.searchPosY) ) / var.stepY
"Full steps : " ^ floor(var.measuredError/var.stepY) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepY)/var.microStepsY)
echo >>{var.logFile} ""
else
if !fileexists(var.logFile)
echo >{var.logFile} "Driver stall log"
echo >>{var.logFile} ""
echo >>{var.logFile} state.time
echo >>{var.logFile} "Print job: " ^ job.file.fileName ^ ""
echo >>{var.logFile} "File position: " ^ job.filePosition ^ " : First report @ " ^ var.filePos
echo >>{var.logFile} "Stall detected on drive " ^ var.thisAxis ^ " was lower than threshold"
echo >>{var.logFile} "" -
@OwenD said in How to report current/last position and move on event:
It might help tuning for false positives.
That is exactly what I am aiming to do. The idea is to configure a too sensitive stall detection on purpose to begin with and let the check macro run as it is triggered. Then at every occurrence of a false positive the macro would reduce the sensitivity and log the new setting. Print things that you can tolerate to last longer due to homing operations during the print job and that you can tolerate to have minimal layer shifting of up to 4 layers+endstop repeatability. At some point in time no more false positives are triggered as the sensitivity has been reduced enough. Then you have reached a situation where provoking a real motor stall event might be helpful, to confirm that the sensitivity settings that were settled down before really work (false positives are filtered but true positives should be still detected).
When a proven final sensitivity has been determined, the check macro can be decommissioned and driver-stall.g can be used with its intended purpose of resuming the print in the event of motor stalling without checking for false positives anymore.
This way, the configuration of stall detection can be more or less automated (at least this is the idea).
I will surely do something with this stuff and let you know the outcome (but I cannot promise when because I will be traveling soon). I am determined to put an end to ruined prints due to layer shifts.
-
I am determined to put an end to ruined prints due to layer shifts.
Therein lies the rub.
You can react to a stall, but you can't fix a hardware problem with a software solution.
I've usually found the root cause of layer shifts to be mechanical in nature (bearing failure etc) or print parameter issues like the time my slicer setting for overhang extrusion was set to 100 (thinking it was %) when it should have been in the range 0-1 🤬 -
It occurred to me that the macro wouldn't work if the axis minima was not zero, so I've adjusted it to cater for that.
After running it many times, it seems to show that in my case at least, the repeatability of the end stops is poor.
Or at least inconsistent enough that the error can amount to between 1 and 3 steps.
So I'm not sure it's going to work as desired. -
@OwenD said in How to report current/last position and move on event:
You can react to a stall, but you can't fix a hardware problem with a software solution.
I do know very well where the problem lies.
I got a cheap kit for a DIY printer with... cheap 2A stepper motors. I am not disappointed since I knew that in advance. But every now and then I forget that and challenge their limits. It is mostly about travel settings. What works for small pieces will fail for large ones (I often blunder into that trap). Or if I print very tall models (a lithophan for example) with the combing setting "Not in skin" and with a very fine layer thickness of 0.08 mm, then the nozzle travels along the solid wall and drags its surface a bit, because either the oozed bits of plastic unwillingly deposited are too much for this layer height, or just a small percentage of overflow increasingly causes slight changes of the height (comparable to the small layer height) causing the nozzle to hit it (hint: never let the nozzle ooze, anywhere). Z hop to avoid that? You get even more debris. Not to speak about curling infills like "lightning". Or infills with crossing lines (with little bumps in the intersections).
And at times I get too ambitious and want to improve the small details of the print to the max. Then I play with jerk and other things and ...bang! Layer shifting! Again and again new situations catch me in the act of gathering experience.
That is not a tragedy at all (this is just a hobby), but I do regret a failed print that was already running for two days and can't be finished on time like a birthday present, as an example. And of course, I also strive for perfection - a questionable goal in 3d printing.
-
@OwenD said in How to report current/last position and move on event:
So I'm not sure it's going to work as desired.
For the check macro it would be enough to do the coordinates comparison with a tolerance of say 4 steps to decide whether false positive or not (im my case, most real layer shifts are significantly larger)
But for the resume function... well, optical endstops would perhaps work better. They are quite cheap.
Still, better a printed piece with minuscule horizontal layer inconsistencies than spaguetti on the bed.
-
I've put some thought into semi-automating the process of adjusting the parameters affecting stall detection.
Unfortunately the values of M915 are not exposed to the object model.
So instead they must be entered into an array.
These initial values will be applied regardless of your M915 settings,
so they should be set to the same value at the start of the process and after any changes to config are made.For this to work I have three files.
The first is driver-stall.g
If this is called, and the axis involved is X or Y then it will call dist2home.g which will measure whether there were steps lost and re-home etc.
You can then from that call auto_adjust_stall.g which will optionally adjust M915, jerk and acceleration values up to pre-defined values.
Any changes are logged to file and the console.
At some point you should stop getting stall events during the test printAt the end of the print you should
- review the settings
- confirm that they will capture valid stalls without false positives
- adjust your config.g to reflect the last adjustment
I've tested the system but not extensively
driver-stall.g
;0:/sys/driver-stall.g var allowedSteps = 3 ; adjust as required. Number of measured steps to constitute a valid error var macroLocation = "0:/macros/homing/dist2home.g" ; adjust as required var filePos = job.filePosition M400 ; wait for moves in queue to stop G60 S5 ; save position to slot 5 M25 ; pause G1 R5 X0 Y0 Z0 F3600; M400 var Axis = "" ; start with no value var subLoop = 0 var mainLoop = 0 echo "stall on driver " ^ param.D while var.mainLoop < #move.axes set var.subLoop = 0 while var.subLoop < #move.axes[var.mainLoop].drivers if (param.D ^ "") = (move.axes[var.mainLoop].drivers[var.subLoop] ^ "") set var.Axis = move.axes[var.mainLoop].letter set var.subLoop = var.subLoop + 1 set var.mainLoop = var.mainLoop + 1 if var.Axis = "" echo "No axis letter found for driver " ^ param.D M99 else echo "Error is on " ^ var.Axis ^ " axis" if (var.Axis="X") || (var.Axis="Y") M98 P{var.macroLocation} A{var.Axis} S{var.allowedSteps} R{var.filePos} D{param.D}; only run the file if it's X or Y axis fault M24 ; resume print
dist2home.g
; dist2home.g ; should be called by driver-stall.g ; ASSUMES HOMING TO MINIMA!! ; only accepts X and Y axes ; assumes X is axes[0] and Y is axes[1] ; send axis by using A parameter ; send threshold for number of steps to constitute false positive as S parameter ; send driver number as D paramater ; send file position of error from driver-stall as R parameter ; e.g. ; M98 P"dist2home.g" A"Y" S"3" D"1" R"43251" ; **********adjust as required********** var dist2move = -500 ; set greater than all axies length var thisAxis = "X" ; default to x axis,but can be changed if parameter sent var moveSpeed = 600; speed during homing moves var homeOnError = true ; home axes is error found var return = true ; return to start position var logErrors = true ; save details to a log file var logFile = "0:/sys/driver_stall_log.txt" ; location of log file var maxErrorSteps = 3 ; can be overwritten by param.S var zLift = 2 ; amount to lift Z before moving var adjustOnError = true; call auto adjust on measured error var adjustOnFalseAlarm = true ; call auto adjust on false alarm var adjustMacro = "0:/macros/homing/auto_adjust_stall.g" ; file to run if automatic adjustments are enabled ;***************************************** ; don't edit below here var stepX = {1 / move.axes[0].stepsPerMm} var stepY= {1 / move.axes[1].stepsPerMm} var microStepsX = var.stepX / move.axes[0].microstepping.value var microStepsY = var.stepY / move.axes[1].microstepping.value var currentXlimit = move.axes[0].min var currentYlimit = move.axes[1].min var currentX = move.axes[0].machinePosition var currentY = move.axes[1].machinePosition var currentZ = move.axes[2].machinePosition var xMove = var.dist2move ; will be reset as needed var yMove = var.dist2move ; will be reset as needed var searchPosX = move.axes[0].machinePosition var searchPosY = move.axes[1].machinePosition var hasErrorX = false; var hasErrorY = false; var measuredError = 0 var filePos = 0 if exists(param.A) set var.thisAxis = param.A if exists(param.S) set var.maxErrorSteps = max(1,floor(param.S)) ; set max error steps to not less than one, or param.S if exists(param.R) set var.filePos = param.R var maxErrorX = var.maxErrorSteps * var.stepX var maxErrorY = var.maxErrorSteps * var.stepY if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed echo "Machine not homed" M99 M400 ; wait for any moves to stop G60 S5 ; save position to slot 5 echo "selected axis is " ^ var.thisAxis echo "start position X" ^ var.currentX ^ " Y" ^ var.currentY if var.thisAxis = "X" set var.yMove = 0 echo "Move amount is " ^ var.xMove G92 X0 ; Set current X position to 0 G4 P100 G91 G1 Z{var.zLift} F120; raise Z M400 G1 H3 X{var.xMove} F{var.moveSpeed}; Home to selected axis to minimum and set the axis limit M400 set var.searchPosX = move.axes[0].min - var.currentXlimit echo "Dist: " ^ abs(var.searchPosX) ^ " Start: " ^ var.currentX set var.measuredError = abs(var.currentX - abs(var.searchPosX)) if var.measuredError <= var.maxErrorX set var.hasErrorX = false echo "Error amount on X ("^ var.measuredError ^ "mm) is less than or equal to " ^ var.maxErrorSteps ^ " steps " ^ "(" ^ var.maxErrorX ^ "mm)" else set var.hasErrorX = true echo "Measured error on X is : " ^ var.measuredError ^ " mm" echo "Full steps : " ^ floor(var.measuredError/var.stepX) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepX)/var.microStepsX) M208 S1 X{var.currentXlimit} Y{var.currentYlimit} ; Set axis limit back to original M208 ; report axis setting G90 ; absolute moves G92 X{var.currentXlimit} elif var.thisAxis = "Y" set var.xMove = 0 G92 Y0 ; Set current position to 0 G91 ; set relative moves G1 H3 Y{var.yMove} F{var.moveSpeed}; Home to selected axis to minimum and set the axis limit M400 echo "Dist: " ^ abs(var.searchPosY) ^ " Start: " ^ var.currentY set var.measuredError = abs(var.currentY - abs(var.searchPosY)) if var.measuredError <= var.maxErrorY set var.hasErrorY = false echo "Error amount on Y ("^ var.measuredError ^ "mm) is less than or equal to " ^ var.maxErrorSteps ^ " steps " ^ "(" ^ var.maxErrorY ^ "mm)" else set var.hasErrorY = true echo "Measured error on Y is : " ^ var.measuredError ^ " mm : Steps = " ^ var.measuredError / var.stepY echo "Full steps : " ^ floor(var.measuredError/var.stepY) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepY)/var.microStepsY) M208 S1 X{var.currentXlimit} Y{var.currentYlimit} ; Set axis limit back to original M208 ; report axis settings G90 ; absolute moves G92 Y{var.currentYlimit} else echo "Undefined axis sent: " ^ param.A echo "Exiting macro with no action" G90 ; absolute moves M99 ; exit macro G90 ; absolute moves if var.homeOnError if var.hasErrorX echo "homing X" G28 X if var.hasErrorY echo "homing Y" G28 Y G1 R5 Z0 ; restore Z position M400 if var.return G1 R5 Z{var.zLift} F60 G1 R5 X0 Y0 Z{var.zLift} F3600; move back to original position G1 R5 Z0 F60 ; lower Z to original M400 echo "Position restored" ;G92 Y{var.currentYlimit}. X{var.currentX} Z{var.currentZ}; Set current position as original if var.hasErrorX || var.hasErrorY if var.logErrors if !fileexists(var.logFile) echo >{var.logFile} "Driver stall log" echo >>{var.logFile} "*******************************************" echo >>{var.logFile} state.time echo >>{var.logFile} "Print job: " ^ job.file.fileName ^ "" echo >>{var.logFile} "File position: " ^ job.filePosition ^ " : First report @ " ^ var.filePos if var.hasErrorX echo >>{var.logFile} "Error amount X:" ^ var.currentX - abs(var.searchPosX) ^ " mm" echo >>{var.logFile} "Full steps : " ^ floor(var.measuredError/var.stepX) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepX)/var.microStepsX) if var.hasErrorY echo >>{var.logFile} "Error amount Y:" ^ var.currentY - abs(var.searchPosY) ^ " mm - Steps = " ^ abs(var.currentY - abs(var.searchPosY) ) / var.stepY "Full steps : " ^ floor(var.measuredError/var.stepY) ^ " + MicroSteps : " ^ floor(mod(var.measuredError,var.stepY)/var.microStepsY) echo >>{var.logFile} "*******************************************" if var.adjustOnError M98 P{var.adjustMacro} D{param.D} else if !fileexists(var.logFile) echo >{var.logFile} "Driver stall log" echo >>{var.logFile} "*******************************************" echo >>{var.logFile} state.time echo >>{var.logFile} "Print job: " ^ job.file.fileName ^ "" echo >>{var.logFile} "File position: " ^ job.filePosition ^ " : First report @ " ^ var.filePos echo >>{var.logFile} "Stall detected on drive " ^ var.thisAxis ^ " was lower than threshold" echo >>{var.logFile} "*******************************************" if var.adjustOnFalseAlarm M98 P{var.adjustMacro} D{param.D}
auto_adjust_stall.g
;auto_adjust_stall.g ; Must be called from dist2home.g ; do not run as stand alone ; NOTE: Values are not stored between boots. ; values must be applied to config.g when satisfied they capture valid stalls without false positives ; Axis diver number must be passed as D parameter ; array containing initial M915 values for X and Y drivers first value is S (threshold) second is H ; set initial values here. Must be manually set as not available from object model ; should match your config.g initially var stallVals = {{4,250},{4,200}} ; values to change and amounts to change by. Also min/max allowed var increaseS = true ; adjust M915 S parameter true/false var amountS = 1 ; amount to adjust (increase) by on each stall event var maxS = 8 ; maximum allowed value before auto adjust stops applying var increaseH = true ; adjust M915 H parameter true/false var amountH = 4 ; amount to adjust (increase) by on each stall event var maxH = 300 ; maximum allowed value before auto adjust stops applying var reduceJerk = true ; adjust (reduce) jerk value on stall event true/false var amountJerk = 10 ; amount to adjust (decrease) jerk on each stall event var minJerk = 500 ; minimum jerk value allowed before auto adjust stops applying var reduceAccel = true ;adjust (reduce) acceleration value on stall event true/false var amountAccel = 20 ;amount to adjust (decrease) acceleration on each stall event var minAccel = 600 ; ; minimum jerk value allowed before auto adjust stops applying var logFile = "0:/sys/driver_stall_log.txt" ; file to log changes to if !fileexists(var.logFile) echo >{var.logFile} "File created : " ^ state.time if !exists(param.D) echo "No D parameter passed. Auto stall adjust not carried out" M99 ; ensure driver number resolves to X or Y (assumes x & Y are axes 0 & 1) var thisAxis = "" var validDriver = false while iterations < #move.axes[0].drivers if (move.axes[0].drivers[iterations]) == {""^param.D^""} set var.validDriver = true set var.thisAxis = "X" while iterations < #move.axes[1].drivers if (move.axes[1].drivers[iterations]) == {""^param.D^""} set var.validDriver = true set var.thisAxis = "Y" if (var.validDriver = false) || (var.thisAxis = "") echo "Only X and Y axis supported - Auto stall not adjusted" M99 echo "Axis to adjust is " ^ var.thisAxis ; Store the stall values in a global so they are persistant between events ; It will be updated each time the macro runs after that if !exists(global.M915vals) global M915vals = var.stallVals if var.thisAxis = "X" M915 X S{global.M915vals[0][0]} H{global.M915vals[0][1]} if var.thisAxis = "Y" M915 X S{global.M915vals[1][0]} H{global.M915vals[1][1]} echo "Current M915 values..." M915 G4 P200 echo >>{var.logFile} "******************************" echo >>{var.logFile} "Auto stall adjust called at " ^ state.time if var.thisAxis = "X" G4 P100 if global.M915vals[0][0] >= var.maxS G4 P200 echo "Maximum S value reached - no further adjustment will occur" if global.M915vals[0][1] >= var.maxH G4 P100 echo "Maximum H value reached - no further adjustment will occur" if (var.increaseS = true) && (global.M915vals[0][0] <= (var.maxS-var.amountS)) ; see if values should be increased set global.M915vals[0][0] = global.M915vals[0][0] + var.amountS G4 P100 echo "S param set to " ^ global.M915vals[0][0] if var.increaseH = true && (global.M915vals[0][1] <= (var.maxH-var.amountH)) set global.M915vals[0][1] = global.M915vals[0][1] + var.amountH if (var.increaseS = true) || (var.increaseH = true) ; check if new values must be applied M915 X S{global.M915vals[0][0]} H{global.M915vals[0][1]} ; set new values echo >>{var.logFile} "New X axis M915 values set - S=" ^ global.M915vals[0][0] ^ " H=" ^ global.M915vals[0][1] G4 P200 echo "New M915 values are..." G4 P200 M915 ; echo new values to console G4 P200 if (var.reduceJerk = true) && (move.axes[0].jerk >= (var.minJerk + var.amountJerk)) ; see if jerk is to be reduced M566 X{move.axes[0].jerk - var.amountJerk} echo >>{var.logFile} "X jerk reduced to " ^ {move.axes[0].jerk - var.amountJerk} G4 P200 M566 if (var.reduceAccel = true) && (move.axes[0].acceleration >= (var.minAccel + var.amountAccel)) ; see if acceleration is to be reduced M201 X{move.axes[0].acceleration - var.amountAccel} echo >>{var.logFile} "X acceleration reduced to " ^ {move.axes[0].acceleration - var.amountAccel} G4 P100 M201 if var.thisAxis = "Y" if global.M915vals[1][0] >= var.maxS G4 P100 echo "Maximum S value reached - no further adjustment will occur" if global.M915vals[1][1] >= var.maxH G4 P100 echo "Maximum H value reached - no further adjustment will occur" if (var.increaseS = true) && (global.M915vals[0][0] <= (var.maxS-var.amountS)) ; see if values should be increased set global.M915vals[1][0] = global.M915vals[1][0] + var.amountS if var.increaseH = true && (global.M915vals[1][1] <= (var.maxH-var.amountH)) set global.M915vals[1][1] = global.M915vals[1][1] + var.amountH if (var.increaseS = true) || (var.increaseH = true) ; check if new values must be applied M915 Y S{global.M915vals[1][0]} H{global.M915vals[1][1]} ; set new values G4 P200 echo >>{var.logFile} "New Y axis M915 values set - S=" ^ global.M915vals[1][0] ^ " H=" ^ global.M915vals[1][1] G4 P100 echo "New M915 values are..." G4 P200 M915 ; echo new values to console G4 P100 if (var.reduceJerk = true) && (move.axes[1].jerk >= (var.minJerk + var.amountJerk)) ; see if jerk is to be reduced M566 Y{move.axes[1].jerk - var.amountJerk} echo >>{var.logFile} "Y jerk reduced to " ^ {move.axes[1].jerk - var.amountJerk} G4 P200 M566 if (var.reduceAccel = true) && (move.axes[1].acceleration >= (var.minAccel + var.amountAccel)) ; see if acceleration is to be reduced M201 Y{move.axes[1].acceleration - var.amountAccel} echo >>{var.logFile} "Y acceleration reduced to " ^ {move.axes[1].acceleration - var.amountAccel} G4 P100 M201
Files for download