• Tags
  • Documentation
  • Order
  • Register
  • Login
Duet3D Logo Duet3D
  • Tags
  • Documentation
  • Order
  • Register
  • Login

How to report current/last position and move on event

Scheduled Pinned Locked Moved
General Discussion
2
18
457
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • undefined
    OwenD
    last edited by 24 Apr 2024, 21:34

    You will need to use the object model rather than a gcode command

    https://github.com/Duet3D/RepRapFirmware/wiki/Object-Model-Documentation

    Look at the move. and job. sections
    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

    https://docs.duet3d.com/User_manual/Tuning/Resume

    undefined 2 Replies Last reply 24 Apr 2024, 23:45 Reply Quote 0
    • undefined
      Triet @OwenD
      last edited by 24 Apr 2024, 23:45

      @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

      Thanks for pointing to the object model, I will have to engage with that.

      Coincidentially, I already have the resurrection function configured and tested, although just for the case of power loss. And of course you are right, if I command a pause triggered by that motor stall event, then the coordinates should be saved. I just did not look at the content of the file thoroughly. That is a good idea indeed.

      But after examining resurrect.g I don't recognize the last executed or next command at a first glance. Nontheless, the coordinates saved at pause should enable me to go through the gcode file and find the relevant line of gcode.

      Thanks sofar.

      undefined 1 Reply Last reply 25 Apr 2024, 01:46 Reply Quote 0
      • undefined
        OwenD @Triet
        last edited by 25 Apr 2024, 01:46

        @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
        offset.png

        undefined 1 Reply Last reply 25 Apr 2024, 11:53 Reply Quote 0
        • undefined
          Triet @OwenD
          last edited by 25 Apr 2024, 11:53

          @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%3A

          Thanks again

          1 Reply Last reply Reply Quote 0
          • undefined
            Triet @OwenD
            last edited by 25 Apr 2024, 17:16

            @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.

            undefined 1 Reply Last reply 25 Apr 2024, 17:36 Reply Quote 0
            • undefined
              Triet @Triet
              last edited by 25 Apr 2024, 17:36

              @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.

              undefined 1 Reply Last reply 25 Apr 2024, 21:13 Reply Quote 0
              • undefined
                OwenD @Triet
                last edited by 25 Apr 2024, 21:13

                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.g

                The 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
                undefined 3 Replies Last reply 25 Apr 2024, 22:49 Reply Quote 0
                • undefined
                  Triet @OwenD
                  last edited by 25 Apr 2024, 22:49

                  @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?).

                  1 Reply Last reply Reply Quote 0
                  • undefined
                    Triet @OwenD
                    last edited by 26 Apr 2024, 01:04

                    @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!

                    1 Reply Last reply Reply Quote 0
                    • undefined
                      Triet @OwenD
                      last edited by 26 Apr 2024, 11:17

                      @OwenD

                      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?

                      undefined 1 Reply Last reply 26 Apr 2024, 23:45 Reply Quote 0
                      • undefined
                        OwenD @Triet
                        last edited by OwenD 26 Apr 2024, 23:45

                        @Triet said in How to report current/last position and move on event:

                        @OwenD

                        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 be

                        G92 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.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} "
                        "
                        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} "
                        "

                        undefined 1 Reply Last reply 27 Apr 2024, 01:16 Reply Quote 0
                        • undefined
                          Triet @OwenD
                          last edited by 27 Apr 2024, 01:16

                          @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.

                          1 Reply Last reply Reply Quote 0
                          • undefined
                            OwenD
                            last edited by 27 Apr 2024, 01:28

                            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 🤬

                            undefined 1 Reply Last reply 27 Apr 2024, 09:45 Reply Quote 0
                            • undefined
                              OwenD
                              last edited by 27 Apr 2024, 06:35

                              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.

                              undefined 1 Reply Last reply 27 Apr 2024, 09:56 Reply Quote 0
                              • undefined
                                Triet @OwenD
                                last edited by 27 Apr 2024, 09:45

                                @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.

                                1 Reply Last reply Reply Quote 0
                                • undefined
                                  Triet @OwenD
                                  last edited by 27 Apr 2024, 09:56

                                  @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.

                                  undefined 1 Reply Last reply 28 Apr 2024, 02:20 Reply Quote 0
                                  • undefined
                                    OwenD @Triet
                                    last edited by OwenD 5 Apr 2024, 22:19 28 Apr 2024, 02:20

                                    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 print

                                    At 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

                                    driver-stall.g

                                    auto_adjust_stall.g

                                    dist2home.g

                                    1 Reply Last reply Reply Quote 0
                                    11 out of 18
                                    • First post
                                      11/18
                                      Last post
                                    Unless otherwise noted, all forum content is licensed under CC-BY-SA