Improved retract handling on bowden extruders:
Separated deretract speed from a retract speed, allowed a partial retract before wipe.
This commit is contained in:
parent
8bd3dec331
commit
70db88dd90
@ -1156,7 +1156,7 @@ sub build {
|
||||
use_volumetric_e variable_layer_height
|
||||
single_extruder_multi_material start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
|
||||
nozzle_diameter extruder_offset
|
||||
retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe
|
||||
retract_length retract_lift retract_speed deretract_speed retract_before_wipe retract_restart_extra retract_before_travel retract_layer_change wipe
|
||||
retract_length_toolchange retract_restart_extra_toolchange
|
||||
printer_notes
|
||||
));
|
||||
@ -1444,7 +1444,7 @@ sub _extruders_count_changed {
|
||||
$self->_on_value_change('extruders_count', $extruders_count);
|
||||
}
|
||||
|
||||
sub _extruder_options { qw(nozzle_diameter min_layer_height max_layer_height extruder_offset retract_length retract_lift retract_lift_above retract_lift_below retract_speed retract_restart_extra retract_before_travel wipe
|
||||
sub _extruder_options { qw(nozzle_diameter min_layer_height max_layer_height extruder_offset retract_length retract_lift retract_lift_above retract_lift_below retract_speed deretract_speed retract_before_wipe retract_restart_extra retract_before_travel wipe
|
||||
retract_layer_change retract_length_toolchange retract_restart_extra_toolchange) }
|
||||
|
||||
sub _build_extruder_pages {
|
||||
@ -1497,7 +1497,7 @@ sub _build_extruder_pages {
|
||||
}
|
||||
|
||||
$optgroup->append_single_option_line($_, $extruder_idx)
|
||||
for qw(retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe);
|
||||
for qw(retract_speed deretract_speed retract_restart_extra retract_before_travel retract_layer_change wipe retract_before_wipe);
|
||||
}
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Retraction when tool is disabled (advanced settings for multi-extruder setups)');
|
||||
@ -1579,8 +1579,12 @@ sub _update {
|
||||
|
||||
# some options only apply when not using firmware retraction
|
||||
$self->get_field($_, $i)->toggle($retraction && !$config->use_firmware_retraction)
|
||||
for qw(retract_speed retract_restart_extra wipe);
|
||||
if ($config->use_firmware_retraction && $config->get_at('wipe', $i)) {
|
||||
for qw(retract_speed deretract_speed retract_before_wipe retract_restart_extra wipe);
|
||||
|
||||
my $wipe = $config->get_at('wipe', $i);
|
||||
$self->get_field('retract_before_wipe', $i)->toggle($wipe);
|
||||
|
||||
if ($config->use_firmware_retraction && $wipe) {
|
||||
my $dialog = Wx::MessageDialog->new($self,
|
||||
"The Wipe option is not available when using the Firmware Retraction mode.\n"
|
||||
. "\nShall I disable it in order to enable Firmware Retraction?",
|
||||
|
@ -376,6 +376,8 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
|
||||
opt = new ConfigOptionStrings ();
|
||||
} else if (optdef->type == coPercent) {
|
||||
opt = new ConfigOptionPercent ();
|
||||
} else if (optdef->type == coPercents) {
|
||||
opt = new ConfigOptionPercents ();
|
||||
} else if (optdef->type == coFloatOrPercent) {
|
||||
opt = new ConfigOptionFloatOrPercent ();
|
||||
} else if (optdef->type == coPoint) {
|
||||
|
@ -57,6 +57,7 @@ class ConfigOptionSingle : public ConfigOption {
|
||||
class ConfigOptionVectorBase : public ConfigOption {
|
||||
public:
|
||||
virtual ~ConfigOptionVectorBase() {};
|
||||
// Currently used only to initialize the PlaceholderParser.
|
||||
virtual std::vector<std::string> vserialize() const = 0;
|
||||
};
|
||||
|
||||
@ -257,6 +258,46 @@ class ConfigOptionPercent : public ConfigOptionFloat
|
||||
};
|
||||
};
|
||||
|
||||
class ConfigOptionPercents : public ConfigOptionFloats
|
||||
{
|
||||
public:
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
for (const auto &v : this->values) {
|
||||
if (&v != &this->values.front()) ss << ",";
|
||||
ss << v << "%";
|
||||
}
|
||||
std::string str = ss.str();
|
||||
return str;
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
std::vector<std::string> vv;
|
||||
vv.reserve(this->values.size());
|
||||
for (const auto v : this->values) {
|
||||
std::ostringstream ss;
|
||||
ss << v;
|
||||
std::string sout = ss.str() + "%";
|
||||
vv.push_back(sout);
|
||||
}
|
||||
return vv;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
std::string item_str;
|
||||
while (std::getline(is, item_str, ',')) {
|
||||
std::istringstream iss(item_str);
|
||||
double value;
|
||||
// don't try to parse the trailing % since it's optional
|
||||
iss >> value;
|
||||
this->values.push_back(value);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
class ConfigOptionFloatOrPercent : public ConfigOptionPercent
|
||||
{
|
||||
public:
|
||||
@ -488,6 +529,8 @@ enum ConfigOptionType {
|
||||
coStrings,
|
||||
// percent value. Currently only used for infill.
|
||||
coPercent,
|
||||
// percents value. Currently used for retract before wipe only.
|
||||
coPercents,
|
||||
// a fraction or an absolute value
|
||||
coFloatOrPercent,
|
||||
// single 2d point. Currently not used.
|
||||
|
@ -15,20 +15,9 @@ Extruder::Extruder(unsigned int id, GCodeConfig *config)
|
||||
this->e_per_mm3 = this->extrusion_multiplier()
|
||||
* (4 / ((this->filament_diameter() * this->filament_diameter()) * PI));
|
||||
}
|
||||
this->retract_speed_mm_min = this->retract_speed() * 60;
|
||||
}
|
||||
|
||||
void
|
||||
Extruder::reset()
|
||||
{
|
||||
this->E = 0;
|
||||
this->absolute_E = 0;
|
||||
this->retracted = 0;
|
||||
this->restart_extra = 0;
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::extrude(double dE)
|
||||
double Extruder::extrude(double dE)
|
||||
{
|
||||
// in case of relative E distances we always reset to 0 before any output
|
||||
if (m_config->use_relative_e_distances)
|
||||
@ -46,8 +35,7 @@ Extruder::extrude(double dE)
|
||||
The restart_extra argument sets the extra length to be used for
|
||||
unretraction. If we're actually performing a retraction, any restart_extra
|
||||
value supplied will overwrite the previous one if any. */
|
||||
double
|
||||
Extruder::retract(double length, double restart_extra)
|
||||
double Extruder::retract(double length, double restart_extra)
|
||||
{
|
||||
// in case of relative E distances we always reset to 0 before any output
|
||||
if (m_config->use_relative_e_distances)
|
||||
@ -65,8 +53,7 @@ Extruder::retract(double length, double restart_extra)
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::unretract()
|
||||
double Extruder::unretract()
|
||||
{
|
||||
double dE = this->retracted + this->restart_extra;
|
||||
this->extrude(dE);
|
||||
@ -75,14 +62,12 @@ Extruder::unretract()
|
||||
return dE;
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::e_per_mm(double mm3_per_mm) const
|
||||
double Extruder::e_per_mm(double mm3_per_mm) const
|
||||
{
|
||||
return mm3_per_mm * this->e_per_mm3;
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::extruded_volume() const
|
||||
double Extruder::extruded_volume() const
|
||||
{
|
||||
if (m_config->use_volumetric_e) {
|
||||
// Any current amount of retraction should not affect used filament, since
|
||||
@ -93,8 +78,7 @@ Extruder::extruded_volume() const
|
||||
return this->used_filament() * (this->filament_diameter() * this->filament_diameter()) * PI/4;
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::used_filament() const
|
||||
double Extruder::used_filament() const
|
||||
{
|
||||
if (m_config->use_volumetric_e) {
|
||||
return this->extruded_volume() / (this->filament_diameter() * this->filament_diameter() * PI/4);
|
||||
@ -105,62 +89,64 @@ Extruder::used_filament() const
|
||||
return this->absolute_E + this->retracted;
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::filament_diameter() const
|
||||
double Extruder::filament_diameter() const
|
||||
{
|
||||
return m_config->filament_diameter.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::filament_density() const
|
||||
double Extruder::filament_density() const
|
||||
{
|
||||
return m_config->filament_density.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::filament_cost() const
|
||||
double Extruder::filament_cost() const
|
||||
{
|
||||
return m_config->filament_cost.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::extrusion_multiplier() const
|
||||
double Extruder::extrusion_multiplier() const
|
||||
{
|
||||
return m_config->extrusion_multiplier.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::retract_length() const
|
||||
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
|
||||
double Extruder::retract_before_wipe() const
|
||||
{
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(this->id) * 0.01));
|
||||
}
|
||||
|
||||
double Extruder::retract_length() const
|
||||
{
|
||||
return m_config->retract_length.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::retract_lift() const
|
||||
double Extruder::retract_lift() const
|
||||
{
|
||||
return m_config->retract_lift.get_at(this->id);
|
||||
}
|
||||
|
||||
int
|
||||
Extruder::retract_speed() const
|
||||
int Extruder::retract_speed() const
|
||||
{
|
||||
return m_config->retract_speed.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::retract_restart_extra() const
|
||||
int Extruder::deretract_speed() const
|
||||
{
|
||||
int speed = m_config->deretract_speed.get_at(this->id);
|
||||
return (speed > 0) ? speed : this->retract_speed();
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra() const
|
||||
{
|
||||
return m_config->retract_restart_extra.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::retract_length_toolchange() const
|
||||
double Extruder::retract_length_toolchange() const
|
||||
{
|
||||
return m_config->retract_length_toolchange.get_at(this->id);
|
||||
}
|
||||
|
||||
double
|
||||
Extruder::retract_restart_extra_toolchange() const
|
||||
double Extruder::retract_restart_extra_toolchange() const
|
||||
{
|
||||
return m_config->retract_restart_extra_toolchange.get_at(this->id);
|
||||
}
|
||||
|
@ -16,12 +16,17 @@ public:
|
||||
double retracted;
|
||||
double restart_extra;
|
||||
double e_per_mm3;
|
||||
double retract_speed_mm_min;
|
||||
|
||||
Extruder(unsigned int id, GCodeConfig *config);
|
||||
virtual ~Extruder() {}
|
||||
|
||||
void reset();
|
||||
void reset() {
|
||||
this->E = 0;
|
||||
this->absolute_E = 0;
|
||||
this->retracted = 0;
|
||||
this->restart_extra = 0;
|
||||
}
|
||||
|
||||
double extrude(double dE);
|
||||
double retract(double length, double restart_extra);
|
||||
double unretract();
|
||||
@ -33,9 +38,11 @@ public:
|
||||
double filament_density() const;
|
||||
double filament_cost() const;
|
||||
double extrusion_multiplier() const;
|
||||
double retract_before_wipe() const;
|
||||
double retract_length() const;
|
||||
double retract_lift() const;
|
||||
int retract_speed() const;
|
||||
int deretract_speed() const;
|
||||
double retract_restart_extra() const;
|
||||
double retract_length_toolchange() const;
|
||||
double retract_restart_extra_toolchange() const;
|
||||
|
@ -159,6 +159,11 @@ WipeTowerIntegration::WipeTowerIntegration(const PrintConfig &print_config) : m_
|
||||
m_impl.reset(wipe_tower);
|
||||
}
|
||||
|
||||
static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const WipeTower::xy &wipe_tower_pt)
|
||||
{
|
||||
return Point(scale_(wipe_tower_pt.x - gcodegen.origin().x), scale_(wipe_tower_pt.y - gcodegen.origin().y));
|
||||
}
|
||||
|
||||
std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer)
|
||||
{
|
||||
bool over_wipe_tower = false;
|
||||
@ -175,6 +180,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
|
||||
gcodegen.writer().toolchange(extruder_id);
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, code_and_pos.second));
|
||||
this->prepare_wipe(gcodegen, code_and_pos.second);
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
over_wipe_tower = true;
|
||||
m_brim_done = true;
|
||||
@ -190,6 +197,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
|
||||
gcode += code_and_pos.first;
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, code_and_pos.second));
|
||||
this->prepare_wipe(gcodegen, code_and_pos.second);
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
}
|
||||
|
||||
@ -218,13 +227,26 @@ std::string WipeTowerIntegration::travel_to(GCode &gcodegen, const WipeTower::xy
|
||||
std::string gcode = gcodegen.retract(true);
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
gcode += gcodegen.travel_to(
|
||||
Point(scale_(dest.x - gcodegen.origin().x), scale_(dest.y - gcodegen.origin().y)),
|
||||
wipe_tower_point_to_object_point(gcodegen, dest),
|
||||
erMixed,
|
||||
"Travel to a Wipe Tower");
|
||||
gcode += gcodegen.unretract();
|
||||
return gcode;
|
||||
}
|
||||
|
||||
void WipeTowerIntegration::prepare_wipe(GCode &gcodegen, const WipeTower::xy ¤t_position)
|
||||
{
|
||||
gcodegen.m_wipe.path.points.clear();
|
||||
// Start the wipe at the current position.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, current_position));
|
||||
// Wipe end point: Wipe direction away from the closer tower edge to the further tower edge.
|
||||
float l = m_impl->position().x;
|
||||
float r = l + m_impl->width();
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen,
|
||||
WipeTower::xy((std::abs(l - current_position.x) < std::abs(r - current_position.x)) ? r : l,
|
||||
current_position.y)));
|
||||
}
|
||||
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id)
|
||||
|
||||
inline void write(FILE *file, const std::string &what)
|
||||
@ -577,7 +599,7 @@ bool GCode::do_export(FILE *file, Print &print)
|
||||
// wher the objects are sorted by their sorted order given by object_indices.
|
||||
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer.first));
|
||||
assert(it_layer_tools != tool_ordering.end() && layer.first);
|
||||
if (m_wipe_tower) {
|
||||
if (it_layer_tools->has_wipe_tower && m_wipe_tower) {
|
||||
bool first_layer = layer.first == layers.begin()->first;
|
||||
auto it_layer_tools_next = it_layer_tools;
|
||||
++ it_layer_tools_next;
|
||||
@ -965,7 +987,7 @@ void GCode::process_layer(
|
||||
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
|
||||
for (unsigned int extruder_id : layer_tools.extruders)
|
||||
{
|
||||
gcode += m_wipe_tower ?
|
||||
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
|
||||
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
|
||||
this->set_extruder(extruder_id);
|
||||
|
||||
@ -1923,8 +1945,10 @@ GCode::retract(bool toolchange)
|
||||
return gcode;
|
||||
|
||||
// wipe (if it's enabled for this extruder and we have a stored wipe path)
|
||||
if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path())
|
||||
if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path()) {
|
||||
gcode += toolchange ? m_writer.retract_for_toolchange(true) : m_writer.retract(true);
|
||||
gcode += m_wipe.wipe(*this, toolchange);
|
||||
}
|
||||
|
||||
/* The parent class will decide whether we need to perform an actual retraction
|
||||
(the extruder might be already retracted fully or partially). We call these
|
||||
|
@ -84,6 +84,7 @@ public:
|
||||
|
||||
private:
|
||||
std::string travel_to(GCode &codegen, const WipeTower::xy &dest);
|
||||
void prepare_wipe(GCode &gcodegen, const WipeTower::xy ¤t_position);
|
||||
std::unique_ptr<WipeTower> m_impl;
|
||||
bool m_brim_done;
|
||||
};
|
||||
|
@ -27,6 +27,8 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
|
||||
it_layer->extruders.push_back(extruder_support);
|
||||
if (has_interface)
|
||||
it_layer->extruders.push_back(extruder_interface);
|
||||
if (has_support || has_interface)
|
||||
it_layer->has_support = true;
|
||||
}
|
||||
// Collect the object extruders.
|
||||
for (auto layer : object.layers) {
|
||||
@ -38,9 +40,11 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
|
||||
if (layerm == nullptr)
|
||||
continue;
|
||||
const PrintRegion ®ion = *object.print()->regions[region_id];
|
||||
if (! layerm->perimeters.entities.empty())
|
||||
if (! layerm->perimeters.entities.empty()) {
|
||||
it_layer->extruders.push_back(region.config.perimeter_extruder.value);
|
||||
bool has_infill = false;
|
||||
it_layer->has_object = true;
|
||||
}
|
||||
bool has_infill = false;
|
||||
bool has_solid_infill = false;
|
||||
for (const ExtrusionEntity *ee : layerm->fills.entities) {
|
||||
// fill represents infill extrusions of a single island.
|
||||
@ -55,6 +59,8 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
|
||||
it_layer->extruders.push_back(region.config.solid_infill_extruder);
|
||||
if (has_infill)
|
||||
it_layer->extruders.push_back(region.config.infill_extruder);
|
||||
if (has_solid_infill || has_infill)
|
||||
it_layer->has_object = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +143,10 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
|
||||
// Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
|
||||
for (int i = int(layers.size()) - 2; i >= 0; -- i)
|
||||
layers[i].wipe_tower_partitions = std::max(layers[i + 1].wipe_tower_partitions, layers[i].wipe_tower_partitions);
|
||||
|
||||
//FIXME this is a hack to get the ball rolling.
|
||||
for (LayerTools < : layers)
|
||||
lt.has_wipe_tower = lt.has_object;
|
||||
}
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
|
@ -11,14 +11,25 @@ namespace ToolOrdering {
|
||||
|
||||
struct LayerTools
|
||||
{
|
||||
LayerTools(const coordf_t z) : print_z(z), wipe_tower_partitions(0) {}
|
||||
LayerTools(const coordf_t z) :
|
||||
print_z(z),
|
||||
has_object(false),
|
||||
has_support(false),
|
||||
has_wipe_tower(false),
|
||||
wipe_tower_partitions(0) {}
|
||||
|
||||
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
|
||||
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
|
||||
|
||||
coordf_t print_z;
|
||||
bool has_object;
|
||||
bool has_support;
|
||||
// Zero based extruder IDs, ordered to minimize tool switches.
|
||||
std::vector<unsigned int> extruders;
|
||||
// Will there be anything extruded on this layer for the wipe tower?
|
||||
// Due to the support layers possibly interleaving the object layers,
|
||||
// wipe tower will be disabled for some support only layers.
|
||||
bool has_wipe_tower;
|
||||
// Number of wipe tower partitions to support the required number of tool switches
|
||||
// and to support the wipe tower partitions above this one.
|
||||
size_t wipe_tower_partitions;
|
||||
|
@ -30,6 +30,9 @@ public:
|
||||
// Return the wipe tower position.
|
||||
virtual const xy& position() const = 0;
|
||||
|
||||
// Return the wipe tower width.
|
||||
virtual float width() const = 0;
|
||||
|
||||
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||
virtual bool finished() const = 0;
|
||||
|
||||
|
@ -348,11 +348,24 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::tool_change(int tool, Pu
|
||||
// Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
toolchange_Wipe(writer, cleaning_box);
|
||||
// Draw a perimeter around cleaning_box and wipe.
|
||||
toolchange_Done(writer, cleaning_box);
|
||||
box_coordinates box = cleaning_box;
|
||||
if (m_current_shape == SHAPE_REVERSED) {
|
||||
std::swap(box.lu, box.ld);
|
||||
std::swap(box.ru, box.rd);
|
||||
}
|
||||
// Draw a perimeter around cleaning_box.
|
||||
writer.travel(box.lu, 7000)
|
||||
.extrude(box.ld, 3200).extrude(box.rd)
|
||||
.extrude(box.ru).extrude(box.lu);
|
||||
// Wipe the nozzle.
|
||||
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
|
||||
writer.travel(box.ru, 7200)
|
||||
.travel(box.lu);
|
||||
}
|
||||
|
||||
// Reset the extruder current to a normal value.
|
||||
writer.set_extruder_trimpot(550)
|
||||
.feedrate(6000)
|
||||
.flush_planner_queue()
|
||||
.reset_extruder()
|
||||
.append("; CP TOOLCHANGE END\n"
|
||||
@ -423,11 +436,15 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::toolchange_Brim(Purpose
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the front left corner and wipe along the front edge.
|
||||
writer.travel(wipeTower_box.ld, 7000)
|
||||
.travel(wipeTower_box.rd)
|
||||
.travel(wipeTower_box.ld)
|
||||
.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
|
||||
// Move to the front left corner.
|
||||
writer.travel(wipeTower_box.ld, 7000);
|
||||
|
||||
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
|
||||
// Wipe along the front edge.
|
||||
writer.travel(wipeTower_box.rd)
|
||||
.travel(wipeTower_box.ld);
|
||||
|
||||
writer.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
|
||||
";-----------------------------------\n");
|
||||
|
||||
// Mark the brim as extruded.
|
||||
@ -616,26 +633,6 @@ void WipeTowerPrusaMM::toolchange_Wipe(
|
||||
writer.set_extrusion_flow(m_extrusion_flow);
|
||||
}
|
||||
|
||||
// Draw a perimeter around cleaning_box and wipe.
|
||||
void WipeTowerPrusaMM::toolchange_Done(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box)
|
||||
{
|
||||
box_coordinates box = cleaning_box;
|
||||
if (m_current_shape == SHAPE_REVERSED) {
|
||||
std::swap(box.lu, box.ld);
|
||||
std::swap(box.ru, box.rd);
|
||||
}
|
||||
// Draw a perimeter around cleaning_box.
|
||||
writer.travel(box.lu, 7000)
|
||||
.extrude(box.ld, 3200).extrude(box.rd)
|
||||
.extrude(box.ru).extrude(box.lu)
|
||||
// Wipe the nozzle.
|
||||
.travel(box.ru, 7200)
|
||||
.travel(box.lu)
|
||||
.feedrate(6000);
|
||||
}
|
||||
|
||||
std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::finish_layer(Purpose purpose)
|
||||
{
|
||||
// This should only be called if the layer is not finished yet.
|
||||
@ -720,11 +717,16 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::finish_layer(Purpose pur
|
||||
writer.extrude(fill_box.ru + xy(- m_perimeter_width * 6, - m_perimeter_width), 2900 * speed_factor)
|
||||
.extrude(fill_box.ru + xy(- m_perimeter_width * 3, - m_perimeter_width))
|
||||
.extrude(fill_box.rd + xy(- m_perimeter_width * 3, m_perimeter_width))
|
||||
.extrude(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width))
|
||||
// Wipe along the front side of the current wiping box.
|
||||
.travel(fill_box.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200)
|
||||
.travel(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width / 2))
|
||||
.append("; CP EMPTY GRID END\n"
|
||||
.extrude(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width));
|
||||
|
||||
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
|
||||
// Wipe along the front side of the current wiping box.
|
||||
writer.travel(fill_box.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200)
|
||||
.travel(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width / 2));
|
||||
else
|
||||
writer.feedrate(7200);
|
||||
|
||||
writer.append("; CP EMPTY GRID END\n"
|
||||
";------------------\n\n\n\n\n\n\n");
|
||||
|
||||
// Indicate that this wipe tower layer is fully covered.
|
||||
|
@ -105,6 +105,8 @@ public:
|
||||
|
||||
// Return the wipe tower position.
|
||||
virtual const xy& position() const { return m_wipe_tower_pos; }
|
||||
// Return the wipe tower width.
|
||||
virtual float width() const { return m_wipe_tower_width; }
|
||||
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||
virtual bool finished() const { return m_max_color_changes == 0; }
|
||||
|
||||
@ -228,10 +230,6 @@ private:
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box);
|
||||
|
||||
void toolchange_Done(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box);
|
||||
|
||||
void toolchange_Perimeter();
|
||||
};
|
||||
|
||||
|
@ -384,22 +384,24 @@ GCodeWriter::extrude_to_xyz(const Pointf3 &point, double dE, const std::string &
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
GCodeWriter::retract()
|
||||
std::string GCodeWriter::retract(bool before_wipe)
|
||||
{
|
||||
double factor = before_wipe ? this->_extruder->retract_before_wipe() : 1.;
|
||||
assert(factor >= 0. && factor <= 1. + EPSILON);
|
||||
return this->_retract(
|
||||
this->_extruder->retract_length(),
|
||||
this->_extruder->retract_restart_extra(),
|
||||
factor * this->_extruder->retract_length(),
|
||||
factor * this->_extruder->retract_restart_extra(),
|
||||
"retract"
|
||||
);
|
||||
}
|
||||
|
||||
std::string
|
||||
GCodeWriter::retract_for_toolchange()
|
||||
std::string GCodeWriter::retract_for_toolchange(bool before_wipe)
|
||||
{
|
||||
double factor = before_wipe ? this->_extruder->retract_before_wipe() : 1.;
|
||||
assert(factor >= 0. && factor <= 1. + EPSILON);
|
||||
return this->_retract(
|
||||
this->_extruder->retract_length_toolchange(),
|
||||
this->_extruder->retract_restart_extra_toolchange(),
|
||||
factor * this->_extruder->retract_length_toolchange(),
|
||||
factor * this->_extruder->retract_restart_extra_toolchange(),
|
||||
"retract for toolchange"
|
||||
);
|
||||
}
|
||||
@ -431,7 +433,7 @@ GCodeWriter::_retract(double length, double restart_extra, const std::string &co
|
||||
gcode << "G10 ; retract\n";
|
||||
} else {
|
||||
gcode << "G1 " << this->_extrusion_axis << E_NUM(this->_extruder->E)
|
||||
<< " F" << this->_extruder->retract_speed_mm_min;
|
||||
<< " F" << float(this->_extruder->retract_speed() * 60.);
|
||||
COMMENT(comment);
|
||||
gcode << "\n";
|
||||
}
|
||||
@ -462,7 +464,7 @@ GCodeWriter::unretract()
|
||||
} else {
|
||||
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
|
||||
gcode << "G1 " << this->_extrusion_axis << E_NUM(this->_extruder->E)
|
||||
<< " F" << this->_extruder->retract_speed_mm_min;
|
||||
<< " F" << float(this->_extruder->deretract_speed() * 60.);
|
||||
if (this->config.gcode_comments) gcode << " ; unretract";
|
||||
gcode << "\n";
|
||||
}
|
||||
|
@ -52,8 +52,8 @@ public:
|
||||
bool will_move_z(double z) const;
|
||||
std::string extrude_to_xy(const Pointf &point, double dE, const std::string &comment = std::string());
|
||||
std::string extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment = std::string());
|
||||
std::string retract();
|
||||
std::string retract_for_toolchange();
|
||||
std::string retract(bool before_wipe = false);
|
||||
std::string retract_for_toolchange(bool before_wipe = false);
|
||||
std::string unretract();
|
||||
std::string lift();
|
||||
std::string unlift();
|
||||
|
@ -169,6 +169,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|
||||
|| *opt_key == "perimeter_acceleration"
|
||||
|| *opt_key == "post_process"
|
||||
|| *opt_key == "retract_before_travel"
|
||||
|| *opt_key == "retract_before_wipe"
|
||||
|| *opt_key == "retract_layer_change"
|
||||
|| *opt_key == "retract_length"
|
||||
|| *opt_key == "retract_length_toolchange"
|
||||
@ -178,6 +179,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|
||||
|| *opt_key == "retract_restart_extra"
|
||||
|| *opt_key == "retract_restart_extra_toolchange"
|
||||
|| *opt_key == "retract_speed"
|
||||
|| *opt_key == "deretract_speed"
|
||||
|| *opt_key == "single_extruder_multi_material"
|
||||
|| *opt_key == "slowdown_below_layer_time"
|
||||
|| *opt_key == "spiral_vase"
|
||||
|
@ -914,6 +914,17 @@ PrintConfigDef::PrintConfigDef()
|
||||
opt->values.push_back(2);
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("retract_before_wipe", coPercents);
|
||||
def->label = "Retract amount before wipe";
|
||||
def->tooltip = "With bowden extruders, it may be wise to do some amount of quick retract before doing the wipe movement.";
|
||||
def->sidetext = "%";
|
||||
def->cli = "retract-before-wipe=s@";
|
||||
{
|
||||
ConfigOptionPercents* opt = new ConfigOptionPercents();
|
||||
opt->values.push_back(0.f);
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("retract_layer_change", coBools);
|
||||
def->label = "Retract on layer change";
|
||||
@ -1007,7 +1018,7 @@ PrintConfigDef::PrintConfigDef()
|
||||
}
|
||||
|
||||
def = this->add("retract_speed", coFloats);
|
||||
def->label = "Speed";
|
||||
def->label = "Retraction Speed";
|
||||
def->full_label = "Retraction Speed";
|
||||
def->tooltip = "The speed for retractions (it only applies to the extruder motor).";
|
||||
def->sidetext = "mm/s";
|
||||
@ -1018,6 +1029,18 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("deretract_speed", coFloats);
|
||||
def->label = "Deretraction Speed";
|
||||
def->full_label = "Deretraction Speed";
|
||||
def->tooltip = "The speed for loading of a filament into extruder after retraction (it only applies to the extruder motor). If left to zero, the retraction speed is used.";
|
||||
def->sidetext = "mm/s";
|
||||
def->cli = "retract-speed=f@";
|
||||
{
|
||||
ConfigOptionFloats* opt = new ConfigOptionFloats();
|
||||
opt->values.push_back(0);
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("seam_position", coEnum);
|
||||
def->label = "Seam position";
|
||||
def->category = "Layers and perimeters";
|
||||
|
@ -317,6 +317,7 @@ class GCodeConfig : public virtual StaticPrintConfig
|
||||
{
|
||||
public:
|
||||
ConfigOptionString before_layer_gcode;
|
||||
ConfigOptionFloats deretract_speed;
|
||||
ConfigOptionString end_gcode;
|
||||
ConfigOptionString extrusion_axis;
|
||||
ConfigOptionFloats extrusion_multiplier;
|
||||
@ -333,6 +334,7 @@ public:
|
||||
ConfigOptionFloat max_volumetric_speed;
|
||||
ConfigOptionFloat max_volumetric_extrusion_rate_slope_positive;
|
||||
ConfigOptionFloat max_volumetric_extrusion_rate_slope_negative;
|
||||
ConfigOptionPercents retract_before_wipe;
|
||||
ConfigOptionFloats retract_length;
|
||||
ConfigOptionFloats retract_length_toolchange;
|
||||
ConfigOptionFloats retract_lift;
|
||||
@ -357,6 +359,7 @@ public:
|
||||
|
||||
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
|
||||
OPT_PTR(before_layer_gcode);
|
||||
OPT_PTR(deretract_speed);
|
||||
OPT_PTR(end_gcode);
|
||||
OPT_PTR(extrusion_axis);
|
||||
OPT_PTR(extrusion_multiplier);
|
||||
@ -373,6 +376,7 @@ public:
|
||||
OPT_PTR(max_volumetric_speed);
|
||||
OPT_PTR(max_volumetric_extrusion_rate_slope_positive);
|
||||
OPT_PTR(max_volumetric_extrusion_rate_slope_negative);
|
||||
OPT_PTR(retract_before_wipe);
|
||||
OPT_PTR(retract_length);
|
||||
OPT_PTR(retract_length_toolchange);
|
||||
OPT_PTR(retract_lift);
|
||||
|
@ -95,6 +95,13 @@ ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def) {
|
||||
} else if (def.type == coPercent) {
|
||||
const ConfigOptionPercent* optv = dynamic_cast<const ConfigOptionPercent*>(&opt);
|
||||
return newSVnv(optv->value);
|
||||
} else if (def.type == coPercents) {
|
||||
const ConfigOptionPercents* optv = dynamic_cast<const ConfigOptionPercents*>(&opt);
|
||||
AV* av = newAV();
|
||||
av_fill(av, optv->values.size()-1);
|
||||
for (const double &v : optv->values)
|
||||
av_store(av, &v - &optv->values.front(), newSVnv(v));
|
||||
return newRV_noinc((SV*)av);
|
||||
} else if (def.type == coInt) {
|
||||
const ConfigOptionInt* optv = dynamic_cast<const ConfigOptionInt*>(&opt);
|
||||
return newSViv(optv->value);
|
||||
@ -148,7 +155,7 @@ ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t
|
||||
if (opt == NULL) return &PL_sv_undef;
|
||||
|
||||
const ConfigOptionDef* def = THIS->def->get(opt_key);
|
||||
if (def->type == coFloats) {
|
||||
if (def->type == coFloats || def->type == coPercents) {
|
||||
ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt);
|
||||
return newSVnv(optv->get_at(i));
|
||||
} else if (def->type == coInts) {
|
||||
@ -191,6 +198,17 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
|
||||
values.push_back(SvNV(*elem));
|
||||
}
|
||||
optv->values = values;
|
||||
} else if (def->type == coPercents) {
|
||||
ConfigOptionPercents* optv = dynamic_cast<ConfigOptionPercents*>(opt);
|
||||
std::vector<double> values;
|
||||
AV* av = (AV*)SvRV(value);
|
||||
const size_t len = av_len(av)+1;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
SV** elem = av_fetch(av, i, 0);
|
||||
if (elem == NULL || !looks_like_number(*elem)) return false;
|
||||
values.push_back(SvNV(*elem));
|
||||
}
|
||||
optv->values = values;
|
||||
} else if (def->type == coInt) {
|
||||
if (!looks_like_number(value)) return false;
|
||||
ConfigOptionInt* optv = dynamic_cast<ConfigOptionInt*>(opt);
|
||||
|
@ -106,7 +106,7 @@ print_config_def()
|
||||
const char* opt_type;
|
||||
if (optdef->type == coFloat || optdef->type == coFloats || optdef->type == coFloatOrPercent) {
|
||||
opt_type = "f";
|
||||
} else if (optdef->type == coPercent) {
|
||||
} else if (optdef->type == coPercent || optdef->type == coPercents) {
|
||||
opt_type = "percent";
|
||||
} else if (optdef->type == coInt || optdef->type == coInts) {
|
||||
opt_type = "i";
|
||||
|
@ -38,8 +38,6 @@
|
||||
%code%{ RETVAL = THIS->restart_extra = val; %};
|
||||
double e_per_mm3()
|
||||
%code%{ RETVAL = THIS->e_per_mm3; %};
|
||||
double retract_speed_mm_min()
|
||||
%code%{ RETVAL = THIS->retract_speed_mm_min; %};
|
||||
|
||||
double filament_diameter();
|
||||
double filament_density();
|
||||
|
Loading…
Reference in New Issue
Block a user