Quantization of G-code export to achieve more precise extrusion

width control.
This commit is contained in:
Vojtech Bubnik 2022-02-07 15:33:34 +01:00
parent 1138c563b2
commit 199dc121a5
6 changed files with 138 additions and 135 deletions
src/libslic3r

View file

@ -27,7 +27,6 @@
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/beast/core/detail/base64.hpp>
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/cstdio.hpp>
@ -155,63 +154,52 @@ namespace Slic3r {
std::string Wipe::wipe(GCode& gcodegen, bool toolchange)
{
std::string gcode;
std::string gcode;
const Extruder &extruder = *gcodegen.writer().extruder();
/* Reduce feedrate a bit; travel speed is often too high to move on existing material.
Too fast = ripping of existing material; too slow = short wipe path, thus more blob. */
double wipe_speed = gcodegen.writer().config.travel_speed.value * 0.8;
// get the retraction length
double length = toolchange
? gcodegen.writer().extruder()->retract_length_toolchange()
: gcodegen.writer().extruder()->retract_length();
// Shorten the retraction length by the amount already retracted before wipe.
length *= (1. - gcodegen.writer().extruder()->retract_before_wipe());
if (length > 0) {
/* Calculate how long we need to travel in order to consume the required
amount of retraction. In other words, how far do we move in XY at wipe_speed
for the time needed to consume retract_length at retract_speed? */
double wipe_dist = scale_(length / gcodegen.writer().extruder()->retract_speed() * wipe_speed);
/* Take the stored wipe path and replace first point with the current actual position
(they might be different, for example, in case of loop clipping). */
Polyline wipe_path;
wipe_path.append(gcodegen.last_pos());
wipe_path.append(
this->path.points.begin() + 1,
this->path.points.end()
);
wipe_path.clip_end(wipe_path.length() - wipe_dist);
// subdivide the retraction in segments
if (!wipe_path.empty()) {
// add tag for processor
// Remaining quantized retraction length.
if (double retract_length = extruder.retract_to_go(toolchange ? extruder.retract_length_toolchange() : extruder.retract_length());
retract_length > 0 && this->path.size() >= 2) {
// Reduce feedrate a bit; travel speed is often too high to move on existing material.
// Too fast = ripping of existing material; too slow = short wipe path, thus more blob.
const double wipe_speed = gcodegen.writer().config.travel_speed.value * 0.8;
// Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
// due to rounding (TODO: test and/or better math for this).
const double xy_to_e = 0.95 * extruder.retract_speed() / wipe_speed;
// Start with the current position, which may be different from the wipe path start in case of loop clipping.
Vec2d prev = gcodegen.point_to_gcode_quantized(gcodegen.last_pos());
auto it = this->path.points.begin();
Vec2d p = gcodegen.point_to_gcode_quantized(*(++ it));
if (p != prev) {
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n";
for (const Line& line : wipe_path.lines()) {
double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
due to rounding (TODO: test and/or better math for this) */
double dE = length * (segment_length / wipe_dist) * 0.95;
auto end = this->path.points.end();
bool done = false;
for (; it != end; ++ it) {
p = gcodegen.point_to_gcode_quantized(*it);
double segment_length = (p - prev).norm();
double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length);
if (dE > retract_length - EPSILON) {
if (dE > retract_length + EPSILON)
// Shorten the segment.
p = prev + (p - prev) * (retract_length / dE);
dE = retract_length;
done = true;
}
//FIXME one shall not generate the unnecessary G1 Fxxx commands, here wipe_speed is a constant inside this cycle.
// Is it here for the cooling markers? Or should it be outside of the cycle?
gcode += gcodegen.writer().set_speed(wipe_speed * 60, "", gcodegen.enable_cooling_markers() ? ";_WIPE" : "");
gcode += gcodegen.writer().extrude_to_xy(
gcodegen.point_to_gcode(line.b),
-dE,
"wipe and retract"
);
gcode += gcodegen.writer().set_speed(wipe_speed * 60, {}, gcodegen.enable_cooling_markers() ? ";_WIPE" : "");
gcode += gcodegen.writer().extrude_to_xy(p, -dE, "wipe and retract");
prev = p;
retract_length -= dE;
}
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n";
gcodegen.set_last_pos(wipe_path.points.back());
gcodegen.set_last_pos(gcodegen.gcode_to_point(prev));
}
// prevent wiping again on same path
this->reset_path();
}
// Prevent wiping again on the same path.
this->reset_path();
return gcode;
}
@ -3010,13 +2998,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
double path_length = 0.;
{
std::string comment = m_config.gcode_comments ? description : "";
for (const Line &line : path.polyline.lines()) {
const double line_length = line.length() * SCALING_FACTOR;
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
auto it = path.polyline.points.begin();
auto end = path.polyline.points.end();
for (++ it; it != end; ++ it) {
Vec2d p = this->point_to_gcode_quantized(*it);
const double line_length = (p - prev).norm();
path_length += line_length;
gcode += m_writer.extrude_to_xy(
this->point_to_gcode(line.b),
e_per_mm * line_length,
comment);
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
prev = p;
}
}
if (m_enable_cooling_markers)
@ -3239,7 +3229,13 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
Vec2d GCode::point_to_gcode(const Point &point) const
{
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
return unscale(point) + m_origin - extruder_offset;
return unscaled<double>(point) + m_origin - extruder_offset;
}
Vec2d GCode::point_to_gcode_quantized(const Point &point) const
{
Vec2d p = this->point_to_gcode(point);
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
}
// convert a model-space scaled point into G-code coordinates