Diag: render-rate rotation-evenness probe + angular-drift instrumentation (task #50 spin residual)
Autonomous headless spin harness (BT_AUTODRIVE+BT_FORCE_TURN) + probes that finally measure what the eye sees, not the sim heading: - BT_RENDHDG (L4VIDEO render loop): per-RENDERED-frame peer heading step evenness -- avgStep/maxStep/max-avg ratio. Confirmed the residual spin 'hesitation' is UNEVEN rendered rotation (max/avg ~2.8x), correlated with the byAngle resync-flood bursts (maxAng ~= pi), NOT a render-vs-sim rate stall (render redraws a fresh heading every frame). - BT_SPIN / BT_ANGSIGN: resync trigger breakdown (byAngle/byVel/byRest) + the frame-level local/update/projected angular-Y that exposed the Abs() macro bug. - gBTReplRenderYaw: peer heading published from the sim to the render probe. - Normalize projectedOrigin.angularPosition after the peer-mirror advance (adding a scaled ang-vel VECTOR to a quaternion denormalizes it) -- correct, but NOT sufficient: the pi divergence is REAL, from the crude large-angle quaternion projection over the sparse angular-record interval during a PURE spin (linear dense-send doesn't fire when not translating; type-4 is the only orientation carrier and resets the horizon, so dense type-4 -> half-rate). Residual ROOT (scoped, not yet fixed): the reckoner (MOVER.cpp:457-466) projects rotation by ADDING vector*t to the heading quaternion -- a small-angle approx the original kept valid via dense records; our pure-spin case has 1.6s record gaps so it diverges to ~180deg -> uneven render. Fix path = proper quaternion integration in the reckoner, or refresh the angular origin without the type-4 horizon reset. Both touch the shared engine dead-reckon -> aligning before the change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7615ecd316
commit
9eff043973
@@ -1863,6 +1863,9 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
// Peer heading published each sim update, sampled by the render loop (BT_RENDHDG).
|
||||
volatile float gBTReplRenderYaw = -999.0f;
|
||||
|
||||
void
|
||||
Mech::PerformAndWatch(const Time& till, MemoryStream *update_stream)
|
||||
{
|
||||
@@ -1930,6 +1933,18 @@ void
|
||||
DeadReckon(dt); // engine: reckoner + lerp
|
||||
localToWorld = localOrigin;
|
||||
|
||||
// RENDER-vs-SIM decoupling probe: publish the heading the RENDER will
|
||||
// actually draw (localToWorld == localOrigin here). The render loop
|
||||
// (L4VIDEO.cpp) logs this PER RENDERED FRAME; if it repeats the same
|
||||
// value across render frames, the peer sim updates slower than the
|
||||
// render draws -> the rotation stutters even though each sim update is
|
||||
// smooth (which the per-update [replhdg] metric could not see).
|
||||
{
|
||||
extern volatile float gBTReplRenderYaw;
|
||||
YawPitchRoll _rry; _rry = localOrigin.angularPosition;
|
||||
gBTReplRenderYaw = (float)_rry.yaw;
|
||||
}
|
||||
|
||||
// Lightweight dead-reckon smoothness probe (one flush/sec, cheap).
|
||||
// PATH length (sum of |per-frame step|) vs NET displacement reveals
|
||||
// jitter: a smooth walk has path==net; oscillation inflates path while
|
||||
@@ -3587,6 +3602,11 @@ void
|
||||
angStepM.Multiply(updateVelocity.angularMotion, dt);
|
||||
projectedOrigin.angularPosition.Add(
|
||||
projectedOrigin.angularPosition, angStepM);
|
||||
// Adding a scaled angular-velocity VECTOR to a quaternion denormalizes
|
||||
// it (the reckoner MOVER.cpp:463 does the same); a non-unit quaternion's
|
||||
// extracted yaw is garbage (~pi), which spiked angDrift and FLOODED angle
|
||||
// resyncs in bursts -> peer horizon reset -> uneven (max/avg ~2.8x) render.
|
||||
projectedOrigin.angularPosition.Normalize();
|
||||
}
|
||||
Scalar angDb = (updateTurnAngleDeadband > 0.0f) ? updateTurnAngleDeadband : -1.0f;
|
||||
Scalar velDb = (updateTurnVelocityDeadband > 0.0f) ? updateTurnVelocityDeadband : -1.0f;
|
||||
|
||||
Reference in New Issue
Block a user