Ultimaker / Cura

3D printer / slicing GUI built on top of the Uranium framework
GNU Lesser General Public License v3.0
6.06k stars 2.06k forks source link

[Feature Request] Display Curent GCODE Line Number in Simulation View #7621

Open quarky42 opened 4 years ago

quarky42 commented 4 years ago

Is your feature request related to a problem? Please describe. After slicing, in simulation view, I would like to be able to see what line number within the generated gcode the current operation is paused at.

The GUI displays the layer number and a slider bar for the progress within that layer, but there is no way to tell where in the gcode file the slider bar is stopped.

To be clear, this should be the line number that is about to be executed if the user selects the horizontal timeline slider bar and "right arrows" one time. Before the user pressed the arrow key some element on the screen would display (at minimum) the current gcode line number and when the user arrows to the right one time, the line number increases, the screen updates and the action that was queued up to perform at that line number happens.

The line number needs to represent the actual line number of the file that would be saved. So the printing likely starts at some line number well into the beginning of the file after the start g-code block.

This is useful for both troubleshooting issues in gcode, finding exact locations in the gcode file, and other things. (I have a use case where I would like to be able to change the color part way through the layer. I can tell from the simulation where I want the line number because the nozzle is in a certain position but I have no easy way of figuring out what line number in the code corresponds to that location on the screen.

Describe the solution you'd like At a minimum, I would like the current line number to be displayed anywhere visible on the Simulation screen. How this is displayed is up to the developers, but I'd suggest a transparent label that gets updated when the UI is paused and gets updated when the user slides or nudges the timeline bar at the bottom to the right or left.

At a maximum, it might be nice to have the whole gcode line itself displayed onscreen.

When the user steps through the simulation to the next line, the new line is displayed, the previous line is executed and the screen refreshes. The screen is now at the beginning of the new line, about to execute that when the timeline is incremented again.

Describe alternatives you've considered As a programmer and a CNC Mill operator, I'm used to using tools all the time that let me step through code, but they all have one thing in common: Line numbers!

Affected users and/or printers Some users won't care. Other users might use the information on the screen as a jumping off point for learning a little bit more about gcode. The intended audience is for people trying to insert custom commands / custom operations within their code that don't align to layer boundaries. On a "sign" print, the layer gets filled in except for the lettering and symbol...that is the last part of the that layer. I'd like to insert a pause (even if I have to do it by hand) and change the filament out so that when it finishes filling in the text and symbols of that layer, it is already on the new color. This also means that the color is embedded deeper into the print, the color change is stronger because it is surrounded by other filament, and I don't have to purge the nozzle quite so carefully because that layer is going to be covered up anyway. Other people will have uses for specific line information in a similar manner but maybe not for color changes.

Additional context Personally, a transparent text label that is updated with the gcode line number or the whole line of gcode itself during simulation time would be great. It doesn't need to have it's own dedicated space, but just overlay at the top or the bottom of the visualization screen.

Ghostkeeper commented 4 years ago

We don't currently have a way in our code to match individual lines to line numbers. For performance reasons, Cura's front-end never reads the g-code that it receives from CuraEngine. It gets its layer view data separately in the form of polylines.

Good feature request though. See also this feature request, which is similar but got deferred due to the difficulty of implementation and because it only benefits expert users: https://github.com/Ultimaker/Cura/issues/7475

Maybe someone has an idea here that could clarify how we can implement this without performance impacts from our Python front-end.

quarky42 commented 4 years ago

If the polylines are being returned from a function, then can python return a struct instead of [polyline, gcode line number] where the display pulls the poly line from the struct and uses it, and only displays the line number under pause and incremental stops?

The intent is not to spend lots of time updating line numbers that can't be seen scrolling by anyway.

If a struct or complex type can't be returned from the function that generates polylines, can you feed it a variable by reference that it can update with the current line number being displayed? The GUI can check that variable and update the display when pause is pressed or when the slider is updated but play isn't active. (Only update when animation isn't present)

I've worked in a lot of languages that aren't Python, so it's okay if I'm way off base here, it just seems like there is always a way to expose something like a line index. The sliced gcode itself can be just stored in memory on the GUI side if that index can be passed in one way or another. Pulling a string out of an array of strings is not intensive at all unless you're trying to update the display in a loop... Which is not what we're talking about here. No need to have data scrolling by that can't be read. Just need to see it when it stops.

Or is only the front end python? What is the backend? Does someone just need to write a get function for the current line number that can be called from the base code?

Ghostkeeper commented 4 years ago

There is a way to build it, of course. We do provide metadata per segment already such as the print speed. It just needs to be built. I don't think we can build this in our front-end due to the performance of reading through 1GB of text in Python. It would need to be built in CuraEngine. Preferably during the g-code writing itself, although that would be very sensitive to offset errors if we forget to count something.

However that only serves to get a line number if we track that. Line numbers don't say anything to the user (especially if they don't save their g-code to a file but just send it over wifi or something). To get the line of g-code we'd need to also store each g-code command separately, which is infeasible I think.

Python comes with a lot of overhead for function calls as well as for objects. We store the sliced g-code itself in the GUI as a list of strings, one per layer. We don't store them one per line because the overhead would be enormous.

In Python everything is passed by reference, and our GUI framework already only updates once something changes by nature, so that's not a problem. Our back-end is a separate application that performs the actual task of turning a 3D object into g-code, and it's written in C++. This back-end is short-lived just to serve one slice per run.

fieldOfView commented 4 years ago

would be very sensitive to offset errors if we forget to count something

Any plugin that processes the gcode after slicing would also screw up that offset (most notably Post Processing plugin, but also Z Offset plugin, etc).

quarky42 commented 4 years ago

Whether saved or not the gcode output should already be built and cached somewhere (in memory) after slicing is done. It isn't gigs and gigs of memory. Once slicing is done it is megabytes.

Post processing is a script. It can be applied and the final result stored in memory. If the gcode really does get large, then cache it to a file. (I've never seen a gcode file for a unlimited z printer or a 2'x4'x2' printer or larger. I guess those can get pretty big but still just hundreds of Meg's, not gigs.

Ghostkeeper commented 4 years ago

Yes, the g-code output is generated and stored in memory. This takes as much memory as the file size would be if you save it. RAM is not really the problem.

However we can't just tell your computer to draw the g-code. We need to tell your computer that certain square tubes have to be drawn, with a certain width, height and colour, and from one position to another. We need to translate the g-code from text into those coordinates and colours. For that the g-code needs to be broken up in millions of pieces, and each piece needs to be parsed, line widths have to be calculated from the amount of extrusion, and missing coordinates have to be inferred from previous lines. This takes a few minutes.

This is precisely what happens when you open a .gcode file with Cura. That progress bar is orders of magnitude slower than any other in Cura. When normally slicing we send over those coordinates and related information via a separate channel as they are generated in CuraEngine. That way we don't need to store them in the g-code and then re-parse them. We can just directly use the coordinates and width of each line and the height of each layer. We just need to translate the colours depending on the colour scheme that the user chose, for which the linetype/layerheight/speed of the line was sent over that same separate channel. My previous comment was about sending line number information over that same separate channel too.

The post-processing scripts by nature work on the g-code itself, not the coordinates. To get the coordinates after the post-processing script has done its work, we'd need to re-parse the result from g-code to coordinates again. This is why you can't see the result of post-processing scripts in layer view.

quarky42 commented 4 years ago

I may be mistaken, but I think this may be a classic problem of being too close to it all, and not realizing that there may be a more simple answer.

The GUI renders the nozzle position. That nozzle position is the start of a line / start of a gcode command. If the underlying functions were updated to communicate the line position within the gcode that coincides with the position of the nozzle, then that information could be displayed. I understand that a change like this may require some deep thought to make sure it is done in a way that doesn't cause other problems, but adding communication between a GUI and the underlying code shouldn't be so impossible.

I believe you are looking at it from a standpoint of: "How do we calculated the gcode line number based on the information that is on the screen." That is not how I would do it. I would look at it as a problem of: "The code at some fundamental level knows exactly what line number the current nozzle location represents. How do we communicate / pass that information to the GUI so that the gcode line number can be displayed to the user in the simplest way possible?"

Once the line number is being passed, it is perfectly reasonable to ask the question that was brought up earlier: Does that line number need to be modified by applying any postscripts to it? Can we find that line number again if we take the block of generated gcode and search for that line number? If it is possible to display the nozzle position for any given moment in the horizontal timeline, then it should be possible to communicate the position within the original gcode. Each line that is added to the screen is the result of a move command. The beginning is the end of the previous move command. The end of the line that is generated contains the move command itself. So even if I had to do a search within the gcode, I could search for the end coordinate as part of a movement command.

I'm sorry my suggestions are so vague. I would have to spend a lot of time getting familiar with this code itself, but this problem is very much like other problems I have solved in different programs (not slicers, but how figuring out how to capture key elements of data during a process) and my gut feeling is that there is a fundamental location within the code where the position is known and a line number could be figured out and passed back to the GUI, or during the pause, there could be a query added to the underlying code so that the GUI could ask for the line number or even the line of gcode itself.

I may have misunderstood something though: Is the gcode created in memory when the slicing completes? When the user steps through the horizontal slider, the renderer code is stepping through the code or stepping through data that was generated by the code but at some fundamental level that rendered data does directly correspond to the gcode, it is just a matter of deciding where in the loop it truly knows its position and tapping into that data.

When I get time, I will try to look at the source for Cura and get a peek under the hood to see if I see something that jumps out at me. It will be a while before I get that kind of time though, but I am really interested in seeing this information so I will do what I can to try and help.

On Mon, May 4, 2020 at 10:31 AM Ghostkeeper notifications@github.com wrote:

Yes, the g-code output is generated and stored in memory. This takes as much memory as the file size would be if you save it. RAM is not really the problem.

However we can't just tell your computer to draw the g-code. We need to tell your computer that certain square tubes have to be drawn, with a certain width, height and colour, and from one position to another. We need to translate the g-code from text into those coordinates and colours. For that the g-code needs to be broken up in millions of pieces, and each piece needs to be parsed, line widths have to be calculated from the amount of extrusion, and missing coordinates have to be inferred from previous lines. This takes a few minutes.

This is precisely what happens when you open a .gcode file with Cura. That progress bar is orders of magnitude slower than any other in Cura. When normally slicing we send over those coordinates and related information via a separate channel as they are generated in CuraEngine. That way we don't need to store them in the g-code and then re-parse them. We can just directly use the coordinates and width of each line and the height of each layer. We just need to translate the colours depending on the colour scheme that the user chose, for which the linetype/layerheight/speed of the line was sent over that same separate channel. My previous comment was about sending line number information over that same separate channel too.

The post-processing scripts by nature work on the g-code itself, not the coordinates. To get the coordinates after the post-processing script has done its work, we'd need to re-parse the result from g-code to coordinates again. This is why you can't see the result of post-processing scripts in layer view.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Ultimaker/Cura/issues/7621#issuecomment-623568845, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALQQATEINWVDIXOIOBOQRJDRP3UUFANCNFSM4MTI4KCQ .

fieldOfView commented 4 years ago

That nozzle position is the start of a line / start of a gcode command.

No, it isn't. Cura does not look at the gcode that CuraEngine produces. It looks at specially created layer data that has no 1:1 relation to the gcode. CuraEngine creates two things: gcode for your printer, and layer data for Cura to display.

The layer data that is created could be extended to include a reference to gcode line numbers to create the correlation between the layer data and the gcode that currently does not exist. There are two remaining problems though: First, the Ultimaker developers have limited time to implement things, and the added value for typical Ultimaker printer owners seems low. Second, the whole correlation breaks if there is any postprocessing done to the gcode after CuraEngine is done creating the gcode.

quarky42 commented 4 years ago

Is applying post processing scripts to the gcode to produce accurate line numbers intensive? I've only used a couple of the post processors, but they seem pretty straight forward. If it were me writing the code I would write a function that takes the original like number, applies the post processing scripts, and produces a final line number after post processing. Seeing where that line moves during post processing is pretty easy to track in the post processors I'm familiar with, but that view is admittedly limited.

If that proves to be too time intensive to step through, calculating an integer array of the size "original line number" where each entry in the array contains the post processed line number and indexing into that array for the converted value would be really quick. This array would need to be generated by the post process scripts, but that could be done and doesn't seem technically difficult to me.

Value to Ultimaker printer owners seems like a hard thing to assume without asking them if they would like this feature. If Ultimaker surveys its customers, perhaps this could be added to the survey rather than assuming they don't want to be able to find something more accurate than the layer number within the gcode. If Ultimaker ever creates a vision for where they want this slicer to go, then maybe there is room on the roadmap to work towards this, not as requested feature that was directly added, but as a goal for a new version to be worked towards over time and as time allows.

If the answer is we don't want to add that feature because we don't think it is valuable enough, then so be it. Im just responding to the technical side of it that a solution wouldn't have to have the limitations that are being placed on it in many of the responses so far. Post processing breaking the line numbers only applies if the developers aren't willing to run the gcode through the post processors and create the proper correlation. The numbers being displayed would jump after post processing added code, but that could be explained in the tooltip or on the line when the display feature is enabled.

If this isn't a feature that should make it into a point release, maybe it could be targeted for a whole new version down the road?

Ghostkeeper commented 4 years ago

Value to Ultimaker printer owners seems like a hard thing to assume without asking them if they would like this feature. If Ultimaker surveys its customers, perhaps this could be added to the survey rather than assuming they don't want to be able to find something more accurate than the layer number within the gcode. If Ultimaker ever creates a vision for where they want this slicer to go, then maybe there is room on the roadmap to work towards this, not as requested feature that was directly added, but as a goal for a new version to be worked towards over time and as time allows.

To be clear, Ultimaker does have visions for where Cura is heading (although quite vague if you ask me) as well as a long-term and a short-term roadmap (which are not vague at all). They include work on upcoming printers and features of printers though, which is company secret so we can't share them. We've always tried to focus on high-level operations though, and manual g-code editing is not part of that. This is very much a feature for experts only. The only way to get this in our roadmap is to be convinced that it's not hard to implement or maintain and doesn't make our code base more complex.

Post-processing scripts and other g-code transformations by plug-ins (like the ChituCodeWriter plug-in from the Marketplace) can make arbitrary changes to the g-code. They work on the g-code string itself, not on the layer view data. We could force them to also update line numbers but that could prove to be quite complex for things like the Search and Replace post-processing script, which can replace newlines if the user types them (using \n). We could also just not display the effect of post-processing there in simulation view. More limited effectiveness if you use those, but fine for most things. Of course then we'll get bug reports that people don't see the effect of post-processing scripts reflected in the g-code.

If post-processing events are left aside, my greatest worries for this feature are:

thanhtacles commented 4 years ago

I second this. I need to step through the gcode lines to see exactly what it is doing because I do post processing scripting. It would really help me interrogate the gcode if you could just put the raw text output of where in the gcode it is as the nozzle moves. Even put a step button next to the play button on the nozzle simulation bar at the bottom.

thanhtacles commented 4 years ago

That nozzle position is the start of a line / start of a gcode command.

No, it isn't. Cura does not look at the gcode that CuraEngine produces. It looks at specially created layer data that has no 1:1 relation to the gcode. CuraEngine creates two things: gcode for your printer, and layer data for Cura to display.

The layer data that is created could be extended to include a reference to gcode line numbers to create the correlation between the layer data and the gcode that currently does not exist. There are two remaining problems though: First, the Ultimaker developers have limited time to implement things, and the added value for typical Ultimaker printer owners seems low. Second, the whole correlation breaks if there is any postprocessing done to the gcode after CuraEngine is done creating the gcode.

@fieldOfView If this is true, then how is it possible that I can load raw gcode from file, and have the nozzle simulation play anyway?

fieldOfView commented 4 years ago

how is it possible that I can load raw gcode from file

Have you ever noticed how long it takes to load a gcode file? Since there is no "layer data" for Cura to display, Cura has to reconstruct this when loading a gcode file. This takes long, and the reconstructed data is less detailed (not all line-types can be easily recovered, eg support interfaces). This is exactly why Cura does not use the gcode by default: it would make opening the preview very slow.

quarky42 commented 4 years ago

So it wouldn't need to load it by default, but being able to load it by request would sure help when trying to insert custom gcode in the middle of a layer.

Doing color changes before the end of a layer but after a certain feature is completed would be very nice to have indeed. I could manually insert the code if I knew the exact location of a line in given layer.

The end of the line should be part of a G1 extrusion command. If I knew that point within the layer I could find it manually.

fieldOfView commented 4 years ago

... but that still would not take into account postprocessing and plugins like Post Processing, Z Offset, Linear Advance and more that alter the gcode after it has been displayed, making the line numbers invalid again.

It would be a lot of effort for something that would only work in a limited fashion for a fairly specific usecase.

quarky42 commented 4 years ago

If I knew the coordinates for the end of the line I could manually find the location in the file regardless of most post processing unless the processing changes the line end point in a given layer.

Maybe simulation should be ran off the final gcode itself instead of something that is an artificial intermediate that doesn't really line up.

I work with CNC gcode and simulations of CNC processes and it just baffles me that we are at a point where you can see something that looks like a part being printed, but heaven forbid you want to actually know where in the code you are within the simulation.

thanhtacles commented 4 years ago

how is it possible that I can load raw gcode from file

Have you ever noticed how long it takes to load a gcode file? Since there is no "layer data" for Cura to display, Cura has to reconstruct this when loading a gcode file. This takes long, and the reconstructed data is less detailed (not all line-types can be easily recovered, eg support interfaces). This is exactly why Cura does not use the gcode by default: it would make opening the preview very slow.

Even if it was a feature that slow, it would still be instrumentally useful just to see what it's trying to render as a text box. It would make helping me step through the g code that much easier just to have a visualization so I can quickly comb through and orient myself exactly where I need to.

andyhibbert commented 1 year ago

I agree with Quarky42. I have had a repeatable problem with Cura 5.1.1 crashing after 90 mins of a 3 hour print. It would be very useful to be able to analyse the gcode at that event. When my cnc machine stops or stutters, I can easily get Mach3 to show me where the problem is.

crckrmn77 commented 1 year ago

Regardless of the correlation between the GCode and layer data, wouldn't displaying the nozzle position allow the user to find the line of code. I know this would help ME tremendously, and it seems like your layer data would have to match the GCode for individual positions within the print geometry. Sure, revisualizing then requires the user to load the GCode and all of the artifacts that creates in the image. But, it would also take ages off of manually post-processing a file.

thanhtacles commented 1 year ago

Regardless of the correlation between the GCode and layer data, wouldn't displaying the nozzle position allow the user to find the line of code. I know this would help ME tremendously, and it seems like your layer data would have to match the GCode for individual positions within the print geometry. Sure, revisualizing then requires the user to load the GCode and all of the artifacts that creates in the image. But, it would also take ages off of manually post-processing a file.

Prusaslicser has this now. So any post-processing script that I have can just be easily visualized to show the exact movement changes it made. Cura should follow suit.

Hal9999 commented 5 months ago

I found this FR. Prusa has a pretty nice gcodeviewer, I'm going to use that at the moment.