A depth camera bolted above the workspace reports every object in camera coordinates: millimetres from the sensor, axes aligned to the housing. The robot wants base coordinates. The bridge is one rigid transform, and because the camera already returns metric XYZ you can measure it directly — no calibration plate, no pose sweep. Touch three non-collinear points in the cell with a pointed tool, record each one as camera XYZ and robot XYZ, and solve tgt = [R|T]src. This guide covers the frames to log, the touch-off itself, the arithmetic of R and T, and the check point that says the result is good.
What you are actually solving
You want a 3 × 3 rotation matrix R and a 3 × 1 translation vector T, in millimetres, that turn any camera-frame point into a base-frame point:
R is orthonormal with det R = +1; T carries the offset between the two origins. The matrix stays constant while the camera and the robot base stay put: solve it once, then publish it as a static camera transform on the controller. At pick time the same matrix converts each detected object into a base-frame target, the step described in eye-to-hand object pose transform for robot picks.
Plate-and-pose hand-eye solvers reach the same matrix through many robot poses; camera to robot transform calibration: stop measuring by hand covers that route. When the camera already hands you metric 3D points, three touch-offs are the short path to the same answer.
What you need on the bench
Five things, in order of how often they get skipped:
- A depth camera with metric XYZ output. Stereo structured light, projected structured light, or a ToF camera with calibrated depth. If your pipeline starts from a raw depth image, convert pixels to XYZ first; depth map to real distance calibration for XYZ point clouds covers that step. A stereo structured-light unit such as the MV-DLS300P-04 or a projected structured-light model such as the MV-DPS200P-02 is the usual fixed-mount choice for a robot cell.
- Type
- Stereo / structured light
- Type
- Stereo / structured light
- A rigid mount. Every 0.1 mm the camera shifts after calibration becomes 0.1 mm of permanent pick error. A heavy camera stand such as the LS-MNT-0040 machine vision camera stand holds its position against knocks. Lock the optics too: calibrate a camera with autofocus by locking the focus first, because refocusing after calibration invalidates the transform.
- Type
- Camera stands
-
Coverage. Check the field before you commit to marks. A camera at 900 mm with a 60° horizontal field covers 2 × 900 × tan(30°) ≈ 2 × 900 × 0.577 ≈ 1,040 mm, so a 700 × 500 mm workspace fits with about 170 mm of margin per side. All three marks, the robot approach, and the parts you will pick must sit inside that footprint.
-
A pointed tool tip with a taught TCP. A nylon or brass cone, sharpened so the contact point repeats better than your pick tolerance. Teach the TCP on it with the pendant's multi-point method before you log anything.
-
One program for both devices. Drive the robot and read the camera from the same script — C#, Python, whatever the cell uses — so poses are logged, never transcribed by hand.
Capture the three point pairs
Placement decides the quality. Spread the three marks with legs at least a third of the workspace diagonal — the 700 × 500 mm example gives sqrt(700² + 500²) ≈ 860 mm, so legs of 290 mm or more — and keep every interior angle of the triangle above 30°. The reason is conditioning: 2 mm of lateral touch error on a 300 mm leg becomes 2 ÷ 300 = 0.0067 rad of rotation, which displaces picks by 0.0067 × 800 ≈ 5.3 mm at 800 mm from the centroid. Doubling the leg length halves that term.
- Teach the TCP on the pointed tip and select that tool as active on the controller.
- Mark three points in the workspace: centre-punched dimples, scribed crosses, or small adhesive rings on rigid surfaces the robot can reach.
- Place them wide: legs at least a third of the diagonal, angles above 30°, and none of the three close to the line through the other two.
- Fix the frame convention. Log the TCP position in base coordinates at every touch. If your interface exposes only the flange pose, add the TCP offset before saving; mixing the two frames is the most common way this calibration fails, as matching tool0 to the sample shows.
- Read the camera side. Click the pixel at the centre of each mark in the depth image and take the median of a 5 × 5 pixel patch, per axis, in millimetres.
- Touch each mark with the tip at reduced speed and record the robot XYZ of the TCP in the same file.
- Save the session — pairs, robot poses, camera settings — so you can replay it later, the workflow in hand-eye calibration pose capture: sample once, replay.
Solve R and T from the pairs
Three exact pairs have a closed-form solution you can check by hand: build a right-handed frame at the first point of each set, shown below. Three or more pairs with noise go through the Kabsch algorithm — the unique closed-form rigid fit in the least-squares sense, built on one singular value decomposition:
With noise-free pairs the fit is exact and the root-mean-square deviation is zero. With six or more pairs, Kabsch minimises that deviation and hands you a per-point residual — the number you will use to accept or reject the calibration. The SVD machinery is the same as in plane fitting on 3D point clouds: least squares vs RANSAC; if one touch is badly off, drop that pair or fit with RANSAC instead of averaging the mistake in.
Worked example: three pairs over a 700 × 500 mm workspace
Camera at 900 mm looking down, marks on the fixture plate, all values in millimetres:
| Pair | Camera XYZ (src) | Robot XYZ (tgt) |
|---|---|---|
| P1 | (400, 100, 900) | (400, 1200, 50) |
| P2 | (700, 100, 900) | (400, 900, 50) |
| P3 | (400, 400, 900) | (700, 1200, 50) |
Build a local frame at P1 in camera coordinates. The x-axis runs from P1 to P2: (300, 0, 0) ÷ 300 = (1, 0, 0). The z-axis is the triangle normal: (300, 0, 0) × (−300, 300, 0) = (0, 0, 90,000), normalised to (0, 0, 1). The y-axis completes the triad: (0, 0, 1) × (1, 0, 0) = (0, 1, 0). Stacked as columns, M_src is the identity.
The same construction at Q1 in robot coordinates gives the axes. x: (Q2 − Q1) ÷ 300 = (0, −300, 0) ÷ 300 = (0, −1, 0). z: (0, −300, 0) × (300, 0, 0) = (0, 0, 90,000), again (0, 0, 1). y: (0, 0, 1) × (0, −1, 0) = (1, 0, 0). Stacked as columns, M_tgt = [[0, 1, 0], [−1, 0, 0], [0, 0, 1]].
R = M_tgt · M_src^T = M_tgt, a rotation of −90° about the z-axis. Then the translation:
Check it back through the pairs. R · P2 + T = (100, −700, 900) + (300, 1600, −850) = (400, 900, 50), which is Q2. R · P3 + T = (400, −400, 900) + (300, 1600, −850) = (700, 1200, 50), which is Q3. The fit closes exactly, as it must with three noise-free pairs.
Now the honest test: touch a fourth mark the fit never saw. The camera reads P4 = (550, 250, 900), so the transform predicts (550, 1050, 50). The robot measures (551, 1048, 52). The residual is sqrt(1² + 2² + 2²) = 3 mm. With a 10 mm pick tolerance and the acceptance rule of residual at most one third of tolerance (3.3 mm), this calibration ships.
Check the result before the first pick
- Fourth-point check. Touch a mark that was not in the fit and compare, as above. Accept when the residual is at most one third of your pick tolerance.
- Round trip on a real part. Place a part, detect it in the depth image, transform the pick point, and send the robot there with the gripper open. The tip should land on the feature you selected in the image.
- Publish and re-check. Load the matrix as a static frame — publishing an eye-to-hand calibration as a static camera transform — then let base-frame picks from the calibration results run the cell. Re-run the fourth-point check weekly and after any collision.
Common mistakes and their fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Every pick off by the same vector | Metres logged against millimetres, or an arithmetic slip in T | Convert to millimetres at import; recompute T = Q1 − R·P1 |
| Error small near the marks, large at the far side | Rotation error from short legs or one bad touch | Re-touch with a wider spread; add pairs and refit |
| Residual tiny, picks off by the tool length | Flange pose (tool0) logged instead of the TCP | Re-log in the TCP frame, or add the TCP offset to every point |
| Good on Monday, drifted by Friday | Stand knocked, focus crept, robot base moved | One check touch-off; recalibrate past one third of tolerance |
| Camera patch jumps between touches | Mark sits on an edge, a hole, or a projector hotspot | Move the mark, or widen the median patch until its spread is steady |
When three points are not enough
Three pairs give you no quality metric: the fit is exact by construction, so it hides its own noise. Move to six or more pairs when your pick tolerance is tighter than about three times the fourth-point residual you measured. Least squares averages the random part, and going from 3 to 12 pairs roughly halves it, because independent noise shrinks with the square root of the pair count. Systematic errors do not average out — a mismeasured TCP or a flexing stand shifts every pair the same way, so fix those at the source.
Two neighbouring cases take different tools. If the camera can move or the intrinsics may change, run a full hand-eye solve over robot poses instead; camera above the robot base: eye-to-hand calibration setup covers placement and coverage planning. And if the cell has only a 2D area scan camera, there is no third coordinate to touch with: map image points onto one known plane with a homography, or run a target-based hand-eye solve, and keep the point-pair method for the depth camera.
Checklist before the first autonomous pick
- TCP taught on the pointed tip; the logged frame is the TCP, not the flange
- All values in millimetres, one file, robot poses included
- Legs at least a third of the workspace diagonal; interior angles above 30°
- Focus and exposure locked before the first touch-off
- Camera XYZ read as the median of a 5 × 5 pixel patch
- R orthonormal with det R = +1; every calibration pair reproduces within rounding
- Fourth-point residual at most one third of the pick tolerance
- Transform published as a static frame; weekly check touch scheduled
The camera side starts in 3D sensors and the 3D camera finder. Send your workspace numbers through the contact page and we will run the coverage arithmetic and stand choice with you. More depth-camera workflows sit on the 3D vision topic page.
Laser profilers and stereo 3D cameras
170 models · from $699.00Questions
Why exactly three point pairs and not two?
Two points fix only a line: rotation about that line stays free, so picks to either side swing. One point fixes translation only. Three non-collinear points fix all six degrees of freedom with a unique rigid transform. More pairs do not change the geometry, they average out touch error and depth noise, and they hand you a residual you can act on.
Should the robot points come from the TCP frame or tool0?
Log the TCP position in base coordinates: the pose your controller reports with the pointed tool active. Reading the tool0 flange pose instead shifts every robot point by the TCP offset and skews the rotation if the tip sits off the flange axis. Whatever you log, the solved transform maps camera coordinates into that same frame, so keep the choice identical for calibration and for runtime picks.
How do I read the camera XYZ of a touched point cleanly?
Click the pixel at the centre of the mark in the depth image, then take the median of a 5 × 5 pixel patch on each axis rather than a single pixel: the median rejects the half-and-half pixels where the mark meets the surface. Reject the patch when its spread is more than about three times the noise you measure on a flat plate, because that means the patch straddles an edge or a hole.
Can I run this calibration with a plain 2D camera?
Not with this method: every touched point needs a metric XYZ, and a 2D camera has none. On a single known plane a homography maps image pixels to robot XY and is enough for flat parts on a conveyor. For full 3D picks you would add a target-based hand-eye solve over many robot poses. Point pairs are the direct route only when a depth camera already gives metric points.
How accurate will picks be after a three-point calibration?
The random part combines as the root of the sum of squares: depth noise on the patch, touch repeatability at the mark, and the rotation term set by leg length. With 2 mm of touch error on 300 mm legs, the rotation term alone is about 5 mm at 800 mm from the centroid. Doubling the leg length halves it; going from 3 to 12 pairs halves the random part again.
How often should I redo the calibration?
Redo it after anything that can move the camera or the robot base: a collision, a bumped stand, a refocused or swapped lens, a relocated cell. Between events, run a single check touch-off on a fixed mark weekly; if the residual exceeds one third of your pick tolerance, recalibrate. A rigid mount and locked focus keep a good calibration stable for months.


