fix(SNNBot): fast recovery on target move + bidirectional fire gate
Problem 1: Dead zone (skip learn when error < 1.5°) means stale exemplars linger in ring buffer after target moves. Fix: detect error jump >5° and reset ring buffer (aimer.count, aimer.nextSlot = 0) for fresh start. Problem 2: Fire gate only checked start condition (err < threshold), never stopped firing when error worsened. Fix: explicit setFire(0.0) when error exceeds tolerance, making gate bidirectional (start and stop). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -215,6 +215,7 @@ type
|
|||||||
velSpeed: float64 # speed (units/tick) from last scan delta
|
velSpeed: float64 # speed (units/tick) from last scan delta
|
||||||
lastDecideGunDir: float # gun heading captured at DECIDE time for EVALUATE
|
lastDecideGunDir: float # gun heading captured at DECIDE time for EVALUATE
|
||||||
lastBinInput: BitVec80 # DECIDE-time binary input, reused in EVALUATE
|
lastBinInput: BitVec80 # DECIDE-time binary input, reused in EVALUATE
|
||||||
|
lastError: float # last aiming error (for jump detection)
|
||||||
|
|
||||||
# ── aimTo helper ──────────────────────────────────────────────────────────────
|
# ── aimTo helper ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -273,6 +274,7 @@ method onRoundStarted*(bot: SNNBot, e: RoundStartedEvent) =
|
|||||||
bot.velSpeed = 0.0
|
bot.velSpeed = 0.0
|
||||||
bot.phase = DECIDE
|
bot.phase = DECIDE
|
||||||
bot.tick = 0
|
bot.tick = 0
|
||||||
|
bot.lastError = -1.0 # sentinel: no error yet
|
||||||
setTargetSpeed(0.0)
|
setTargetSpeed(0.0)
|
||||||
setTurnRate(0.0)
|
setTurnRate(0.0)
|
||||||
|
|
||||||
@@ -382,9 +384,21 @@ method run*(bot: SNNBot) =
|
|||||||
of WAITING:
|
of WAITING:
|
||||||
aimTo(bot.targetAngle, gunDir)
|
aimTo(bot.targetAngle, gunDir)
|
||||||
let err = abs(normalizeRelativeAngle(bot.targetAngle - gunDir))
|
let err = abs(normalizeRelativeAngle(bot.targetAngle - gunDir))
|
||||||
|
|
||||||
|
# Bidirectional fire gate: fire only when error within tolerance
|
||||||
if err < AIM_TOL:
|
if err < AIM_TOL:
|
||||||
discard setFire(FIRE_POWER)
|
discard setFire(FIRE_POWER)
|
||||||
bot.phase = EVALUATE
|
bot.phase = EVALUATE
|
||||||
|
else:
|
||||||
|
discard setFire(0.0)
|
||||||
|
|
||||||
|
# Fast recovery: detect error jump (regime change) and reset ring buffer
|
||||||
|
# ponytail: >5° jump triggers reset; tune threshold if target moves frequently
|
||||||
|
if bot.lastError >= 0.0 and err - bot.lastError > 5.0:
|
||||||
|
bot.res.count = 0
|
||||||
|
bot.res.nextSlot = 0
|
||||||
|
|
||||||
|
bot.lastError = err
|
||||||
|
|
||||||
of EVALUATE:
|
of EVALUATE:
|
||||||
# Predictive error signal: extrapolate enemy position at bullet impact time.
|
# Predictive error signal: extrapolate enemy position at bullet impact time.
|
||||||
|
|||||||
Reference in New Issue
Block a user