docs/schema: server-side GNSS lever-arm correction - #680
Open
dirkwa wants to merge 5 commits into
Open
Conversation
Document the data-model contract for server-corrected navigation.position when GPS antenna offsets are configured. Adds sensors.<id>.sourceRef so sensor metadata can be linked to its data stream; describes navigation.position as the Common Coordinate Reference Point (CCRP) at center-of-vessel on the centerline (body coordinates (length/2, 0) measured from the bow) when correction is active; documents the meta.gpsOffsetCorrection entry that preserves the raw value and the correction provenance. Motivated by SignalK/signalk-server#2399, which adds the multi-GPS configuration UI and the in-server lever-arm corrector.
Rename the linkage field on the sensor object to $source per the $-prefix reference convention, the correction meta to gnssOffsetCorrection with $sensor referencing the sensor instance, and the surrounding prose from GPS to GNSS. Matches the server implementation in SignalK/signalk-server#2399.
added 3 commits
July 9, 2026 05:58
Update the spec to match the server implementation: correction is an opt-in server option (replace or both modes) rather than always-on, and is not signalled in-band. Drop the meta.gnssOffsetCorrection description - position deltas are high volume so no per-delta marker is added; the 'both' mode keeps the raw antenna value as a separate <id>.ccrp source instead. Document the notifications.navigation.gnss.headingUnavailable notification raised when correction is active but heading is missing.
fromCenter was the only signed athwartships quantity in the specification declaring +ve to port. Every other signed lateral or rotational key -- rudderAngle, attitude.roll, attitude.yaw, rateOfTurn, thrustAngle, keel.angle, environment.wind.angle* -- is +ve to starboard. The wording dates to fa162f7 (2014) and has never been revisited; there is no issue or discussion in the repository recording a rationale for it. The clash became load-bearing with server-side lever-arm correction, which combines fromCenter with a heading taken from the same body frame as attitude.yaw. A port-positive offset against a starboard-positive rotation forces a non-standard rotation matrix; under this change it collapses to the standard NED form. Implementations already disagree with the schema and with each other: n2k-signalk emits +ve to starboard while signalk-to-nmea2000 encodes +ve to port, so an AIS reference point round-trips mirrored across the hull. NMEA 2000 itself carries no sign here -- positionReferenceFromStarboard is unsigned -- so the signed form is a Signal K invention and there is no external convention to preserve. Also documents the body frame explicitly (x forward, y to starboard, right-handed) in data_model.md, and syncs the stale inline descriptions in the AIS test fixture with the schema. This inverts the meaning of existing data and is a MODEL-level change under SchemaVer.
steering.autopilot.target.windAngleApparent and windAngleTrue declared "+port -starboard", while environment.wind.angleApparent, angleTrueGround and angleTrueWater all declare "negative to port". These describe the same physical quantity -- measured apparent wind angle and the target apparent wind angle an autopilot steers to -- so an autopilot comparing the two had to negate one or steer to the mirror image of the requested angle. The measured side is already starboard-positive in practice: n2k-signalk maps the NMEA 2000 wind angle (0..2pi clockwise from the bow) into (-pi, pi], so 0..pi is starboard. This is a description-only clarification. No consumer of the autopilot target wind angle keys was found in signalk-server, signalk-autopilot, signalk-to-nmea2000 or Freeboard-SK, and the only test fixture holds positive values, so no existing data encodes a side.
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Document the data-model contract for server-corrected
navigation.positionwhen GNSS antenna offsets are configured.sensors.<id>.$source(new, optional) links a sensor instance to the source of its data stream — needed when multiple sensors of the same class are present (e.g. multi-GNSS). Named per the$-prefix reference convention established by$sourcein deltas.navigation.positiondescription expanded to define the Common Coordinate Reference Point (CCRP) as center-of-vessel on the centerline (body coordinates(design.length.value.overall / 2, 0)measured from the bow), matching the NMEA 2000 / radar / AIS industry convention.meta.gnssOffsetCorrectionentry that travels with correctednavigation.positiondeltas so history-recording consumers can preserve both the corrected value and the raw antenna measurement (with full provenance:$sensorreferencing the sensor instance, fromBow, fromCenter, lengthOverall, headingTrue, rawValue).mdbook/src/data_model.mdexplaining the lever-arm correction model end-to-end.Motivation
This is the specification side of SignalK/signalk-server#2399, which adds the multi-GNSS configuration UI and the in-server lever-arm corrector. Source priorities mean the active position source can flip between antennas with different offsets, which is fragile to correct client-side; the server has the active-source resolution and the heading, so it applies the correction in-process and emits the raw value plus correction provenance in
metafor downstream history.Update: athwartships sign convention (RFC #685)
Two further commits, added after review feedback from @keesverruijt on SignalK/signalk-server#2399, who pointed out that
fromCenterreads backwards versus every other signed lateral quantity in the spec.fix: make sensors fromCenter positive to starboard— flipssensors.*.fromCenterto+ve to starboard, -ve to port, documents the body frame explicitly indata_model.md(x forward, y starboard, right-handed), and syncs the stale inline descriptions in the AIS test fixture. This inverts the meaning of existing data and is a MODEL-level change under SchemaVer.fix: align autopilot target wind angles with environment.wind—steering.autopilot.target.windAngle*said+port -starboardwhileenvironment.wind.angle*says the opposite, for the same physical quantity. Description-only, ADDITION-level, kept as a separate commit so it can be split out and landed independently.Full argument, provenance and blast radius in #685 — including that the AIS round trip is already broken today because
n2k-signalkandsignalk-to-nmea2000disagree with each other.This PR should not merge until #685 is settled. If the RFC resolves the other way, these two commits come off and the rest of the PR stands on its own.
Downstream: SignalK/signalk-server#2943, SignalK/signalk-to-nmea2000#162.
npm testpasses (207).