Coordinate frames, handedness, and unit hygiene
The silent source of half of all robotics bugs. Name your frames, declare your units, watch your handedness — discipline that costs ten minutes and saves weeks.
A robot has dozens of coordinate frames. The base. Each link. Each sensor. The map. The world. Every "the robot drove into a wall for no reason" debug session ends with someone realizing two frames disagreed about which way is "up." Discipline upfront prevents weeks of confusion.
The naming convention that pays off
Name every transform by the frames it relates: T_AB = "the pose of frame B expressed in frame A." Read as "A from B."
The rule that makes composition obvious: inner letters must match:
T_world_camera = T_world_base @ T_base_camera
The "base" cancels in the middle. Inverting flips the letters: T_BA = T_AB^{-1}.
If you compose two transforms whose middle letters don't match, you've made the classic inversion mistake. Once you see this convention, the bugs become visible at code review.
Right-handed everywhere (almost)
Almost all robotics math assumes right-handed coordinate systems: x cross y = z. Use the right-hand rule:
- Point your right index finger along x
- Curl middle finger to y
- Thumb points along z
Right-handed conventions across robotics:
- ROS: x forward, y left, z up. Right-handed.
- Gazebo / ENU: x east, y north, z up. Right-handed.
- Aviation / NED: x north, y east, z down. Right-handed.
- OpenGL / three.js: x right, y up, z toward viewer. Right-handed.
- Most CAD tools (FreeCAD, Onshape): right-handed.
Watch out:
- Unity / DirectX: left-handed (z forward instead of toward viewer). Conversion needed when importing from CAD.
- Image coordinates: y typically points down (origin at top-left). When you see
vincrease down the screen, you're in image-coords; convert before applying 3D math.
The frame zoo on a typical robot
- world / map: globally consistent reference. SLAM updates it.
- odom: locally continuous (no jumps). Drifts slowly. Wheel-odometry or IMU.
- base_link: robot body origin. Convention: at the center of rotation for wheeled robots, between the feet for legged.
- base_footprint:
base_linkprojected to the ground plane. - imu_link, camera_link, lidar_link: sensor mounts. Static relative to base_link.
- tool_frame / end_effector: where the gripper / tool tip is.
REP 105 (ROS) defines these formally. Match the convention or have a strong reason not to.
Units: declare them, don't infer them
Most robotics code accumulates a mix of:
- Position: meters (radians-of-Earth latitude/longitude don't count as a unit)
- Orientation: radians for code; degrees for human input
- Time: seconds (sometimes nanoseconds in ROS timestamps)
- Mass: kilograms
- Force: Newtons
- Voltage: volts
- Current: amperes
The minute you mix them silently, your robot does something violent. Three mitigations:
- Suffix variables:
length_m = 0.5,angle_rad = 1.57,angle_deg = 90.0. The compiler doesn't care; future-you does. - Prefer SI base units. Convert at I/O boundaries (UI shows degrees, internals are radians).
- Doc strings. Every function comment starts with the units of its arguments.
Common bugs you'll catch with this discipline
- Multiplying transforms in the wrong order. Catch with the inner-letters rule.
- Using a left-handed transform from CAD in a right-handed sim. Inverts one axis. Robot drives backward.
- Mixing radians and degrees. Robot moves 57× too far or 1/57× too far.
- Wheel slip "fixed" by inflating Kp. Actually a unit conversion bug between wheel-radians and meters.
- SLAM map in odom instead of map. Drifts away from any known landmarks over time.
The TF tree as documentation
In ROS, the TF tree is a runtime, queryable description of every frame on your robot and the transforms between them. ros2 run tf2_tools view_frames generates a PDF showing the whole tree. Look at this tree for any new robot you touch — half the questions you'd ask are answered there.
Five-minute checklist for any new module
- What frame is each input in? What frame should each output be in?
- Are positions in meters? Are angles in radians? Did you convert at boundaries?
- If transforms are involved, are inner letters matching when you compose?
- Did you verify with a known-good test case (FK(IK(target)) ≈ target)?
- If you're consuming an external sensor or library, did you check its handedness convention?
Five minutes of front-loaded checking saves hours of debugging.
Exercise
Pick any robotics codebase (yours, an open-source one). Search for any literal number with units (* 0.0254, * 180 / pi, 1000 *). For each one, ask: is this conversion local, documented, and necessary? You'll find unit conversions hiding in unexpected places — and once you see them, you'll start renaming variables to make them explicit. The codebase becomes legible.
Next
How to read a robotics paper — the last Foundations track lesson. Where to start, what to skip, how to tell breakthrough from bluster.
Comments
Sign in to post a comment.