Fix belt printer illegal gantry move at print start

On a belt printer the first travel of the print emitted a bogus move to
the bed corner with the nozzle far up the gantry, e.g.
  G1 X95 Y168.19 Z237.857 F12000
right after the first "; printing object" line. Y168 (≈ the layer Z)
is out of the gantry's range.

Root cause: the layer-change z-hop is deferred via lazy_lift and consumed
by the first BeltGCodeWriter::travel_to_xyz, whose NormalLift branch does a
separate lift-in-place via _travel_to_z(target.z()). On a normal printer
_travel_to_z emits a Z-only move, but in belt mode Z is coupled to Y/X, so
_travel_to_z re-emits the current m_pos through the belt shear. At print
start (and after custom gcode) m_pos.xy is still the uninitialised origin
(0,0), which the back-transform + axis-remap shear into machine
(X=bed_max, Y=layer_z) — the illegal move.

Guard the NormalLift branch on is_current_position_clear(), matching the
SlopeLift branch directly above it which already does so. When the position
isn't established there is nothing to lift over, and the xy_z_move that
follows travels straight to the destination with full XYZ, establishing the
correct position. Bookkeeping is unaffected: in this path m_lifted stays 0,
so no spurious restore move is produced.

Verified by re-slicing the repro project: the start-of-print move is now
G1 X44.946 Y.621 Z237.857 (straight to the first object point), no move
touches the bed-max X edge, and the max Y over the whole file is 62.8mm
(printable_height 100).
This commit is contained in:
harrierpigeon
2026-06-27 01:47:20 -05:00
parent 0342e06d87
commit 04554abae6

View File

@@ -217,7 +217,17 @@ std::string BeltGCodeWriter::travel_to_xyz(const Vec3d &point, const std::string
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
slop_move = w0.string();
}
else if (m_to_lift_type == LiftType::NormalLift) {
else if (m_to_lift_type == LiftType::NormalLift && this->is_current_position_clear()) {
// Only lift-in-place when the current position is known. On a normal
// printer _travel_to_z emits a Z-only move, but in belt mode Z is coupled
// to Y/X, so _travel_to_z re-emits the current m_pos through the belt
// shear. At print start (and after custom gcode) m_pos.xy is still the
// uninitialised origin (0,0), which shears into a bogus machine point
// (e.g. X=bed_max, Y=layer_z) far up the gantry. Skipping the separate
// lift here is safe: there is nothing to lift over yet, and the
// xy_z_move below travels straight to the destination with full XYZ,
// establishing the correct position. This mirrors the SlopeLift branch
// above, which already guards on is_current_position_clear().
slop_move = _travel_to_z(target.z(), "normal lift Z");
}
}