Browse Source

Fix fan mover kickstart
supermerill/SuperSlicer#4113

supermerill 1 year ago
parent
commit
52a1685daf

+ 24 - 14
src/libslic3r/GCode/FanMover.cpp

@@ -91,12 +91,18 @@ int16_t get_fan_speed(const std::string &line, GCodeFlavor flavor) {
 
 }
 
-void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator item_to_split, float nb_sec_since_itemtosplit_start, BufferData &&line_to_write) {
+void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator item_to_split, float nb_sec_since_itemtosplit_start, BufferData &&line_to_write, float max_time) {
     assert(item_to_split != m_buffer.end());
-    if (nb_sec_since_itemtosplit_start > item_to_split->time * 0.9) {
+    // if the fan is at the end of the g1 and the diff is less than 10% of the delay, then don't bother
+    if (nb_sec_since_itemtosplit_start > item_to_split->time * 0.9 && (item_to_split->time - nb_sec_since_itemtosplit_start) < max_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_since_itemtosplit_start < item_to_split->time * 0.1) {
+    } else 
+        // does it need to be split?
+        // if it's almost at the start of the g1, and the time "lost" is less than 10%
+        if (nb_sec_since_itemtosplit_start < item_to_split->time * 0.1 && nb_sec_since_itemtosplit_start < max_time * 0.1 &&
+        // and the previous isn't a fan value
+        (item_to_split == m_buffer.begin() || std::prev(item_to_split)->fan_speed < 0)) {
         // 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);
@@ -340,11 +346,18 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode
             if (fan_speed >= 0) {
                 const auto fan_baseline = (m_writer.config.fan_percentage.value ? 100.0 : 255.0);
                 fan_speed = 100 * fan_speed / fan_baseline;
-                //speed change: stop kickstart reverting if any
-                m_current_kickstart.time = -1;
                 if (!m_is_custom_gcode) {
                     // if slow down => put in the queue. if not =>
-                    if (m_back_buffer_fan_speed < fan_speed) {
+                    if (m_current_kickstart.time > 0) {
+                        assert(m_back_buffer_fan_speed == m_current_kickstart.fan_speed);
+                    }
+                    if (m_back_buffer_fan_speed >= fan_speed) {
+                        if (m_current_kickstart.time > 0) {
+                            // stop kiskstart, and slow down
+                            m_current_kickstart.time = -1;
+                            //this fan speed will be printed, to make and end to the kickstart
+                        }
+                    } else {
                         if (nb_seconds_delay > 0 && (!only_overhangs || current_role == ExtrusionRole::erOverhangPerimeter)) {
                             //don't put this command in the queue
                             time = -1;
@@ -376,7 +389,7 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode
                                     time_count -= it->time;
                                     if (time_count< 0) {
                                         //found something that is lower than us
-                                        _put_in_middle_G1(it, it->time + time_count, BufferData(std::string(line.raw()), 0, fan_speed, true));
+                                        _put_in_middle_G1(it, it->time + time_count, BufferData(std::string(line.raw()), 0, fan_speed, true), nb_seconds_delay);
                                         //found, stop
                                         break;
                                     }
@@ -502,7 +515,7 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode
             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, true });
+                _put_in_middle_G1(prev(m_buffer.end()), time + m_current_kickstart.time, BufferData{ m_current_kickstart.raw, 0, m_current_kickstart.fan_speed, true }, kickstart);
             }
         }
     }/* else {
@@ -547,17 +560,14 @@ void FanMover::write_buffer_data()
     if (frontdata.fan_speed < 0 || frontdata.fan_speed != m_front_buffer_fan_speed || frontdata.is_kickstart) {
         if (frontdata.is_kickstart && frontdata.fan_speed < m_front_buffer_fan_speed) {
             // you have to slow down! not kickstart! rewrite the fan speed.
-            m_process_output += _set_fan(
-                frontdata.fan_speed); // m_writer.set_fan(frontdata.fan_speed,true); //FIXME extruder id (or use the
-                                      // gcode writer, but then you have to disable the multi-thread thing
-
+            m_process_output += _set_fan(frontdata.fan_speed) + "\n";
             m_front_buffer_fan_speed = frontdata.fan_speed;
         } else {
             m_process_output += frontdata.raw + "\n";
-            if (frontdata.fan_speed >= 0) {
+            if (frontdata.fan_speed >= 0 || frontdata.is_kickstart) {
                 // note that this is the only place 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 from the back of the queue...
-                m_front_buffer_fan_speed = frontdata.fan_speed;
+                m_front_buffer_fan_speed = frontdata.is_kickstart ? 100 : frontdata.fan_speed;
             }
         }
     }

+ 10 - 5
src/libslic3r/GCode/FanMover.hpp

@@ -35,11 +35,11 @@ class FanMover
 {
 private:
     const std::regex regex_fan_speed;
-    const float nb_seconds_delay;
+    const float nb_seconds_delay; // in s
     const bool with_D_option;
     const bool relative_e;
     const bool only_overhangs;
-    const float kickstart;
+    const float kickstart; // in s
 
     GCodeReader m_parser{};
     const GCodeWriter& m_writer;
@@ -76,8 +76,13 @@ public:
 
 private:
     BufferData& put_in_buffer(BufferData&& data) {
-        m_buffer_time_size += data.time;
-        m_buffer.emplace_back(data);
+         m_buffer_time_size += data.time;
+        if (data.fan_speed >= 0 && !m_buffer.empty() && m_buffer.back().fan_speed >= 0) {
+            // erase last item
+            m_buffer.back() = data;
+        } else {
+            m_buffer.emplace_back(data);
+        }
         return m_buffer.back();
     }
     std::list<BufferData>::iterator remove_from_buffer(std::list<BufferData>::iterator data) {
@@ -88,7 +93,7 @@ private:
     void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line);
     void _process_ACTIVATE_EXTRUDER(const std::string_view command);
     void _process_T(const std::string_view command);
-    void _put_in_middle_G1(std::list<BufferData>::iterator item_to_split, float nb_sec, BufferData&& line_to_write);
+    void _put_in_middle_G1(std::list<BufferData>::iterator item_to_split, float nb_sec, BufferData&& line_to_write, float max_time);
     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);
     void write_buffer_data();

+ 51 - 0
tests/data/test_gcode/4113_fan_mover.gcode

@@ -0,0 +1,51 @@
+
+;WIDTH:0.237984
+M106 S35.7 ; set fan for Gap fill
+G1 X40.391 Y46.717 E0.00302 ; Gap fill
+G1 X40.369 Y46.899 E0.00245 ; Gap fill
+M106 S20.4 ; set default fan
+M106 S51 ; set fan for new extruder
+;LAYER_CHANGE
+G1 Z0.68 F3000 ; move to next layer (2)
+SET_PRINT_STATS_INFO CURRENT_LAYER=3
+G92 E0 ; reset extruder position to flush any extruder axis rounding
+M204 S12000 ; adjust acceleration
+G1 X51.732 Y55.09 F42000 ; move to first perimeter point (acceleration)
+M204 S7000 ; adjust acceleration
+G1 X59.535 Y60.716 ; move to first perimeter point (deceleration)
+SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=5
+;WIDTH:0.45
+M106 S51 ; set fan for Internal perimeter
+G1 F15681
+G1 X31.554 Y60.716 E0.78256 ; perimeter
+G1 X31.554 Y32.734 E0.78256 ; perimeter
+G1 X59.535 Y32.734 E0.78256 ; perimeter
+G1 X59.535 Y60.656 E0.78088 ; perimeter
+M106 S51 ; set default fan
+G1 X59.942 Y61.123 F42000 ; move to first perimeter point (minimum acceleration)
+M106 S51 ; set fan for Internal perimeter
+G1 F15681
+G1 X31.147 Y61.123 E0.80533 ; perimeter
+G1 X31.147 Y32.327 E0.80533 ; perimeter
+G1 X59.942 Y32.327 E0.80533 ; perimeter
+G1 X59.942 Y61.063 E0.80365 ; perimeter
+M106 S51 ; set default fan
+M204 S6000 ; adjust acceleration
+G1 X60.335 Y61.515 F42000
+M106 S51 ; set fan for External perimeter
+G1 F15000
+G1 X30.755 Y61.515 E0.76629 ; perimeter
+G1 X30.755 Y31.935 E0.76629 ; perimeter
+G1 X60.335 Y31.935 E0.76629 ; perimeter
+G1 X60.335 Y61.455 E0.76474 ; perimeter
+M106 S51 ; set default fan
+;WIPE_START
+M204 S7000 ; adjust acceleration
+G1 X59.988 Y61.315 F42000 ; move inwards before travel
+;WIPE_END
+G1 X58.97 Y60.501 ; move to first Internal infill point (minimum acceleration)
+; custom gcode: feature_gcode
+M106 S51 ; set fan for Internal infill
+G1 F15681
+G1 X56.527 Y60.501 E0.06831 ; Internal infill
+G1 X59.321 Y50.076 E0.30183 ; Internal infill

+ 46 - 0
tests/data/test_gcode/4113_fan_mover_ok.gcode

@@ -0,0 +1,46 @@
+
+;WIDTH:0.237984
+M106 S255
+G1 X0.654 Y0.756 E0.00005 ; Gap fill
+M106 S33.15
+G1 X40.391 Y46.717 E0.00297 ; Gap fill
+G1 X40.369 Y46.899 E0.00245 ; Gap fill
+M106 S255
+;LAYER_CHANGE
+G1 Z0.68 F3000 ; move to next layer (2)
+SET_PRINT_STATS_INFO CURRENT_LAYER=3
+G92 E0 ; reset extruder position to flush any extruder axis rounding
+M204 S12000 ; adjust acceleration
+G1 X51.732 Y55.09 F42000 ; move to first perimeter point (acceleration)
+M204 S7000 ; adjust acceleration
+G1 X59.535 Y60.716 ; move to first perimeter point (deceleration)
+SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=5
+;WIDTH:0.45
+M106 S51 ; set fan for Internal perimeter
+G1 F15681
+G1 X31.554 Y60.716 E0.78256 ; perimeter
+G1 X31.554 Y32.734 E0.78256 ; perimeter
+G1 X59.535 Y32.734 E0.78256 ; perimeter
+G1 X59.535 Y60.656 E0.78088 ; perimeter
+G1 X59.942 Y61.123 F42000 ; move to first perimeter point (minimum acceleration)
+G1 F15681
+G1 X31.147 Y61.123 E0.80533 ; perimeter
+G1 X31.147 Y32.327 E0.80533 ; perimeter
+G1 X59.942 Y32.327 E0.80533 ; perimeter
+G1 X59.942 Y61.063 E0.80365 ; perimeter
+M204 S6000 ; adjust acceleration
+G1 X60.335 Y61.515 F42000
+G1 F15000
+G1 X30.755 Y61.515 E0.76629 ; perimeter
+G1 X30.755 Y31.935 E0.76629 ; perimeter
+G1 X60.335 Y31.935 E0.76629 ; perimeter
+G1 X60.335 Y61.455 E0.76474 ; perimeter
+;WIPE_START
+M204 S7000 ; adjust acceleration
+G1 X59.988 Y61.315 F42000 ; move inwards before travel
+;WIPE_END
+G1 X58.97 Y60.501 ; move to first Internal infill point (minimum acceleration)
+; custom gcode: feature_gcode
+G1 F15681
+G1 X56.527 Y60.501 E0.06831 ; Internal infill
+G1 X59.321 Y50.076 E0.30183 ; Internal infill

+ 31 - 0
tests/superslicerlibslic3r/test_fan_mover.cpp

@@ -596,3 +596,34 @@ TEST_CASE("G2/G3 gcode")
     }
 }
 
+TEST_CASE("4113 bug (erase all fan command after a point)") {
+    std::string gcode_input = read_to_string(std::string(TEST_DATA_DIR) + "/test_gcode/4113_fan_mover.gcode");
+    std::string gcode_output = read_to_string(std::string(TEST_DATA_DIR) + "/test_gcode/4113_fan_mover_ok.gcode");
+    
+    //"M106 S25.5\n";
+    GCodeWriter       writer;
+    // what's used from the writer:
+    writer.config.gcode_flavor.value   = gcfMarlinFirmware;
+    writer.config.gcode_comments.value = false;
+    writer.config.fan_percentage.value = false; // 0 -> 255
+    // writer.tool[0] = nullptr;
+    assert(writer.tool() == nullptr);
+    assert(writer.get_tool(0) == nullptr);
+
+    SECTION("disable evrything")
+    {
+        Slic3r::FanMover fan_mover(writer,
+                                   1,     // fan_speedup_time.value,
+                                   false, // with_D_option
+                                   true,  // use_relative_e_distances.value,
+                                   true, // fan_speedup_overhangs.value,
+                                   0.5      // fan_kickstart.value));
+        );
+        std::string      processed_gcode = fan_mover.process_gcode(gcode_input, true);
+        //remove
+        //REQUIRE(good_gcode == processed_gcode);
+        REQUIRE(processed_gcode.find("M106 S51") != std::string::npos);
+        REQUIRE(gcode_output == processed_gcode);
+    }
+
+}