Избавляем Qidi Q2 от «сопливого носа» при старте печати

от автора

Наверное редкий владелец принтера Qidi Q2 и подобных с тензодатчиком не сталкивался с проблемой: на кончик сопла налипла капля пластика, датчик из-за неё сработал раньше времени, и в итоге вся карта высот стола (Bed Mesh) “улетела” вверх. Результат — первый слой печатается в воздухе, адгезии ноль, печать испорчена.

Вместо того чтобы надеяться на удачу или бесконечно тереть сопло об щетку, предлагаю добавить простую проверку в стартовый макрос печати.

Идея

Проблема возникает именно из-за наличия тензодатчика (это новация Qidi Q2) и логики подготовки печати. Принтер выполняет “продувку” сопла в корзину, охлаждает сопло до 140 градусов и выполняет пару проходов по силиконовой щетке. Это срабатывает не всегда, иногда на холодном сопле остается капля довольно жесткого пластика при такой температуре. И с таким носом принтер уже едет делать Z_TILT_ADJUST и G29.

Если посмотреть на стартовый скрипт печати Qidi Q2:

PRINT_START
[gcode_macro PRINT_START]gcode:    SKEW_PROFILE LOAD=qidi_q2_skew    AUTOTUNE_SHAPERS    DISABLE_ALL_SENSOR    CLEAR_PAUSE        {% set bedtemp = params.get('BED') | int %}    {% set hotendtemp = params.get('HOTEND') | int %}    {% set chambertemp = params.get('CHAMBER', 0) | int %}    {% set extruder = params.EXTRUDER|default(0)|int %}    {% set Polar_cooler = printer.save_variables.variables.enable_polar_cooler|default(0) %}    M104 S0    {% if chambertemp == 0 %}        M106 P3 S255    {% endif %}    M140 S{bedtemp}        G28       M141 S{chambertemp}        SET_GCODE_OFFSET Z=0 MOVE=0    BUFFER_MONITORING ENABLE=0    {% if printer.save_variables.variables.box_count >= 1 and printer["box_extras"] %}         SAVE_VARIABLE VARIABLE=load_retry_num VALUE=0        SAVE_VARIABLE VARIABLE=retry_step VALUE=None        CLEAR_TOOLCHANGE_STATE        {% for i in range(16) %}            SAVE_VARIABLE VARIABLE=runout_{i} VALUE=0            G4 P100        {% endfor %}        {% if printer.save_variables.variables.enable_box == 1 %}            BOX_PRINT_START EXTRUDER={extruder} HOTENDTEMP={hotendtemp}            M400            EXTRUSION_AND_FLUSH HOTEND={hotendtemp}        {% endif %}    {% endif %}    CLEAR_NOZZLE HOTEND={hotendtemp}    #切料调平    CUT_FILAMENT_1    M104 S140    G4 P3000    M400    G28        Z_TILT_ADJUST    M104 S140    M190 S{bedtemp}       M191 S{chambertemp}    M400    G4 P3000        G29    G0 Z50 F600    G0 X260 Y5  F30000    {% if printer.save_variables.variables.box_count >= 1 and printer["box_extras"] and printer.save_variables.variables.enable_box == 1 %}        BUFFER_MONITORING ENABLE=1     {% endif %}    M191 S{chambertemp}    M109 S{hotendtemp}    M204 S10000    M106 P4 S{Polar_cooler}                    #根据设置开启空调    set_zoffset    ENABLE_ALL_SENSOR    save_last_file

Видно что единственное куда стоит вмешаться это команда G29 (bed mesh), остальное от смещения по z пострадать не должно, даже Z_TILT_ADJUST отработает корректно. Но после G29 с грязным соплом вся последующая сетка высот стола (kamp) будет иметь положительное смещение.

Реализация защиты

Предлагаю следующий макрос, который после построения сетки вычисляет среднее арифметическое значение Z всех точек. Если оно выше определенного порога, принтер уходит на повторную чистку и переделывает сетку заново. После этого мы повторяем G29 и если повторная сетка высот легла выше порога — выбрасываем алерт и прерываем печать.

  1. Добавьте код макроса _CHECK_NOZZLE_DIRTYв gcode_macro.cfg:

[gcode_macro _CHECK_NOZZLE_DIRTY]description: Детекция грязного сопла и автоматический повтор очисткиvariable_retry_count: 0gcode:    {% set profile = params.PROFILE|default('kamp') %}    {% set hotendtemp = params.HOTEND|default(250)|int %}        # Проверяем наличие профиля сетки в системе    {% if profile in printer.bed_mesh.profiles %}        {% set mesh = printer.bed_mesh.profiles[profile].points %}        {% set total_z = namespace(val=0) %}        {% set count = namespace(val=0) %}        # Считаем сумму всех значений Z в сетке        {% for row in mesh %}            {% for z in row %}                {% set total_z.val = total_z.val + z %}                {% set count.val = count.val + 1 %}            {% endfor %}        {% endfor %}        # Вычисляем средний по Z        {% if count.val > 0 %}            {% set avg_z = total_z.val / count.val %}        {% endif %}        # Порог 0.07 — мое значение, подберите под себя.        {% if avg_z > 0.07 %}            {% if retry_count < 1 %}                { action_respond_info("ВНИМАНИЕ: Сопло грязное (Z-avg: %.3f). Попытка очистки..." % avg_z) }                SET_GCODE_VARIABLE MACRO=_CHECK_NOZZLE_DIRTY VARIABLE=retry_count VALUE=1                                CLEAR_NOZZLE HOTEND={hotendtemp} # стандартный макрос чистки qidi                G28 Z                G29 # повторный замер сетки (получим новые цифры в 'kamp')            {% else %}                SET_GCODE_VARIABLE MACRO=_CHECK_NOZZLE_DIRTY VARIABLE=retry_count VALUE=0                { action_raise_error("ОШИБКА: Повторная чистка не помогла (Z-avg: %.3f). Остановка." % avg_z) }            {% endif %}        {% else %}            { action_respond_info("ПРОВЕРКА: Сопло чистое (Z-avg: %.3f). Печать разрешена." % avg_z) }            SET_GCODE_VARIABLE MACRO=_CHECK_NOZZLE_DIRTY VARIABLE=retry_count VALUE=0        {% endif %}    {% else %}        { action_respond_info("ПРОВЕРКА: Профиль сетки %s не найден." % profile) }    {% endif %}
  1. Вставьте вызов макроса в ваш PRINT_START сразу после калибровки стола G29:

# ... подготовка, нагрев ...G29 ; Калибровка сетки стола_CHECK_NOZZLE_DIRTY PROFILE=kamp HOTEND={hotendtemp}# ... продолжение печати ...

Вот так работа макроса выглядит в логах klipper:

...Mesh Bed Leveling Completesave_config: set [bed_mesh kamp] version = 1save_config: set [bed_mesh kamp] points =   0.031094, 0.072891, 0.070781, 0.028594  0.153359, 0.182891, 0.177109, 0.173594  0.212812, 0.222578, 0.060469, 0.208047  0.254922, 0.230703, 0.238828, 0.230625  0.219219, 0.217187, 0.008594, -0.021797  0.143516, 0.169922, 0.005234, -0.037188save_config: set [bed_mesh kamp] x_count = 4save_config: set [bed_mesh kamp] y_count = 6save_config: set [bed_mesh kamp] mesh_x_pps = 2save_config: set [bed_mesh kamp] mesh_y_pps = 2save_config: set [bed_mesh kamp] algo = lagrangesave_config: set [bed_mesh kamp] tension = 0.2save_config: set [bed_mesh kamp] min_x = 60.0save_config: set [bed_mesh kamp] max_x = 210.0save_config: set [bed_mesh kamp] min_y = 10.0save_config: set [bed_mesh kamp] max_y = 260.0Bed Mesh state has been saved to profile [kamp]for the current session.  The SAVE_CONFIG command willupdate the printer config file and restart the printer.SAVE_CONFIG to '/home/mks/printer_data/config/printer.cfg' (backup in '/home/mks/printer_data/config/printer-20260412_211059.cfg')ВНИМАНИЕ: Сопло грязное (Z-avg: 0.136). Попытка очистки №1...Heater extruder approaching new target of 240.000...

Совет по настройке: Начните с порога 0.07 — 0.1 мм. Он должен быть выше погрешности вашего датчика и теплового расширения, но меньше высоты первого слоя вашего пластика.

В норме среднее значение Z по сетке после G29 должно быть близким к нулю, с разбросом не более 0.2. Если вы не выполняли калибровку стола, то применяйте макрос аккуратнее — подберите свое пороговое значение. А лучше выполните калибровку стола. Мой порог в 0.07 мм — гарантированно ловит попытки мешинга с грязным носом.

Если есть желание протестировать работу, можно так — подсовывая при каждом замере сложенную в пару слоев бумажку (я проверял щупом 0.1).

Надеюсь это сэкономит Вам кучу времени при удаленном запуске печати, когда нет возможности лично проверить чистоту сопла.

Удачи в печати.

ссылка на оригинал статьи https://habr.com/ru/articles/1024908/