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
    455
    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.
    • Trietundefined
      Triet
      last edited by

      I have set up a way to determine if a driver stall event has occurred and then I get the time of the event.

      This is how it works:

      config.g:
      M915 X Y S20 R2 ; stall detection, executes driver-stall.g, logs to driver-stall.txt

      driver-stall.g:
      echo >>"driver-stall.txt" {state.time},"Stepper stall detection: "^{param.B}^"."^{param.D}

      Example of driver-stall.txt:
      2024-04-23T18:36:42 Stepper stall detection: 0.1
      2024-04-24T06:21:58 Stepper stall detection: 0.0

      (thanks to the people who contributed valuable hints).

      Now I would like to

      • list itemrecord the position at which the event happened

      • list itemas well as the last executed move or current move or next planned move in queue, in order to identify that line in the gcode

      • list item then stop the print job and disable heating.

      I found that using M114: Get current position work do what I want, but don't know how to put that output in a file. Or should I try "M114>>"driver-stall.txt" ?

      Then I could not find any gcode command in RRF to identify the involved move at an event. I know there is an internal command queue, but dealing with that is beyond my capabilities of understanding RRF right now. I want to identify the line in the gcode file whose execution caused the event, in order to analyse the problem after the fact.

      Some suggestions please?

      1 Reply Last reply Reply Quote 0
      • OwenDundefined
        OwenD
        last edited by

        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

        Trietundefined 2 Replies Last reply Reply Quote 0
        • Trietundefined
          Triet @OwenD
          last edited by

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

          OwenDundefined 1 Reply Last reply Reply Quote 0
          • OwenDundefined
            OwenD @Triet
            last edited by

            @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

            Trietundefined 1 Reply Last reply Reply Quote 0
            • Trietundefined
              Triet @OwenD
              last edited by

              @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
              • Trietundefined
                Triet @OwenD
                last edited by

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

                Trietundefined 1 Reply Last reply Reply Quote 0
                • Trietundefined
                  Triet @Triet
                  last edited by

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

                  OwenDundefined 1 Reply Last reply Reply Quote 0
                  • OwenDundefined
                    OwenD @Triet
                    last edited by

                    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
                    
                    Trietundefined 3 Replies Last reply Reply Quote 0
                    • Trietundefined
                      Triet @OwenD
                      last edited by

                      @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
                      • Trietundefined
                        Triet @OwenD
                        last edited by

                        @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
                        • Trietundefined
                          Triet @OwenD
                          last edited by

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

                          OwenDundefined 1 Reply Last reply Reply Quote 0
                          • OwenDundefined
                            OwenD @Triet
                            last edited by OwenD

                            @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} "
                            "

                            Trietundefined 1 Reply Last reply Reply Quote 0
                            • Trietundefined
                              Triet @OwenD
                              last edited by

                              @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
                              • OwenDundefined
                                OwenD
                                last edited by

                                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 🤬

                                Trietundefined 1 Reply Last reply Reply Quote 0
                                • OwenDundefined
                                  OwenD
                                  last edited by

                                  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.

                                  Trietundefined 1 Reply Last reply Reply Quote 0
                                  • Trietundefined
                                    Triet @OwenD
                                    last edited by

                                    @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
                                    • Trietundefined
                                      Triet @OwenD
                                      last edited by

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

                                      OwenDundefined 1 Reply Last reply Reply Quote 0
                                      • OwenDundefined
                                        OwenD @Triet
                                        last edited by OwenD

                                        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
                                        • First post
                                          Last post
                                        Unless otherwise noted, all forum content is licensed under CC-BY-SA