mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-14 09:51:47 +08:00
FanMover rework
- new code path - add kickstart - add bypass for not-overhangs fan calls todo: unit test
This commit is contained in:
parent
62d64b4f61
commit
b66901672f
@ -15,7 +15,12 @@ group:silent_mode_event:Firmware
|
||||
setting:gcode_flavor
|
||||
setting:silent_mode
|
||||
setting:remaining_times
|
||||
setting:fan_speedup_time
|
||||
group:Cooling fan
|
||||
line:Speedup
|
||||
setting:label$Speedup time:fan_speedup_time
|
||||
setting:label$Only for overhangs:fan_speedup_overhangs
|
||||
end_line
|
||||
setting:label$Small:fan_kickstart
|
||||
group:Thumbnails
|
||||
line:Size for Gcode
|
||||
setting:id$0:label$Small:thumbnails
|
||||
|
@ -263,7 +263,6 @@ double ExtrusionLoop::min_mm3_per_mm() const
|
||||
return min_mm3_per_mm;
|
||||
}
|
||||
|
||||
|
||||
std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
|
||||
{
|
||||
switch (role) {
|
||||
|
@ -3495,30 +3495,6 @@ void GCode::use(const ExtrusionEntityCollection &collection) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string extrusion_role_2_string(const ExtrusionRole &er) {
|
||||
switch (er) {
|
||||
case erNone: return "none";
|
||||
case erPerimeter: return "perimeter";
|
||||
case erExternalPerimeter: return "perimeter external";
|
||||
case erOverhangPerimeter: return "perimeter overhang";
|
||||
case erInternalInfill: return "infill internal";
|
||||
case erSolidInfill: return "infill solid";
|
||||
case erTopSolidInfill: return "infill solid top";
|
||||
case erBridgeInfill: return "infill bridge";
|
||||
case erThinWall: return "thin_wall";
|
||||
case erGapFill: return "gap_fill";
|
||||
case erSkirt: return "skirt";
|
||||
case erSupportMaterial: return "support_material";
|
||||
case erSupportMaterialInterface: return "support_material_interface";
|
||||
case erWipeTower: return "wipe_tower";
|
||||
case erMilling: return "milling";
|
||||
case erCustom: return "custom";
|
||||
case erMixed: return "mixed";
|
||||
case erCount: return "count";
|
||||
}
|
||||
return " unkown";
|
||||
}
|
||||
|
||||
std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) {
|
||||
|
||||
ExtrusionPath simplifed_path = path;
|
||||
@ -3676,12 +3652,15 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
||||
void GCode::_post_process(std::string& what, bool flush) {
|
||||
|
||||
//if enabled, move the fan startup earlier.
|
||||
if (this->config().fan_speedup_time.value != 0) {
|
||||
if (this->config().fan_speedup_time.value != 0 || this->config().fan_kickstart.value > 0) {
|
||||
if (this->m_fan_mover.get() == nullptr)
|
||||
this->m_fan_mover.reset(new Slic3r::FanMover(
|
||||
std::abs(this->config().fan_speedup_time.value),
|
||||
this->config().fan_speedup_time.value > 0,
|
||||
this->config().use_relative_e_distances.value));
|
||||
this->m_writer,
|
||||
std::abs(this->config().fan_speedup_time.value),
|
||||
this->config().fan_speedup_time.value > 0,
|
||||
this->config().use_relative_e_distances.value,
|
||||
this->config().fan_speedup_overhangs.value,
|
||||
this->config().fan_kickstart.value));
|
||||
what = this->m_fan_mover->process_gcode(what, flush);
|
||||
}
|
||||
|
||||
@ -3769,7 +3748,7 @@ std::vector<double> cut_corner_cache = {
|
||||
|
||||
std::string GCode::_extrude(const ExtrusionPath &path, const std::string &description, double speed) {
|
||||
|
||||
std::string descr = description + extrusion_role_2_string(path.role());
|
||||
std::string descr = description + ExtrusionEntity::role_to_string(path.role());
|
||||
std::string gcode = this->_before_extrude(path, descr, speed);
|
||||
|
||||
// calculate extrusion length per distance unit
|
||||
|
@ -22,13 +22,17 @@ const std::string& FanMover::process_gcode(const std::string& gcode, bool flush)
|
||||
{
|
||||
m_process_output = "";
|
||||
|
||||
// recompute buffer time to recover from rounding
|
||||
m_buffer_time_size = 0;
|
||||
for (auto& data : m_buffer) m_buffer_time_size += data.time;
|
||||
|
||||
m_parser.parse_buffer(gcode,
|
||||
[this](GCodeReader& reader, const GCodeReader::GCodeLine& line) { /*m_process_output += line.raw() + "\n";*/ this->_process_gcode_line(reader, line); });
|
||||
|
||||
if (flush) {
|
||||
while (!buffer.empty()) {
|
||||
m_process_output += buffer.back().raw + "\n";
|
||||
buffer.pop_back();
|
||||
while (!m_buffer.empty()) {
|
||||
m_process_output += m_buffer.front().raw + "\n";
|
||||
remove_from_buffer(m_buffer.begin());
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,15 +75,152 @@ void change_axis_value(std::string& line, char axis, const float new_value, cons
|
||||
line = line.replace(pos, end - pos, ss.str());
|
||||
}
|
||||
|
||||
int16_t get_fan_speed(const std::string &line, GCodeFlavor flavor) {
|
||||
if (line.compare(0, 4, "M106") == 0) {
|
||||
if (flavor == (gcfMach3) || flavor == (gcfMachinekit)) {
|
||||
return (int16_t)get_axis_value(line, 'P');
|
||||
} else {
|
||||
return (int16_t)get_axis_value(line, 'S');
|
||||
}
|
||||
} else if (line.compare(0, 4, "M127") == 0 || line.compare(0, 4, "M107") == 0) {
|
||||
return 0;
|
||||
} else if ((flavor == (gcfMakerWare) || flavor == (gcfSailfish)) && line.compare(0, 4, "M126") == 0) {
|
||||
return (int16_t)get_axis_value(line, 'T');
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator &item_to_split, float nb_sec, BufferData &&line_to_write) {
|
||||
//std::cout << "_put_in_middle_G1\n";
|
||||
assert(item_to_split != m_buffer.end());
|
||||
if (nb_sec < item_to_split->time * 0.1) {
|
||||
// doesn't really need to be split, print it after
|
||||
m_buffer.insert(next(item_to_split), line_to_write);
|
||||
} else if (nb_sec > item_to_split->time * 0.9) {
|
||||
// doesn't really need to be split, print it before
|
||||
//will also print before if line_to_split.time == 0
|
||||
m_buffer.insert(item_to_split, line_to_write);
|
||||
} else if (item_to_split->raw.size() > 2
|
||||
&& item_to_split->raw[0] == 'G' && item_to_split->raw[1] == '1' && item_to_split->raw[2] == ' ') {
|
||||
float percent = nb_sec / item_to_split->time;
|
||||
BufferData before = *item_to_split;
|
||||
before.time *= percent;
|
||||
item_to_split->time *= (1-percent);
|
||||
if (item_to_split->dx != 0) {
|
||||
before.dx = item_to_split->dx * percent;
|
||||
item_to_split->x += before.dx;
|
||||
item_to_split->dx = item_to_split->dx * (1-percent);
|
||||
change_axis_value(before.raw, 'X', before.x + before.dx, 3);
|
||||
}
|
||||
if (item_to_split->dy != 0) {
|
||||
before.dy = item_to_split->dy * percent;
|
||||
item_to_split->y += before.dy;
|
||||
item_to_split->dy = item_to_split->dy * (1 - percent);
|
||||
change_axis_value(before.raw, 'Y', before.y + before.dy, 3);
|
||||
}
|
||||
if (item_to_split->dz != 0) {
|
||||
before.dz = item_to_split->dz * percent;
|
||||
item_to_split->z += before.dz;
|
||||
item_to_split->dz = item_to_split->dz * (1 - percent);
|
||||
change_axis_value(before.raw, 'Z', before.z + before.dz, 3);
|
||||
}
|
||||
if (item_to_split->de != 0) {
|
||||
if (relative_e) {
|
||||
before.de = item_to_split->de * percent;
|
||||
change_axis_value(before.raw, 'E', before.de, 5);
|
||||
item_to_split->de = item_to_split->de * (1 - percent);
|
||||
change_axis_value(item_to_split->raw, 'E', item_to_split->de, 5);
|
||||
} else {
|
||||
before.de = item_to_split->de * percent;
|
||||
item_to_split->e += before.de;
|
||||
item_to_split->de = item_to_split->de * (1 - percent);
|
||||
change_axis_value(before.raw, 'E', before.e + before.de, 5);
|
||||
change_axis_value(item_to_split->raw, 'E', item_to_split->e + item_to_split->de, 5);
|
||||
}
|
||||
}
|
||||
//add before then line_to_write, then there is the modified data.
|
||||
m_buffer.insert(item_to_split, before);
|
||||
m_buffer.insert(item_to_split, line_to_write);
|
||||
|
||||
} else {
|
||||
//not a G1, print it before
|
||||
m_buffer.insert(item_to_split, line_to_write);
|
||||
}
|
||||
}
|
||||
|
||||
void FanMover::_print_in_middle_G1(BufferData& line_to_split, float nb_sec, const std::string &line_to_write) {
|
||||
//std::cout << "_print_in_middle_G1\n";
|
||||
if (nb_sec < line_to_split.time * 0.1) {
|
||||
// doesn't really need to be split, print it after
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n'?"":"\n");
|
||||
} else if (nb_sec > line_to_split.time * 0.9) {
|
||||
// doesn't really need to be split, print it before
|
||||
//will also print before if line_to_split.time == 0
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
}else if(line_to_split.raw.size() > 2
|
||||
&& line_to_split.raw[0] == 'G' && line_to_split.raw[1] == '1' && line_to_split.raw[2] == ' ') {
|
||||
float percent = nb_sec / line_to_split.time;
|
||||
std::string before = line_to_split.raw;
|
||||
std::string& after = line_to_split.raw;
|
||||
if (line_to_split.dx != 0) {
|
||||
change_axis_value(before, 'X', line_to_split.x + line_to_split.dx * percent, 3);
|
||||
}
|
||||
if (line_to_split.dy != 0) {
|
||||
change_axis_value(before, 'Y', line_to_split.y + line_to_split.dy * percent, 3);
|
||||
}
|
||||
if (line_to_split.dz != 0) {
|
||||
change_axis_value(before, 'Z', line_to_split.z + line_to_split.dz * percent, 3);
|
||||
}
|
||||
if (line_to_split.de != 0) {
|
||||
if (relative_e) {
|
||||
change_axis_value(before, 'E', line_to_split.de * percent, 5);
|
||||
change_axis_value(after, 'E', line_to_split.de * (1 - percent), 5);
|
||||
} else {
|
||||
change_axis_value(before, 'E', line_to_split.e + line_to_split.de * percent, 5);
|
||||
change_axis_value(after, 'E', line_to_split.e + line_to_split.de * (1 - percent), 5);
|
||||
}
|
||||
}
|
||||
m_process_output += before + "\n";
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
|
||||
} else {
|
||||
//not a G1, print it before
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void FanMover::_remove_slow_fan(int16_t min_speed, float past_sec) {
|
||||
//erase fan in the buffer -> don't slowdown if you are in the process of step-up.
|
||||
//we began at the "recent" side , and remove as long as we don't push past_sec to 0
|
||||
auto it = m_buffer.begin();
|
||||
while (it != m_buffer.end() && past_sec > 0) {
|
||||
past_sec -= it->time;
|
||||
if (it->fan_speed >= 0 && it->fan_speed < min_speed){
|
||||
//found something that is lower than us
|
||||
it = remove_from_buffer(it);
|
||||
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// processes 'normal' gcode lines
|
||||
std::string cmd = line.cmd();
|
||||
double time = 0;
|
||||
float fan_speed = -1;
|
||||
int16_t fan_speed = -1;
|
||||
if (cmd.length() > 1) {
|
||||
if (line.has_f())
|
||||
current_speed = line.f() / 60.0f;
|
||||
m_current_speed = line.f() / 60.0f;
|
||||
switch (::toupper(cmd[0])) {
|
||||
case 'G':
|
||||
{
|
||||
@ -90,129 +231,141 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode
|
||||
double dist = distx * distx + disty * disty + distz * distz;
|
||||
if (dist > 0) {
|
||||
dist = std::sqrt(dist);
|
||||
time = dist / current_speed;
|
||||
time = dist / m_current_speed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'M':
|
||||
{
|
||||
if (::atoi(&cmd[1]) == 106) {
|
||||
if (line.has_value('S', fan_speed) ) {
|
||||
int nb_M106_erased = 0;
|
||||
if (fan_speed > expected_fan_speed) {
|
||||
time = -1; // don't write!
|
||||
buffer.emplace_front(BufferData("; erased: "+line.raw(), 0, -1));
|
||||
//erase M106 in the buffer -> don't slowdown if you are in the process of step-up.
|
||||
auto it = buffer.begin();
|
||||
int i = 0;
|
||||
while (it != buffer.end()) {
|
||||
if (it->raw.compare(0, 4, "M106") == 0 && it->fan_speed < fan_speed) {
|
||||
//found something that is lower than us -> change is speed by ours and delete us
|
||||
it->fan_speed = fan_speed;
|
||||
std::stringstream ss; ss << "S" << (int)fan_speed;
|
||||
it->raw = std::regex_replace(it->raw, regex_fan_speed, ss.str());
|
||||
nb_M106_erased++;
|
||||
} else {
|
||||
++it;
|
||||
i++;
|
||||
}
|
||||
fan_speed = get_fan_speed(line.raw(), m_writer.config.gcode_flavor);
|
||||
if (fan_speed > 0) {
|
||||
if (!only_overhangs || current_role != ExtrusionRole::erOverhangPerimeter) {
|
||||
// this M106 need to go in the past
|
||||
//check if we have !( kickstart and not in slowdown )
|
||||
if (kickstart <= 0 || fan_speed < m_current_fan_speed) {
|
||||
// first erase everything lower that that value
|
||||
_remove_slow_fan(fan_speed, m_buffer_time_size + 1);
|
||||
// then write the fan command
|
||||
if (m_buffer_time_size > nb_seconds_delay) {
|
||||
_print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, line.raw());
|
||||
remove_from_buffer(m_buffer.begin());
|
||||
} else {
|
||||
m_process_output += line.raw() + "\n";
|
||||
}
|
||||
|
||||
if (nb_M106_erased == 0) {
|
||||
//try to split the G1/G0 line to increae precision
|
||||
if (!buffer.empty()) {
|
||||
BufferData& backdata = buffer.back();
|
||||
if (buffer_time_size > nb_seconds_delay * 1.1f && backdata.raw.size() > 2
|
||||
&& backdata.raw[0] == 'G' && backdata.raw[1] == '1' && backdata.raw[2] == ' ') {
|
||||
float percent = (buffer_time_size - nb_seconds_delay) / backdata.time;
|
||||
std::string before = backdata.raw;
|
||||
std::string& after = backdata.raw;
|
||||
if (backdata.dx != 0) {
|
||||
change_axis_value(before, 'X', backdata.x + backdata.dx * percent, 3);
|
||||
}
|
||||
if (backdata.dy != 0) {
|
||||
change_axis_value(before, 'Y', backdata.y + backdata.dy * percent, 3);
|
||||
}
|
||||
if (backdata.dz != 0) {
|
||||
change_axis_value(before, 'Z', backdata.z + backdata.dz * percent, 3);
|
||||
}
|
||||
if (backdata.de != 0) {
|
||||
if (relative_e) {
|
||||
change_axis_value(before, 'E', backdata.de * percent, 5);
|
||||
change_axis_value(after, 'E', backdata.de * (1 - percent), 5);
|
||||
} else {
|
||||
change_axis_value(before, 'E', backdata.e + backdata.de * percent, 5);
|
||||
change_axis_value(after, 'E', backdata.e + backdata.de * (1 - percent), 5);
|
||||
}
|
||||
}
|
||||
m_process_output += before + "\n";
|
||||
buffer_time_size -= backdata.time * percent;
|
||||
backdata.time -= backdata.time * percent;
|
||||
|
||||
}
|
||||
} else {
|
||||
//if kickstart
|
||||
// first erase everything lower that that value
|
||||
_remove_slow_fan(fan_speed, m_buffer_time_size + 1);
|
||||
// first erase everything lower that kickstart
|
||||
_remove_slow_fan(255, kickstart);
|
||||
// print me
|
||||
if (m_buffer_time_size > nb_seconds_delay) {
|
||||
_print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, m_writer.set_fan(100, true));
|
||||
remove_from_buffer(m_buffer.begin());
|
||||
} else {
|
||||
m_process_output += m_writer.set_fan(100, true);
|
||||
}
|
||||
//write it in the queue if possible
|
||||
float time_count = kickstart;
|
||||
auto it = m_buffer.begin();
|
||||
while (it != m_buffer.end() && time_count > 0) {
|
||||
if (time_count - it->time < 0) {
|
||||
//found something that is lower than us
|
||||
_put_in_middle_G1(it, time_count, BufferData{ line.cmd(), 0, fan_speed });
|
||||
//found, stop
|
||||
break;
|
||||
}
|
||||
|
||||
//print it
|
||||
if (with_D_option) {
|
||||
std::stringstream ss;
|
||||
ss << " D" << (uint32_t)(buffer_time_size * 1000) << "\n";
|
||||
m_process_output += line.raw() + ss.str();
|
||||
} else {
|
||||
m_process_output += line.raw() + "\n";
|
||||
}
|
||||
current_fan_speed = fan_speed;
|
||||
++it;
|
||||
time_count -= it->time;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (kickstart <= 0) {
|
||||
//nothing to do
|
||||
//we don't put time = -1; so it will printed in the buffer as other line are done
|
||||
} else {
|
||||
//if kickstart, write the M106 255 first
|
||||
time = -1;
|
||||
//set the target speed and set the kickstart flag
|
||||
put_in_buffer(BufferData(m_writer.set_fan(100, true), 0, fan_speed, true));
|
||||
//add the normal speed line for the future
|
||||
m_current_kickstart.fan_speed = fan_speed;
|
||||
m_current_kickstart.time = kickstart;
|
||||
m_current_kickstart.raw = line.raw();
|
||||
}
|
||||
|
||||
//update
|
||||
expected_fan_speed = fan_speed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(!line.raw().empty() && line.raw().front() == ';')
|
||||
{
|
||||
if (line.raw().size() > 10 && line.raw().rfind(";TYPE:", 0) == 0) {
|
||||
// get the type of the next extrusions
|
||||
std::string extrusion_string = line.raw().substr(6, line.raw().size() - 6);
|
||||
current_role = ExtrusionEntity::string_to_role(extrusion_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (time >= 0) {
|
||||
buffer.emplace_front(BufferData(line.raw(), time, fan_speed));
|
||||
BufferData& front = buffer.front();
|
||||
BufferData& new_data = put_in_buffer(BufferData(line.raw(), time, fan_speed));
|
||||
if (line.has(Axis::X)) {
|
||||
front.x = reader.x();
|
||||
front.dx = line.dist_X(reader);
|
||||
new_data.x = reader.x();
|
||||
new_data.dx = line.dist_X(reader);
|
||||
}
|
||||
if (line.has(Axis::Y)) {
|
||||
front.y = reader.y();
|
||||
front.dy = line.dist_Y(reader);
|
||||
new_data.y = reader.y();
|
||||
new_data.dy = line.dist_Y(reader);
|
||||
}
|
||||
if (line.has(Axis::Z)) {
|
||||
front.z = reader.z();
|
||||
front.dz = line.dist_Z(reader);
|
||||
new_data.z = reader.z();
|
||||
new_data.dz = line.dist_Z(reader);
|
||||
}
|
||||
if (line.has(Axis::E)) {
|
||||
front.e = reader.e();
|
||||
if(relative_e)
|
||||
front.de = line.e();
|
||||
new_data.e = reader.e();
|
||||
if (relative_e)
|
||||
new_data.de = line.e();
|
||||
else
|
||||
front.de = line.dist_E(reader);
|
||||
new_data.de = line.dist_E(reader);
|
||||
}
|
||||
|
||||
if (m_current_kickstart.time > 0) {
|
||||
m_current_kickstart.time -= time;
|
||||
if (m_current_kickstart.time < 0) {
|
||||
//prev is possible because we just do a emplace_back.
|
||||
_put_in_middle_G1(prev(m_buffer.end()), time + m_current_kickstart.time, BufferData{ m_current_kickstart.raw, 0, m_current_kickstart.fan_speed });
|
||||
}
|
||||
}
|
||||
buffer_time_size += time;
|
||||
}
|
||||
// puts the line back into the gcode
|
||||
//if buffer too big, flush it.
|
||||
if (time > 0) {
|
||||
while (buffer_time_size - buffer.back().time > nb_seconds_delay) {
|
||||
BufferData &backdata = buffer.back();
|
||||
if (backdata.fan_speed < 0 || (int)backdata.fan_speed != (int)current_fan_speed) {
|
||||
buffer_time_size -= backdata.time;
|
||||
m_process_output += backdata.raw + "\n";
|
||||
if (backdata.fan_speed >= 0) {
|
||||
current_fan_speed = backdata.fan_speed;
|
||||
while (!m_buffer.empty() && m_buffer_time_size - m_buffer.front().time > nb_seconds_delay) {
|
||||
BufferData& backdata = m_buffer.front();
|
||||
if (backdata.fan_speed < 0 || backdata.fan_speed != m_current_fan_speed) {
|
||||
if (backdata.is_kickstart && backdata.fan_speed < m_current_fan_speed) {
|
||||
//you have to slow down! not kickstart! rewrite the fan speed.
|
||||
m_process_output += m_writer.set_fan(backdata.fan_speed,true);
|
||||
m_current_fan_speed = backdata.fan_speed;
|
||||
} else {
|
||||
m_process_output += backdata.raw + "\n";
|
||||
if (backdata.fan_speed >= 0) {
|
||||
//note that this is the only plce where the fan_speed is set and we print from the buffer, as if the fan_speed >= 0 => time == 0
|
||||
//and as this flush all time == 0 lines fromt he back of the queue...
|
||||
m_current_fan_speed = backdata.fan_speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.pop_back();
|
||||
remove_from_buffer(m_buffer.begin());
|
||||
}
|
||||
}
|
||||
float sum = 0;
|
||||
for (auto& data : m_buffer) sum += data.time;
|
||||
assert( std::abs(m_buffer_time_size - sum) < 0.01);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "../Point.hpp"
|
||||
#include "../GCodeReader.hpp"
|
||||
#include "../GCodeWriter.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace Slic3r {
|
||||
@ -16,10 +17,14 @@ class BufferData {
|
||||
public:
|
||||
std::string raw;
|
||||
float time;
|
||||
float fan_speed;
|
||||
int16_t fan_speed;
|
||||
bool is_kickstart;
|
||||
float x = 0, y = 0, z = 0, e = 0;
|
||||
float dx = 0, dy = 0, dz = 0, de = 0;
|
||||
BufferData(std::string line, float time = 0, float fan_speed = 0) : raw(line), time(time), fan_speed(fan_speed) {}
|
||||
BufferData(std::string line, float time = 0, int16_t fan_speed = 0, float is_kickstart = false) : raw(line), time(time), fan_speed(fan_speed), is_kickstart(is_kickstart){
|
||||
//avoid double \n
|
||||
if(!line.empty() && line.back() == '\n') line.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
class FanMover
|
||||
@ -29,28 +34,54 @@ private:
|
||||
const float nb_seconds_delay;
|
||||
const bool with_D_option;
|
||||
const bool relative_e;
|
||||
const bool only_overhangs;
|
||||
const float kickstart;
|
||||
|
||||
// in unit/second
|
||||
double current_speed = 1000 / 60.0;;
|
||||
float buffer_time_size = 0;
|
||||
GCodeReader m_parser{};
|
||||
int expected_fan_speed = 0;
|
||||
int current_fan_speed = 0;
|
||||
GCodeWriter& m_writer;
|
||||
|
||||
//current value (at the back of the buffer), when parsing a new line
|
||||
ExtrusionRole current_role = ExtrusionRole::erCustom;
|
||||
// in unit/second
|
||||
double m_current_speed = 1000 / 60.0;
|
||||
|
||||
// variable for when you add a line (front of the buffer)
|
||||
int m_current_fan_speed = 0;
|
||||
BufferData m_current_kickstart{"",-1,0};
|
||||
|
||||
//buffer
|
||||
std::list<BufferData> m_buffer;
|
||||
double m_buffer_time_size = 0;
|
||||
|
||||
// The output of process_layer()
|
||||
std::list<BufferData> buffer;
|
||||
std::string m_process_output;
|
||||
|
||||
public:
|
||||
FanMover(const float nb_seconds_delay, const bool with_D_option, const bool relative_e)
|
||||
: regex_fan_speed("S[0-9]+"), nb_seconds_delay(nb_seconds_delay), with_D_option(with_D_option), relative_e(relative_e){}
|
||||
FanMover(GCodeWriter& writer, const float nb_seconds_delay, const bool with_D_option, const bool relative_e,
|
||||
const bool only_overhangs, const float kickstart)
|
||||
: regex_fan_speed("S[0-9]+"),
|
||||
nb_seconds_delay(nb_seconds_delay>0 ? std::max(0.01f,nb_seconds_delay) : 0),
|
||||
with_D_option(with_D_option)
|
||||
, relative_e(relative_e), only_overhangs(only_overhangs), kickstart(kickstart), m_writer(writer){}
|
||||
|
||||
// Adds the gcode contained in the given string to the analysis and returns it after removing the workcodes
|
||||
const std::string& process_gcode(const std::string& gcode, bool flush);
|
||||
|
||||
private:
|
||||
BufferData& put_in_buffer(BufferData&& data) {
|
||||
m_buffer_time_size += data.time;
|
||||
m_buffer.emplace_back(data);
|
||||
return m_buffer.back();
|
||||
}
|
||||
std::list<BufferData>::iterator remove_from_buffer(std::list<BufferData>::iterator& data) {
|
||||
m_buffer_time_size -= data->time;
|
||||
return m_buffer.erase(data);
|
||||
}
|
||||
// Processes the given gcode line
|
||||
void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line);
|
||||
void _put_in_middle_G1(std::list<BufferData>::iterator& item_to_split, float nb_sec, BufferData&& line_to_write);
|
||||
void _print_in_middle_G1(BufferData& line_to_split, float nb_sec, const std::string& line_to_write);
|
||||
void _remove_slow_fan(int16_t min_speed, float past_sec);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -252,7 +252,7 @@ std::string GCodeWriter::set_fan(const unsigned int speed, bool dont_save, uint1
|
||||
gcode << "\n";
|
||||
} else {
|
||||
if (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) {
|
||||
gcode << "M126";
|
||||
gcode << "M126 T";
|
||||
} else {
|
||||
gcode << "M106 ";
|
||||
if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) {
|
||||
|
@ -641,7 +641,11 @@ const std::vector<std::string>& Preset::printer_options()
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
"printer_technology",
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset",
|
||||
"fan_kickstart",
|
||||
"fan_speedup_overhangs",
|
||||
"fan_speedup_time",
|
||||
"gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"min_length",
|
||||
"host_type", "print_host", "printhost_apikey", "printhost_cafile", "printhost_slug",
|
||||
@ -662,7 +666,6 @@ const std::vector<std::string>& Preset::printer_options()
|
||||
"wipe_advanced_nozzle_melted_volume",
|
||||
"wipe_advanced_multiplier",
|
||||
"wipe_advanced_algo",
|
||||
"fan_speedup_time",
|
||||
"time_estimation_compensation",
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::machine_limits_options().begin(), Preset::machine_limits_options().end());
|
||||
|
@ -101,6 +101,8 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
||||
"extrusion_multiplier",
|
||||
"fan_always_on",
|
||||
"fan_below_layer_time",
|
||||
"fan_kickstart",
|
||||
"fan_speedup_overhangs",
|
||||
"fan_speedup_time",
|
||||
"filament_colour",
|
||||
"filament_diameter",
|
||||
|
@ -2072,12 +2072,29 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("fan_speedup_time", coFloat);
|
||||
def->label = L("Fan startup delay");
|
||||
def->category = OptionCategory::firmware;
|
||||
def->tooltip = L("Move the M106 in the past by at least this delay (in seconds, you can use decimals) and add the 'D' option to it to tell to the firware when the fan have to be at this speed."
|
||||
" It assume infinite acceleration for this time estimation, and only takes into account G1 and G0 moves. Use 0 to deactivate, negative to remove the 'D' option.");
|
||||
def->tooltip = L("Move the fan start in the past by at least this delay (in seconds, you can use decimals)."
|
||||
" It assumes infinite acceleration for this time estimation, and will only take into account G1 and G0 moves. Use 0 to deactivate.");
|
||||
def->sidetext = L("s");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(-0.5));
|
||||
|
||||
def = this->add("fan_speedup_overhangs", coBool);
|
||||
def->label = L("Fan startup delay");
|
||||
def->category = OptionCategory::firmware;
|
||||
def->tooltip = L("Will only take into account the delay for the cooling of overhangs.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("fan_kickstart", coFloat);
|
||||
def->label = L("Fan KickStart time");
|
||||
def->category = OptionCategory::firmware;
|
||||
def->tooltip = L("Add a M106 S255 (max speed for fan) for this amount of seconds before gonig down to the desired speed to kick-start the cooling fan."
|
||||
"\nSet to 0 to deactivate.");
|
||||
def->sidetext = L("s");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("machine_limits_usage", coEnum);
|
||||
def->label = L("How to apply");
|
||||
def->full_label = L("Purpose of Machine Limits");
|
||||
|
@ -964,6 +964,8 @@ public:
|
||||
ConfigOptionFloats extruder_temperature_offset;
|
||||
ConfigOptionString extrusion_axis;
|
||||
ConfigOptionFloats extrusion_multiplier;
|
||||
ConfigOptionFloat fan_kickstart;
|
||||
ConfigOptionBool fan_speedup_overhangs;
|
||||
ConfigOptionFloat fan_speedup_time;
|
||||
ConfigOptionFloats filament_cost;
|
||||
ConfigOptionFloats filament_density;
|
||||
@ -1067,6 +1069,8 @@ protected:
|
||||
OPT_PTR(extruder_temperature_offset);
|
||||
OPT_PTR(extrusion_axis);
|
||||
OPT_PTR(extrusion_multiplier);
|
||||
OPT_PTR(fan_kickstart);
|
||||
OPT_PTR(fan_speedup_overhangs);
|
||||
OPT_PTR(fan_speedup_time);
|
||||
OPT_PTR(filament_diameter);
|
||||
OPT_PTR(filament_density);
|
||||
|
Loading…
x
Reference in New Issue
Block a user