Skip to content

Commit

Permalink
lift & lift_min update:
Browse files Browse the repository at this point in the history
 * At the first move, merge Z-move and don't split the travel, so the printer won't "dance", whatever where the nozzle is.
Note:it's a hack, please redo it properly when reworking gcode-writer.
 * retract_lift_first_layer is gone back to the old simple behavior (revert b16ecbf)
 * removed auto extra lift for first layer, now that lift_min exists.
 * with complete object, don't unlift at object/first layer change, to avoid Z-dance
 * lift_min will be used between brims, skirts, objects but not between object-skirt, object-brim and their object
#1783
#1775
#1575
#599
#429
#395
#241
  • Loading branch information
supermerill committed Nov 4, 2021
1 parent cf019af commit e015c3a
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 55 deletions.
105 changes: 67 additions & 38 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,22 +219,19 @@ std::string Wipe::wipe(GCode& gcodegen, bool toolchange)
}

//if first layer, ask for a bigger lift for travel to object, to be on the safe side
static inline void set_extra_lift(const float previous_print_z, const int layer_id, const Print& print, GCodeWriter & writer, int extruder_id) {
static inline void set_extra_lift(const float previous_print_z, const int layer_id, const PrintConfig& print_config, GCodeWriter & writer, int extruder_id) {
//if first layer, ask for a bigger lift for travel to object, to be on the safe side
double extra_lift_value = 0;
if (layer_id == 0 &&
(print.config().retract_lift.get_at(extruder_id) != 0 || print.config().retract_lift_first_layer.get_at(extruder_id))) {
//get biggest first layer height and set extra lift for first travel, to be safe.
for (const PrintObject* obj : print.objects())
extra_lift_value = std::max(extra_lift_value, print.get_object_first_layer_height(*obj));
if(previous_print_z == 0)
extra_lift_value *= 3;
else
extra_lift_value *= 2;
}
if (print.config().lift_min.value > 0) {
if (previous_print_z + extra_lift_value < print.config().lift_min.value) {
extra_lift_value = print.config().lift_min.value - previous_print_z;
if (print_config.lift_min.value > 0) {
double retract_lift = 0;
//get the current lift (imo, should be given by the writer... i'm duplicating stuff here)
if(//(previous_print_z == 0 && print_config.retract_lift_above.get_at(writer.tool()->id()) == 0) ||
print_config.retract_lift_above.get_at(writer.tool()->id()) <= previous_print_z + EPSILON
|| (layer_id == 0 && print_config.retract_lift_first_layer.get_at(writer.tool()->id())))
retract_lift = writer.tool()->retract_lift();
// see if it's positive
if (previous_print_z + extra_lift_value + retract_lift < print_config.lift_min.value) {
extra_lift_value = print_config.lift_min.value - previous_print_z - retract_lift;
}
}
if(extra_lift_value > 0)
Expand Down Expand Up @@ -1408,6 +1405,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu

// Write the custom start G-code
_writeln(file, start_gcode);
m_last_pos_defined = false;

//flush FanMover buffer to avoid modifying the start gcode if it's manual.
if (this->config().start_gcode_manual && this->m_fan_mover.get() != nullptr) {
std::string to_write = this->m_fan_mover.get()->process_gcode("", true);
Expand Down Expand Up @@ -1524,7 +1523,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
m_avoid_crossing_perimeters.use_external_mp_once();
set_extra_lift(m_last_layer_z, 0, print, m_writer, initial_extruder_id);
set_extra_lift(m_last_layer_z, 0, print.config(), m_writer, initial_extruder_id);
_write(file, this->retract());
std::string gcode;
//go to origin of the next object (it's 0,0 because we shifted the origin to it)
Expand All @@ -1544,7 +1543,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
_writeln(file, between_objects_gcode);
} else {
set_extra_lift(0, 0, print, m_writer, initial_extruder_id);
set_extra_lift(0, 0, print.config(), m_writer, initial_extruder_id);
}
//reinit the seam placer on the new object
m_seam_placer.init(print);
Expand All @@ -1569,7 +1568,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
m_second_layer_things_done = false;
prev_object = &object;
}
set_extra_lift(m_last_layer_z, prev_object->layers().back()->id(), print, m_writer, initial_extruder_id /* osef, it's only for the lift_min */);
set_extra_lift(m_last_layer_z, prev_object->layers().back()->id(), print.config(), m_writer, initial_extruder_id /* osef, it's only for the lift_min */);
} else {
// Sort layers by Z.
// All extrusion moves with the same top layer height are extruded uninterrupted.
Expand Down Expand Up @@ -2278,8 +2277,19 @@ void GCode::process_layer(
print.config().before_layer_gcode.value, m_writer.tool()->id(), &config)
+ "\n";
}
gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer;
// print z move to next layer UNLESS
// if it's going to the first layer, then we may want to dealy the move in these condition:
// there is no "after layer change gcode" and it's the first move from the unknown
if (print.config().layer_gcode.value.empty() && m_last_pos_defined && (
// there is a lift (on the first llyer, so the first move will bring us to the required height
(m_writer.tool()->retract_lift() > 0 && (m_config.retract_lift_above.get_at(m_writer.tool()->id()) == 0 || BOOL_EXTRUDER_CONFIG(retract_lift_first_layer)))
|| // or lift_min is higher than the first layer height.
m_config.lift_min.value > layer.print_z
))
m_delayed_layer_change = this->change_layer(print_z); //HACK for superslicer#1775
else
gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer;
if (! print.config().layer_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("previous_layer_z", new ConfigOptionFloat(previous_print_z));
Expand Down Expand Up @@ -2494,9 +2504,11 @@ void GCode::process_layer(

//if first layer, ask for a bigger lift for travel to object, to be on the safe side
if(single_object_instance_idx == size_t(-1))
set_extra_lift(m_last_layer_z, layer.id(), print, m_writer, extruder_id);
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);

if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
// before goin to and from a global skirt, please ensure you are a a safe height
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);
const std::pair<size_t, size_t> loops = loops_it->second;
this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp();
Expand All @@ -2520,21 +2532,25 @@ void GCode::process_layer(
// Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
if (first_layer && loops.first == 0)
m_avoid_crossing_perimeters.disable_once();
// before goin to and from a global skirt, please ensure you are a a safe height
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);
}

// Extrude brim with the extruder of the 1st region.
if (! m_brim_done) {
//if first layer, ask for a bigger lift for travel to object, to be on the safe side
if (single_object_instance_idx == size_t(-1))
set_extra_lift(m_last_layer_z, layer.id(), print, m_writer, extruder_id);

this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp();
gcode += this->extrude_entity(print.brim(), "Brim", m_config.support_material_speed.value);
for (const ExtrusionEntity* brim_entity : print.brim().entities) {
//if first layer, ask for a bigger lift for travel to each brim, to be on the safe side
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);
gcode += this->extrude_entity(*brim_entity, "Brim", m_config.support_material_speed.value);
}
m_brim_done = true;
m_avoid_crossing_perimeters.use_external_mp(false);
// Allow a straight travel move to the first object point.
m_avoid_crossing_perimeters.disable_once();
//to go to the object-only skirt or brim, or to the object (May be overriden here but I don't care)
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);
}
//extrude object-only skirt
//TODO: use it also for wiping like the other one (as they are exlusiev)
Expand Down Expand Up @@ -2607,7 +2623,7 @@ void GCode::process_layer(
}
//if first layer, ask for a bigger lift for travel to object, to be on the safe side
if (single_object_instance_idx == size_t(-1))
set_extra_lift(m_last_layer_z, layer.id(), print, m_writer, extruder_id);
set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id);
// When starting a new object, use the external motion planner for the first travel move.
const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift;
std::pair<const PrintObject*, Point> this_object_copy(&instance_to_print.print_object, offset);
Expand Down Expand Up @@ -3916,7 +3932,10 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
if (m_config.travel_acceleration.value > 0)
travel_acceleration = m_config.travel_acceleration.get_abs_value(acceleration);
}

if (m_writer.get_max_acceleration() > 0) {
acceleration = std::min((double)m_writer.get_max_acceleration(), acceleration);
travel_acceleration = std::min((double)m_writer.get_max_acceleration(), travel_acceleration);
}
if (travel_acceleration == acceleration) {
m_writer.set_acceleration((uint32_t)floor(acceleration + 0.5));
// go to first point of extrusion path (stop at midpoint to let us set the decel speed)
Expand All @@ -3926,10 +3945,13 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
}
} else {
// go to midpoint to let us set the decel speed)
if (!m_last_pos_defined || m_last_pos != path.first_point()) {
if ( !m_last_pos_defined || m_last_pos != path.first_point()) {
Polyline poly_start = this->travel_to(gcode, path.first_point(), path.role());
coordf_t length = poly_start.length();
if (length > SCALED_EPSILON) {
// if length is enough, it's not the hack for first move, and the travel accel is different than the normal accel
// then cut the travel in two to change the accel in-between
// TODO: compute the real point where it should be cut, considering an infinite max speed.
if (length > std::max(scale_d(EPSILON), scale_d(m_config.min_length)) && m_last_pos_defined && floor(travel_acceleration) != floor(acceleration)) {
Polyline poly_end;
coordf_t min_length = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.5)) * 20;
if (poly_start.size() > 2 && length > min_length * 3) {
Expand Down Expand Up @@ -3968,7 +3990,18 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
_add_object_change_labels(gcode);

// compensate retraction
gcode += this->unretract();
if (m_delayed_layer_change.empty()) {
gcode += m_writer.unlift();//this->unretract();
} else {
//check if an unlift happens
std::string unlift = m_writer.unlift();
if (unlift.empty()) {
unlift = m_delayed_layer_change;
m_delayed_layer_change.clear();
}
gcode += unlift;
}
gcode += m_writer.unretract();

speed = _compute_speed_mm_per_sec(path, speed);
double F = speed * 60; // convert mm/sec to mm/min
Expand Down Expand Up @@ -4199,7 +4232,9 @@ std::string GCode::retract(bool toolchange)
methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();
bool need_lift = !m_writer.tool_is_extruder() || toolchange || (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0) || m_config.lift_min.value > this->m_writer.get_position().z();
bool need_lift = !m_writer.tool_is_extruder() || toolchange
|| (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0)
|| this->m_writer.get_extra_lift() > 0;
bool last_fill_extusion_role_top_infill = (this->m_last_extrusion_role == ExtrusionRole::erTopSolidInfill || this->m_last_extrusion_role == ExtrusionRole::erIroning);
if(this->m_last_extrusion_role == ExtrusionRole::erGapFill)
last_fill_extusion_role_top_infill = (this->m_last_notgapfill_extrusion_role == ExtrusionRole::erTopSolidInfill || this->m_last_notgapfill_extrusion_role == ExtrusionRole::erIroning);
Expand All @@ -4212,13 +4247,7 @@ std::string GCode::retract(bool toolchange)
need_lift = true;
}
if (need_lift)
if (m_writer.tool()->retract_length() > 0
|| m_config.use_firmware_retraction
|| (!m_writer.tool_is_extruder() && m_writer.tool()->retract_lift() != 0)
|| (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && this->m_layer_index == 0)
|| m_config.lift_min.value > this->m_writer.get_position().z()
)
gcode += m_writer.lift();
gcode += m_writer.lift(this->m_layer_index);

return gcode;
}
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/GCode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ class GCode : ExtrusionVisitorConst {
// Markers for the Pressure Equalizer to recognize the extrusion type.
// The Pressure Equalizer removes the markers from the final G-code.
bool m_enable_extrusion_role_markers;
// HACK to avoid multiple Z move.
std::string m_delayed_layer_change;
// Keeps track of the last extrusion role passed to the processor
ExtrusionRole m_last_processor_extrusion_role;
// How many times will change_layer() be called?
Expand Down
29 changes: 17 additions & 12 deletions src/libslic3r/GCodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,14 +510,14 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment)
/* If target Z is lower than current Z but higher than nominal Z
we don't perform the move but we only adjust the nominal Z by
reducing the lift amount that will be used for unlift. */
if (!this->will_move_z(z)) {
// note that if we move but it's lower and we are lifted, we can wait a bit for unlifting, to avoid possible dance on layer change.
if (!this->will_move_z(z) || z < m_pos.z() && m_lifted > EPSILON) {
double nominal_z = m_pos.z() - m_lifted;
m_lifted -= (z - nominal_z);
if (std::abs(m_lifted) < EPSILON)
m_lifted = 0.;
return "";
}

/* In all the other cases, we perform an actual Z move and cancel
the lift. */
m_lifted = 0;
Expand Down Expand Up @@ -548,7 +548,7 @@ bool GCodeWriter::will_move_z(double z) const
we don't perform an actual Z move. */
if (m_lifted > 0) {
double nominal_z = m_pos.z() - m_lifted;
if (z >= nominal_z && z <= m_pos.z())
if (z >= nominal_z + EPSILON && z <= m_pos.z() - EPSILON)
return false;
}
return true;
Expand Down Expand Up @@ -698,15 +698,19 @@ std::string GCodeWriter::unretract()
/* If this method is called more than once before calling unlift(),
it will not perform subsequent lifts, even if Z was raised manually
(i.e. with travel_to_z()) and thus _lifted was reduced. */
std::string GCodeWriter::lift()
std::string GCodeWriter::lift(int layer_id)
{
// check whether the above/below conditions are met
double target_lift = 0;
if(this->tool_is_extruder()){
//these two should be in the Tool class methods....
double above = this->config.retract_lift_above.get_at(m_tool->id());
double below = this->config.retract_lift_below.get_at(m_tool->id());
if (m_pos.z() >= above && (below == 0 || m_pos.z() <= below))
bool can_lift = this->config.retract_lift_first_layer.get_at(m_tool->id()) && layer_id == 0;
if (!can_lift) {
//these two should be in the Tool class methods....
double above = this->config.retract_lift_above.get_at(m_tool->id());
double below = this->config.retract_lift_below.get_at(m_tool->id());
can_lift = (m_pos.z() >= above - EPSILON && (below == 0 || m_pos.z() <= below + EPSILON));
}
if(can_lift)
target_lift = m_tool->retract_lift();
} else {
target_lift = m_tool->retract_lift();
Expand All @@ -717,15 +721,16 @@ std::string GCodeWriter::lift()
target_lift = config_region->print_retract_lift.value;
}

if (this->extra_lift > 0) {
target_lift += this->extra_lift;
this->extra_lift = 0;
// one-time extra lift (often for dangerous travels)
if (this->m_extra_lift > 0) {
target_lift += this->m_extra_lift;
this->m_extra_lift = 0;
}

// compare against epsilon because travel_to_z() does math on it
// and subtracting layer_height from retract_lift might not give
// exactly zero
if (std::abs(m_lifted) - target_lift < EPSILON && target_lift > 0) {
if (std::abs(m_lifted) < target_lift - EPSILON && target_lift > 0) {
std::string str = this->_travel_to_z(m_pos.z() + target_lift - m_lifted, "lift Z");
m_lifted = target_lift;
return str;
Expand Down
11 changes: 7 additions & 4 deletions src/libslic3r/GCodeWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class GCodeWriter {
std::string set_fan(uint8_t speed, bool dont_save = false, uint16_t default_tool = 0);
void set_acceleration(uint32_t acceleration);
uint32_t get_acceleration() const;
uint32_t get_max_acceleration() { return this->m_max_acceleration; }
std::string write_acceleration();
std::string reset_e(bool force = false);
std::string update_progress(uint32_t num, uint32_t tot, bool allow_100 = false) const;
Expand All @@ -73,11 +74,12 @@ class GCodeWriter {
std::string retract(bool before_wipe = false);
std::string retract_for_toolchange(bool before_wipe = false);
std::string unretract();
std::string lift();
void set_extra_lift(double extra_zlift) { this->m_extra_lift = extra_zlift; }
double get_extra_lift() { return this->m_extra_lift; }
std::string lift(int layer_id);
std::string unlift();
Vec3d get_position() const { return m_pos; }

void set_extra_lift(double extra_zlift) { this->extra_lift = extra_zlift; }
private:
// Extruders are sorted by their ID, so that binary search is possible.
std::vector<Extruder> m_extruders;
Expand All @@ -96,14 +98,15 @@ class GCodeWriter {
int16_t m_last_temperature_with_offset;
int16_t m_last_bed_temperature;
bool m_last_bed_temperature_reached;
// if positive, it's set, and the next lift wil have this extra lift
double m_extra_lift = 0;
// current lift, to remove from m_pos to have the current height.
double m_lifted;
Vec3d m_pos = Vec3d::Zero();

std::string _travel_to_z(double z, const std::string &comment);
std::string _retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment);

// if positive, it's set, and the next lift wil have this extra lift
double extra_lift = 0;
};

} /* namespace Slic3r */
Expand Down
Loading

0 comments on commit e015c3a

Please sign in to comment.