new: fan startup delay. (or advanced speed-up)

This commit is contained in:
supermerill 2019-02-21 19:10:55 +01:00
parent aec5a563bb
commit c6239850b0
10 changed files with 185 additions and 6 deletions

View File

@ -2452,11 +2452,27 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
return gcode;
}
void GCode::_post_process(std::string& what) {
//if enabled, move the fan startup earlier.
if (this->config().fan_speedup_time.value != 0) {
FanMover fen_post_process(std::abs(this->config().fan_speedup_time.value), this->config().fan_speedup_time.value>0);
what = fen_post_process.process_gcode(what);
}
}
void GCode::_write(FILE* file, const char *what)
{
if (what != nullptr) {
//const char * gcode_pp = _post_process(what).c_str();
std::string str_preproc = what;
_post_process(str_preproc);
const std::string str_ana = m_analyzer.process_gcode(str_preproc);
// apply analyzer, if enabled
const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what;
const char * gcode = m_enable_analyzer ? str_ana.c_str() : str_preproc.c_str();
// writes string to file
fwrite(gcode, 1, ::strlen(gcode), file);

View File

@ -354,6 +354,7 @@ protected:
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); }
void _write(FILE* file, const char *what);
// Write a string into a file.
// Add a newline, if the string does not end with a newline already.
// Used to export a custom G-code section processed by the PlaceholderParser.
@ -362,6 +363,9 @@ protected:
// Formats and write into a file the given data.
void _write_format(FILE* file, const char* format, ...);
//some post-processing on the file, before the analyzer
void _post_process(std::string& what);
std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
std::string _after_extrude(const ExtrusionPath &path);

View File

@ -863,5 +863,110 @@ size_t GCodeAnalyzer::memory_used() const
out += m_process_output.size();
return out;
}
const std::string& FanMover::process_gcode(const std::string& gcode) {
m_process_output = "";
buffer.clear();
buffer_time_size = 0;
current_speed = 1000 / 60.0;
expected_fan_speed = 0;
current_fan_speed = 0;
m_parser.parse_buffer(gcode,
[this](GCodeReader& reader, const GCodeReader::GCodeLine& line) { /*m_process_output += line.raw() + "\n";*/ this->_process_gcode_line(reader, line); });
while (!buffer.empty()) {
m_process_output += buffer.back().raw + "\n";
buffer.pop_back();
}
return m_process_output;
}
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;
if (cmd.length() > 1) {
if (line.has_f())
current_speed = line.f() / 60.0f;
switch (::toupper(cmd[0])) {
case 'G':
{
if (::atoi(&cmd[1]) == 1 || ::atoi(&cmd[1]) == 0) {
double dist = line.dist_X(reader)*line.dist_X(reader) + line.dist_Y(reader)*line.dist_Y(reader) + line.dist_Z(reader)*line.dist_Z(reader);
if (dist > 0) {
dist = std::sqrt(dist);
time = dist / 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!
//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->speed < fan_speed) {
//found somethign that is lower than us -> change is speed by ours and delete us
it->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++;
}
}
if (nb_M106_erased == 0) {
//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;
}
}
//update
expected_fan_speed = fan_speed;
}
}
break;
}
}
}
if (time >= 0) {
buffer.emplace_front(BufferData(line.raw(), time, 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.speed < 0 || (int)backdata.speed != (int)current_fan_speed) {
buffer_time_size -= backdata.time;
m_process_output += backdata.raw + "\n";
if (backdata.speed >= 0) {
current_fan_speed = backdata.speed;
}
}
buffer.pop_back();
}
}
}
} // namespace Slic3r

View File

@ -7,6 +7,7 @@
#include "../Point.hpp"
#include "../GCodeReader.hpp"
#include <regex>
namespace Slic3r {
@ -239,6 +240,42 @@ private:
void _calc_gcode_preview_unretractions(GCodePreviewData& preview_data);
};
class BufferData {
public:
std::string raw;
float time;
float speed;
BufferData(std::string line, float time = 0, float speed = 0) : raw(line), time(time), speed(speed) {}
};
class FanMover
{
private:
const std::regex regex_fan_speed;
const float nb_seconds_delay;
const bool with_D_option;
// in unit/second
double current_speed;
float buffer_time_size;
GCodeReader m_parser;
int expected_fan_speed;
int current_fan_speed;
// 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) : regex_fan_speed("S[0-9]+"), nb_seconds_delay(nb_seconds_delay), with_D_option(with_D_option){}
// 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);
private:
// Processes the given gcode line
void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line);
};
} // namespace Slic3r
#endif /* slic3r_GCode_Analyzer_hpp_ */

View File

@ -117,6 +117,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"extrusion_multiplier",
"fan_always_on",
"fan_below_layer_time",
"fan_speedup_time",
"filament_colour",
"filament_diameter",
"filament_density",

View File

@ -1338,19 +1338,31 @@ void PrintConfigDef::init_fff_params()
def = this->add("remaining_times", coBool);
def->label = L("Supports remaining times");
def->category = L("Firmware");
def->tooltip = L("Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute"
" intervals into the G-code to let the firmware show accurate remaining time."
" As of now only the Prusa i3 MK3 firmware recognizes M73."
" Also the i3 MK3 firmware supports M73 Qxx Sxx for the silent mode.");
def->cli = "remaining-times!";
def->mode = comExpert;
def->default_value = new ConfigOptionBool(false);
def = this->add("silent_mode", coBool);
def->label = L("Supports silent mode");
def->category = L("Firmware");
def->tooltip = L("Set silent mode for the G-code flavor");
def->mode = comExpert;
def->default_value = new ConfigOptionBool(true);
def = this->add("fan_speedup_time", coFloat);
def->label = L("fan startup delay");
def->category = L("Firmware");
def->tooltip = L("Move the M106 in the past by at least this delay 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->cli = "fan-speedup-time=f";
def->mode = comExpert;
def->default_value = new ConfigOptionFloat(0);
const int machine_limits_opt_width = 70;
{
struct AxisDefault {

View File

@ -716,6 +716,7 @@ public:
ConfigOptionStrings end_filament_gcode;
ConfigOptionString extrusion_axis;
ConfigOptionFloats extrusion_multiplier;
ConfigOptionFloat fan_speedup_time;
ConfigOptionFloats filament_diameter;
ConfigOptionFloats filament_density;
ConfigOptionStrings filament_type;
@ -795,6 +796,7 @@ protected:
OPT_PTR(end_filament_gcode);
OPT_PTR(extrusion_axis);
OPT_PTR(extrusion_multiplier);
OPT_PTR(fan_speedup_time);
OPT_PTR(filament_diameter);
OPT_PTR(filament_density);
OPT_PTR(filament_type);

View File

@ -861,7 +861,7 @@ namespace SupportMaterialInternal {
for (const ExtrusionEntity *ee : perimeters.entities) {
if (ee->is_collection()) {
for (const ExtrusionEntity *ee2 : static_cast<const ExtrusionEntityCollection*>(ee)->entities) {
assert(! ee2->is_collection());
//assert(! ee2->is_collection()); // there are loops for perimeters and collections for thin walls !!
if (ee2->is_loop())
collect_bridging_perimeter_areas(*static_cast<const ExtrusionLoop*>(ee2), expansion_scaled, out);
}

View File

@ -409,7 +409,8 @@ const std::vector<std::string>& Preset::printer_options()
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
"machine_min_extruding_rate", "machine_min_travel_rate",
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e",
"fan_speedup_time"
};
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
}

View File

@ -1940,6 +1940,7 @@ void TabPrinter::build_fff()
optgroup->append_single_option_line("gcode_flavor");
optgroup->append_single_option_line("silent_mode");
optgroup->append_single_option_line("remaining_times");
optgroup->append_single_option_line("fan_speedup_time");
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) {
wxTheApp->CallAfter([this, opt_key, value]() {