Generic-профиль слайсера теряет машинные настройки
Профили филамента в слайсерах семейства Bambu Studio / OrcaSlicer / QIDI Studio образуют цепочку наследования, и от того, к какой ветке прицепиться, зависит гораздо больше, чем кажется. Обычная ошибка — взять Generic PETG @System (или библиотечный профиль бренда) и подкрутить температуры. Всё, что знает про машину, при этом теряется молча: ни предупреждения, ни подсветки в интерфейсе.
Как это выглядит
У меня в профиле стоял Generic ASA @System. Вся геометрия и температуры выглядели разумно, печать шла. При разборе среза выяснилось, что в стартовый G-code уезжает
PRINT_START BED=105 HOTEND=260 CHAMBER=0 EXTRUDER=0
то есть камера не грелась вообще, хотя принтер её греть умеет и для ASA это критично.
Механика видна в машинном стартовом G-code:
PRINT_START BED=[bed_temperature_initial_layer_single] HOTEND=[nozzle_temperature_initial_layer] CHAMBER=[chamber_temperature] EXTRUDER=[initial_no_support_extruder]
...
M141 S[chamber_temperature]
chamber_temperature — поле профиля филамента. У вендорского профиля под этот принтер там 55, у библиотечного Generic этого ключа нет вовсе, и подставляется ноль. После замены базы в том же месте среза появилось CHAMBER=60, M141 S60.
Вторая потеря из того же места, видна в конфиг-блоке того же файла:
; enable_pressure_advance = 0
Профиль печатал без компенсации давления, и это тоже нигде не видно, кроме среза. У вендорской цепочки там 1, и в срезе появляется строка SET_PRESSURE_ADVANCE ADVANCE=0.03.
Сколько именно теряется
Я сравнил вендорский профиль под свой принтер с библиотечным профилем того же бренда и материала. В вендорском есть 33 ключа, которых в библиотечном нет вообще:
chamber_temperature, box_temperature, box_temperature_range_low, box_temperature_range_high, bed_type, additional_cooling_fan_speed, additional_cooling_fan_speed_unseal, dont_slow_down_outer_wall, filament_adhesiveness_category, filament_dev_ams_drying_ams_limitations, filament_dev_ams_drying_heat_distortion_temperature, filament_dev_ams_drying_temperature, filament_dev_ams_drying_time, filament_dev_chamber_drying_bed_temperature, filament_dev_chamber_drying_time, filament_dev_drying_cooling_temperature, filament_dev_drying_softening_temperature, filament_flush_temp, filament_flush_volumetric_speed, filament_long_retractions_when_ec, filament_pre_cooling_temperature, filament_ramming_travel_time, filament_ramming_volumetric_speed, filament_retraction_distances_when_ec, filament_tower_interface_pre_extrusion_dist, filament_tower_interface_pre_extrusion_length, filament_tower_interface_print_temp, filament_tower_interface_purge_volume, filament_tower_ironing_area, impact_strength_z, textured_cool_plate_temp, textured_cool_plate_temp_initial_layer.
Смысл групп: температура камеры и сушки в автоподатчике, дополнительный обдув, категория адгезии для авто-подбора, вся обвязка смены материала (продувка, рамминг, башня очистки), поведение при обрезке прутка, температуры разных типов столов.
И это не считая ключей, которые в библиотечном профиле есть, но с другими значениями. Мой случай, ASA:
| Ключ | Библиотечный профиль бренда | Вендорский под мой принтер |
|---|---|---|
nozzle_temperature | 270 | 255 |
nozzle_temperature_initial_layer | 270 | 250 |
hot_plate_temp | 90 | 90 |
filament_max_volumetric_speed | 12 | 16 |
fan_max_speed | 80 | 50 |
overhang_fan_speed | 80 | 80 |
pressure_advance | 0.04 | 0.03 |
filament_density | 1.1 | 1.07 |
chamber_temperature | ключа нет | 55 |
Скрипт: схлопнуть цепочку и сравнить два профиля
Ключи разбросаны по цепочке, и глазами это не проверить. Разбор в лоб: собрать индекс всех системных профилей по имени, рекурсивно применить inherits, сравнить два результата.
import json, os
SYS = os.path.expanduser("~/Library/Application Support/OrcaSlicer/system")
index = {}
for root, _, files in os.walk(SYS):
for fn in files:
if not fn.endswith(".json"):
continue
try:
d = json.load(open(os.path.join(root, fn), encoding="utf-8"))
except Exception:
continue
if d.get("type") == "filament" and "name" in d:
index[d["name"]] = d
def resolve(d, depth=0):
if depth > 12:
raise RuntimeError("цикл наследования")
parent = d.get("inherits")
if not parent:
out = dict(d); out.pop("inherits", None); return out
base = resolve(index[parent], depth + 1)
base.update({k: v for k, v in d.items() if k != "inherits"})
return base
mine = resolve(json.load(open("<путь к моему профилю>", encoding="utf-8")))
factory = resolve(index["<имя вендорского профиля>"])
# ключи, которых у кандидата нет вовсе
print(sorted(set(factory) - set(mine)))
# и расхождения значений
for k in sorted(set(mine) & set(factory)):
if mine[k] != factory[k]:
print(k, factory[k], "->", mine[k])Каталог системных профилей в OrcaSlicer на macOS — ~/Library/Application Support/OrcaSlicer/system/<Вендор>/filament/, пользовательские — .../user/default/filament/. Профили конкретной серии принтеров могут лежать в подкаталоге (у меня — filament/Q2/), поэтому обход только верхнего уровня половину пропустит; нужен именно os.walk.
Правило
Наследоваться от вендорского профиля под конкретный принтер и сопло (<Бренд> <Материал> @<Принтер> 0.4 nozzle), а поверх переопределять только то, что относится к катушке: температуры, плотность, коэффициент подачи, pressure advance, лимит расхода, вендор.
Если нужного бренда у вендора нет — брать вендорский профиль ближайшего материала того же класса и переопределять под свой бренд. Это правильнее, чем брать библиотечный профиль своего бренда: класс материала одинаковый, а машинная обвязка сохраняется. Именно так я и сделал: свой ASA собран поверх вендорского ASA под мою машину, а не поверх библиотечного ASA моего бренда.
Итоговая цепочка выглядит так:
Мой профиль -> <Вендор> ASA @<Принтер> 0.4 nozzle -> <Вендор> ASA@<Серия> -> fdm_filament_<вендор>_common
Гоча: «Generic» и «библиотечный профиль бренда» — не одно и то же
Я сначала записал у себя, что enable_pressure_advance = 1 встречается только в вендорской цепочке, и это неверно. У библиотечного профиля бренда он тоже 1. Ноль стоит именно у Generic <материал> @System — то есть у самого общего профиля, который наследуется напрямую от шаблона материала (fdm_filament_asa и подобных).
Разница важна практически: библиотечный профиль бренда — это «правильные температуры без машины», а Generic — «ни машины, ни бренда». Оба не годятся как база, но по разным причинам, и путать их не стоит. Ошибку я поймал только когда сел считать расхождения скриптом, а не по памяти.
Гоча: имя нового профиля может столкнуться с алиасом
У системных профилей бывает поле renamed_from — старое имя, под которым слайсер их ещё узнаёт. У библиотечного <Бренд> ASA @System это <Бренд> ASA. Поэтому свой профиль нельзя называть ровно так же: имя формально свободно (файла с ним нет), но алиас на него уже указывает. Я назвал свой <Бренд> ASA <Принтер>.
Второй файл рядом с профилем — .info, где поле base_id указывает на setting_id родительского системного профиля. При ручном создании профиля его надо заполнять тем же setting_id, который стоит в родителе, иначе слайсер считает профиль осиротевшим.
Почему ошибка живучая
- Печать не падает. Деталь выходит, просто хуже — а «хуже» на глаз списывается на материал или на калибровку.
- Интерфейс слайсера показывает поле «температура камеры» и в Generic-профиле тоже. Оно там просто равно нулю, и ноль выглядит как «не задано», а не как «выключено».
- Профиль легко переживает смену принтера: скопировали настройки со старой машины — и потеряли всю обвязку новой. У меня ровно так и вышло: старые профили остались от предыдущего принтера и продолжали работать «нормально».
- Ни один линтер слайсера этого не ловит: с точки зрения формата профиль корректен.
Как проверить, что у вас
- Схлопнуть цепочку наследования скриптом выше и сравнить с вендорским кандидатом.
- Прочитать конфиг-блок среза — в конце файла G-code слайсер печатает все эффективные значения строками
; ключ = значение. Это единственный источник правды: там уже применены и наследование, и дефолты самого слайсера, которых в цепочке вообще нет. См. Проверка настроек слайсера по срезанному gcode. - Проверить точечно три ключа, которые чаще всего оказываются нулём или дефолтом:
chamber_temperature,enable_pressure_advance,filament_max_volumetric_speed.
Источники
- Настройки для прочной печати — почему температура камеры вообще важна
- Проверка настроек слайсера по срезанному gcode — как убедиться в эффективных значениях
- Ограничение печати объёмным расходом — почему
filament_max_volumetric_speedиз этого списка самый важный