mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-28 09:11:11 -07:00
bench+docs: IG threshold LSB is FS/256; factory HA* seed values recovered
The captured pulse headers carry the factory's IG programming: hunts off, travels abort-only (HAar=133 at +/-4 g), the cut alert-only (HAxr=132, HAyr=112), Z and idle never armed. The factory abort value itself rules out an FS/128 LSB (4.16 g would sit over the measurable range), and two Z-only bench windows bracket gravity between thresholds 100 and 150, which only FS/256 explains. The drill script's printed g conversion is corrected, and the stale motion-profile reading of HAxr/HAyr/HAar as accel limits is corrected in the facts bank. No catalog consequence: a bench script's printed conversion and the docs record; no shipped behavior changes.
This commit is contained in:
+15
-7
@@ -890,8 +890,10 @@ is committed.
|
|||||||
all-positive from that corner.
|
all-positive from that corner.
|
||||||
- **Factory motion profile** (measured from captured factory pulse streams
|
- **Factory motion profile** (measured from captured factory pulse streams
|
||||||
with `puls_profile.py`): accel ≈ 700 mm/s² X / 590 mm/s² Y on v2.6.0 firmware
|
with `puls_profile.py`): accel ≈ 700 mm/s² X / 590 mm/s² Y on v2.6.0 firmware
|
||||||
(2018 firmware used ≈1000); header HAxr=132/HAyr=112/HAar=133 ⇒ ≈5.3 mm/s²
|
(2018 firmware used ≈1000). The HAxr/HAyr/HAar header tags are NOT motion
|
||||||
per HA unit. Travel moves peak 202 mm/s vector (≈ 8 in/s) at STfr=28160 Hz;
|
accel limits; they are LIS2HH12 IG threshold register values (the crash
|
||||||
|
detector, "The head accelerometer" below).
|
||||||
|
Travel moves peak 202 mm/s vector (≈ 8 in/s) at STfr=28160 Hz;
|
||||||
prints and hunts run STfr=10000. Cut feed in the sample print: 145 mm/s. Z
|
prints and hunts run STfr=10000. Cut feed in the sample print: 145 mm/s. Z
|
||||||
cadence ≈ 61–115 ms per half-step (≈ 5.7 mm/s max).
|
cadence ≈ 61–115 ms per half-step (≈ 5.7 mm/s max).
|
||||||
- **Factory analog config** (constant across all captured jobs, 2018→2026):
|
- **Factory analog config** (constant across all captured jobs, 2018→2026):
|
||||||
@@ -1048,11 +1050,17 @@ is committed.
|
|||||||
running ODR, so an armed detector must set the ODR itself and re-assert it
|
running ODR, so an armed detector must set the ODR itself and re-assert it
|
||||||
after any liveness read (each one-shot powers the part down again). The IG
|
after any liveness read (each one-shot powers the part down again). The IG
|
||||||
registers coexist with the bound driver over i2c-dev (I2C_SLAVE_FORCE):
|
registers coexist with the bound driver over i2c-dev (I2C_SLAVE_FORCE):
|
||||||
IG_SRC1 polls at ~166 Hz from Python with `st_accel` raw reads intact. At
|
IG_SRC1 polls at ~166 Hz from Python with `st_accel` raw reads intact. The
|
||||||
the factory +/-2 g full scale the threshold LSB is ~15.6 mg, so 1 g ~= 64;
|
IG_THS LSB is **full scale / 256** (bench-confirmed against gravity: at
|
||||||
gravity rides Z on the head (raw ~-16916), so Z trips any sub-1 g
|
+/-2 g, threshold 100 = 0.78 g trips on the 1.03 g gravity reading and
|
||||||
threshold at rest while X and Y stay silent at rest and through a jog at
|
threshold 150 = 1.17 g does not; FS/128 would make the trip at 100
|
||||||
threshold 40 (~0.62 g).
|
impossible). Gravity rides Z on the head (raw ~-16916), so Z trips any
|
||||||
|
sub-1 g threshold at rest while X and Y stay silent at rest and through a
|
||||||
|
jog at threshold 40 (0.31 g). The factory arms the IG per job from the
|
||||||
|
HA* header tags: hunts all-zero (off), travel files abort-only
|
||||||
|
(`HAar=133` at `HAsr=4`, +/-4 g, ~2.08 g), the cut job alert-only
|
||||||
|
(`HAxr=132` ~2.06 g, `HAyr=112` ~1.75 g, +/-4 g), Z and the idle
|
||||||
|
thresholds zero in every captured header.
|
||||||
- **Beam detect in the head MCU.** PTE16 into ADC0 gives reg 0x16, the raw
|
- **Beam detect in the head MCU.** PTE16 into ADC0 gives reg 0x16, the raw
|
||||||
analog level (`beam_detect_analog`, a head sysfs attr): near 1834 dark, 2600
|
analog level (`beam_detect_analog`, a head sysfs attr): near 1834 dark, 2600
|
||||||
to 2890 during S300/S400 fire (the acceptance suite's mark witness),
|
to 2890 during S300/S400 fire (the acceptance suite's mark witness),
|
||||||
|
|||||||
@@ -6828,6 +6828,36 @@ one gentle jog (`$J=G91 X5 F1000`, +X first). No emission, no unbind.
|
|||||||
the strike magnitude, 3x and more over a threshold that gravity
|
the strike magnitude, 3x and more over a threshold that gravity
|
||||||
already trips; a physical tap would add nothing the design needs.
|
already trips; a physical tap would add nothing the design needs.
|
||||||
|
|
||||||
|
## 2026-08-31: IG threshold LSB confirmed FS/256; the factory HA* seed values recovered
|
||||||
|
|
||||||
|
Two facts that size the crash detector's thresholds, found while seeding
|
||||||
|
them from the captured headers. They correct the previous entry's g
|
||||||
|
conversion, which assumed FS/128 (values half of what it stated: the
|
||||||
|
drill's threshold 40 is 0.31 g, not 0.62 g).
|
||||||
|
|
||||||
|
- **The captured headers carry the factory's IG programming.** All 23
|
||||||
|
captured `.puls` headers parse (gfutilities `PulseSource`): hunts ship
|
||||||
|
every HA threshold zero (detector off, `HAsi/HAsr=2`); travel files
|
||||||
|
ship abort-only (`HAar=133`, `HAsr=4`); the cut job ships alert-only
|
||||||
|
(`HAxr=132`, `HAyr=112`, `HAsr=4`, `HAar=0`). `HAz*` and every idle
|
||||||
|
(`*i`) threshold are zero in every header. So the factory never arms
|
||||||
|
Z (the gravity axis), never arms the idle state, pauses cuts on a
|
||||||
|
~2 g event and fails travels on one.
|
||||||
|
- **IG_THS LSB = full scale / 256, twice proven.** By the factory's own
|
||||||
|
values: at FS/128 the travel abort 133 would be 4.16 g at +/-4 g,
|
||||||
|
over the measurable range, an abort that could never trip. On the
|
||||||
|
bench (two Z-only coexist windows, dev 20260831204710): threshold
|
||||||
|
100 trips on the 1.03 g gravity reading and threshold 150 does not;
|
||||||
|
under FS/256 those are 0.78 g and 1.17 g, bracketing gravity, while
|
||||||
|
under FS/128 the trip at 100 (1.56 g) would be impossible. The
|
||||||
|
datasheet states no IG_THS LSB (only ACT_THS = FS/128), so the bench
|
||||||
|
check was the proof. The drill script's printed conversion is fixed
|
||||||
|
to FS/256 in the same change.
|
||||||
|
- **The factory seed values in g**: X alert 132 = 2.06 g, Y alert
|
||||||
|
112 = 1.75 g, abort 133 = 2.08 g, all at the +/-4 g run full scale.
|
||||||
|
Normal commanded motion reads under 0.2 g and a rail strike 1.8 g
|
||||||
|
and up, so the factory band sits where the bench says it should.
|
||||||
|
|
||||||
## Reference notes
|
## Reference notes
|
||||||
|
|
||||||
### Head-IRQ source validation — the beam-emission hypothesis
|
### Head-IRQ source validation — the beam-emission hypothesis
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ Usage:
|
|||||||
but liveness is down meanwhile, so stop the controller and
|
but liveness is down meanwhile, so stop the controller and
|
||||||
forgectrl first)
|
forgectrl first)
|
||||||
--ths N per-axis threshold register value 0..255 (default 40); the
|
--ths N per-axis threshold register value 0..255 (default 40); the
|
||||||
LSB is full-scale dependent, so the printed CTRL4 FS fixes
|
LSB is full scale / 256 (bench-confirmed against gravity:
|
||||||
the g conversion (+/-2 g default: ~15.6 mg/LSB, 1 g ~= 64)
|
+/-2 g gives ~7.8 mg/LSB, 1 g ~= 128), so the printed CTRL4
|
||||||
|
FS fixes the g conversion
|
||||||
--dur N IG_DUR1 duration counter, samples at the running ODR
|
--dur N IG_DUR1 duration counter, samples at the running ODR
|
||||||
(default 0 = fire on the first over-threshold sample)
|
(default 0 = fire on the first over-threshold sample)
|
||||||
--axes which axes arm high events (default xyz)
|
--axes which axes arm high events (default xyz)
|
||||||
@@ -172,7 +173,7 @@ def main():
|
|||||||
if (ctrl1 & 0x70) == 0: # ODR bits 6:4 zero = power-down; IG needs
|
if (ctrl1 & 0x70) == 0: # ODR bits 6:4 zero = power-down; IG needs
|
||||||
wr(fd, CTRL1, 0x6F) # a running ODR: 800 Hz, BDU, XYZ on
|
wr(fd, CTRL1, 0x6F) # a running ODR: 800 Hz, BDU, XYZ on
|
||||||
ctrl1 = rd(fd, CTRL1)
|
ctrl1 = rd(fd, CTRL1)
|
||||||
lsb_mg = (fs * 1000.0 / 128.0) if isinstance(fs, int) else 0
|
lsb_mg = (fs * 1000.0 / 256.0) if isinstance(fs, int) else 0
|
||||||
print('WHO_AM_I=0x%02x CTRL1=0x%02x CTRL4=0x%02x FS=+/-%sg '
|
print('WHO_AM_I=0x%02x CTRL1=0x%02x CTRL4=0x%02x FS=+/-%sg '
|
||||||
'ths=%d (~%.0f mg, ~%.2f g) dur=%d axes=%s mode=%s'
|
'ths=%d (~%.0f mg, ~%.2f g) dur=%d axes=%s mode=%s'
|
||||||
% (who, ctrl1, ctrl4, fs, ths, ths * lsb_mg, ths * lsb_mg / 1000.0,
|
% (who, ctrl1, ctrl4, fs, ths, ths * lsb_mg, ths * lsb_mg / 1000.0,
|
||||||
|
|||||||
Reference in New Issue
Block a user