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