mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-05 09:07:39 +00:00
Harden wait_for_temp_on_wipe_tower parking and temperature deferral
Share one wait_for_temp_enabled gate between the tower and append_tcr2 so a SEMM profile carrying the flag keeps its blocking ooze-prevention wait. Park beside the tower on custom polygonal beds via point-in-polygon, clamp the near-side park toward the bed edge before crossing to the far side, and start non-blocking heating at the toolchange when ooze prevention emits nothing so heat-up overlaps the travel.
This commit is contained in:
@@ -1557,7 +1557,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
toolchange_temp_override = interface_temp;
|
||||
}
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override,
|
||||
gcodegen.config().wait_for_temp_on_wipe_tower.value); // TODO: toolchange_z vs print_z
|
||||
WipeTower2::wait_for_temp_enabled(gcodegen.m_config)); // TODO: toolchange_z vs print_z
|
||||
if (!travel_to_tower_now && !tcr.priming && WipeTower2::use_gap_wall(gcodegen.m_config)) {
|
||||
// The tool changed in place (multi-tool printer without ramming), so the
|
||||
// tower entry is the tcr's own positioning move — a straight line across
|
||||
@@ -9350,8 +9350,23 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
// Set the new extruder to the operating temperature.
|
||||
std::string restore_temp_gcode;
|
||||
if (m_ooze_prevention.enable)
|
||||
gcode += m_ooze_prevention.post_toolchange(*this, !defer_temp_wait);
|
||||
restore_temp_gcode = m_ooze_prevention.post_toolchange(*this, !defer_temp_wait);
|
||||
if (defer_temp_wait && restore_temp_gcode.empty()) {
|
||||
// The blocking M109 is emitted by the wipe tower generator; with no temperature
|
||||
// command here the nozzle would only start heating once the head arrives there.
|
||||
// Heat non-blocking now so the heat-up overlaps the travel, targeting what the
|
||||
// tower will wait on (OozePrevention::_get_temp logic plus the interface override).
|
||||
int temp = toolchange_temp_override > 0 ?
|
||||
toolchange_temp_override :
|
||||
(m_layer == nullptr || m_layer->id() == 0 || m_config.nozzle_temperature.get_at(new_fi) == 0 ?
|
||||
m_config.nozzle_temperature_initial_layer.get_at(new_fi) :
|
||||
m_config.nozzle_temperature.get_at(new_fi));
|
||||
if (temp > 0)
|
||||
restore_temp_gcode = m_writer.set_temperature(temp, false, new_filament_id);
|
||||
}
|
||||
gcode += restore_temp_gcode;
|
||||
|
||||
if (m_config.enable_pressure_advance.get_at(new_filament_id)) {
|
||||
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(new_filament_id));
|
||||
|
||||
@@ -1009,6 +1009,13 @@ bool WipeTower2::use_gap_wall(const PrintConfig& config)
|
||||
return config.prime_tower_skip_points.value && config.wipe_tower_wall_type.value != wtwCone;
|
||||
}
|
||||
|
||||
bool WipeTower2::wait_for_temp_enabled(const PrintConfig& config)
|
||||
{
|
||||
// SEMM runs its own unload/load temperature sequence; the GUI hides the option
|
||||
// there but a profile may still carry it set.
|
||||
return config.wait_for_temp_on_wipe_tower.value && !config.single_extruder_multi_material.value;
|
||||
}
|
||||
|
||||
WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& default_region_config,int plate_idx, Vec3d plate_origin, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
|
||||
m_semm(config.single_extruder_multi_material.value),
|
||||
m_enable_filament_ramming(config.enable_filament_ramming.value),
|
||||
@@ -1039,7 +1046,7 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_use_gap_wall(use_gap_wall(config)),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value),
|
||||
m_wait_for_temp_on_wipe_tower(config.wait_for_temp_on_wipe_tower.value && !config.single_extruder_multi_material.value)
|
||||
m_wait_for_temp_on_wipe_tower(wait_for_temp_enabled(config))
|
||||
{
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
// it is taken over following default. Speeds from config are not
|
||||
@@ -1090,6 +1097,7 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_bed_bottom_left = m_bed_shape == RectangularBed
|
||||
? Vec2f(bed_points.front().x(), bed_points.front().y())
|
||||
: Vec2f::Zero();
|
||||
m_bed_polygon = Polygon::new_scale(bed_points);
|
||||
}
|
||||
|
||||
|
||||
@@ -1703,9 +1711,10 @@ void WipeTower2::toolchange_Change(
|
||||
// The Tn above was issued without a blocking temperature wait (OozePrevention::post_toolchange
|
||||
// only restores the target); block here, before the deretraction below, which must not extrude
|
||||
// on a cold nozzle. Like the Bambu H2C, park beside the tower for the heat-up so drool lands
|
||||
// next to it instead of on its top surface — nearest x side first, the other side as fallback,
|
||||
// in place if both would leave the bed. Raw pre-rotated moves (see the repositioning move
|
||||
// below) keep the writer's tracked position at the tower entry. The tag keeps the
|
||||
// next to it instead of on its top surface — nearest x side first, then that side clamped
|
||||
// toward the bed edge, then the far side, in place if all would leave the bed. Raw
|
||||
// pre-rotated moves (see the repositioning move below) keep the writer's tracked position
|
||||
// at the tower entry. The tag keeps the
|
||||
// interface-temp deduplication pass in append_tcr2 from stripping the M109.
|
||||
if (wait_for_temp_here && wait_beside_tower) {
|
||||
// The rib wall and the stabilization cone bulge past the nominal width rectangle
|
||||
@@ -1736,28 +1745,54 @@ void WipeTower2::toolchange_Change(
|
||||
min_x -= brim;
|
||||
max_x += brim;
|
||||
}
|
||||
constexpr float gap = 2.f;
|
||||
const float near_x = writer.x() < m_wipe_tower_width / 2.f ? min_x - gap : max_x + gap;
|
||||
const float far_x = near_x < m_wipe_tower_width / 2.f ? max_x + gap : min_x - gap;
|
||||
const float a = float(m_wipe_tower_rotation_angle * M_PI / 180.);
|
||||
constexpr float gap = 2.f;
|
||||
constexpr float min_gap = 0.5f;
|
||||
const bool on_left = writer.x() < m_wipe_tower_width / 2.f;
|
||||
const float near_x = on_left ? min_x - gap : max_x + gap;
|
||||
const float far_x = on_left ? max_x + gap : min_x - gap;
|
||||
const float a = float(m_wipe_tower_rotation_angle * M_PI / 180.);
|
||||
const float c = std::cos(a), s = std::sin(a);
|
||||
for (float side_x : { near_x, far_x }) {
|
||||
const Vec2f stop = writer.rotated(Vec2f(side_x, writer.y()));
|
||||
const Vec2f wt = stop + m_rib_offset;
|
||||
auto park_pt_on_bed = [this, &writer, c, s](float side_x) {
|
||||
const Vec2f wt = writer.rotated(Vec2f(side_x, writer.y())) + m_rib_offset;
|
||||
const Vec2f bed_pt(c * wt.x() - s * wt.y() + m_wipe_tower_pos.x(),
|
||||
s * wt.x() + c * wt.y() + m_wipe_tower_pos.y());
|
||||
bool on_bed = false;
|
||||
if (m_bed_shape == RectangularBed)
|
||||
on_bed = m_bed_bbox.contains(bed_pt.cast<double>());
|
||||
else if (m_bed_shape == CircularBed)
|
||||
on_bed = (bed_pt.cast<double>() - m_bed_bbox.center()).norm() <= m_bed_width / 2.;
|
||||
if (!on_bed)
|
||||
continue;
|
||||
return m_bed_bbox.contains(bed_pt.cast<double>());
|
||||
if (m_bed_shape == CircularBed)
|
||||
return (bed_pt.cast<double>() - m_bed_bbox.center()).norm() <= m_bed_width / 2.;
|
||||
return m_bed_polygon.contains(Point::new_scale(bed_pt.x(), bed_pt.y()));
|
||||
};
|
||||
float park_x = near_x;
|
||||
bool have_park = park_pt_on_bed(near_x);
|
||||
if (!have_park) {
|
||||
// The ideal near point hangs off the bed: pull it back to the bed edge as long
|
||||
// as that still clears the tower envelope by min_gap (the BBL tower clamps its
|
||||
// stop_pos against the bed the same way in append_tcr). Bisection, because with
|
||||
// tower rotation and non-rectangular beds the bed edge is not axis-aligned.
|
||||
const float limit_x = on_left ? min_x - min_gap : max_x + min_gap;
|
||||
if (park_pt_on_bed(limit_x)) {
|
||||
float on = limit_x, off = near_x;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
const float mid = 0.5f * (on + off);
|
||||
if (park_pt_on_bed(mid))
|
||||
on = mid;
|
||||
else
|
||||
off = mid;
|
||||
}
|
||||
park_x = on;
|
||||
have_park = true;
|
||||
}
|
||||
}
|
||||
if (!have_park && park_pt_on_bed(far_x)) {
|
||||
park_x = far_x;
|
||||
have_park = true;
|
||||
}
|
||||
if (have_park) {
|
||||
const Vec2f stop = writer.rotated(Vec2f(park_x, writer.y()));
|
||||
writer.feedrate(m_travel_speed * 60.f)
|
||||
.append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(stop.x())
|
||||
+ " Y" + Slic3r::float_to_string_decimal_point(stop.y())
|
||||
+ never_skip_tag() + "\n");
|
||||
break;
|
||||
}
|
||||
writer.set_extruder_temp(wait_for_temp, true, wait_for_temp_tag());
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ public:
|
||||
// Shared with the entry routing in GCode.cpp so the router and the tower agree.
|
||||
static bool use_gap_wall(const PrintConfig& config);
|
||||
|
||||
// Whether the blocking toolchange temperature wait moves onto the wipe tower.
|
||||
// Shared with the defer flag in GCode.cpp append_tcr2 so the deferral and the
|
||||
// tower's tagged M109 can never disagree.
|
||||
static bool wait_for_temp_enabled(const PrintConfig& config);
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||
@@ -268,6 +273,7 @@ private:
|
||||
float m_bed_width; // width of the bed bounding box
|
||||
Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds)
|
||||
BoundingBoxf m_bed_bbox; // bounding box of the printable area
|
||||
Polygon m_bed_polygon; // printable_area contour (scaled), for beds neither rectangular nor circular
|
||||
|
||||
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
||||
Reference in New Issue
Block a user