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

Create PurgeLinesAndUnload.py #20013

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

GregValiant
Copy link
Collaborator

@GregValiant GregValiant commented Dec 9, 2024

Description

This script has 4 options.
Add Purge Lines:
Will draw lines left, right, top, or bottom of the build plate and either full length of half length. If a print takes up the entire width then the purge lines could be moved to the bottom.
Circle Around To Layer Start:
Creates an orthogonal tool path that moves the nozzle around the periphery of the build plate before moving in to the Layer Start location. This keeps strings from dragging across the print location on the build plate.
Adjust Starting E Location:
Cura adds a retraction after the StartUp Gcode. If there is also a retraction within the StartUp Gcode (or when using Add Purge Lines) it causes a double retraction. This option will change that "G1 E-" line to a "G92 E" so the filament location within the nozzle can be adjusted to provide for an exact start to the skirt/brim/raft.
Unload FIlament at Print End:
Adds an unload sequence of G1 E commands to back the filament out of the hot end and out of the extruder. Works well with long-tube bowden printers.

The script supports:
Absolute and Relative extrusion
Rectangular and Elliptic beds
Origin-At-Center whether True or False.
Disallowed Areas

Settings

image

Type of change

  • [ X] New feature (non-breaking change which adds functionality)

How Has This Been Tested?

I've been using this script for a year.

Test Configuration:
Dell Laptop 16mb of RAM

  • Operating System:
    Windows 10 Pro
    Cura versions 4.13.1 and up.

Checklist:

  • [ X] My code follows the style guidelines of this project as described in UltiMaker Meta and Cura QML best practices
  • [ X] I have read the Contribution guide
  • [ X] I have commented my code, particularly in hard-to-understand areas
  • [ X] I have uploaded any files required to test this change
  • [ X] I apologize ahead of time for my coding style.

This script has 4 options.
Add Purge Lines will draw lines left, right, top, or bottom of the build plate and either fill length of half length.  If a print takes up the entire width then the purge lines could be moved to the bottom.
@github-actions github-actions bot added the PR: Community Contribution 👑 Community Contribution PR's label Dec 9, 2024
Copy link
Contributor

github-actions bot commented Dec 9, 2024

Test Results

0 tests   - 23 370   0 ✅  - 23 368   0s ⏱️ -54s
0 suites  -      1   0 💤  -      2 
0 files    -      1   0 ❌ ±     0 

Results for commit 28f8e2a. ± Comparison against base commit 382b98e.

♻️ This comment has been updated with latest results.

@GregValiant
Copy link
Collaborator Author

@HellAholic the "Move around to the print start" function is something that came up in a post a while ago. I did account for cases where Cura adds the "Move to prime tower" line at the end of the startup. The script will add an orthogonal move to an edge before the actual move to the prime tower location.
I have high confidence in the code for "Rectangular" beds. The G2/G3 coding in the "Elliptic" section seems OK but needs another set of eyeballs.
I'll leave this as a draft for now.

@GregValiant GregValiant marked this pull request as draft December 9, 2024 02:11
@HellAholic
Copy link
Contributor

I'll take a look to see if I can update the code style. Will also try to play around with the current iteration to first get a grasp on how things work and what the output looks like. Might be a slow burner but it's on my todo list 👍

Changed 'Execute' procedure per suggestion.
Add 'G10' firmware retraction support to 'Adjust Starting E'.
@HellAholic
Copy link
Contributor

HellAholic commented Dec 14, 2024

I went with the purge everything approach and it started working, something else I had in the background was interfering with the script.
On the functionality side, would it be an idea to account for the disallowed area of the build plate?
[extreme example chosen for demonstration purposes] on the method series, the nozzle/extruder physically cannot reach there. Don't think there are any other printers with that type of restriction. But just as a discussion point, might be something to consider.
The worry I have with that (disallowed area) is then you might open up the whole shrinkage factor compensation thing, but it's just a worry, since you're applying the position in post processing, it does not get modified by the engine, so just as something to maybe check later if the disallowed area logic is introduced.

image

Update:
Had a bit of a though about it, we could add an extra field (offset from the edge), this would allow for adjustments in case you would want to adjust for the disallowed area or maybe you have a build plate with damaged edges and you want to do the purge a bit more towards the inside.
Also I'm a bit annoyed by the preview not showing the post processing results and having to load things back in to check. I'll see if I can do some adjustments to re-load the preview with the changes.

@GregValiant
Copy link
Collaborator Author

Good morning.
I missed the "machine_disallowed_areas" thing. After looking at the MethodX disallowed areas I think simply excluding 'Purge Lines' and 'Move to Start' is the best way to go. The polygons in a definition file can be written differently by different authors. They are easy to draw, but tough to parse.
The same thing might be true for any multi-extruder machine that does not "Share Heater" and "Share Nozzle since both the Purge Lines and the Unload will be for the active nozzle.
I'll spend some time thinking on those.

Regarding not showing the post-processed gcode in the initial preview, I recall seeing complaints about that here in the bug reports. The Initial Preview is done before any post-processing so the file would need to be saved, and then the gcode read back in. That'll take a while. Maybe a "Load Gcode file for Preview" button (that popped up after saving, or became yet another function of the "Slice" button) would be better so the user would have an option. (If Arc-Welder is enabled then it won't show correctly anyway.)

On a different subject...
It would be nice if there was a ToolTip attached to each name in the "Post Processing Scripts" list. Something like:
image
You would still need to load the PP to see the description, but there would be an indication of what it actually does.

@HellAholic
Copy link
Contributor

HellAholic commented Dec 14, 2024

Aloha,
Let me know what you come up with, you can always add "single extruder only" to the script or something.
I checked the offset, it works somewhat, but also needs a secondary field for start and end of the purge line. There are some general patterns in how the gcode is made, so if I can make a template out of it, then adjusting the values would be easier. I'll see if I can make something that's more generic but simple and robust.

The slice result preview "should" in theory be simple enough, just have to figure out where I need to poke in the code to make it move. I think reloading the changed gcode is the doable part, but loading back to the original does not sound like a feasible option.

On a different subject...
It would be nice if there was a ToolTip attached to each name in the "Post Processing Scripts" list.

That should also be doable, but it requires some changes to the qml, adding a getter to the python with a pyqtsignal and such, and reading the description in a try/except to handle scripts without a description.
The main issue is that the qml for that part is fairly old, so it will probably need some updating:

  • List is not properly spaced (line height / label height) -> this is mostly my OCD and other things being triggered
  • The selected highlights is not great -> same as above xD
  • The text (script name) is added to the list makes it so that the tooltip only appears if you hover over the left part (first 50 pixels or something)
  • There is also always the risk of the unexpected bug popping out of nowhere

@GregValiant
Copy link
Collaborator Author

I hate unexpected bugs. The expected ones are much better.
I think I've got the "disallowed areas" figured out without having to exclude those printers.

@GregValiant
Copy link
Collaborator Author

Wow. I have been integrating the "Disallowed Areas" into the code. There wasn't a lot of breakage, but there are more variable names to deal with (and there was already a lot).
Straightening that out is going to take a minute. There are a lot of combinations to set up for to debug.
Fortunately, not many (if any) delta's have disallowed areas so I'm ignoring it for the G2/G3's.

I'll go through your suggestions and make the changes and then push another commit.

@HellAholic
Copy link
Contributor

HellAholic commented Dec 15, 2024

It might also be an idea to use enum strings, doesn't even need to be linked to the string value it can be an int, but to keep it as close to the current implementation as possible:

from enum import Enum

# class syntax
class Location(Enum):
    LEFT_FRONT = "LF"
    LEFT_REAR = "LR"
    RIGHT_FRONT = "RF"
    RIGHT_REAR =  "RR"
    
 # usage
 if purge_end_loc == Location.LEFT_FRONT

makes it easier to work with strings in the comparisons and also reduces the chance of making a typo, also helps with autocomplete xD

You can also do the calculations for some values and store them in the self, since it's being passed along to the different functions, that will reduce the number of variables you need to pass with each function call.
curaApp is one example, but probably you'll find other things that can be done the same way.
so if in your initialize() function instead of curaApp = ... you say self.curaApp = ...
then in all the following functions that have the self as the first argument, you can just reference it by saying:
self.curaApp.getProperty("something", "something")
the only thing you need to keep in mind is not adding the same name as the super class. (make unique names)

TLDR:
Add the bits you're comfortable with and I'll do a refactor afterwards, make sure functionality is there, I'll make it pretty :P

@GregValiant
Copy link
Collaborator Author

I have to append this to my "List of things I didn't know".
image
IS A LIE.
Any gcode file (or UFP file) opened in Cura can be post-post-processed if the "Save to..." button is clicked. That extra post-processing generally makes a mess.

Plugins have a block so that doesn't happen. I've blocked that from happening with this script.

@HellAholic
Copy link
Contributor

Although it's a bit of a rare usecase to reload a gcode and run a post processing script on it, since the information regarding the post processing is already in at the end of header of the gcode file it should be possible to allow for running additional post processing without re-running the same scripts that already were executed on the gcode.
So reading the gcode, looking if there is a POSTPROCESSED comment in it, if so, filtering out the scripts already executed, and executing the other ones.

;END_OF_HEADER
;POSTPROCESSED
;  [PurgeLinesAndUnload]

@GregValiant
Copy link
Collaborator Author

In the next week or two I'm going to tear this down and put it back together. It's working, but with the changes I've hacked in for the Prime Tower move and the Disallowed Areas it's turned into spaghetti code. It's pretty bad when even I can't stand it.

So take a break. I'll add a new commit when I get done changing it.

@GregValiant
Copy link
Collaborator Author

@HellAholic
I have made alterations, added a procedure, moved things around, found a couple of typos, and altered comments.
There are a lot of changes.
Do you want me to add a commit or go about updating this some other way?

@HellAholic
Copy link
Contributor

Hey Greg,
Add the commit and I'll work based on that. Took a break and didn't do much, mostly end of year work.

Added a "quick purge" option before the actual unload to insure the filament is free to pull back.
Made adjustments for "Machine Disallowed Areas".
Added some comments.
Re-ordered some of the code.
@GregValiant
Copy link
Collaborator Author

There it is. New and improved.

One of the printers I used for the Disallowed Areas was a UM3. It has 6 areas defined and because I used a simple method of determining the "useable space" as a rectangle (rather than the actual shape), it ends up pushing the purge lines towards the print. There aren't many printers with the problem though, so the warning message I added should (hopefully) be sufficient.

@GregValiant
Copy link
Collaborator Author

Ready for review.

Copy link
Contributor

@HellAholic HellAholic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, second opinion of a Cura Dev is also needed. :)

@HellAholic
Copy link
Contributor

I've played around with the script a bit more, couple of things that might be nice to add:

  • Currently only extruder[0] values are in effect -> if we can make it to purge for active extruder [0,1,2,3,4,...] then it would be more generic
  • I tested on my S3 (I print PLA on extruder 0 and TPLA on extruder 1), so if I try the script on extruder 1, the offset of the nozzle means that the file is not accepted (out of bounds error). I assume it would be the case for other multi-extruders with a nozzle offset.
    image

@GregValiant
Copy link
Collaborator Author

Any line with an "E" in it that does not specifically state which tool will be for the active extruder. That's why I didn't go any further into it. The "purge lines" don't have a retraction so the retract_amount doesn't come up. The purge lines would seem to be tool independent.

The one thing I do see is that if there is a "Nozzle switch retraction distance" then it might not get accounted for at the start. In that case I don't know how the printer would know where the end of the filament is without the prime blob or something.
But it isn't really "changing tools" at the beginning, but if your last print ended with T0 and this one starts with T1, then the location of the end of the filament is either an unknown, or maybe the firmware knows. If the end is 16mm back from the nozzle then it's going to take a very long purge line before it starts actually extruding. The total purge distance for your printer looks to be about 6.6mm so it won't purge at all if the filament is in a "Nozzle switch" retracted location.
If "Prime Blob" is enabled, that should take into account a print start with the filament retracted and the purge lines should be fine without worrying about the active tool.

We start to get into a lot more combinations of things. Since much of the start of a print on a UM machine is within the firmware, I can't check it out.

@HellAholic
Copy link
Contributor

So all of that is handled in FW for the UM printers, priming and such, no need to go that deep.
The only case I think we should pay attention to is the nozzle offset. My proposal is as follows:

  • Adding a setting to the script for "Purge Extruder": "Default: 0, options: 0,1,2,..."
  • Followed by nozzle offset X/Y that can either be retrieved from the extruder setting or manually typed by the user -> used as offset to the machine_(X->left/right)/(Y->front/back) && self.start_x, self.start_y
  • Default behavior is extruder[0] so nothing changes for majority of single extruder printers
  • If anything other than the extruder[0] is selected, the only affected changes would be the nozzle offset X/Y applied in calculations && the following settings:
        retract_dist = self.extruder[0].getProperty("retraction_amount", "value")
        retract_enable = self.extruder[0].getProperty("retraction_enable", "value")
        retract_speed = self.extruder[0].getProperty("retraction_retract_speed", "value") * 60
        material_diameter = self.extruder[0].getProperty("material_diameter", "value")
        mm3_per_mm = (material_diameter / 2) ** 2 * 3.14159
        init_line_width = self.extruder[0].getProperty("skirt_brim_line_width", "value")
        print_speed = round(self.extruder[0].getProperty("speed_print", "value") * 60 * .75)

Outside of this, I don't think it's necessary to worry too much about the FW settings in UM machines, I used it as an example to showcase why we might need to consider the nozzle offset X/Y and allowing for extruder selection by user.

@GregValiant
Copy link
Collaborator Author

I understand. If we are starting with T1 then the offset needs to be applied and the possibility of some other different parameters is there.
I'll take a look. This shouldn't take long to add. Debugging won't have to include a bunch of different printer definitions so that should go easier.

@GregValiant
Copy link
Collaborator Author

Alright, I give...Where is "initial_extruder_nr" stored?

@HellAholic
Copy link
Contributor

I'm not 100% sure if there is a better way for it or not, based on where it lives in CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()

So need to:

from cura.CuraApplication import CuraApplication

then add the self.initial_extruder_nr = None to the init(self)
and when you're executing the script, you need to get the reference, if you attempt to get it in the init, it will crash or at least it did on my attempt.
Here it worked and I think it's the correct place to get the value since you're about to execute the script on the generated gcode, so all setting changes have been applied by the user.

    def execute(self, data):
        self.initial_extruder_nr = CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()

I moved the message for the startup warning in the execute to see if I get the correct extruder and it seems to be working,
image

@GregValiant
Copy link
Collaborator Author

Thanks for that.

Are these statements true?
"Extruder 1 is always T0, and is always the primary extruder"
"Extruder 1 will never have offsets."

Some machine definitions refer to "Right Extruder" and "Left Extruder". I've always found that confusing. I really didn't want to have to go through a bunch of definitions again.

I'm currently dealing with "Y" offsets and it is making my head hurt. "X" offsets seems to be working fine BUT I have made the assumption that the above statements are in fact true (at least for UM machines). Another assumption I've made is that any X offset will be a positive number, but the text boxes for offsets will allow negative numbers.

@HellAholic
Copy link
Contributor

HellAholic commented Dec 28, 2024

"Extruder 1 is always T0, and is always the primary extruder"
That's how Cura is set up (you can look at support blockers for example, they get assigned to T0 as a mesh)

"Extruder 1 will never have offsets."
It might have an offset, it's machine dependent. For UM printers that is the correct assumption as far as I remember.

"Right Extruder" and "Left Extruder" in case of the UM printers is used as position, since you can use different extruder variants in left or right position on the head, so you need the reference to where the Extruder of Type A is placed (left position or right position). That allows you to make the extruder variant definitions themselves position agnostic. left extruder will be equal to saying T0, right extruder will be the same as saying T1

share\cura\resources\extruders\deltacomb_dc20dual_extruder_0.def.json negative offset of x example

For the negative/positive value, it will sort itself out, meaning:

  • If you define the travel allowed area in the x axis as 0 - nozzle_offset_x < allowed < machine_width - nozzle_offset_x then if nozzle offset is negative it would still shift in correct direction.
    Same for the Y I think, so if you can work it for the positive, the negative is also gonna work without touching it.

@GregValiant
Copy link
Collaborator Author

I didn't change that warning message. Regardless of the extruder number, if there are purge lines in the Startup they are going to be commented out.

Here is the script with the extruder offsets considered.
Assumptions:
Delta printers will not have "disallowed areas".
T0 is the primary extruder and will not have Offsets.
If T1 has offsets then they will be positive "X" values and "Y" can be negative or positive.

I added a function at the bottom that determines the values for the "initial extruder". Whether a print starts with T0 or T1 makes no difference and the proper values are applied.
I'll post it here and you can take a look. If you request minor changes then I'll do a commit.
PurgeLinesAndUnload.zip

I'm getting on a motorcycle and getting out of here. Have fun.

@HellAholic
Copy link
Contributor

Not gonna poke at it too much xD You're pretty much on point.
Just one comment:

    def _get_initial_tool(self) -> int:
        # Find the Initial Extruder
        self.init_ext_nr = Application.getInstance().getExtruderManager().getInitialExtruderNr()
        # If there is an extruder offset X then it will be used to adjust the "machine_right" and a Y offset will adjust the "machine_back"
        if bool(self.curaApp.getProperty("machine_use_extruder_offset_to_offset_coords", "value")):
            self.nozzle_offset_x = self.extruder[1].getProperty("machine_nozzle_offset_x", "value")
            self.nozzle_offset_y = self.extruder[1].getProperty("machine_nozzle_offset_y", "value")
        else:
            self.nozzle_offset_x = 0.0
            self.nozzle_offset_y = 0.0
        num = self.init_ext_nr

to

    def _get_initial_tool(self) -> int:
        # Find the Initial Extruder
        num = Application.getInstance().getExtruderManager().getInitialExtruderNr()
        # If there is an extruder offset X then it will be used to adjust the "machine_right" and a Y offset will adjust the "machine_back"
        if bool(self.curaApp.getProperty("machine_use_extruder_offset_to_offset_coords", "value")):
            self.nozzle_offset_x = self.extruder[num].getProperty("machine_nozzle_offset_x", "value")
            self.nozzle_offset_y = self.extruder[num].getProperty("machine_nozzle_offset_y", "value")
        else:
            self.nozzle_offset_x = 0.0
            self.nozzle_offset_y = 0.0

Since you're returning the num it will be assigned to self.init_extruder_nr in line 203 so no need for assigning it here.
I would use the initial extruder number for getting the nozzle offset still rather than defaulting to 1, since you might be printing with the first extruder T0 and applying the offset of T1.

Have fun and ride safe.

@GregValiant
Copy link
Collaborator Author

"I would use the initial extruder number for getting the nozzle offset still rather than defaulting to 1"

On a dual-head printer with "side-by-side" nozzles - one of the nozzles must always have an offset.
One of the assumptions in the code is that T0 will always be the primary and that T1 will always be the one that is offset. That will be true for very close to 100% of the supported printers.

If the "primary" nozzle is T1, then the code (as written) should probably exit with a message. It might be possible to evaluate "T0 offset vs. T1 offset" and make a decision as to which one to use (and I'll think about that) but that seems a very small selection set of printers that would be defined that way. I suppose it would be possible to have "T0 Xoffset = -12.5" and "T1 Xoffset = 12.5" but I've never seen that.

Changing from the hard coded "extruder[1]" to "extruder[num]" would keep the offsets from loading when T0 starts the print but that would allow "T0" to make it all the way to the right extents of the bed which would not be possible with hotends on a common printhead.

My thinking is that: If there are offsets, they will be listed under T1, and those offsets are always in play regardless of which nozzle is in use.

@HellAholic
Copy link
Contributor

I get your point, without going into a multitude of checks it's not possible to do. Some machines can move with both extruders in the entire build plate area and others have physical limitations (S3 vs Method for example).
Then you can ignore that part. We're getting into the realm of expecting too much from a post processing script xD
I think it would be just easier to add it to the engine at this point :P

@GregValiant
Copy link
Collaborator Author

GregValiant commented Dec 29, 2024

I recall a post you made a couple of months ago where you indicated you were in favor of adding it directly to the engine rather than as a post-processor. An alternative would be to change this to an Extension/Plugin. The settings wouldn't be out of place in "Bed Adhesion".

With the additions of the disallowed areas and tool offsets, it has grown in scope. As a post-processor (or plugin) it could be a stop-gap until changes are made to the engine. With the code in the Engine, a definite plus is that it would show up in the preview without having to load the gcode file. People would see right away if their Purge Line location was interfering with something else on the build plate (Prime Tower, brim, etc.).

I'll continue the debugging today but I haven't seen any issues and certainly no show-stoppers.

I did add "kick-outs" to both "Add Purge Lines" and "Circle around to..." if the particular printer has offsets assigned to T0.

@GregValiant
Copy link
Collaborator Author

One change you made that I don't care for very much involves the end location of the "wipe" move at the end of the purge.
An example would be when the purge location is "Purge Left. The nozzle ends up at Y=35 after the wipe, and the next move added might be to machine_right. That X move is made at Y=35. The original design had a move off the purge line first, then a move to Y=1, and then the move to machine_right. That insures that the nozzle is moving around the periphery rather than 35mm into the build surface.
The same thing happens if the purge lines are at "Purge Front" and the first move is to machine_depth. That move is made at X=35 rather than X=1.0.

It requires a close examination of the gcode preview to see that travel move at Y=35 and it would be hard for most people to notice it if it was in fact a problem and ran across the footprint of their print. You just know that someone will complain.

@HellAholic
Copy link
Contributor

I don't think you mean the ones with the purge_str += bit.
The other one is easy to adjust:
Copy over the code below for the move_to_location function.

    def _move_to_location(self, location_name: str, location: tuple) -> str:
        """
        Compare the input tuple (B) with the end purge location (A) and describe the move from A to B.
        Parameters:
            location_name (str): A descriptive name for the target location.
            location (tuple): The target tuple (e.g., ("right", "front")).
        Returns:
            str: G-code for the move from A to B or an empty string if no move is required.
        """
        # Validate input
        if len(self.end_purge_location) != 2 or len(location) != 2:
            raise ValueError("Both locations must be tuples of length 2.")

        # Extract components
        start_side, start_depth = self.end_purge_location
        target_side, target_depth = location

        moves = [f";MESH:NONMESH---------[Move to {location_name}]\nG0 F600 Z2 ; Move up\n"]

        # Helper function to add G-code for moves
        def add_move(axis: str, position: float) -> None:
            moves.append(
                f"G0 F{self.speed_travel} {axis}{position} ; Start move\n"
                f"G0 F600 Z0 ; Nail down the string\n"
                f"G0 F600 Z2 ; Move up\n"
            )

        # Compare sides
        if start_side != target_side:
            if target_side == Location.RIGHT:
                add_move("X", self.machine_left + 5)
                if start_depth == Location.FRONT:
                    add_move("Y", self.machine_front + 5)
                else:
                    add_move("Y", self.machine_back - 5)
                add_move("X", self.machine_right)
            else:
                add_move("X", self.machine_right - 5)
                if start_depth == Location.FRONT:
                    add_move("Y", self.machine_front + 5)
                else:
                    add_move("Y", self.machine_back - 5)
                add_move("X", self.machine_left)

        # Compare positions
        if start_depth != target_depth:
            if target_depth == Location.REAR:
                add_move("Y", self.machine_front + 5)
                if start_side == Location.LEFT:
                    add_move("X", self.machine_left + 5)
                else:
                    add_move("X", self.machine_right - 5)
                add_move("Y", self.machine_back)
            else:
                add_move("Y", self.machine_back - 5)
                if start_side == Location.LEFT:
                    add_move("X", self.machine_left + 5)
                else:
                    add_move("X", self.machine_right - 5)
                add_move("Y", self.machine_front)
        if len(moves) == 1 and self.start_y:
            moves.append(f"G0 F{self.speed_travel} Y{self.start_y} ; Move to start Y\n")
        # Combine moves into a single G-code string or return a comment if no movement is needed
        return "".join(moves) if len(moves) > 1 else f";----------[Already at {location_name}, No Moves necessary]\n"

@HellAholic
Copy link
Contributor

You can adjust the distance from the edge of the build plate, currently set to 5 based on the original code.
You can add a setting to the script which is "Travel distance from build plate edge" or something like that and just set that one :P
Something along the lines of: self.travel_margin = self.getSettingValueByKey("travel_distance_from_edge") in the init, and then use the self.travel_margin instead of 5.

Added consideration for Disallowed Areas and Tool Offsets.
This also includes a lot of variables moved into "self".
@GregValiant
Copy link
Collaborator Author

I didn't get that fancy.
This doesn't seem to create any double moves, and puts the nozzle in the corner before going to a far edge.
I put it in right before "Compare Sides". It does a double move and then dips to the plate. Without the added Z moves it's a little quicker.

        # Move to a corner
        if start_side == Location.LEFT:
            moves.append(f"G0 F{self.speed_travel} X{self.machine_left + 6} ; Init move\n")
        elif start_side == Location.RIGHT:
            moves.append(f"G0 F{self.speed_travel} X{self.machine_right - 6} ; Init move\n")
        if start_depth == Location.FRONT:
            add_move("Y", self.machine_front + 6)
        elif start_depth == Location.REAR:
            add_move("Y", self.machine_back - 6)
        # Compare sides

That creates this:

;MESH:NONMESH---------[Move to Layer Start]
G0 F600 Z2                         ; Move up
G0 F7200 X223.0                    ; Init move
G0 F7200 Y223.0                    ; Start move
G0 F600 Z0                         ; Nail down the string
G0 F600 Z2                         ; Move up
G0 F7200 X1                        ; Start move
G0 F600 Z0                         ; Nail down the string
G0 F600 Z2                         ; Move up
;---------------------[End of layer start travels]

I just pushed a commit on this.

@GregValiant
Copy link
Collaborator Author

Timing is everything...Reddit

@PartySausage
Copy link

I just pushed a commit on this.

Loaded the new commit & sliced on my E3 S1 Pro. G-code looks good & seems to be functioning as expected in the PrusaSlicer G-code viewer with the Purge Lines on the Front Edge & Circle around to layer start enabled. I'll be doing a print tomorrow so can test it in the real world.

@PartySausage
Copy link

PartySausage commented Dec 31, 2024

I just pushed a commit on this.

Loaded the new commit & sliced on my E3 S1 Pro. G-code looks good & seems to be functioning as expected in the PrusaSlicer G-code viewer with the Purge Lines on the Front Edge & Circle around to layer start enabled. I'll be doing a print tomorrow so can test it in the real world.

I can't comment on the coding side & best practice but I've done several small prints with this commit on my simple setup & didn't experience any functional issues

- variable names updated to reflect their use more clearly
- removed obsolete if/else for move (the length of the list will be always 2)
@GregValiant
Copy link
Collaborator Author

Looks good.
I would suggest a small revision to "moves" in line 331:

moves = [f";MESH:NONMESH---------[Circle around to {location_name}]    Start from: {str(start_side)} {str(start_depth)}    Go to: {target_side} {target_depth}\nG0 F600 Z2 ; Move up\n"]

and line 358 is deleted.

That moves the comment from the end of data[1]) to the beginning of the travel section. Fits better I think.

;MESH:NONMESH---------[Circle around to Layer Start]    Start from: right rear    Go to: right rear

I'll add a commit with that change.

On another slightly different topic:
When I was playing around in 5.9.0 and trying different things with the Purge Lines script - I noticed that I cannot change the "Layer Start". It appears to always be "right rear".
Prior to 5.9.0 it wasn't like that. The "Layer Start" was always positioned according to the "Layer Start X" and "Layer Start Y" in the Travel Settings. That no longer appears to be true in 5.9.0 and those two settings appear to not have any effect. Not being able to adjust the layer start point can mean a lot of extra travel in models that are "C" shaped, or evolve into a "C" shape as the print progresses.
I'm thinking about opening a bug report in regards to that. If you get a chance, take a quick look and let me know what you think.

Change the comment line location from the end of data[1] to the first line of the "moves".

Update PurgeLinesAndUnload.py

Move the "start from" comment from the end of data[1] to the first line of the "moves" list.

Update PurgeLinesAndUnload.py

Change the comment line location from the end of data[1] to the first line of the "moves".
@HellAholic
Copy link
Contributor

I have a ticket open for that in the backlog, should be in before the next release. That includes making the travel move an optional move so it can be active / inactive and should always listen to the Layer Start X and Layer Start Y regardless of all other elements (prime tower position).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: Community Contribution 👑 Community Contribution PR's
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants