Homing¶
The machine has no limit or home switches as it ships. This page describes how ForgeFIRM establishes an origin in each mode: camera-referenced homing through the Glowforge service, what the controller assumes when it runs unhomed, and the planned limit-switch cycle.
- The operator's view (when to home, what the panel shows, the settings) is Homing.
- The origin, the work area, and the Z reference are The motion hardware.
The homing methods¶
homing_mode in /data/forgefirm/forgefirm.conf selects what $H does. The panel's
Machine tab sets it, and the driver re-reads the file on every $H:
gfcloud: camera homing through the Glowforge web service, the same cycle the factory machine runs. A cycle takes roughly a minute.manual: the operator puts the head against the gantry stops by hand and$Hdeclares that spot X0 Y0, or minusmanual_home_x,manual_home_yand then jogs the head to X0 Y0 (Manual homing).switches: the planned limit-switch cycle.$His refused (error 53).none:$His rejected (error 5).
The methods are rows of one table in the driver, homing_providers[] in
glowforge_homing.c: an id, a kind, and the function $H runs. The kind is
a property of the code, never of configuration. A builtin provider is a
function in the driver. A runner-fd provider hands the pulse device to a
root process that moves the machine; it suspends and resumes the stream
engine around its session, and it is refused while the motors are released.
Every provider ends in the same completion code: the soft limits, the
planner's position, the kernel counters cleared, the anchor written, the
core's homing-completed event, and the idle state.
Camera-referenced homing in GRBL mode¶
What the driver does¶
glowforge_homing.c in the grblHAL driver registers a driver $H that
shadows the core's homing cycle. Under gfcloud:
- The driver suspends the stream engine, and only from a fully idle kernel: closing the flock'd pulse-device fd mid-program is an emergency stop, so a handover never happens with a run in flight.
- It forks the homing runner,
/usr/sbin/gfhome.py. The runner inherits the brokered pulse device and its environment (GF_PULSE_FD), so the handover opens and closes no device and never moves the 40 V rail (forgectrl). The runner's configuration is/data/forgefirm/gfhome.conf, seeded from/etc/gfhome.conf.sampleon first run. The runner also reports job state to the cooling engine in the driver's place, which reports nothing while the session runs, so the driver hands it the report channel's secret at its spawn (The cooling engine). - While the session runs, the driver pumps the Grbl protocol, so the sender keeps getting status reports and does not time out. What the service does during it is the factory's own camera homing (Factory firmware).
- On completion it reacquires the device and re-applies the analog
configuration and
step_freq, then writes the homing anchor,/run/grblhal.homed, which forgectrl uses to serve position.
^X aborts the session (SIGTERM, then SIGKILL) with ALARM:6, and the
position is lost (Faults). A failure or a timeout
queues ALARM:18, like a failed core homing cycle; the budget is
gfcloud_home_timeout_s (default 300 s, held to 10 to 3600 s: a value
outside is clamped with a log line, as gfcloud_home_x and
gfcloud_home_y are to the axis travel either side of the origin). The ok for $H is sent when the
session ends, so a sender that waits for it waits the whole session while
the status reports keep flowing.
The homing session¶
The runner dispatches with allow_print=False, so a print can never run
inside a homing session. It drives the GFUIService dispatch loop itself,
because the stock run() loop can neither stop nor close the socket. The
service's sequence, as it runs against the current service, is settings,
hunt, lid_image, a single corner move, lid_image, then silence: the
service takes a lid image, moves the head, takes another, and computes where
the head is (The cloud protocol). The hunt is
answered as done without moving the lens or playing its file: the session
borrows the service for its camera homing only.
Completion is guarded:
- The runner treats a hunt, plus at least one motion window witnessed by the head accelerometer, plus 10 s of quiet as complete.
- A run of near-identical service corrections aborts: the machine is not physically moving.
- A quiet service without an accelerometer-witnessed motion window is a failure, not a homing. Position counters advancing are not proof of motion.
- A motion that does not run whole fails the session at its end: canceled, stopped short (a fault, the cooling engine's stop), or ended with no step totals on record. The service goes quiet after it all the same, and the head is short of the home.
After the service goes quiet the lens takes the run's one reference, on the hall sensor's edge, and the driver places it in Z.
The lid¶
Homing is lid-gated in practice, even though the grblHAL core does not see
the door signal during $H. The session's move to the home corner is an
ordinary motion action: refused with the lid open, and stopped if the lid
opens partway through. The camera steps need the lid closed anyway
(The video pipeline). Only the lens (Z) hunt inside
the session ignores the lid, and in GRBL mode a hunt happens only inside a
homing session; there is no hunt outside one.
What the session needs¶
- A service session. This is the factory homing method, so it signs in
to the Glowforge service with the machine's built-in identity (the fuse
serial and password), or with the
gf_serial/gf_passwordoverrides (Cloud mode), and names its software asForgeFIRM/<version>through the User-Agent, as cloud mode does. The service holds one session per machine. It is the one part of GRBL mode that needs the service, and an internet connection. - The lid closed, for the motion and for the camera captures.
- The head accelerometer, as the motion witness.
The position after a home¶
After a successful session the machine coordinates are set to
gfcloud_home_x and gfcloud_home_y on the step grid (defaults 0 and 0;
either may be negative, and then the work envelope reaches back to the home
position on that axis, since the head stands there). Those two keys belong to
this provider alone, as manual_home_x and manual_home_y belong to the
manual one: no provider reads another's. Z is set to the park
height: the runner leaves the lens on the hall's rising edge, whose focal
height the setup's Focus burn measured (lens_hall_edge_z_mm), then moves it the
whole half-steps to lens_park_z_mm (default 3 mm), inside the window every
head reaches without touching a stop
(The grblHAL driver).
The factory home is the machine origin, the back-left corner,
with the workspace all-positive from there
(The motion hardware). The position is then
anchored, and the panel shows it normally. A successful home also turns the
driver's X and Y soft limits on, with the bed as the envelope (to the far
edges, The far edges), whatever $20 says; they go off with the anchor whenever the position is invalidated
(The grblHAL driver).
Manual homing¶
The operator's procedure is Homing, Manual homing.
The manual provider¶
$H under manual is accepted in Idle or Alarm, as every provider is. It
waits for the kernel to finish any decel tail, energizes X and Y if they are
released, and then declares the position: sys.position X and Y to minus
manual_home_x and manual_home_y on the step grid, X and Y added to the
homed mask, the kernel counters cleared, and the anchor written with the
source manual. The two keys are how far in front of the gantry stops the
origin lies, and they belong to this provider alone. Unset, the gantry stops
are X0 Y0. They are never negative (forgectrl refuses one, and the driver
holds a hand-edited value to 0 up to the axis travel, with a log line). The
work envelope starts at the origin, so the strip between the stops and the
origin is outside it, and ends at the far edges
(The far edges). Z is not touched: its position, its
reference, and its envelope stay as they were, and since the counters are
cleared for all three axes the anchor carries the height the lens stands at.
With no offset nothing moves: there is no stream suspend, no runner, and no
pulse byte. With one, the sender is told where the head was declared, and the
driver jogs the head to X0 Y0 at the X and Y rate limit through the core's jog
(mc_jog_execute), pumping the protocol until the jog ends and the kernel has
played its tail, and only then does $H answer; a sender's next line never
meets the jog. The jog is the motion that ships dark whatever the modal
spindle state is (The grblHAL driver), and like every jog
it runs with the lid open, since the door is hidden from the core while it
jogs; a jog cancel, a feed hold, a cooling verdict, or a reset ends it. The
core acts on a jog cancel when its main loop reads it out of the input
stream, and that loop is waiting for $H, so while the jog runs the driver
turns a jog cancel into a motion cancel itself. The
home stands whatever becomes of the move, and a move that ends short of the
origin is reported with where it stopped. There is no lid gate on the home
itself: the lid is open while the head is being pushed.
The sender gets a warning at every manual home, and the anchor names its source so a reader can tell a position a hand declared from one the machine found. The soft limits are exactly as true as the placement: a misplaced home shifts the whole envelope, so a move inside the limits can reach the frame. That is a mechanical matter and never an emission one. The crash watch is not a backstop for it, since it arms only inside the laser's armed window (The cooling engine).
The far edges¶
Every provider ends X's and Y's envelope at the same far edges:
envelope_x_mm and envelope_y_mm, the machine coordinates the Setup
page's Bed size check measured, counted from the origin (so a changed
manual home offset moves them by the same amount)
(Setup), and the axis travel ($130,
$131) while they are unset. The driver reads them at every home, and holds
a value to 50 mm up to the travel plus 30 mm, with a log line; forgectrl
refuses one outside 50 to 600 mm. The travel keeps a margin the factory took
for its tolerances, which the check gives back: the operator jogs the head
to each far end, watching it, and the edge is set 1 mm short of where they
stopped.
For the measurement the check opens the envelope through the controller
port (envelope open): X's and Y's far edges go to the travel plus 30 mm,
for the port's jogs alone
(The controller port). envelope
apply sets them from the keys again without a home. A home, a soft reset, a
Grbl sender's line, and the port's client going away each close an open
envelope.
The motor release¶
glowforge_release.c registers two system commands, the way $H is
registered.
| Command | What it does |
|---|---|
$MD |
Waits up to 3 s for the kernel to finish a move's tail, then releases X and Y by taking their step currents (pic/x_step_current, pic/y_step_current) to 0. On the bench reference that lets the gantry and the head move freely by hand, with the steppers' detents still felt; the drivers stay enabled and the 40 V rail stays up. Accepted in Idle or Alarm with the kernel idle, and refused while a laser job is armed or arming. It drops the X and Y reference at once (homed bits, soft limits, their part of the anchor) and keeps Z's. |
$ME |
Energizes X and Y: the hold currents. The position stays invalid until a home. The machine returns to the state it was in before the release, so an alarm that was already standing is not cleared. |
While released, every motion is refused, and nothing but $ME or a manual
$H energizes the motors. The operator's hands are on the gantry, and a
stray jog from a sender, the panel, or a bounced button must not snap the
rotors to a detent under them. The lock is the core's own alarm state
(ALARM:11), where the core refuses every g-code line and every jog with an
error, whoever sent it. The driver makes the lock unpickable:
$Xis shadowed and refused (error 9) while released.- A soft reset leaves the alarm standing, as the core does for any alarm.
- A
runner-fdhoming provider is refused, since its session would energize the motors and move the head. - The realtime poll puts the alarm back if anything else clears it.
- The driver's current scheme writes 0 to X and Y, and nothing else, for as long as the release is held, so neither the run nor the hold posture can energize them.
- The release leaves a marker,
motors.released, in the state directory. A controller that starts over it (the one before it died, or was restarted) takes the release over before it writes its first current, and comes up locked. - forgectrl reads the same marker: its motion probe is skipped and a switch to cloud mode is refused while it stands (forgectrl).
A refused line gets a [MSG:] that says the motors are released, at most one
every two seconds.
Homing in cloud mode¶
Cloud homing is camera-based, in the same way: the service takes a lid image, moves the head, takes another, and computes where it is. The lens hunt references Z against the hall sensor. Hunts are not lid-gated.
- Connecting zeroes the machine's counters at the head's current position. GRBL-mode coordinates do not survive a switch to cloud mode and back: re-home after switching.
- The connect-time hunt. A process's first settings report carries the
machine's values, and the service answers it with its connect-time hunt: a
Z home, the service's XY hunt pattern, and the home offset. A report in the
reconnect form (no values) makes the service keep the head position it
already has instead, which is what the factory client does on every
reconnect within a session.
gfcloud.py --no-huntstarts that way on purpose (Cloud mode); a print placed on a stale head position can run the gantry into a rail, so a fresh boot always reports the values and gets the hunt. - The service dead-reckons position from the hunt onward. After any
mid-job abort it re-hunts, and after a completed print it issues a
lid_imageand a Z re-hunt. The park after every print, finished or aborted, matters for that reckoning: a park cut short would offset every motion until the next camera home, which is why the park ignores the lid and the cancel flag (Cloud mode).
The lens reference at every start¶
The lens does not wait for a home. Before any controller starts, forgectrl
sweeps the lens onto the hall sensor's rising edge in the motion-verify
window, and the controller reads the focal height of that edge out of
lens_hall_edge_z_mm. Z is therefore referenced on every start, on its own,
while X and Y wait for a home (forgectrl).
The one exception is a setup step that moves the lens and then cannot put
it back on its edge
(forgectrl).
A lens that cannot reach its edge is a hard fault, not a fallback: the lens motor is wedged, the carriage is jammed, or the hall sensor is dead, and a machine whose focal height would be a guess does not get to run. The supervisor holds every controller down and the panel names the reason.
Running unhomed¶
The machine cuts fine unhomed in GRBL mode. Without a reference, X and Y are relative to wherever the head happened to be when the controller started, so the panel shows them in red to say so, and the sender should use a job-start mode that does not depend on machine coordinates (GRBL mode). After a successful home the position is anchored and shown normally. Z is the exception: it carries its own reference from the start, so it reads normally while X and Y do not.
Position comes from the kernel step counters, anchored through
/run/grblhal.homed, which the controller writes. forgectrl serves it from
there and never queries the Grbl socket (forgectrl). The
anchor names the axes it references, so the lens reference anchors Z alone
and a completed home anchors all three. Its last field names what set it:
gfcloud, manual, or startup for the lens reference.
Anything that invalidates position (an underrun, a stream fault, a soft reset whose position cannot be read back, a soft reset during the web-service homing session) drops the anchor deliberately, so a stale origin cannot be reused. A motor release drops X and Y from it and keeps Z (The grblHAL driver). Z is never driven blind, homed or not: the lens carriage is referenced against the hall sensor's edge, low in its travel (The motion hardware).