Susi Server

Differential IMU

Node ID: differentialImu · Role: Filter · Realtime config: no

Description

Computes differential orientation between two IMU sensors (e.g. reference body and headset). Outputs transformed IMU data with the relative orientation removed.

Algorithm notes

What this node computes

The Differential IMU node is not a filter in the estimation sense - it carries no internal state estimate, no covariance, and no tuning gains. It is a deterministic per-sample frame subtraction: it removes the rotation rate of a moving platform from the rotation rate measured on a device riding that platform, so that downstream orientation estimators see motion relative to the platform rather than relative to the earth.

The classic use case is a headset inside a moving vehicle. The headset’s own gyroscope reports the sum of the wearer’s head motion and the vehicle’s motion. Subtracting the vehicle’s rate leaves head-relative rate, which is what a head-tracking pipeline should integrate.

Three frames are involved: the reference IMU’s own sensor frame (mounted on the vehicle or other moving body), the global frame shared by the tracking system, and the primary IMU’s sensor frame (on the headset). The reference rate is rotated from its mounting frame into the global frame using the configured static orientation, then rotated from global into the current headset frame using the headset’s live orientation, and finally subtracted from the primary gyroscope. Only the gyroscope is modified. Accelerometer, magnetometer, quaternion, Euler, timestamp, latency, and period fields pass through from the primary sample untouched - the node does not attempt to remove platform acceleration or centrifugal effects.

How the inputs are used

The node has three inputs and treats them asymmetrically.

The Primary IMU input is the clock. Every primary sample triggers one computation and one output sample, so the output rate and timestamps exactly match the primary stream.

The Reference IMU input is a latched value. Each arriving reference sample overwrites the stored angular velocity, and the most recent value is used whenever a primary sample arrives. There is no interpolation and no timestamp matching, so the reference rate applied to a given primary sample is up to one reference sample period old.

The Fused Pose input supplies the current headset orientation used for the global-to-headset rotation. Only orientation is read; position is ignored.

There is no explicit initialization phase and nothing converges. Before the first reference sample arrives, the stored reference rate is zero, so the output is simply a copy of the primary gyroscope. Before the first fused pose arrives, the headset orientation is treated as identity, so the subtraction is performed in the global frame instead of the headset frame - correct only while the headset happens to be aligned with global. Both effects vanish as soon as the first sample of each stream is received, typically within milliseconds.

Routing is by wire, not by sender name. The node distinguishes primary from reference purely by which input handle a source is connected to. An IMU arriving without a handle assignment is dropped and logged.

Parameters

There are only two user-facing settings, and they address separate concerns.

Mounting geometry. The reference orientation quaternion describes how the reference IMU is bolted to the moving body relative to the global frame. This is the only parameter that affects the numerical result, and it is the only one worth tuning. Its default is not identity - it encodes a specific mounting convention, so it must be revisited for any new installation.

Stream identity. The output sender identifier is stamped on emitted samples so downstream nodes can distinguish this differential stream from raw IMU sources. It has no effect on the math; change it only when several IMU streams would otherwise collide downstream.

Tuning and failure modes

Verify the mounting quaternion with a static test: with the headset held still relative to the vehicle, rotate the whole platform. A correct configuration drives the output gyroscope to near zero on all three axes. Residual on a single axis usually means a sign error in the quaternion; residual that swaps between axes as you change the direction of rotation means two axes are exchanged.

Known limitations to watch for:

Inputs / Outputs

Config aliases

DifferentialImuFilter, differentialImuFilter, differentialImu

Required feature

differential_imu_fusion

Properties

The following fields are exposed in the node’s Properties panel in the UI. Types map to UI widgets (e.g. string → text input, number → numeric, boolean → toggle, select → dropdown, json → JSON editor).

KeyLabelTypeDefaultDescription / Notes
referenceOrientationQuatReference Orientationquaternion{"w":1,"x":-1,"y":1,"z":1}Quaternion (w,x,y,z) rotating the reference IMU’s frame into the global frame. The reference IMU’s angular velocity is rotated by this, transformed into the headset frame, and subtracted from the headset IMU’s gyroscope so the output gyro is relative to the moving reference (e.g. a vehicle). Edit when the reference IMU is mounted at a different orientation.
outputSenderIdOutput Sender IDstringdifferentialImuSender identifier stamped on the output IMU stream, used downstream to distinguish this differential IMU from other IMU sources.

Example node definition

A full node definition in config.json looks like the block below. Paste it under the sinks key of your config, keyed by the node’s instance name (any identifier; it doesn’t have to match the node ID).

{
  "sinks": {
    "differentialImu": {
      "dataEndpoint": "inproc://differentialImu_data",
      "inputEndpoints": [
        "inproc://primaryImu_data",
        "inproc://referenceImu_data",
        "inproc://fusedPose_data"
      ],
      "inputDataFilter": [
        "Imu",
        "Imu",
        "FusedPose"
      ],
      "settings": {
        "outputSenderId": "differentialImu",
        "referenceOrientationQuat": {
          "w": 1,
          "x": -1,
          "y": 1,
          "z": 1
        }
      }
    }
  }
}

Field reference

FieldPurpose
dataEndpointEndpoint this node binds to publish its output. Omit to let the runtime generate one.
inputEndpointsList of upstream endpoints this node connects to (outEndpoint / dataEndpoint values from upstream nodes).
inputDataFilterOptional whitelist of data types. Messages whose type isn’t in the list are dropped at the subscriber.
settingsAll user-configurable fields — see the Properties table above.

Connections can also be declared at the top-level connections array when settings.explicitConnections is true, as an alternative to filling inputEndpoints on each node.

Loading documentation…