Ultimaker / CuraEngine

Powerful, fast and robust engine for converting 3D models into g-code instructions for 3D printers. It is part of the larger open source project Cura.
https://ultimaker.com/en/products/cura-software
GNU Affero General Public License v3.0
1.67k stars 880 forks source link

Erroneous "Micron Moves" in curves #607

Closed lylecheatham closed 6 years ago

lylecheatham commented 7 years ago

I've taken to calling this anomaly a "Micron Move"

In the Gcode generated for curves, there is occasionally a very small move in a seemingly random direction. So far I have only observed this in Rafts, but frankly it could be happening everywhere, I just haven't stared at the printer for long enough.

Below is a excerpt from real Gcode, generated in Cura 2.7, stock settings (except for raft turned on)

57 | G1 X137.485 Y141.359 E0.54257
58 | G1 X137.068 Y141.46 E0.56
59 | G1 X136.436 Y141.598 E0.58629
60 | G1 X136.436 Y141.599 E0.58633
61 | G1 X136.05 Y141.674 E0.6023
62 | G1 X135.425 Y141.784 E0.62809

Excerpt 1. Micron moves in a harmless direction

Here is an example of a random micron move in a harmless direction. In this example we are moving in the X-, Y+ direction. On line 60 we get a micron move in the positive Y direction, which has no effect on the print.

This manifestation of the bug causes no problems in the print, as the planner will just glide right over it.

129 | G1 X78.647 Y126.597 E3.19854
130 | G1 X78.498 Y126.213 E3.21527
131 | G1 X78.271 Y125.589 E3.24225
132 | G1 X78.27 Y125.589 E3.24229
133 | G1 X78.134 Y125.192 E3.25934
134 | G1 X78.135 Y125.192 E3.25938
135 | G1 X77.941 Y124.572 E3.28578
136 | G1 X77.827 Y124.18 E3.30237

Excerpt 2. Micron moves in a harmful direction

This is an example of a random micron move in a harmful direction. In this example we are moving in the X-, Y- direction, however on line 134 we get a micron move in the positive X direction. This is highly problematic because the GRBL planner (used in almost every firmware) sees this and interprets it as a line segment in the opposite direction. To complete this, it must come to a full stop from the curve it was making, move backwards by one step, and then accelerate back up to speed. Side Note: This excerpt also contains a harmless micron move on line 132

Here are some images that demonstrate this behavior on stock Marlin 1.1.5. I ran it on a RUMBA board hooked up to a Saleae Logic analyzer, and then ran the capture through a python script to extract the movement data. These are shown in Figures 1-4. When reading these graphs you can ignore the position and acceleration data in these captures, the interesting bits are in the Velocity traces.

In Figure 1, we see that the printer is making what essentially amounts to a square with rounded corners, and during the corners, it occasionally slows to a dead stop and then speeds back up. Doing a movement like this will cause printers to pool plastic along the bead, and also increases print times.

micronmove zoom0 Figure 1. Micron Moves at 29.5s, 35.3s, 35.5s, 35.7s and 35.9s

Zooming further on the anomaly in Figure 1, we see that what is really happening is that the X, Y, and E axes come to a full stop, and then the X axis makes a very small movement in the opposite direction. This can be seen in Figures 2 and 3.

micronmove0 zoom1 Figure 2. Zooming in on the move at 29.5s micronmove0 zoom2 Figure 3. Further zoom on the move at 29.5s

For a clearer view of this, we can look at the raw Logic captures. In Figures 4 and 5, we can see that it slows to a halt, then the X axis reverses direction for a short while, and then we pick back up to speed in the direction we were going initially.

capture 1 Figure 4. Logic Capture of the move at 29.5s

capture 2 Figure 5. Zoomed Logic Capture of the move at 29.5s

To show that this problem is exactly what I'm saying it is, If I remove line 64 from Excerpt 2, as demonstrated in Excerpt 3 and run it, the first spike will disappear. Please note, the times will not align from the second capture because I am just triggering it by hand.

129 | G1 X78.647 Y126.597 E3.19854
130 | G1 X78.498 Y126.213 E3.21527
131 | G1 X78.271 Y125.589 E3.24225
132 | G1 X78.27 Y125.589 E3.24229
133 | G1 X78.134 Y125.192 E3.25934
134 |
135 | G1 X77.941 Y124.572 E3.28578
136 | G1 X77.827 Y124.18 E3.30237

Excerpt 3. Micron move from Excerpt 2 removed

Figure 6. shows the same print, with the micron move on line 134 removed.

micronmove2 zoom0 Figure 6. Micron move removed

Clearly line 134 had a large impact on the print. That small micron move caused the printer to come to a complete stop, which would impact print quality on curves. Micron moves seem to be prevalent throughout Gcodes generated by Cura, but most of the time have no impact on the print because they are in the same direction that the printhead was moving originally.

-Lyle Cheatham


Attached is the Gcode file I was running. Please note that I deleted several lines related to temperature as I am just running a detached RUMBA board hooked up to my logic analyzer on my desk, and I didn't want temp commands causing strange behavior.

Also attached is the config file I used for Marlin 1.1.5 if you are looking to replicate. I set steps/mm all the way up to 1000 to ensure that the problem would show through. If the Micron move does not generate any steps GRBL will throw the move away.

attach.zip

smartavionics commented 7 years ago

That's a great analysis that you have done there. I have already had a discussion with some of the Cura devs about the fact that it generates a lot of small extrusions (I noticed them because they actually triggered a bug in my printer firmware). Because I build Cura from source, I have added a little bit of code to replace extrusions less than 5um long with moves. Perhaps, given what you say above, I should just ignore those short extrusions completely.

smartavionics commented 7 years ago

See #591.

lylecheatham commented 7 years ago

My current fix to this problem is probably going to be a python post-processor script that just deletes the micron moves, but that is just a big band-aid. I'm not too familiar with the code base but applying something similar in Cura, or even finding the root cause of these micron moves would probably be best.

The interesting thing about this problem, is that I would probably expect this to be a 'bug' in pretty much any GRBL based Firmware, which probably makes up 80%+ of the community. The only things necessary to bring it out are either a high st/mm extruder (fairly common, especially on 2.85mm systems) or high st/mm XY axes (less common, but still should not be alienated). Also untested, but I'm fairly certain a high extrusion multiplier could also trigger this.

I saw some discussion on #591 on whether the slicer or the firmware should be filtering them, and in my opinion it is a two sided fix. The slicer should not generate unreasonable moves, and the printer should not execute moves it deems unreasonable (e.g. moves that are smaller than a reasonable mechanical tolerance for the machine). However, depending on the quality and precision of your machine, or depending on the extrusion multiplier, this could be considered a reasonable move.

DDDirk commented 7 years ago

I disagree with the printer ignoring moves it deems unreasonable because the gcode may have been written or programmed for precisely the effect you descibe. I don't know why someone would want to do that, but that is precisely the point. You can never know what weird stuff someone might want to do with the printer. The move itself may be nonsensical, but the deceleration may be what the writer of the code wants. Or indeed a slicer. If it is indeed a bad move, a slicer should not generate it.

nallath commented 6 years ago

Wow, I'm seriously impressed with the amount of work & logging you put into this. I don't say this lightly; I wish more bug reports were this detailed!

Ghostkeeper commented 6 years ago

The argument for the printer removing them (at least how I understood it) was because of the printer not being able to keep up with the speed of processing required for making moves of <5 micrometres. You need a lot of processing power to draw a curve of 20,000 line segments in 0.5s. That's not something a slicer should have to take into account.

This argument is different and valid. If Cura is making erroneous moves that cause the acceleration and jerk to kick in at the firmware, that is expected result in the firmware and unexpected result from Cura.

Ghostkeeper commented 6 years ago

I've made this regex to find such micron moves:

G1 [F\d\. ]*(X\d+\.\d{2})\d* (Y\d+\.\d{2})\d* [Z\d\. ]*[E\d\.]*\nG1 [F\d\. ]*\1\d* \2\d* [Z\d\. ]*[E\d\. ]*
lylecheatham commented 6 years ago

Hey all,

Glad everyone is enjoying the depth of the bug report. The main reason it got that deep is because I originally thought it was a firmware bug, and spent a while tracking it down on Smoothieware, eventually I came to the realization that it was all due to strange input from Cura, I already had all the hardware logging set up so I figured I might as well include it. I also wanted to check if it existed in Marlin because if I could replicated it in two implementations of GRBL, I could extrapolate that it's probably a problem in almost every firmware variant that implements GRBL

About the printer filter vs slicer filter, I think it's a pretty philosophical discussion, but I wrote my take below. Note that this is just my friendly addition to the conversation, no offense taken if you disagree

I think G1/G0s should be used to define waypoints for the printer, with very little guidance on how they get from one to the next. You might point out that there is a feedrate attached to G1/G0, but on the firmware side of things, it is taken merely as a suggestion. Once the printer receives these G-Codes, it is entirely up to the firmware on how to get from one waypoint to another.

One thing the firmware needs to consider with these waypoints is tolerance. At any given moment, the nozzle has a slop of tens, sometimes hundreds of microns. So as the print is running along, and it is coming from point A to point B 100mm away, and then immediately after is point C 1 micron away from point B, it has essentially hit point C and B at the same time due to real world tolerances. For planning purposes, there is no reason to plan a line between these two almost-identical points, so we should filter one of them out.

Now, to address @DDDirk's concerns of 'what if the G-code was there to get this exact effect?' and this is where I go back to these waypoints having little guidance on how. If the slicer desires behavior like this, I think it should not attain it through the use of G1/G0, it should use other G-Codes more closely tied with the 'how' of printing. An example of one of those codes would be G4 dwell. this exact effect could be achieved with a G4 S0, which introduces a stop in the planner.

On the slicer side, I think these should be filtered purely because it's unintentional and takes up space/bandwidth at no benefit (and occasionally some detriment) to the part.

Of course another argument, as @Ghostkeeper brought up, is bandwidth. Many firmwares lock up if you give it G-codes too fine, especially Marlin which physically can not send the G-Code fast enough due to the 250 Kbaud hardware serial connection. Unrelated to this, but I find the continued use of hardware serial in 3D printers to be almost comical, for the price of an FTDI chip you could just upgrade to a microcontroller with USB built in, and then you have a much faster connection (USB standard is 12Mb/s).

smartavionics commented 6 years ago

Ever since I found the issue with the printer firmware getting upset by very small extrusions I have been using the following..

 void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFillType space_fill_type, float flow, bool spiralize, double speed_factor)
 {
    // ignore extrusions less than 5uM long
    if(vSize2(p - *last_planned_position) >= 25)
    {
        getLatestPathWithConfig(config, space_fill_type, flow, spiralize, speed_factor)->points.push_back(p);
        last_planned_position = p;
    }
 }

That only emits extrusions that are at least 5um long. Needless to say, I can't see any visual difference in the print quality. Unless you can fix all the places where the short extrusions are being generated, I think you have to filter them out like this to avoid the kind of problems that the OP has so expertly identified.

Ghostkeeper commented 6 years ago

All right, after investigating a bit, I've made a fix similar to Smartavionics', but more specific. The problem, I think, was that the rafts are offset with a large offset and a round joint type. This round joint type introduced a lot of extra vertices with small details, which in itself isn't a problem but it apparently is if you then do an inset because the vertices at the start and end of the rounded corner fell 1 micron next to the longer line. We do the inset with half a line width because the nozzle needs to move through the centre of the line but we want the outside edge of the line to coincide with the original polygon, not the centre.

I'm calling the simplify() function on the polygon in question. This does something similar to Smartavionics' idea. So that one's fixed in fb5a705c6ff3dd7793732be2454b246d3addac5a. I'm not getting these movements any more now. At least not with the raft, and I couldn't find them elsewhere.

smartavionics commented 6 years ago

That's great but I see loads of extrusions less than 5um long and I never use rafts!

smartavionics commented 6 years ago

Related to this discussion. See #614 for a fix for short segments being created in zigzags which were triggering unnecessary travel moves even when the short extrusion was thrown away.

Ghostkeeper commented 6 years ago

I fixed the micron moves in the rafts for 3.0 and the micron moves in zigzag patterns were fixed by Smartavionics for 3.1. We believe they don't occur any more now.

smartavionics commented 6 years ago

However, there is still an outstanding PR for a fix to zigzags (see #629). This needs to be merged.