mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-15 06:11:45 +08:00
integration of time estimator into gcode export - save time estimation into gcode file
This commit is contained in:
parent
092d271fa2
commit
a0a503e4a8
@ -5,10 +5,6 @@
|
|||||||
#include "GCode/PrintExtents.hpp"
|
#include "GCode/PrintExtents.hpp"
|
||||||
#include "GCode/WipeTowerPrusaMM.hpp"
|
#include "GCode/WipeTowerPrusaMM.hpp"
|
||||||
|
|
||||||
//############################################################################################################
|
|
||||||
#include "GCodeTimeEstimator.hpp"
|
|
||||||
//############################################################################################################
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@ -263,16 +259,77 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen)
|
|||||||
|
|
||||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
||||||
|
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
// Helper class for writing to file with/without time estimation
|
||||||
|
class Write
|
||||||
|
{
|
||||||
|
static GCodeTimeEstimator* s_time_estimator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void set_time_estimator(GCodeTimeEstimator* time_estimator)
|
||||||
|
{
|
||||||
|
s_time_estimator = time_estimator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write(FILE* file, const std::string& what)
|
||||||
|
{
|
||||||
|
if (!what.empty())
|
||||||
|
{
|
||||||
|
fwrite(what.data(), 1, what.size(), file);
|
||||||
|
|
||||||
|
if (s_time_estimator != nullptr)
|
||||||
|
{
|
||||||
|
const char endLine = '\n';
|
||||||
|
std::string::size_type beginPos = 0;
|
||||||
|
std::string::size_type endPos = what.find_first_of(endLine, beginPos);
|
||||||
|
while (endPos != std::string::npos)
|
||||||
|
{
|
||||||
|
s_time_estimator->add_gcode_line(what.substr(beginPos, endPos - beginPos + 1));
|
||||||
|
|
||||||
|
beginPos = endPos + 1;
|
||||||
|
endPos = what.find_first_of(endLine, beginPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//std::string Write::s_cache = "";
|
||||||
|
GCodeTimeEstimator* Write::s_time_estimator = nullptr;
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
|
||||||
inline void write(FILE *file, const std::string &what)
|
inline void write(FILE *file, const std::string &what)
|
||||||
{
|
{
|
||||||
fwrite(what.data(), 1, what.size(), file);
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
Write::write(file, what);
|
||||||
|
#else
|
||||||
|
fwrite(what.data(), 1, what.size(), file);
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
inline void write_format(FILE* file, const char* format, ...)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int res = ::vsnprintf(buffer, 1024, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (res >= 0)
|
||||||
|
write(file, buffer);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
|
||||||
inline void writeln(FILE *file, const std::string &what)
|
inline void writeln(FILE *file, const std::string &what)
|
||||||
{
|
{
|
||||||
if (! what.empty()) {
|
if (! what.empty()) {
|
||||||
write(file, what);
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
fprintf(file, "\n");
|
write_format(file, "%s\n", what.c_str());
|
||||||
|
#else
|
||||||
|
write(file, what);
|
||||||
|
fprintf(file, "\n");
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,20 +436,28 @@ bool GCode::do_export(Print *print, const char *path)
|
|||||||
if (! result)
|
if (! result)
|
||||||
boost::nowide::remove(path_tmp.c_str());
|
boost::nowide::remove(path_tmp.c_str());
|
||||||
|
|
||||||
//############################################################################################################
|
// debug only -> tests time estimator from file
|
||||||
GCodeTimeEstimator timeEstimator;
|
{
|
||||||
timeEstimator.calculate_time_from_file(path);
|
GCodeTimeEstimator timeEstimator;
|
||||||
float time = timeEstimator.get_time();
|
timeEstimator.calculate_time_from_file(path);
|
||||||
std::string timeHMS = timeEstimator.get_time_hms();
|
float time = timeEstimator.get_time();
|
||||||
|
std::string timeHMS = timeEstimator.get_time_hms();
|
||||||
|
|
||||||
std::cout << std::endl << ">>> estimated time: " << timeHMS << " (" << time << " seconds)" << std::endl << std::endl;
|
std::cout << std::endl << "Time estimated from file:" << std::endl;
|
||||||
//############################################################################################################
|
std::cout << std::endl << ">>> estimated time: " << timeHMS << " (" << time << " seconds)" << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCode::_do_export(Print &print, FILE *file)
|
bool GCode::_do_export(Print &print, FILE *file)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
// resets time estimator
|
||||||
|
m_time_estimator.reset();
|
||||||
|
Write::set_time_estimator(&m_time_estimator);
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
|
||||||
// How many times will be change_layer() called?
|
// How many times will be change_layer() called?
|
||||||
// change_layer() in turn increments the progress bar status.
|
// change_layer() in turn increments the progress bar status.
|
||||||
m_layer_count = 0;
|
m_layer_count = 0;
|
||||||
@ -496,7 +561,7 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
fprintf(file, "; %s\n", line.c_str());
|
fprintf(file, "; %s\n", line.c_str());
|
||||||
}
|
}
|
||||||
if (! lines.empty())
|
if (! lines.empty())
|
||||||
fprintf(file, "\n");
|
fprintf(file, "\n");
|
||||||
}
|
}
|
||||||
// Write some terse information on the slicing parameters.
|
// Write some terse information on the slicing parameters.
|
||||||
{
|
{
|
||||||
@ -555,8 +620,8 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
|
|
||||||
// Disable fan.
|
// Disable fan.
|
||||||
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
|
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
|
||||||
write(file, m_writer.set_fan(0, true));
|
write(file, m_writer.set_fan(0, true));
|
||||||
|
|
||||||
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
|
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
|
||||||
{
|
{
|
||||||
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
|
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
|
||||||
@ -565,7 +630,7 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
std::string gcode = m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id), true);
|
std::string gcode = m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id), true);
|
||||||
if (boost::ifind_first(print.config.start_gcode.value, std::string("M140")).empty() &&
|
if (boost::ifind_first(print.config.start_gcode.value, std::string("M140")).empty() &&
|
||||||
boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty())
|
boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty())
|
||||||
write(file, gcode);
|
write(file, gcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set extruder(s) temperature before and after start G-code.
|
// Set extruder(s) temperature before and after start G-code.
|
||||||
@ -715,15 +780,28 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
bbox_prime.offset(0.5f);
|
bbox_prime.offset(0.5f);
|
||||||
// Beep for 500ms, tone 800Hz. Yet better, play some Morse.
|
// Beep for 500ms, tone 800Hz. Yet better, play some Morse.
|
||||||
write(file, this->retract());
|
write(file, this->retract());
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
write_format(file, "M300 S800 P500\n");
|
||||||
|
#else
|
||||||
fprintf(file, "M300 S800 P500\n");
|
fprintf(file, "M300 S800 P500\n");
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
if (bbox_prime.overlap(bbox_print)) {
|
if (bbox_prime.overlap(bbox_print)) {
|
||||||
// Wait for the user to remove the priming extrusions, otherwise they would
|
// Wait for the user to remove the priming extrusions, otherwise they would
|
||||||
// get covered by the print.
|
// get covered by the print.
|
||||||
fprintf(file, "M1 Remove priming towers and click button.\n");
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
} else {
|
write_format(file, "M1 Remove priming towers and click button.\n");
|
||||||
|
#else
|
||||||
|
fprintf(file, "M1 Remove priming towers and click button.\n");
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Just wait for a bit to let the user check, that the priming succeeded.
|
// Just wait for a bit to let the user check, that the priming succeeded.
|
||||||
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
||||||
fprintf(file, "M1 S10\n");
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
write_format(file, "M1 S10\n");
|
||||||
|
#else
|
||||||
|
fprintf(file, "M1 S10\n");
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
write(file, WipeTowerIntegration::prime_single_color_print(print, initial_extruder_id, *this));
|
write(file, WipeTowerIntegration::prime_single_color_print(print, initial_extruder_id, *this));
|
||||||
@ -778,6 +856,11 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
}
|
}
|
||||||
fprintf(file, "; total filament cost = %.1lf\n", print.total_cost);
|
fprintf(file, "; total filament cost = %.1lf\n", print.total_cost);
|
||||||
|
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
m_time_estimator.calculate_time();
|
||||||
|
fprintf(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms());
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
|
||||||
// Append full config.
|
// Append full config.
|
||||||
fprintf(file, "\n");
|
fprintf(file, "\n");
|
||||||
{
|
{
|
||||||
@ -785,7 +868,7 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||||||
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) {
|
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) {
|
||||||
StaticPrintConfig *cfg = configs[i];
|
StaticPrintConfig *cfg = configs[i];
|
||||||
for (const std::string &key : cfg->keys())
|
for (const std::string &key : cfg->keys())
|
||||||
fprintf(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
|
fprintf(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef slic3r_GCode_hpp_
|
#ifndef slic3r_GCode_hpp_
|
||||||
#define slic3r_GCode_hpp_
|
#define slic3r_GCode_hpp_
|
||||||
|
|
||||||
|
#define ENABLE_TIME_ESTIMATOR 1
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
#include "GCodeWriter.hpp"
|
#include "GCodeWriter.hpp"
|
||||||
@ -15,6 +17,9 @@
|
|||||||
#include "GCode/SpiralVase.hpp"
|
#include "GCode/SpiralVase.hpp"
|
||||||
#include "GCode/ToolOrdering.hpp"
|
#include "GCode/ToolOrdering.hpp"
|
||||||
#include "GCode/WipeTower.hpp"
|
#include "GCode/WipeTower.hpp"
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
#include "GCodeTimeEstimator.hpp"
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
#include "EdgeGrid.hpp"
|
#include "EdgeGrid.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -267,6 +272,11 @@ protected:
|
|||||||
// Index of a last object copy extruded.
|
// Index of a last object copy extruded.
|
||||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||||
|
|
||||||
|
#if ENABLE_TIME_ESTIMATOR
|
||||||
|
// Time estimator
|
||||||
|
GCodeTimeEstimator m_time_estimator;
|
||||||
|
#endif // ENABLE_TIME_ESTIMATOR
|
||||||
|
|
||||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
||||||
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait);
|
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait);
|
||||||
// this flag triggers first layer speeds
|
// this flag triggers first layer speeds
|
||||||
|
@ -131,20 +131,33 @@ namespace Slic3r {
|
|||||||
|
|
||||||
GCodeTimeEstimator::GCodeTimeEstimator()
|
GCodeTimeEstimator::GCodeTimeEstimator()
|
||||||
{
|
{
|
||||||
|
reset();
|
||||||
|
set_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
||||||
{
|
{
|
||||||
_reset();
|
|
||||||
_parser.parse(gcode, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
_parser.parse(gcode, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||||
_calculate_time();
|
_calculate_time();
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
|
void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
|
||||||
{
|
{
|
||||||
_reset();
|
|
||||||
_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||||
_calculate_time();
|
_calculate_time();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line)
|
||||||
|
{
|
||||||
|
_parser.parse_line(gcode_line, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeTimeEstimator::calculate_time()
|
||||||
|
{
|
||||||
|
_calculate_time();
|
||||||
|
_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeTimeEstimator::set_axis_position(EAxis axis, float position)
|
void GCodeTimeEstimator::set_axis_position(EAxis axis, float position)
|
||||||
@ -281,6 +294,12 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCodeTimeEstimator::reset()
|
||||||
|
{
|
||||||
|
_blocks.clear();
|
||||||
|
_reset();
|
||||||
|
}
|
||||||
|
|
||||||
float GCodeTimeEstimator::get_time() const
|
float GCodeTimeEstimator::get_time() const
|
||||||
{
|
{
|
||||||
return _time;
|
return _time;
|
||||||
@ -294,20 +313,16 @@ namespace Slic3r {
|
|||||||
int minutes = (int)(timeinsecs / 60.0f);
|
int minutes = (int)(timeinsecs / 60.0f);
|
||||||
timeinsecs -= (float)minutes * 60.0f;
|
timeinsecs -= (float)minutes * 60.0f;
|
||||||
|
|
||||||
char buf[16];
|
char buffer[16];
|
||||||
::sprintf(buf, "%02d:%02d:%02d", hours, minutes, (int)timeinsecs);
|
::sprintf(buffer, "%02d:%02d:%02d", hours, minutes, (int)timeinsecs);
|
||||||
return buf;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeTimeEstimator::_reset()
|
void GCodeTimeEstimator::_reset()
|
||||||
{
|
{
|
||||||
_blocks.clear();
|
|
||||||
|
|
||||||
_curr.reset();
|
_curr.reset();
|
||||||
_prev.reset();
|
_prev.reset();
|
||||||
|
|
||||||
set_default();
|
|
||||||
|
|
||||||
set_axis_position(X, 0.0f);
|
set_axis_position(X, 0.0f);
|
||||||
set_axis_position(Y, 0.0f);
|
set_axis_position(Y, 0.0f);
|
||||||
set_axis_position(Z, 0.0f);
|
set_axis_position(Z, 0.0f);
|
||||||
|
@ -175,6 +175,12 @@ namespace Slic3r {
|
|||||||
// Calculates the time estimate from the gcode contained in the file with the given filename
|
// Calculates the time estimate from the gcode contained in the file with the given filename
|
||||||
void calculate_time_from_file(const std::string& file);
|
void calculate_time_from_file(const std::string& file);
|
||||||
|
|
||||||
|
// Adds the given gcode line
|
||||||
|
void add_gcode_line(const std::string& gcode_line);
|
||||||
|
|
||||||
|
// Calculates the time estimate from gcode lines added using add_gcode_line()
|
||||||
|
void calculate_time();
|
||||||
|
|
||||||
void set_axis_position(EAxis axis, float position);
|
void set_axis_position(EAxis axis, float position);
|
||||||
void set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec);
|
void set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec);
|
||||||
void set_axis_max_acceleration(EAxis axis, float acceleration);
|
void set_axis_max_acceleration(EAxis axis, float acceleration);
|
||||||
@ -209,6 +215,9 @@ namespace Slic3r {
|
|||||||
|
|
||||||
void set_default();
|
void set_default();
|
||||||
|
|
||||||
|
// Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator
|
||||||
|
void reset();
|
||||||
|
|
||||||
// Returns the estimated time, in seconds
|
// Returns the estimated time, in seconds
|
||||||
float get_time() const;
|
float get_time() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user