setup.check-envelope: the head goes back to the home, or the run fails

The test's cleanup jogged the head back to the camera home through the
panel's relative jog, the increment taken from the port's position. The
core refused it every time (error:15, "the move would leave the work
envelope"), eight tries each run, and the test logged "the head is not
back at the home" and passed. The takeover that puts the setup record
back restarts the controller, which zeroes the kernel counters where the
head stands, so the baseline read (0, 0, 0) and called the machine
clean. On the bench reference the head was left 10 mm from the home in X
and in Y by every run of 2026-09-23 that got that far (three PASSes and
one FAIL, images 20260922225653, 20260923084705, 20260923220034).

Why the jog was refused: the port reports the step counters, while the
core adds a relative jog to its own parser position. The bed check's
last jogs, sized from the counters, leave the two apart by up to half a
step. The arithmetic reproduces every logged value: the parser held X
60.1 after the answers, the port read 60.099, the check jogged -50.099
toward X 10, so the parser took 10.001, which the step grid (213.33
steps/mm) turned into 2134 steps, read back as 10.003. The test's
return of -10.003 then targeted X -0.002, and a camera home's envelope
begins at exactly 0, so the core refused the whole jog. No product path returns the head by a relative
jog sized from the counters; the panel's Jog card sends fixed steps.

Now the head goes back in one jog from a Grbl client to the home in
machine coordinates ($J=G90 G53, 0.5 um inside the envelope's start,
far under half a step), and the run fails unless the port reads the head
on the home's step. That reading is taken before the restart, because
nothing after it can see a head left out.

Bench reference, image 20260923220034 with the suite file bind-mounted:
a negative control that aims the return 1 mm off the home FAILs with
"the head is not back at the home (0.0, 0.0, 3.08): [0.998, 0.998,
3.08]" while the baseline still says clean; the fix PASSes with
"$J=G90 G53 X0.0005 Y0.0005 F1200 -> ok" and the head at [0.0, 0.0,
3.08]. forgetest's unit tests 454 OK; the coverage lint passes with
--enforce on the image's manifest.
This commit is contained in:
ScottW514
2026-09-23 19:22:10 -04:00
parent c95b5aa771
commit 56af6eaab2
+40 -19
View File
@@ -29,7 +29,10 @@ X_STEPS = ["X+10"] * 6 + ["X+1", "X+0.1", "X-1"]
Y_STEPS = ["Y+10"] * 6 + ["Y+1", "Y+0.1"]
X_OUT, Y_OUT = 60.1, 61.1
MARGIN_MM = 1.0
KEYS = ("envelope_x_mm", "envelope_y_mm", "homing_mode")
# The head is back on the home's step: half a step (213.3 steps/mm) and
# the port's three decimals.
HOME_TOL_MM = 0.003
KEYS =("envelope_x_mm", "envelope_y_mm", "homing_mode")
CLOSED = "closed the check's envelope"
CLOSED_MSG = "Bed check envelope closed: a sender line"
@@ -107,20 +110,31 @@ def _put_back(ctx, fc, found):
def _back_home(ctx, fc, home):
"""The head back where the home put it, in the port's bounded steps, so
the run ends where it began."""
for _ in range(8):
at = _port(fc).get("mpos") or [home[0], home[1]]
dx, dy = home[0] - at[0], home[1] - at[1]
if abs(dx) < 0.005 and abs(dy) < 0.005:
return
st, body = _jog(fc, max(-100.0, min(100.0, dx)), max(-100.0, min(100.0, dy)))
if st != 200:
ctx.log("the jog back to the home -> %s %s", st, body)
ctx.wait_for(lambda: fc.status().get("state") == "idle", 10, poll=0.5)
continue
_port_idle(ctx, fc)
ctx.log("the head is not back at the home: %s", _port(fc).get("mpos"))
"""The head back where the home put it: one jog to the home in machine
coordinates, from a Grbl client. A relative jog aimed at the home from
the port's position can be refused whole: the port reports the step
counters, the core adds a relative jog to its own position, which the
check's jogs leave up to half a step off the counters, and the envelope
begins at the home, so the target can land microns behind it (error:15).
Where the head stands after, from the port; None when unread."""
# 0.5 um inside an envelope that begins at the home (a camera home
# behind the origin), far under half a step: the head lands on the
# home's own step.
line = "$J=G90 G53 X%.4f Y%.4f F1200" % (home[0] + 0.0005, home[1] + 0.0005)
try:
with ctx.grbl() as g:
reply = g.command(line, timeout=10)
ctx.log("the jog back to the home: %s -> %s", line, " | ".join(reply))
if reply[-1:] == ["ok"]:
t0 = time.time()
ctx.wait_for(lambda: time.time() - t0 > 0.5 and g.status_report()["state"].startswith("Idle"),
60, poll=0.2)
except (OSError, ValueError) as e:
ctx.log("the jog back to the home: %s", e)
ctx.wait_for(lambda: _port(fc).get("sender") is False and _port(fc).get("state") == "Idle", 20, poll=0.5)
at = _port(fc).get("mpos")
ctx.log("the head after the jog back: %s (the home %s)", at, home)
return at
def _port_idle(ctx, fc):
@@ -171,8 +185,9 @@ def _edge(ctx, fc, ev, axis, edge):
"closed the envelope and then ok; the port's state then says the envelope is closed, and the "
"next answer ends the check in words, with the keys as the "
"first run left them and the edges still in force. The keys, the homing mode, and the setup "
"record are put back as found, the record under a restart, and the head is jogged back to "
"the home.")
"record are put back as found, the record under a restart, and the head goes back to the "
"home by a Grbl client's jog in machine coordinates; the run fails unless the port reads "
"the head on the home's step before the restart.")
def check_envelope(ctx):
fc = ctx.forgectrl
ev = ctx.evidence
@@ -181,7 +196,7 @@ def check_envelope(ctx):
raw = read_file(record_path())
found = {k: s0.get(k) or "" for k in KEYS}
ev["found"] = found
home = None
home = back = None
try:
st, body = fc.post("/settings", data={"homing_mode": "gfcloud"})
ctx.check(st == 200, "homing_mode=gfcloud -> %s %s", st, body)
@@ -245,7 +260,7 @@ def check_envelope(ctx):
fc.post("/wiz/%s/abort" % WID)
if home and home[0] is not None:
ctx.wait_for(lambda: not dark(fc).get("running"), 30, poll=0.5)
_back_home(ctx, fc, home)
back = _back_home(ctx, fc, home)
_put_back(ctx, fc, found)
# The check records itself when it completes; the record goes back
# as found under a restart, which also ends the envelope it set.
@@ -253,3 +268,9 @@ def check_envelope(ctx):
with ctx.takeover():
write_file(record_path(), raw)
ctx.log("the previous setup record is back under a restart")
# Judged from the reading before the restart: the restart zeroes the
# counters where the head stands, so the baseline's position check
# after it cannot see a head left out.
ev["back"] = back
ctx.check(back and all(abs(back[i] - home[i]) < HOME_TOL_MM for i in (0, 1)),
"the head is not back at the home %s: %s", home, back)