Belt printers can't slice a tall vertical temperature tower. This adds a
belt-specific temperature-tower model — a row of discrete, individually
engraved provini laid along the belt, each printed at one temperature via
custom per-layer M104. Each provino is an inverted-L overhang that stresses
print quality, so the operator reads the best temperature off overhang
quality rather than a continuous ramp.
It is offered as a "Test model" choice in the temperature calibration dialog
(mirroring the Cornering test's selector), so users keep Joe's counter-rotated
sectioned tower as "Standard" and can pick this one as "Overhang":
- Calib_Params::test_model (existing field) carries the choice.
- Temp_Calibration_Dlg gets a Standard/Overhang radio.
- Plater::calib_temp belt branch: test_model 0 -> _calib_temp_belt_sectioned
(unchanged Standard path), 1 -> the discrete-provini Overhang path.
Assets: belt_temp_provino_unit.stl + belt_temp_tower_<start>_<end>.stl (6
ranges) + gen_belt_temp_tower.py (manifold engraving). Based on
belt/generic-calibrations. The Overhang path is HW-validated on the IdeaFormer
IR3 V2 (discrete M104 + engraved numbers); not re-validated since the rebase.
The IdeaFormer IR3 V2 End G-code ran `G28 ; home all`, which homes the
Z (belt) and Y (gantry) axes. On a belt printer Z is the conveyor, so
homing it runs the belt all the way back to origin, dragging the finished
part back under the gantry that G28 has just lowered — the head knocks the
print (reported by an IR3 V2 user; the `G1 Y50` lift came after the G28,
too late).
Replace the end sequence with a belt-safe one: switch to relative mode
(G91), lift the gantry for clearance, advance the belt forward one full
machine-depth (Z676, the 676 mm product depth) to eject the part and cycle
the belt surface clean, then home X only — never the Z/belt axis.
collect_layers_to_print() warns (CRITICAL) when an extrusion layer sits above
the previous one with an empty gap below — the fixed-bed assumption that
material with nothing under it is floating and unprintable. On a belt printer a
*leading* empty range (the gap starts at Z=0, no prior extrusion layer) is not
floating: it is the conveyor lead-in, and the part rests on the advancing belt
as the first material is laid down well above Z=0. A part not designed for a
belt (e.g. a flat test model tilted into the belt frame) then trips this as a
false "Object can't be printed for empty layer between 0 and N" error.
Suppress only the leading case (belt_printer && last_extrusion_layer == null);
genuine internal gaps are still flagged, since on a belt those can be an
over-angle overhang printing into air. Non-belt output is unchanged.
* Add IdeaFormer IR3 V2 belt printer profile
Self-contained vendor profile for the IdeaFormer IR3 V2 (45 deg belt printer):
machine (0.4 nozzle) + 0.20mm process + Generic PLA/PETG filaments, with the
belt machine-frame transforms set explicitly on the machine preset
(belt_printer, belt_slice_rotation x/45/global, build_plate_tilt_x=45,
gcode_remap_x/y/z, gcode_shear_z=pos_tan, gcode_scale_y=inv_cos).
The vendor bundles its own machine/process commons (fdm_belt_common,
fdm_klipper_common, fdm_machine_common, fdm_process_common) on purpose:
OrcaSlicer resolves system-preset inheritance per-vendor, so a profile that
inherits the Custom vendor's commons cross-vendor fails to resolve its parent
and the whole IdeaFormer vendor silently fails to load. Bundling the commons
(and listing them in IdeaFormer.json in dependency order) keeps the vendor
self-contained, matching how every other vendor folder is structured.
Machine limits, bed temperature (75 C for belt PLA) and start/end G-code are
taken from a working IdeaFormer IR3 V2.
* feat(belt/profile): eSUN PLA @IdeaFormer IR3 V2 — HW-calibrated belt filament
Add an eSUN PLA belt profile for the IR3 V2, inheriting Generic PLA @IdeaFormer
IR3 V2 (self-contained: parent is in the same IdeaFormer vendor, registered
after it in filament_list). HW-calibrated on the IR3 V2:
- nozzle_temperature 200/200 (temp-tower calibration)
- pressure_advance 0.12 (PA calibration)
- filament_max_volumetric_speed 10 mm³/s (max-vol-speed calibration: wall
failed at 126 mm/s → 126 × 0.0798 mm³/mm ≈ 10 mm³/s)