Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cura 3.2.1: PauseAtHeight resume wrong feed on UM3 #3676

Closed
Dim3nsioneer opened this issue Apr 16, 2018 · 19 comments
Closed

Cura 3.2.1: PauseAtHeight resume wrong feed on UM3 #3676

Dim3nsioneer opened this issue Apr 16, 2018 · 19 comments

Comments

@Dim3nsioneer
Copy link

Application Version
3.2.1

Platform
Windows 10

Qt
version from Ultimaker's website

PyQt
version from Ultimaker's website

Display Driver
n/a

Printer
UM3

Steps to Reproduce
Use PauseAtHeight on any object on an UM3; test: 4mm retract

Actual Results
retracts 4mm before pause ->ok
retracts another 4mm before pause -> nok
retracts a long distance (16mm?) before moving to park position ->nok
retracts another long distance (16mm?) after resuming ->nok
primes 4mm -> ok
retracts 4mm -> unnecessary?
primes 4mm -> unnecessary?

Expected results
proper priming after resuming

Summary:
The pauseAtHeight script leads to additional e-moves which are not compensated at resuming. Result is printing a lot of air.

@Dim3nsioneer
Copy link
Author

Additional remark: The issue might be in the firmware of the UM3; thus used firmware: 4.3.2

@Ghostkeeper
Copy link
Collaborator

Ghostkeeper commented May 4, 2018

I can't reproduce this bug. I don't get the additional retract that you're seeing. I do get the unnecessary ones though. Here is a snippet of the g-code that it produces for me:

G1 X121.325 Y112.325 E71.55008
M204 S5000
M205 X30 Y30
G0 F15000 X121.125 Y112.325
G0 X120.94 Y111.94
G0 X120.7 Y111.7
G0 X120.55 Y111.55
;TIME_ELAPSED:412.984091
;TYPE:CUSTOM
;added code by post processing
;script: PauseAtHeight.py
;current z: 5.27
;current height: 5.0
M83
G1 F1500 E-4 ;Retracts 4mm before pause -> ok
G1 F300 Z6.27
G1 F9000 X190 Y190
G1 F300 Z15
M84 E0
M104 S0; standby temperature
M0;Do the actual pause
M109 S0; resume temperature
G1 F1500 E4 ;Primes 4mm -> ok
G1 F1500 E-4 ;Retracts 4mm -> unnecessary?
G1 F300 Z6.27
G1 F9000 X120.55 Y111.55
G1 F1500 E4 ;Retracts 4mm -> unnecessary?
G1 F9000
M82
G92 E71.55008
;LAYER:50
G0 X120.55 Y111.55 Z5.27
M204 S4000
M205 X25 Y25
;TYPE:FILL
G1 F4200 X120.548 Y106.414 E71.5839

I think the "unnecessary" ones are just to retract while it's doing that long travel move in between though.

@Ghostkeeper Ghostkeeper added Status: Needs Info Needs more information before action can be taken. Category: Cura labels May 4, 2018
@Dim3nsioneer
Copy link
Author

Gcode also looks symmetrical in my case and those of some customers. As I mentioned it might also be an issue in the firmware. Could you pass it on in this case internally please? There is no Github repository for the firmware of the UM3 I think...

@MarcoTvM
Copy link
Contributor

MarcoTvM commented Jun 1, 2018

What I miss here is the version of the UM3 firmware this was found. Can you add this? I know we have found some issues (and made some patches) that might fix this, but it is still being tested.

@Dim3nsioneer
Copy link
Author

Dim3nsioneer commented Jun 27, 2018

@MarcoTvM
It also happens on the S5 - printing thin air after resume due to a massive retract of about 20mm right before printing starts. FW 5.0.19 - Cura 3.4
FW version on the UM3: last tested with 4.3.2 and Cura 3.3
Can you actually reproduce it in your lab? Let me know if you need a Cura project - I'm highly interested in a solution due to support cases of my customers.

@Ghostkeeper Ghostkeeper added Category: Hardware and removed Category: Cura Status: Needs Info Needs more information before action can be taken. labels Aug 8, 2018
@robinmdh
Copy link
Member

robinmdh commented Aug 16, 2018

For the UM3 the firmware already does retract and un-retract so all of that code and especially putting it in M83 mode will mess up.
Since it is very likely the pause procedure assumes it is running in absolute E steps mode.
I couln't find this plugin though so I could not test it, a M0 with nothing added between layers works fairly well, there is still some under extrusion after oozing though.

EDIT: confirmed the pause procedure just starts sending gcode strating with a G92 E0 and then a G1 E-xxx

@Dim3nsioneer
Copy link
Author

Dim3nsioneer commented Aug 16, 2018

@robinmdh , what do you mean with "could not find the plugin"? It's in the Postprocessing plugin in Cura... ;-)
So the right way would be to make the script staying in absolute mode for the UM3 and the S5?
There is btw. a small bug in resumeStep.py: the saved state is [last position] - [short rectract] - [long retract] but then resumeStep.py mix it up a bit by assuming [long retract] is the whole retraction. A second bug (minus sign instead of plus sign) cancels that bug. I can provide you a corrected resumeStep.py for the UM3 if you like.

@ckielstra
Copy link
Contributor

@Dim3nsioneer, we made several changes to that file, but I'm still curious to see the improvements you made. Can you mail your version?

@robinmdh
Copy link
Member

robinmdh commented Aug 16, 2018

@Dim3nsioneer my internal nightly build of cura on Linux does not get the download page for this plugin nor was it listed as installed. perhaps I should just move to a newer one, it might be a Linux thing, etc.

The script should do nothing Except insert A "M0" on a new line at the start of a layer.
The printer firmware does the rest, the same as when you pause manually.

I'm fairly sure we've messed about with the UM3's version of the pause a bit!!!
Small bugs like these are a great reason for the opinicus/griffin code to just be open source, but alas that plan still looks fragile... but here's everything from getting the saved state and using the E value saved in it to clearing the saved state.

        saved_state = self.__resume_procedure.getSavedState()

        prepause_uncorrected_pos = cast(Move, saved_state["move"])

        compensator = c.getGCodeProcessor().gcode_compensator
        active_hotend = saved_state["active_hotend"]
        prepause_corrected_pos = prepause_uncorrected_pos if compensator is None else \
            compensator.compensatePoint(prepause_uncorrected_pos, active_hotend )

        # reset the position of the filament because it could have been reset by the change material procedure while paused.
        e_pos = prepause_corrected_pos.e[cast(int, active_hotend)] - PauseStep.RETRACT_LENGTH_ON_PAUSE #type: ignore
        c.sendRawGCode("G92 E{0}".format(e_pos))
        # unretract the big part
        c.sendRawGCode("G1 E{E:f} F{F:f}".format(E=e_pos + PauseStep.RETRACT_LENGTH_ON_PAUSE - PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE, F=deprime_speed))

        # return Z (XY already moved to the right location in resumePrintProcedure).
        c.sendRawGCode("G1 Z{Z:f} F{F:f}".format(Z=prepause_corrected_pos.z, F=move_speed))
        c.getGCodeProcessor().setLastMove(prepause_uncorrected_pos)

        # Finally restore the speed to what it was before.
        log.info("gcode: G1 F{F:f}".format(F=prepause_uncorrected_pos.f))
        c.sendRawGCode("G1 F{F:f}".format(F=prepause_uncorrected_pos.f))

        cooling_fan_speed = saved_state.get("cooling_fan_speed", 0)
        if cooling_fan_speed is not None:
            c.getPrintHeadController().getPropertyContainer().get("cooling_fan_speed").set(cooling_fan_speed) # type: ignore

        c.waitForQueueToBeEmpty(wait_for_motion_controller=True)
        c.setPaused(False)

        # reset the saved state
        self.__resume_procedure.setSavedState({})

so first the state is set to be retracted the retract lenght on pause. e_pos = prepause_corrected_pos.e[cast(int, active_hotend)] - PauseStep.RETRACT_LENGTH_ON_PAUSE with a G92 E=epos
then we unretract to the leave us still a bit retracted.... c.sendRawGCode("G1 E{E:f} F{F:f}".format(E=e_pos + PauseStep.RETRACT_LENGTH_ON_PAUSE - PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE, F=deprime_speed))
Then Gcode will automatically unretract that last bit by doing a normal move with E or a travel move after which the gcode unretracts a small bit extra.
Since it takes a few milliseconds to switch over from file in control to paused it "should" hopefully be better to let the gcode unretract that last bit on the move as you don't want to drool all over your print.

So I guess you mean that whole quick retract length can be left out?
My tests showed extra oozing blips in those cases... so I'm curious as well!

@robinmdh
Copy link
Member

I should have included the pausing...
the whole length retracted is the RETRACT_LENGHT ON PAUSE and not more or less.

        saved_state = {"move": c.getLastMove()}     # type: Dict[str, Union[Move, int]]

        # Filament tracking is disabled for the the gcode will do the retraction so the RetractedLength has to be updated afterwards.
        # In EM-2528 this should be fixed.
        pre_pause_retracted_length = c.getHotendRetractedLength(c.getGCodeActiveHotend())

        # Wipe left or right to prevent running into the end limits
        wipe_x_pos = saved_state["move"].x - self.__HORIZONTAL_WIPE_DISTANCE if saved_state["move"].x > self.__HORIZONTAL_WIPE_DISTANCE else saved_state["move"].x + self.__HORIZONTAL_WIPE_DISTANCE

        c.sendRawGCode("G92 E0")
        c.sendRawGCode("G1 E%d F%f" % (-self.QUICK_RETRACT_LENGTH_ON_PAUSE, deprime_speed * 2))         # High speed retract to prevent oozing
        c.sendRawGCode("G0 X%f Y%f F%d" % (wipe_x_pos, saved_state["move"].y, move_speed))                   # wipe nozzle
        c.sendRawGCode("G0 Z%f F%d" % (saved_state["move"].z + self.__Z_HOP_HEIGHT, move_speed))               # hop
        c.sendRawGCode("G1 E%d F%f" % (-self.RETRACT_LENGTH_ON_PAUSE, deprime_speed))                   # Long retract

@Dim3nsioneer
Copy link
Author

Dim3nsioneer commented Aug 16, 2018

I made changes on the base of FW 4.3.3:

    saved_state = self.__resume_procedure.getSavedState()

    # reset the position of the filament because it could have been reset by the change material procedure while paused.
    e_pos = saved_state.get("E" + str(saved_state["active_hotend"]), 0) - PauseStep.RETRACT_LENGTH_ON_PAUSE - PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE # added quick retract length by Dim3nsioneer
    c.sendRawGCode("G92 E{0}".format(e_pos))
    # unretract the big part
    c.sendRawGCode("G1 E{E:f} F{F:f}".format(E=e_pos + PauseStep.RETRACT_LENGTH_ON_PAUSE + PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE, F=deprime_speed)) # changed minus sign of quick retract to plus sign by Dim3nsioneer
    # return Z (XY already moved to the right location in resumePrintProcedure).
    c.sendRawGCode("G0 X{X:f} Y{Y:f} Z{Z:f} ".format(**saved_state) + "F{F:f}".format(F=move_speed))
    # Finally restore the speed to what it was before.
    c.sendRawGCode("G0 F{F:f}".format(**saved_state))

    c.getPrintHeadController().getPropertyContainer().get("cooling_fan_speed").set(saved_state.get("cooling_fan_speed", 0))
    c.setPaused(False)

    # reset the saved state
    self.__resume_procedure.setSavedState({})

As mentioned before, it also worked without the changes (in absolute e mode) but like this it mirrors the logic in pauseStep.py.

@robinmdh
Copy link
Member

@Dim3nsioneer I do believe you un-retract too much in your case.
The total unretracted lenght is RETRACT_LENGTH_ON_PAUSE not RETRACT_LENGTH_ON_PAUSE + QUICK_RETRACT_LENGTH_ON_PAUSE

Of course you next gcode line read from the file will compensateand depending on your paused print's current line type/length it might be a good thing but try pausing on the outer wall of a cylinder?

here is the pause logic from 4.3

        c.sendRawGCode("G92 E0")
        c.sendRawGCode("G1 E%d F%f" % (-self.QUICK_RETRACT_LENGTH_ON_PAUSE, deprime_speed * 2))         # High speed retract to prevent oozing
        c.sendRawGCode("G0 X%f Y%f F%d" % (wipe_x_pos, saved_state["Y"], move_speed))                   # wipe nozzle
        c.sendRawGCode("G0 Z%f F%d" % (saved_state["Z"] + self.__Z_HOP_HEIGHT, move_speed))               # hop
        c.sendRawGCode("G1 E%d F%f" % (-self.RETRACT_LENGTH_ON_PAUSE, deprime_speed))                   # Long retract

So first we retract to the quick retract length, then we retract to the RETRACT_LENGTH_ON_PAUSE position, since we;re in absolute mode this does not include an additional QUICK_RETRACT_LENGTH_ON_PAUSE

Or am I missing something here?

@Dim3nsioneer
Copy link
Author

If we are in absolute mode then yes. I looked at it with the script POV which change into relative mode and then it would do two separate movements with each the full length of those retracts.
So I guess we can agree that the script should not change to relative mode and then the firmware should handle it fine?

@Dim3nsioneer
Copy link
Author

Dim3nsioneer commented Aug 17, 2018

On second thought, I think we should then get rid of that - PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE in

c.sendRawGCode("G1 E{E:f} F{F:f}".format(E=e_pos + PauseStep.RETRACT_LENGTH_ON_PAUSE - PauseStep.QUICK_RETRACT_LENGTH_ON_PAUSE, F=deprime_speed))

in resumeStep.py, correct?

@robinmdh
Copy link
Member

robinmdh commented Aug 17, 2018

That is a well hidden plugin/script @ckielstra helped me find the plugin/script in my Cura (I kept looking at that list of installed plugins and saw no pause at... calling pause at height a plugin is a big misnomer IMHO)
Surprisingly only put in a M0 is exactly what Cura 3.5.x will do for griffin type gcode 👍

Resulting Gcode:

M204 S5000
M205 X30 Y30
G0 F15000 X111.856 Y94.737
G0 X111.869 Y94.774
;TIME_ELAPSED:171.761287
;TYPE:CUSTOM
;added code by post processing
;script: PauseAtHeight.py
;current z: 0.57
;current height: 0.29999999999999993
M0;Do the actual pause
;LAYER:3
M106 S255
G0 X111.869 Y94.774 Z0.57
M204 S1000
M205 X10 Y10
;TYPE:WALL-INNER
G1 F1800 X110.777 Y95.227 E33.99907

So I think this issue can be closed once Cura 3.5.x is released?

@Dim3nsioneer
Copy link
Author

Has it been tested? Is that the version of the script which is in the master branch here (54b990c)?

@ckielstra
Copy link
Contributor

ckielstra commented Aug 17, 2018

Yep, the Cura master branch should contain the most recent version.
What do you mean with 'Has it been tested'? The script was tested against the reported problems, and as such it was verified ok. A full system test has not been performed yet, that will happen with the Cura v3.5 beta release. So it is possible the new changes/fixes have introduced new bugs in other system parts that we are unaware of.

Summarizing:

  • The pause-at-height script should only send an M0 command for the UM3/S5
  • M82 & M83 commands mess up the UM3/S5 position tracking. Until recently this wasn't a problem since nobody was using those commands. Open for discussion is if we should spend time in adding support for these commands or that we are actively going to block them.
  • Retraction at the end of a print / unretract at print start in the UM3/S5 do have some known problems. Improvements were made for the coming firmware 5.1 release but some serious rework is still planned.

@Dim3nsioneer
Copy link
Author

I meant the first one, tested against reported problems.
Thanks everybody who contributed to this fix.

@Ghostkeeper
Copy link
Collaborator

3.5.0 has been released. I hope it works! Thanks for the debugging, guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants