Fix duplicate G29 preparation time (#15274)

The time estimate added 260 s for every G29 on non-Bambu printers. Prusa MK4, MK4S and CORE One start G-code splits bed leveling across six G29 commands, so those printers showed about 26 extra minutes. The 260 s is now added once per G-code processing run. Bambu printers still only count a G29 inside an M622 J1 block, and their estimates are unchanged.

Fixes #15088
This commit is contained in:
TheLegendTubaGuy
2026-10-13 11:03:43 -05:00
committed by GitHub
parent 5c8a287b5e
commit 84feeaa587
3 changed files with 57 additions and 13 deletions
+7 -9
View File
@@ -3730,6 +3730,7 @@ void GCodeProcessor::reset()
m_detect_layer_based_on_tag = false;
m_seams_count = 0;
m_g29_time_added = false;
m_preheat_time = 0.f;
m_preheat_steps = 1;
}
@@ -6131,15 +6132,12 @@ void GCodeProcessor::process_G4(const GCodeReader::GCodeLine& line)
//BBS
void GCodeProcessor::process_G29(const GCodeReader::GCodeLine& line)
{
//BBS: hardcode 260 seconds for G29
//Todo: use a machine related setting when we have second kind of BBL printer
const float value_s = 260.0;
if (s_IsBBLPrinter){
if(m_measure_g29_time)
simulate_st_synchronize(value_s);
}
else{
simulate_st_synchronize(value_s);
// Firmware may split one bed-leveling sequence across multiple G29 subcommands.
constexpr float g29_time = 260.0f;
const bool should_add_time = !s_IsBBLPrinter || m_measure_g29_time;
if (should_add_time && !m_g29_time_added) {
simulate_st_synchronize(g29_time);
m_g29_time_added = true;
}
}
+1
View File
@@ -1280,6 +1280,7 @@ inline constexpr float DEFAULT_FILAMENT_DENSITY = 1.245f;
bool m_detect_layer_based_on_tag {false};
int m_seams_count;
bool m_measure_g29_time {false};
bool m_g29_time_added {false};
bool m_single_extruder_multi_material;
float m_preheat_time;
int m_preheat_steps;
+49 -4
View File
@@ -7,6 +7,7 @@
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "libslic3r/MultiNozzleUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Utils.hpp"
#include "test_utils.hpp"
@@ -21,6 +22,7 @@
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "libslic3r/Config.hpp"
@@ -52,12 +54,16 @@ FullPrintConfig make_config(double load_time, double unload_time, double tool_ch
return config;
}
void run_processor(GCodeProcessor& proc, const FullPrintConfig& config, const char* gcode)
void run_processor(GCodeProcessor& proc, const FullPrintConfig& config, const char* gcode, bool is_bbl_printer = true)
{
// reserved_tag() selects between two tag tables based on this shared static, and
// other tests in the binary mutate it -- pin it so our "; FEATURE:" role tags are
// parsed deterministically regardless of test execution order.
GCodeProcessor::s_IsBBLPrinter = true;
// other tests in the binary mutate it -- pin it so role tags are parsed
// deterministically regardless of test execution order.
const bool previous_is_bbl_printer = GCodeProcessor::s_IsBBLPrinter;
GCodeProcessor::s_IsBBLPrinter = is_bbl_printer;
const ScopeGuard restore_flag([previous_is_bbl_printer] {
GCodeProcessor::s_IsBBLPrinter = previous_is_bbl_printer;
});
ScopedTemporaryFile temp(".gcode");
{
std::ofstream os(temp.string());
@@ -99,6 +105,45 @@ double filament_change_delay(const GCodeProcessorResult& r)
} // namespace
TEST_CASE("G29 preparation time is added only once", "[GCodeTiming][Regression]")
{
const FullPrintConfig config = make_config(0.0, 0.0, 0.0);
auto estimate = [&config](bool is_bbl_printer, const char* commands) {
const auto mode = PrintEstimatedStatistics::ETimeMode::Normal;
std::string gcode = is_bbl_printer ? "; FEATURE: Custom\n" : ";TYPE:Custom\n";
gcode += "G1 X10 Y10 Z0.2 F600\nG1 X20 Y10 F600\n";
if (is_bbl_printer)
gcode += "M622 J1\n";
gcode += commands;
if (is_bbl_printer)
gcode += "M623\n";
gcode += "G1 X20 Y20 F600\nG1 X10 Y20 F600\n";
GCodeProcessor processor;
run_processor(processor, config, gcode.c_str(), is_bbl_printer);
return std::make_pair(processor.get_time(mode), processor.get_prepare_time(mode));
};
const auto [baseline_time, baseline_prepare] = estimate(false, "G4 S0\n");
const auto [one_time, one_prepare] = estimate(false, "G29\n");
const auto [repeated_time, repeated_prepare] = estimate(false,
"G29 P9 X10 Y-4 W32 H4\nG29 P1\nG29 P1 X0 Y0 W50 H20 C\nG29 P3.2\nG29 P3.13\nG29 A\n");
REQUIRE_THAT(one_time - baseline_time, WithinAbs(260.0, 1e-2));
REQUIRE_THAT(one_prepare - baseline_prepare, WithinAbs(260.0, 1e-2));
REQUIRE_THAT(repeated_time, WithinAbs(one_time, 1e-2));
REQUIRE_THAT(repeated_prepare, WithinAbs(one_prepare, 1e-2));
const auto [baseline_bbl_time, baseline_bbl_prepare] = estimate(true, "G4 S0\n");
const auto [one_bbl_time, one_bbl_prepare] = estimate(true, "G29\n");
const auto [repeated_bbl_time, repeated_bbl_prepare] = estimate(true, "G29\nG29\n");
REQUIRE_THAT(one_bbl_time - baseline_bbl_time, WithinAbs(260.0, 1e-2));
REQUIRE_THAT(one_bbl_prepare - baseline_bbl_prepare, WithinAbs(260.0, 1e-2));
REQUIRE_THAT(repeated_bbl_time, WithinAbs(one_bbl_time, 1e-2));
REQUIRE_THAT(repeated_bbl_prepare, WithinAbs(one_bbl_prepare, 1e-2));
}
TEST_CASE("Filament-change time is attributed to tool-change moves, not extrusion roles", "[GCodeTiming]")
{
// Relative extrusion (M83) so every "E5" is a real 5mm extrusion move rather