Your camera job finds the part, the calibration in your newly taught plane passes, and then the move after the job refuses to run in that plane — it only works in base. This is the fixed-camera trap: the camera stack reports every result in the robot base frame, and a MoveL set to a custom feature applies the plane transform on top of numbers that never needed it. The fix is not another calibration. Keep the plane, read the camera result from your own program, and convert it once so the plane move receives plane coordinates. Below is the arithmetic, the pose composition, the hardware that keeps the frames stable, and the checks to run before you trust the move at speed. It is written for a camera fixed above the workspace; a camera on the arm has a different fix, linked near the end.
Why the plane move lands in the wrong place
A move programmed in a feature reads its target in that feature's frame: before the axes move, the controller adds the plane's origin and rotates by the plane's orientation. Your camera result already carries one conversion, camera to base, done inside the camera stack. Set the move to the plane and the controller applies a second transform, plane to base, on top. Two transforms where one belongs: the target lands a full plane offset away from the part. That is the whole failure, and it is why the same job works the moment you switch the move back to base.
Count the conversions and keep exactly one between the camera result and the motion target. In practice: drop the ready-made move step, open the result connection yourself, and convert the single vision point into the plane. The alternative, leaving the feature at base for that move, is legitimate when nothing else in the program needs the plane.
| Route | Conversions applied | What you script | Use it when |
|---|---|---|---|
| Vendor move step, move in base | Camera to base, inside the camera stack | Nothing | Every target can run in base |
| Recalibrate the job in the plane, move in the plane | Camera to base, then plane to base again | Nothing | Never for this symptom; the job still reports in base |
| Read the result, convert once, MoveL in the plane | Camera to base, then base to plane, once | The read, the conversion, the move | The taught pattern must replay at several fixtures |
What a feature plane is
A feature is a named six-dimensional pose, position plus orientation, relative to the robot base, and a plane feature is the one you teach on a fixture so a motion pattern can live in the fixture's own coordinates. Teach the process points once in the plane; rotate the fixture or move to a second station, re-teach the plane, and every stored point follows. The stored plane variable can also drive a dynamic path offset, the pattern this feature-plane variable for dynamic path offset walkthrough uses.
The camera does not know the plane exists. It is calibrated against base, so its result and your plane move speak different frames. Turning image coordinates into robot coordinates is the first half of the problem — convert image coordinates to robot coordinates for servo moves covers it — and this guide is the second half: robot frame to robot frame.
The one conversion that fixes it
Here t is the plane's taught origin and R its rotation, both read from the Features page where you taught the plane. In URScript the composition is pose_trans: it applies a plane pose to an offset expressed in that plane. Going the other way, base data into plane data, needs the plane pose inverted first and then the same composition. For a planar correction with no angle term you can also run the arithmetic on the raw numbers, which the worked example below does so every step stays visible. The choice between composing and adding has traps of its own; vision offsets: pose_trans vs pose_add and the array index lists them, and camera frame to servo frame: one plane, one affine transform shows the single-plane affine route.
Hardware that keeps the frames stable
The conversion assumes the camera-to-base relationship never moves, so bolt the camera to a floor-standing structure, not to the fixture table. A 2.5 MP GigE camera with a global shutter and a 1/1.7-inch sensor on a C-mount covers planar picking at fixture scale; the MV-CU020-90GC prints exactly that combination.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
Mount it on the LS-MNT-0040 machine-vision camera stand: a 700 mm height on a 400 x 450 mm base keeps a small camera steady over one station, and the wider camera stands range adds slide stages for sweeping the field between stations. For denser grids, the area scan cameras finder filters by resolution and interface.
- Type
- Camera stands
Give the job a home with its own networks. The MV-VC3301H-128G66 vision controller offers 5+ LAN ports, 4 built-in light channels, 8 GB of memory and an included VM6200Pro license, so camera, robot and plant network each stay on their own link. The rest of the vision controllers range scales from there.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
The mounting geometry, camera fixed above the workspace and calibrated once to base, is set up in camera above the robot base: eye-to-hand calibration setup, and the picks themselves, once the frames agree, are computed as in use eye-to-hand calibration results to compute robot-base picks.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Worked example: one pick point from a 4 × 5 grid at a 90° plane
The case: a fixture table turned a quarter turn, a 4 × 5 grid of taught process points on it, a fixed camera above, and a job that reports in base.
Inputs:
- Plane feature, taught: origin t = (500, -300, 40) mm in base, rotated +90° about Z, no tilt.
- Camera job result: pick point p_base = (560, -250, 45) mm in base.
- Taught pattern: 4 × 5 points stored in plane coordinates.
Rule in words: subtract the plane origin from the reported point, then rotate the difference by minus the plane's Z angle.
p_base - t = (560 - 500, -250 + 300, 45 - 40) = (60, 50, 5) mm
Rotate (60, 50) by -90°:
- x = 60 · cos(-90°) - 50 · sin(-90°) = 0 + 50 = 50
- y = 60 · sin(-90°) + 50 · cos(-90°) = -60 + 0 = -60
So p_plane = (50, -60, 5) mm, and the pick sits 5 mm above the plane's taught origin height.
Check: rotation preserves distance from the origin. The length of (60, 50) is √(60² + 50²) = √6100 ≈ 78.1 mm before conversion, and the length of (50, -60) is √(50² + 60²) = √6100 ≈ 78.1 mm after. Equal, so the arithmetic is sound.
Quantified failure: feed the base numbers straight into the plane move and the controller computes t + R · p_base = (500 + 250, -300 + 560, 40 + 45) = (750, 260, 85) mm. That point sits √(190² + 510² + 40²) = √297800 ≈ 546 mm from the part.
Decision: MoveL in the feature to (50, -60, 5) mm, first cycle at reduced speed, confirm the tool stops on the fiducial, then release the grid. A converted point that lands hundreds of millimetres outside the fixture bounds means a sign error or a second transform — fix the script, not the calibration.
Step by step: read the result and convert once
- Teach the plane and copy its pose. Create the plane on the Features page in the pendant's installation settings, name it, and note the origin and rotation values it reports; the script needs them verbatim.
- Prove the result frame. Place a fiducial at a location you can measure in base, run the job, and read the raw result line. Numbers that track base coordinates confirm the frame you are converting from.
- Open the connection from the robot program. Many smart cameras serve their job results over a Telnet-style ASCII interface: open the socket, send the run command, read the result line, and parse X, Y and Z, plus the angle term if the job reports one.
- Convert once. Subtract the plane origin and rotate by minus the plane's Z angle, or make one pose composition call with the plane pose. Take the rotation exactly as the Features page reports it.
- Move in the feature. MoveL to the converted point with the move's feature set to your plane, first cycles at reduced speed.
- Replay the grid. Loop the taught plane-coordinate points; per cycle only the converted vision point changes, so one program serves every station that has a taught plane.
Verify the conversion before speed
Three checks, in order:
- Known point: at low speed, the converted target brings the tool down on the fiducial you measured in step 2.
- Length preserved: the distance from the plane origin is identical before and after conversion, for every point.
- Bounds: every converted grid point falls inside the fixture's taught extents.
When the usual answer is wrong
- Recalibrate in the plane: calibration rebuilds the pixel-to-millimetre mapping, it does not change the frame the result is reported in, so the plane move still consumes base numbers.
- Camera on the arm: a wrist-mounted camera needs a different pipeline, one full hand-eye calibration and then new work planes; define a new work plane after one full wrist camera calibration covers it.
- Whole cell moved between setups: re-teach one table feature and everything re-anchors; robot repositioned between setups: teach one table feature shows the shortest path.
- Pattern shared across planes: when the same taught motion must run in a different plane, transfer a UR10 movement pattern between feature planes is the direct procedure.
- Angle corrections: if the job reports part rotation, carry it through the pose composition. For a plane rotated about Z only, subtract the plane's angle from the reported angle; never add degrees to taught point coordinates.
Checks before you commit
- Exactly one frame conversion counted between the camera result and the motion target.
- The known-point test passes: the raw result matches a fiducial measured in base.
- Distance from the plane origin is preserved through the conversion.
- The first MoveL in the plane ran at reduced speed and stopped on the fiducial.
- The plane pose is re-read after any fixture or station change.
- Every converted grid point sits inside the fixture bounds.
Once the count is one and the checks pass, the plane stops fighting you: teach a plane per station and one program serves all of them. Build the camera side from the configurator above, or send us the two poses — the reported camera result and the taught plane — and we will check the composition with you.
Questions
Should I convert the vision result into the plane, or the taught points into base?
Convert whichever side has fewer points, and only that side. Usually that is the single vision result: express it in plane coordinates and keep the whole taught pattern in plane coordinates, so a new fixture means re-teaching the plane, not the pattern. If only one taught point matters per cycle, compose that point into base instead and leave the move's feature at base. Never convert both sides, because that is the double transform again.
How can I check a converted point without moving the robot?
Rotation preserves distance from the plane origin. Take the length of the reported point minus the plane origin, and the length of your converted point; the two must match. In the worked example both come to 78.1 mm, from 60² + 50² and 50² + 60². A mismatch means a sign error or a rotation applied in the wrong direction; a match within rounding says the arithmetic is sound.
Do I recalibrate the camera when the plane or fixture changes?
Not unless the camera itself moved. With a fixed camera over the workspace, the camera-to-base relationship survives every fixture change: re-teach or re-select the plane, read its new pose, and run the same conversion. If the camera or its stand is bumped, re-run the camera calibration and repeat the known-point check before trusting converted targets again.
What if the plane is tilted, not just rotated about Z?
The subtract-and-rotate shortcut covers planes rotated about their own normal only. A tilted plane needs the full three-axis rotation, so use pose composition on the pendant rather than a hand-written two-axis rotation, reading the plane pose from the Features page instead of converting units by hand. The distance-from-origin check still applies, in all three axes.
Can the camera URCap still be used at all?
Yes, for what it does well. Keep it for job triggering and result display while every move runs in base. When moves must run in a taught feature, read the result from the robot program over the socket or Telnet-style interface and convert it there. That split, with the camera doing vision and the robot owning the frames, is the arrangement that keeps working as fixtures change.


