Skip to the lesson
FixTheRobot Home / VLA / Phase 9 / 9.3

VLA · Phase 9 · VLA Deployment and Robot Integration

9.3 — Coordinate Frames and Camera Calibration

Keeping image, robot and world coordinates consistent.

  • Roadmap phase 9
  • VLA Deployment and Robot Integration
  • About 13 minutes to read

A grasp is only as accurate as the geometry behind it. This lesson shows how a point moves between frames, how a camera maps points to pixels and how fast small calibration errors grow.

Claims about papers, models and textbooks carry numbered references, listed with what each one is cited for in the References. Code marked “Toy model” is our own illustration, not the cited system.

Learning objectives

After this lesson, you should be able to:

  • Transform a point between camera and robot frames.
  • Project and back-project with a pinhole camera.
  • Compute the sideways error of a small orientation error.
  • Explain why a moved camera breaks a learned policy.
  1. The camera sees a point in its own frame
  2. Calibration gives base_from_camera
  3. Transform the point into the base frame
  4. Plan the motion in the base frame
  5. Recalibrate when the camera moves
Frames and calibration.

The one-sentence idea

Every number needs a frame; every frame needs a calibrated transform.

Small angular errors become large position errors.

Where is it, in whose coordinates?

“The cup is at (0.3, 0.1, 0.0)” means nothing until you say measured from where, with which axes. A camera sees the world in its own frame; the robot arm moves in the base frame; a gripper has its own frame. Everything a robot does with vision needs the transformations between them (you met frames in the kinematics prerequisites). If the transformation between the camera and the robot base is wrong by a few centimetres, a grasp that is perfect in the image misses in the world. This lesson shows how such errors arise, how large they get and how calibration fixes them.

Moving a point between frames

A rigid transformation is a rotation plus a translation. In the common 4×4 homogeneous form it can be composed by matrix multiplication. Suppose the camera looks down at the table from above, offset from the robot base. A point seen by the camera becomes a point in the base frame:

import numpy as np

def transform(rotation_deg_about_z, translation):
    a = np.radians(rotation_deg_about_z)
    T = np.eye(4)
    T[:2, :2] = [[np.cos(a), -np.sin(a)], [np.sin(a), np.cos(a)]]
    T[:3, 3] = translation
    return T

base_from_camera = transform(90, [0.5, 0.0, 0.8])             # camera pose in the base frame: turned 90 degrees, 0.5 m forward, 0.8 m up
point_in_camera = np.array([0.1, 0.2, -0.8, 1.0])             # a cup seen by the camera (homogeneous point)

point_in_base = base_from_camera @ point_in_camera
print("cup in the camera frame:", point_in_camera[:3].tolist())
print("cup in the robot base frame:", np.round(point_in_base[:3], 3).tolist())
print("going back gives the original:", bool(np.allclose(np.linalg.inv(base_from_camera) @ point_in_base, point_in_camera)))

Output:

cup in the camera frame: [0.1, 0.2, -0.8]
cup in the robot base frame: [0.3, 0.1, 0.0]
going back gives the original: True

Toy model. A camera pose invented for the example. The pose of a real camera comes from calibration.

Name transformations as “base_from_camera” (it maps camera coordinates to base coordinates): the name tells you which way a point travels and prevents the classic mistake of using the inverse.

From pixels to rays: the camera model

A pinhole camera projects a 3D point (X, Y, Z) in the camera frame to pixel coordinates u = f·X/Z + cx, v = f·Y/Z + cy. The numbers f (focal length in pixels) and cx, cy (the image centre) are the intrinsic parameters. A single pixel does not give a 3D point, only a ray: you need depth to complete it.

import numpy as np

f, cx, cy = 600.0, 320.0, 240.0                                # intrinsic parameters (pixels)

def project(P):
    X, Y, Z = P
    return np.array([f * X / Z + cx, f * Y / Z + cy])

def back_project(u, v, Z):
    return np.array([(u - cx) * Z / f, (v - cy) * Z / f, Z])

P = np.array([0.10, -0.05, 0.80])
pixel = project(P)
print("pixel:", np.round(pixel, 1).tolist())
print("back-projected with the right depth:", np.round(back_project(*pixel, 0.80), 3).tolist())
print("back-projected with 5 cm too much depth:", np.round(back_project(*pixel, 0.85), 3).tolist())

Output:

pixel: [395.0, 202.5]
back-projected with the right depth: [0.1, -0.05, 0.8]
back-projected with 5 cm too much depth: [0.106, -0.053, 0.85]

A depth error of 5 cm moves the recovered point sideways too, by about 0.6 cm here. Calibration is what supplies f, cx, cy and lens distortion. A classic method (Zhang) has the camera observe a planar pattern in at least two different orientations (the motion need not be known), then solves in closed form and refines by maximum likelihood, including radial lens distortion.[1]

How big does a calibration error get?

Small angular errors become large position errors at a distance. If the camera's orientation is off by 1 degree, a point at distance d is mislocated sideways by about d × tan(1°):

import numpy as np

for degrees in (0.5, 1.0, 2.0):
    for d in (0.5, 1.0, 2.0):
        error_cm = d * np.tan(np.radians(degrees)) * 100
        print(f"orientation error {degrees} deg, object {d} m away -> {error_cm:4.1f} cm sideways error")

Output:

orientation error 0.5 deg, object 0.5 m away ->  0.4 cm sideways error
orientation error 0.5 deg, object 1.0 m away ->  0.9 cm sideways error
orientation error 0.5 deg, object 2.0 m away ->  1.7 cm sideways error
orientation error 1.0 deg, object 0.5 m away ->  0.9 cm sideways error
orientation error 1.0 deg, object 1.0 m away ->  1.7 cm sideways error
orientation error 1.0 deg, object 2.0 m away ->  3.5 cm sideways error
orientation error 2.0 deg, object 0.5 m away ->  1.7 cm sideways error
orientation error 2.0 deg, object 1.0 m away ->  3.5 cm sideways error
orientation error 2.0 deg, object 2.0 m away ->  7.0 cm sideways error

A 1-degree error puts a point 1 m away 1.7 cm off, enough to miss a small object. This is why calibration quality, camera mounting stiffness (a camera that is bumped loses its calibration) and checking the calibration regularly matter more for learned policies than they might seem: the policy learned the geometry of its training setup.

Why frames matter for VLAs in particular

A VLA trained on a dataset implicitly learned that dataset's camera placement and action frame. Move the camera, or change the axes of the action (lesson 4.1), and the same pixels now mean different motions, with no error message. Pooled datasets, like the 22-embodiment Open X-Embodiment data,[2] make these differences explicit work for the dataset builders. For you: record the camera pose with every dataset, check it at deployment, and treat a changed camera as a changed robot.

Common misconceptions

Misconception 1 “A pixel gives a 3D point.”

Correction A pixel gives a ray; depth completes it.

Misconception 2 “Calibration is done once.”

Correction A bumped or shifted camera needs recalibration.

Misconception 3 “A learned policy does not need calibration.”

Correction It silently learned its training setup’s geometry.

Engineering takeaways

  1. Name transforms afrom_b.
  2. Pinhole: u = fX/Z + cx.
  3. 1° at 1 m is 1.7 cm.
  4. Treat a moved camera as a changed robot.

Say which frame, every time.

Knowledge check

Try each question first, then reveal the explanation.

Question 1

What does base_from_camera map?

Explanation

Points in camera coordinates to base coordinates.

Question 2

A 2° orientation error at 1 m: sideways error?

Explanation

About 3.5 cm.

Question 3

Why do you need depth to recover a 3D point from a pixel?

Explanation

A pixel only defines a ray.

References

Numbered notes in the text, like [1], point here. Each entry says what it is cited for and how that was checked. Papers and books can be revised or misread, so follow the links before relying on a detail. Code marked “Toy model” is our own illustration of an idea, not the code of the cited system.

  1. Zhang, Z. (2000). A flexible new technique for camera calibration. IEEE Transactions on Pattern Analysis and Machine Intelligence 22(11), 1330–1334.

    Cited for:

    • Calibrates a camera by observing a planar pattern shown in at least two different orientations (the motion need not be known); a closed-form solution is refined by a nonlinear maximum-likelihood step, and radial lens distortion is modelled. Checked against the paper’s abstract.
  2. Open X-Embodiment Collaboration (2023). Open X-Embodiment: Robotic learning datasets and RT-X models. arXiv:2310.08864

    Cited for:

    • Pools more than one million robot trajectories from 22 robot embodiments, assembled by 21 institutions and covering 527 skills. Checked against the paper’s abstract.

What’s next

Next: joint limits and collision checking.

Next lesson

9.4 — Joint limits and collision checking

Rejecting or adjusting actions that would be unsafe or impossible.

Back to the VLA roadmap