IMU-Optical Intercalibration
Node ID: imuOpticalIntercalibration · Role: Sink · Realtime config: no
Description
Estimates the rotation alignment between an IMU and an optical tracking sensor. Run this to compute the calibration quaternion, then apply results to the IMU-Optical Fusion filter.
Algorithm notes
How it works
This node watches two synchronised pose streams and works out the fixed rotation (and, in Hand-Eye mode, the translation) between the two coordinate frames they report in. It collects sample pairs while you move the tracked object by hand, keeps only the pairs that are clean and far enough apart from each other, and solves once it has enough well-distributed motion. The result is reported back to the UI as a quaternion (plus a translation for Hand-Eye), which you then enter into the fusion node that needs it. The node produces no data output of its own - it is a calibration tool, not part of the live pipeline.
What you must configure
Calibration Type decides everything else about the node, including which input handles appear.
- IMU to Optical takes one IMU stream and one optical stream from the same rigidly mounted device. It recovers only the rotation between the IMU axes and the optical body axes.
- Hand-Eye takes two pose sources, one on each side (either an optical stream or a fused pose on each). It recovers the full rigid transform - rotation and translation - between the two attached frames. Use this when you need the position offset too, or when neither side is a raw IMU.
Wire the inputs deliberately. In Hand-Eye mode the A and B handles are not interchangeable: the result describes the transform from the A frame to the B frame, so swapping them gives you the inverse.
How it starts
Nothing is collected until you press Start. Incoming samples before that are ignored, and the node sits idle after a restart until you start it again. Start also clears any previous result, so a second run always begins from scratch. While running, the node reports live progress: how many pose pairs it has gathered, how they are spread across the three rotation axes, and how many were rejected. It stops by itself the moment it has a valid solution; Stop pauses collection and Reset throws the collected data away.
Tuning
There is nothing to tune here beyond Calibration Type - the quality of the result comes from how you move, not from settings. Rotate the device slowly and smoothly, pausing between distinct orientations, and make sure you cover all three axes: yaw, pitch and roll. Roll is the one people forget, and a run with little roll will simply never finish.
Troubleshooting
- Progress counters stay at zero - both inputs are not wired, or you never pressed Start. In Hand-Eye mode check that both A and B handles are connected.
- Pose count climbs but the run never finishes - one rotation axis is under-covered. Watch the per-axis progress and deliberately roll the device around the axis that is lagging.
- Many samples rejected for fast motion - you are moving too quickly. Move between poses, then hold still for a moment before moving again.
- Many pairs rejected for timestamp mismatch - the two streams are not time-aligned. Check that both sources are running and that neither is lagging behind the other.
- Many pairs rejected as inconsistent - the two streams disagree about how far the device rotated. This usually means wrong gyro units or scaling on the IMU side, or a large delay between the streams. Check the sensor’s configuration before recalibrating.
- The result looks like the opposite of what you expect - the inputs are swapped. Swap the two sources between the A and B handles and run again.
Inputs / Outputs
- Inputs:
Imu,Optical,OpticalA(Optical) - Optical A,OpticalB(Optical) - Optical B,FusedPoseA(FusedPose) - FusedPose A,FusedPoseB(FusedPose) - FusedPose B - Outputs: (none)
Config aliases
ImuOpticalIntercalibrationFilter, imuOpticalIntercalibration
Properties
Each row shows the setting’s label in the node’s Properties panel and, in code, its key in the node’s settings object in the config file. A setting omitted from the config file uses the default shown here.
| Property | Type | Default | Description |
|---|---|---|---|
Calibration Type type | select | imuOptical | Which inter-calibration to run. ‘IMU to Optical’ recovers the rotation between an IMU-derived orientation stream and an optical stream using gyro integration. ‘Hand-Eye’ solves AX = XB between two pose sources, recovering the full rigid 6-DOF transform (rotation and translation) between the two attached coordinate frames. Options: imuOptical, handEye. |
Example node definition
A minimal entry in config.json looks like the block below. Paste it under the sinks key, keyed by an instance name of your choice. All settings are optional: anything not listed under settings uses the default from the Properties table above. See The configuration file for how the sections and endpoint wiring work.
{
"sinks": {
"imuOpticalIntercalibration": {
"inputEndpoints": [
"inproc://imu_data",
"inproc://optical_data",
"inproc://opticalA_data",
"inproc://opticalB_data",
"inproc://fusedPoseA_data",
"inproc://fusedPoseB_data"
],
"inputDataFilter": [
"Imu",
"Optical",
"Optical",
"Optical",
"FusedPose",
"FusedPose"
],
"settings": {}
}
}
}