System designHow-to

Camera to odometry extrinsics: calibration with a checkerboard jig

Calibrate the camera to odometry extrinsics on a mobile robot: build a docking jig, run the checkerboard calibration, chain them and validate the result.

LumaSpec Vision11 min read Share on LinkedIn

On this page 9 sections
  1. 01Camera to body or camera to odometry: which pair do you calibrate?
  2. 02Why not just copy the transform out of the CAD model?
  3. 03What does the checkerboard jig method actually compute?
  4. 04How do you build a docking jig that repeats?
  5. 05How many pixels does the checkerboard need?
  6. 06What are the calibration steps, in order?
  7. 07How do you validate the extrinsics before trusting them?
  8. 08When is the jig the wrong tool?
  9. 09Questions

A mobile robot with a fixed external camera needs one transform before any detection becomes useful: where the camera sits relative to the robot's own frame. Get it wrong and every projected obstacle lands in the world with the same offset and tilt. This how-to walks the calibration that works when there is no arm to wave and no joint encoders to record. Dock the robot to a repeatable checkerboard jig, solve the board-to-camera pose, chain it with the jig-measured robot-to-board pose, and validate against a marked feature. The method fits warehouse AMRs, inspection platforms and any rig with the camera bolted to the chassis. You finish with a robot_T_camera transform, an error budget in millimetres, and a dock-and-shoot check that reruns in under a minute.

Camera to body or camera to odometry: which pair do you calibrate?

Calibrate the physical mount. The constant you want is body-to-camera, because the odometry frame drifts with wheel slip and a camera-to-odometry number goes stale the moment the robot moves.

Wheel odometry on a smooth indoor floor typically accumulates 0.5 to 2 percent of distance travelled as position error. That drift is exactly what separates the odometry frame from the body frame. Deliver body-to-camera, publish it as a static transform with the body frame as parent, and let the runtime chain multiply the live body-in-odometry estimate on top when camera data is needed in the world. Publishing a fixed camera this way follows the same pattern as publishing eye-to-hand calibration as a static camera transform, just with a docking jig in place of arm poses.

Why not just copy the transform out of the CAD model?

Use CAD as the starting seed only: mount tolerances stack, and a 0.5° tilt shifts the view centre by about 26 mm at a 3 m working distance, since tan 0.5° × 3000 mm ≈ 26 mm.

The model is exact; the assembly is not. A bracket slotted with 1 mm of clearance, a camera base seated 1 mm off its face, and half a degree of lens squareness already spend most of a perception budget. Keep the CAD number as a sanity band around the solve: if the checkerboard solve lands more than 5° or 100 mm from the seed, suspect a folded board frame or a wrong corner origin, not the mount. The case against hand-measuring a mount is made in camera to robot transform calibration: stop measuring by hand, for the arm version of the same problem.

What does the checkerboard jig method actually compute?

The method chains two measured transforms: robot_T_target, the board's pose in the robot frame, held by mechanical docking; and target_T_camera, the board-to-camera pose a checkerboard solve returns for the docked shot. One matrix product gives robot_T_camera.

robot_T_camera = robot_T_target × target_T_camera camera_T_robot = inverse(robot_T_camera)

robot_T_target comes from the jig: the board origin is a defined corner, and during jig commissioning you measure that corner against the dock stops and the floor datum with calipers and a height gauge. Machined stops hold ±0.5 mm in translation and ±0.1° in yaw. target_T_camera comes from software: a solvePnP-style checkerboard solve, which needs calibrated intrinsics — fix those first, as camera intrinsics for hand-eye calibration: fix the pose first explains.

How do you build a docking jig that repeats?

Aim for a jig that puts the robot back within ±1 mm and ±0.1°: two orthogonal contact stops fix position and yaw, the floor fixes height, and a board bonded to flat aluminium composite panel stays planar to a fraction of a millimetre.

Build the frame from aluminium extrusion and dock the robot from two sides: a front stop the bumper or rollers touch, and a left stop that kills yaw. The numbers agree — a 600 mm body yawed by 0.1° swings 1.05 mm across that width, the same order as the ±1 mm translation budget. Give the stops a defined contact: hard faces at a fixed approach speed, or a ramp the robot settles against. Print the target 9 × 6 inner corners at 30 mm, laminate it onto 3 to 4 mm composite panel, check it with a straightedge, and mark one corner so the board frame cannot fold 180°.

How many pixels does the checkerboard need?

Give every square at least 50 pixels on the long side and let the board fill a third of the frame or more: with 30 mm squares spanning 100 px, a 0.3 px corner error is 0.09 mm, invisible next to a ±1 mm dock.

Corner detection localises each inner corner to roughly 0.1 to 0.3 px, so pixel size at the board sets your noise floor. Board size also feeds distance: a solvePnP solution turns board size into range, so a print 2 percent undersized reads as 2 percent too far.

Worked example, using the jig above: a 1/1.7-inch sensor — about 7.2 mm across the active width, 4000 pixels wide — behind a 12 mm lens, docked 700 mm from the board.

FOV = WD × sensor width / focal length = 700 mm × 7.2 mm / 12 mm = 420 mm scale = FOV / pixels across = 420 mm / 4000 px = 0.105 mm per px pixels per 30 mm square = 30 / 0.105 ≈ 286 px

The 240 × 150 mm corner grid then spans about 2286 × 1429 px, 57 percent of the frame width and comfortably over the one-third rule. Corner noise of 0.3 px is 0.03 mm at the board. Shoot at 5 ms and around f/4 under a small front light: the scene is static, so blur follows floor vibration alone, and one pixel costs 0.105 mm of motion in 5 ms — about 21 mm/s of deck movement. Suspended decks move faster than that; autofocus vs fixed focus lenses on mobile robots: vibration and blur quantifies the same effect at driving speed.

Cameras that fit those numbers, one parked-still pick and one for a deck that creeps:

The LS-CMR-0166 resolves 4000 × 3000 pixels at 30 fps over USB3 on a 1/1.7-inch sensor.

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

The MV-CU020-90GC is a 2.5 MP GigE camera with a 1/1.7-inch sensor, global shutter and C-mount.

Area scan camerasHikrobot MV-CU020-90GC 2.5 MP Area Scan Camera, GigE, GMAX4002, ColorMV-CU020-90GC
Sensor format
1/1.7"
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
$309.00View partBuild a system with it

Check your own dock distance, lens and target the same way with the resolution calculator:

Camera resolution for the smallest feature
Units
Pixels needed
–
Sensor size
– MP
Smallest sensor that fits
–
Pixel on the part
– mm
Pixels across the feature, that sensor
–

Pixels needed = field / feature × pixels per feature on each axis (field incl. margin). The lens must resolve the pixels too: Nyquist = 1000 / (2 × pixel µm) lp/mm.

Find cameras with enough pixels Open the full calculator

What are the calibration steps, in order?

Eight steps cover it: solve intrinsics first, lock the focus, measure the jig, dock, shoot the board five times, average the board-to-camera solves, multiply the two transforms, and publish the result as a static body-to-camera transform.

Run the intrinsics session at a bench before the robot work starts. Fix the camera to a stand — the LS-MNT-0040 camera stand holds it at up to 700 mm on a 400 × 450 mm base. At that height you can present the board at 15 to 25 tilted poses across the frame without tripod gymnastics. No stand yet? The camera stands category or the stand step of the configurator sizes one to the bench.

Camera standsMachine vision camera stand, professional slide-table type, height 700 mm, 400 x 450 mm base (LS-MNT-0040)LS-MNT-0040
Type
Camera stands
$629.00View partBuild a system with it
  1. Solve intrinsics at the bench: 15 to 25 board images, tilted, covering every region of the frame; re-projection error below about 0.5 px is the target.
  2. Lock the optics: tape the focus ring and stop the aperture down so focus holds across the board depth. An autofocus lens must be pinned — calibrate a camera with autofocus: lock the focus first shows why.
  3. Measure robot_T_target during jig commissioning: calipers and height gauge from the dock stops and floor datum to the marked board origin; record all six values, expecting ±0.5 mm and ±0.1°.
  4. Dock the robot, switch the light on, and shoot five to ten board images at the 5 ms exposure; confirm corners detect on every shot before undocking.
  5. Solve target_T_camera for each image with a solvePnP-style checkerboard solve; OpenCV's camera calibration tutorial walks the intrinsics and pose calls.
  6. Average the solves: translations component-wise; average the rotation by quaternion-vector averaging and renormalise — safe here because the spread sits far under a degree.
  7. Compose robot_T_camera = robot_T_target × target_T_camera and publish it as a static transform with the body frame as parent.
  8. Run the validation tests below, and ship the calibration only when both pass.

How do you validate the extrinsics before trusting them?

Accept the calibration when a marked jig feature lands within 2 mm of its measured robot-frame position and five repeat docks reproduce the board-to-camera solve within ±1 mm and ±0.1°: a bigger spread means the jig, not the maths, is the error.

Test one, dock spread. Dock five times, solving target_T_camera from each shot; max-minus-min must stay inside ±1 mm and ±0.1° of yaw. When it does not, the solver is not the problem — check stop faces, approach speed, tyre contact and board bonding.

Test two, re-projection. During jig build, mark a point on the jig structure that lies in the board plane and measure it against the same datums to ±0.5 mm. After calibration, undistort that point's pixel, cast the camera ray, intersect the board plane, and compare robot-frame XY with the measurement. Judge in millimetres, not pixels: in the example optics 2 mm is 2 ÷ 0.105 ≈ 19 px, which is why pixel judgements mislead here. Beyond the board plane the yaw term grows linearly — 0.1° is about 1.7 mm per metre of range — so set distant-feature expectations on that scale.

Test three, system check. Run a closed loop and compare the camera's tracked trajectory against odometry: matching shapes with a near-constant offset and rotation is the signature of residual extrinsic error plus odometry scale error. It mixes drift in, so it stays a sanity check and never replaces the millimetre tests. The logic mirrors eye-to-hand calibration: verify the camera-to-base result, for a fixed camera watching a robot.

When is the jig the wrong tool?

Skip the jig when the camera moves with the mechanism it serves: an arm-mounted camera is the hand-eye problem, and a one-off cell is often better served by a CAD seed plus the validation test, which settles the error budget within an hour.

For a camera on a robot arm, there is nothing to dock: the transform lives between flange and camera, and the data that solves it is joint angles paired with board poses across many arm positions. That input set — the same robot pose and frame pairs collected per pose — is eye-in-hand calibration inputs: the same robot pose and frame pairs.

The calibration literature does describe joint estimation that solves odometry and camera together from wheel-encoder data and board snapshots, and camera-plus-LiDAR rigs have their own target-based methods. Those routes work, but they add solver sensitivity and seeding problems, and for a fixed camera they rarely beat a repeatable mechanical dock.

Decision, by rig: parked camera with room to dock — build the jig; it is an afternoon of extrusion and a rerunnable check. Camera on an arm — hand-eye calibration from joint poses. One-off cell — CAD seed, then the 2 mm re-projection test; upgrade only if it fails. Camera plus LiDAR — a target-based multi-sensor solve. Once the transform passes, project detections onto the ground the way camera frame to servo frame: one plane, one affine transform does, and every detection lands on the map.

Next step: choose the camera and the bench stand together, because the pixel budget and the intrinsics session both hang on them. The camera step of the configurator pairs sensor, interface and lens, the accessories finder narrows stands by type, and the systems topic collects the rest of the calibration walks. If your dock geometry is unusual, contact us with the layout and the numbers, and we will check the budget with you.

Questions

Can I get the transform without building a jig?

Yes, as a first pass: read the pose out of the CAD assembly, refine it with a tape measure against datum features, and run the re-projection test described above. Expect millimetre-to-centimetre error at the board and proportionally more at range. That is often enough for obstacle projection. Move to the jig when the residual exceeds the application's budget, or when a fleet of identical robots needs one repeatable procedure.

How many board images does each stage need?

For intrinsics, 15 to 25 images with the board tilted and placed in every region of the frame, corners included; a board that only sits centre-frame makes focal length absorb distortion. For extrinsics the robot holds one pose, so shoot five to ten dock repeats and average: ten repeats cut random corner noise by roughly a factor of three, the square root of ten.

What square size should the checkerboard print at?

Work backwards from docked distance and focal length so each square keeps at least 50 pixels. In the worked example, 30 mm squares give about 286 px at 700 mm with a 12 mm lens; even 10 mm squares would hold 95 px and still solve well. Print laser-sharp and check the pitch with calipers: a board 2 percent undersized reads as 2 percent too far.

Does rolling shutter ruin calibration images?

Not when the robot is parked and the board is fixed, because rolling shutter artefacts need scene motion during the line-by-line readout. They matter if you calibrate on a moving lift, a suspended deck, or reuse driving footage; then pick a global shutter sensor or drop exposure to about 1 ms so the smear stays under a pixel. The 30 fps LS-CMR-0166 solves cleanly on a parked robot with its rolling shutter.

How should the finished transform be published at runtime?

Publish it as a static transform with the robot body frame as parent and the camera frame as child, and multiply the live odometry estimate on top whenever camera data is needed in the world frame. Never bake odometry into the static value: wheel drift would freeze yesterday's error into today's geometry. Recompute the static transform only after mechanical work on the mount or the jig.

How often does the calibration need redoing?

Only after mechanical change: a bumped bracket, a refocused or swapped lens, a new board, or jig repair. The mount does not drift electrically, and temperature is a non-issue at this scale — a 700 mm aluminium column grows about 0.016 mm per °C at aluminium's 23 µm/m·K, far under the budget. Rerun the dock-and-shoot check after any collision and the marked-feature test monthly on racking duty.