🚚 WIA Delivery Robot Standard Ebook | Chapter 2 of 8


Chapter 2: Localization and Perception Fundamentals — Turning Robot State into Numbers

Every message a WIA ROB-010 robot sends to its fleet platform starts with a claim about the physical world: I am here, I am facing this way, and these are the things around me. Phase 1 gives that claim a shape: the position, heading and speed fields of RobotState and the optional sensors block of type SensorReadings. Phase 3 describes, in §2 and §3, how a robot is expected to arrive at those numbers: global positioning, SLAM, multi-sensor fusion and obstacle classification. This chapter explains the engineering underneath both, so that the values you put into a payload mean what a consumer on the other side of the API will assume they mean.

The scope is deliberately narrow. This chapter covers sensing and state estimation: coordinate frames, position sources, mapping, sensor characteristics, filtering and the path from raw detections to tracked obstacles. What the robot does with that information (path planning, safety margins, the behaviour state machine, emergency stops) belongs to Chapter 5. The formal schema walk-through, including the full RobotState example and validation code, is in Chapter 3; here schema fields appear only where a sensing decision determines their value.

Throughout, numbers taken from the standard are labelled as such. Ranges that describe typical hardware are called "typical" and are not requirements. Worked examples use illustrative values and say so.


2.1 Coordinate Frames and Conventions

A position is meaningless without its frame, and most integration defects in robot telemetry are frame defects rather than arithmetic ones. A delivery robot uses at least three frames at once, and the standard touches two of them directly.

2.1.1 The global frame: WGS84 latitude, longitude, altitude

Phase 1 §2.2 defines Position with latitude (−90 to 90), longitude (−180 to 180), an optional altitude described as "meters above sea level", an optional accuracy in metres and an optional source. The schema does not name a datum, but latitude/longitude pairs exchanged between GNSS receivers, map services and fleet dashboards are, by overwhelming convention, expressed in WGS84, the datum GPS itself uses. An implementation should state this explicitly in its documentation, because a robot localizing against a national survey grid or a building's CAD drawing must convert before it publishes.

Altitude deserves a second look. A GNSS receiver natively computes ellipsoidal height above the WGS84 ellipsoid. "Above sea level" is orthometric height, measured from the geoid. The difference, the geoid undulation, varies across the globe and amounts to tens of metres in many places. Some receivers output one, some the other, some both. Because Phase 1 says "above sea level", a conformant producer should publish orthometric height, or document clearly that it does not. For a sidewalk robot, absolute altitude is rarely safety-relevant; relative height is what matters when the robot must tell which floor of a building it is on, which is why indoor deployments usually carry a floor identifier in their own map data rather than relying on altitude alone.

Numeric precision matters too. One degree of latitude spans roughly 111 km, so the fifth decimal place of a degree is about 1.1 m and the seventh about 1.1 cm. JSON numbers are usually parsed into 64-bit doubles, which carry more than enough precision. The trap is an intermediate store or message definition that uses 32-bit floats: a float32 has about seven significant decimal digits, so a longitude such as 126.97801 loses resolution at roughly the metre scale. If your telemetry pipeline claims centimetre accuracy from RTK, check every hop between the receiver and the database for a float32.

2.1.2 Robot-local frames

Perception and control do not work in latitude and longitude. They work in Cartesian metres. The Robot Operating System ecosystem, which Chapter 1 identified as the common middleware layer, codifies two conventions that most delivery-robot stacks follow:

Phase 3 §3.2 publishes obstacle positions as {"x", "y", "z"} without naming a frame. Section 2.6 returns to this; for now, note that "x = 5.2" means something entirely different in base_link (5.2 m ahead of the robot) and in map (5.2 m east of an arbitrary map origin).

To move between the global and local frames over the few kilometres a delivery robot covers, many stacks pick a local origin (latitude φ0, longitude λ0) and use a local tangent-plane approximation:

east_m  ≈ R · (λ − λ0) · cos(φ0)      (angles in radians)
north_m ≈ R · (φ − φ0)
R = 6,378,137 m  (WGS84 semi-major axis)

This equirectangular approximation is adequate for short distances around the origin; for larger areas or survey-grade work, use a proper projection library (for example, a UTM projection or a full geodetic-to-ENU conversion) rather than growing the approximation's error.

2.1.3 Two heading conventions

RobotState carries heading in degrees, range 0–360, described in Phase 1 §2.1 as "0 = North, 90 = East". That is a compass (navigation) convention: clockwise from north. ROS yaw in an ENU frame is the mathematical convention: 0 points east and angles increase counter-clockwise, in radians. The two are related by a reflection and a quarter-turn offset:

heading_deg = (90 − yaw_deg) mod 360
yaw_deg     = (90 − heading_deg) mod 360     (same formula, it is its own inverse)
Table 2-1. Heading conventions compared
PropertyPhase 1 headingROS yaw (REP-103, ENU)
Zero directionNorthEast
Positive rotationClockwise (seen from above)Counter-clockwise (seen from above)
UnitDegreesRadians
Range0 to 360 (schema)Commonly −π to π
Robot facing east900
Robot facing north0π/2
Robot facing south-west225−3π/4 (−135°)

Mixing the two produces errors that are hard to see in testing. A robot driving due north-east reads 45 in both conventions, so a test route along that diagonal passes. A robot driving north reports 90 instead of 0, and the fleet dashboard draws it driving east. The fix is a single conversion function at the boundary where internal state becomes a Phase 1 payload, with unit tests on the cardinal directions. Two small details: the schema allows both 0 and 360, so normalize to [0, 360) to avoid two encodings of north; and ROS stores orientation as a quaternion, so yaw must first be extracted from it.

import math

def quaternion_to_yaw(qx: float, qy: float, qz: float, qw: float) -> float:
    """Yaw (rotation about z) in radians from a ROS orientation quaternion."""
    siny_cosp = 2.0 * (qw * qz + qx * qy)
    cosy_cosp = 1.0 - 2.0 * (qy * qy + qz * qz)
    return math.atan2(siny_cosp, cosy_cosp)

def ros_yaw_to_phase1_heading(yaw_rad: float) -> float:
    """REP-103 ENU yaw (0 = East, CCW, radians) -> Phase 1 heading
    (0 = North, CW, degrees, normalized to [0, 360))."""
    heading = (90.0 - math.degrees(yaw_rad)) % 360.0
    # Guard against floating-point results such as 359.9999999 or 360.0
    return 0.0 if math.isclose(heading, 360.0) else heading

# Cardinal-direction tests: the cheapest insurance against frame bugs
assert ros_yaw_to_phase1_heading(0.0) == 90.0                  # facing east
assert ros_yaw_to_phase1_heading(math.pi / 2) == 0.0           # facing north
assert ros_yaw_to_phase1_heading(math.pi) == 270.0             # facing west
assert ros_yaw_to_phase1_heading(-math.pi / 2) == 180.0        # facing south

Python's % operator returns a non-negative result for a positive divisor, which is why the formula works for negative yaw without extra branches. In C or C++, fmod keeps the sign of the dividend, so add 360 and take the remainder again.


2.2 Global Positioning: GNSS, RTK and Dead Reckoning

Phase 3 §2.1 lists three tiers of global positioning: GPS/GNSS as primary, RTK-GPS as enhanced, and dead reckoning as fallback. They differ in mechanism, not just accuracy, and those mechanisms explain when each one fails.

2.2.1 GNSS

A GNSS receiver estimates its position from the travel times of signals from several satellites, using pseudoranges measured with the satellites' code signals. Modern receivers combine constellations (GPS, Galileo, GLONASS, BeiDou and regional systems), which helps in partially obstructed sky. Phase 3 gives typical figures of 1–5 m accuracy in open areas and 1–10 Hz update rates, and names the limitations: degradation in urban canyons, tunnels and indoors.

The urban-canyon problem matters most for sidewalk robots. Tall buildings block direct line-of-sight to many satellites, and the remaining signals often arrive after reflecting off façades (multipath). A reflected signal travels further than the direct path, so the receiver computes a range that is too long, and the position solution can be displaced by far more than the open-sky figure, often toward the street's centre line or across it. Worse, the receiver's own reported accuracy estimate may not reflect the displacement. A robot on the correct side of a street can be reported on the wrong side. For a platform whose safety depends on staying on the sidewalk, raw GNSS is therefore a coarse global anchor, not a lane-level position.

2.2.2 RTK-GPS

Real-time kinematic (RTK) positioning uses the carrier phase of the satellite signal rather than only the code. The carrier wavelength is on the order of 20 cm, so phase measurements can resolve position far more finely, provided the receiver can determine the integer number of whole wavelengths between satellite and antenna (the "integer ambiguity"). A base station at a known position observes the same satellites and transmits corrections, commonly as RTCM messages over a network protocol such as NTRIP. Because most atmospheric and orbital errors are shared between nearby receivers, the rover can cancel them. Phase 3 gives 1–10 cm as the typical accuracy and notes the base-station requirement.

RTK has distinct operating states that telemetry should not hide. With ambiguities resolved ("fixed"), accuracy is at the centimetre level. With ambiguities unresolved ("float"), accuracy degrades to decimetres or worse. When the correction link drops, the receiver falls back to standalone GNSS. In urban canyons, the same multipath that hurts GNSS makes fixes harder to obtain and to keep. A robot that reports source: "rtk-gps" with a 2 cm accuracy after it has silently dropped to float mode is publishing a false claim. Publish the source and accuracy of the current solution, not the capability of the hardware.

2.2.3 Dead reckoning

Dead reckoning estimates motion from the robot's own sensors: wheel encoders measure how far each wheel has turned, and an inertial measurement unit (IMU) measures acceleration and angular rate. Integrating these gives a pose relative to the starting point. It works indoors, underground and in any weather, and it runs at high rate, which is why every delivery robot has it. Its weakness is structural: errors accumulate because every step's estimate builds on the previous one.

Dead reckoning is therefore a bridge, not a destination: it carries the estimate across a GNSS outage or between SLAM updates. The Phase 3 failure-mode table sets a time limit on how long a robot may operate after losing GPS; Chapter 5 covers that behaviour. From a sensing standpoint, the relevant point is that the accuracy a robot reports must grow during dead reckoning, because the uncertainty is growing.

Table 2-2. Global positioning tiers (typical figures from Phase 3 §2.1; not requirements)
TierMechanismTypical accuracyMain failure conditionposition.source
GNSS (primary)Code pseudoranges from multiple satellites1–5 m, open skyUrban canyons, tunnels, indoors, multipathgps
RTK-GPS (enhanced)Carrier phase plus base-station corrections1–10 cm with fixed solutionLoss of correction link, loss of fix, obstructed skyrtk-gps
Dead reckoning (fallback)Wheel odometry plus IMU integrationUnbounded drift; degrades with distance and timeWheel slip, sensor bias, long outagesNo dedicated value; normally reported inside fused

The last column exposes a small gap: the source enum (gps, rtk-gps, slam, visual-odometry, fused) has no value for pure dead reckoning. In practice, a robot running on odometry alone is still running its fusion filter with the other inputs absent, so fused with an honestly inflated accuracy is the defensible encoding. Document that choice in your implementation notes so consumers do not read fused as "high quality".


2.3 SLAM Essentials

Simultaneous localization and mapping solves a chicken-and-egg problem: to localize you need a map, and to build a map you need to know where you are. SLAM estimates both together. For a delivery robot it provides what GNSS cannot: accurate, frame-consistent position in places where satellites are blocked or unavailable, and a model of the local environment against which the robot can recognize where it is.

2.3.1 The six-step pipeline

Phase 3 §2.2 outlines SLAM as six steps. Each step has a characteristic failure, and knowing them helps interpret what a robot reports.

  1. Sensor data acquisition. LiDAR scans and camera frames arrive with timestamps. If the robot is moving while a scanning LiDAR sweeps, points in one scan are captured from slightly different poses; stacks compensate ("deskew") using odometry. Without it, straight walls appear bent.
  2. Feature extraction. The algorithm reduces raw data to things it can recognize again: corners, edges and planes in point clouds; keypoints in images. Featureless environments (long uniform corridors, open plazas, glass façades that LiDAR sees through or reflects from) starve this step.
  3. Data association. Current features are matched to previously seen ones. This is where most catastrophic SLAM errors start: a wrong match (two identical doorways, repeated shopfronts) pulls the estimate to the wrong place with high confidence.
  4. State estimation. Phase 3 names two estimators. An extended Kalman filter (EKF) keeps a single Gaussian estimate of pose and landmarks, linearizing the non-linear motion and measurement models; it is efficient but struggles as the map grows and when errors are not Gaussian. A particle filter represents the belief as many weighted samples, so it can carry several hypotheses at once (useful after a wrong association or when the robot is "kidnapped" and relocated). Many current systems also use graph-based optimization, which stores poses and constraints as a graph and solves for the most consistent configuration; the standard does not require any particular estimator.
  5. Map update. New landmarks are added and existing ones refined. Dynamic objects (pedestrians, parked cars that later leave) must be kept out of the persistent map or the robot will localize against things that move.
  6. Loop closure. When the robot recognizes a place it has visited, it adds a constraint that corrects accumulated drift across the whole loop. The corrected pose can jump, which is exactly why REP-105 separates the smooth odom frame from the globally consistent map frame.

2.3.2 Map representations

Table 2-3. Map types named in Phase 3 §2.2
Map typeContentStrengthTypical use on a delivery robot
Occupancy grid2D (or 3D voxel) cells, each occupied, free or unknown, often stored as a probabilityDirectly usable for collision checking and planningLocal costmaps, indoor floor plans, obstacle inflation
Feature mapSparse set of distinctive landmarks with positionsCompact; efficient for localization and loop closureRe-localizing along a known route; visual SLAM
Semantic mapObjects and regions labelled by type (tree, building, crosswalk)Carries meaning that rules can useKnowing where crosswalks, ramps and doorways are; zone-based behaviour

Deployed robots usually combine them: a prior semantic map built during a survey, a feature map for localization, and a rolling occupancy grid around the robot for real-time obstacle handling. None of these maps are exchanged through Phase 1 payloads; the standard exchanges the result of localization, not the map itself.

2.3.3 Reporting SLAM-derived position

SLAM produces a pose in the map frame. To fill position.latitude and longitude, the map frame must be georeferenced, meaning its origin and orientation have been tied to WGS84 (by surveying control points, or by aligning the map with RTK fixes collected during mapping). A robot localizing perfectly in an imperfectly georeferenced map publishes a precise but wrong global position. The accuracy figure should include the georeferencing error, not only the SLAM residual.

The distinction between slam and visual-odometry in the enum is also worth keeping clear. Visual odometry estimates incremental motion from successive camera frames; like wheel odometry, it drifts, because it has no map to correct against. SLAM corrects drift through map matching and loop closure. Reporting visual odometry as slam overstates the reliability of the estimate over long distances.


2.4 Sensor Modalities

Phase 3 §3.1 compares four sensor types for obstacle detection. The figures below are the spec's, labelled as typical: actual values depend strongly on the specific product, mounting and environment, and the standard does not set minimum sensor performance.

Table 2-4. Sensor modalities (typical ranges from Phase 3 §3.1; not requirements)
SensorRangeField of viewWeather/lightingUpdate rateRelative costSensorReadings field
LiDAR0.1–100 m360°Poor in rain/fog10–20 HzHighlidar[] (points x, y, z, intensity)
Camera0.5–50 m60–120°Poor in dark/glare30–60 HzLowcameras[] (image_url, detections)
Ultrasonic0.02–5 m15–30°Excellent10–40 HzVery lowultrasonic[] (distance_cm)
Radar1–200 m15–120°Excellent10–20 HzMediumNone defined

LiDAR measures range directly by timing laser returns, producing accurate 3D geometry independent of ambient light. That makes it the backbone of most SLAM and obstacle-detection pipelines. Its weaknesses are scattering by rain, fog, snow and dust (which can produce phantom returns close to the sensor), difficulty with transparent and highly reflective surfaces, and sparse sampling at long range, where a small object may be hit by only a few beams.

Cameras provide dense texture and colour, which is what classification needs: telling a pedestrian from a post, reading a crosswalk signal, recognizing a guide dog. A single camera does not measure depth directly; depth comes from stereo pairs, from motion, or from learned estimation, all of which are less direct than LiDAR ranging. Cameras suffer at night, in backlight and glare, and when the lens is wet or dirty. They also raise privacy obligations, because they capture faces and licence plates; Chapter 6 covers how to handle that in the fleet pipeline.

Ultrasonic sensors emit a sound pulse and time the echo. They are cheap, robust to lighting and largely unaffected by rain, and they see glass that LiDAR may miss. Their cone-shaped beam gives poor angular resolution, and soft or angled surfaces may not return an echo. On delivery robots they typically form a close-range safety ring around the chassis, covering the blind zone that a roof-mounted LiDAR cannot see.

Radar measures range and, through the Doppler effect, relative radial velocity directly, and it penetrates rain and fog well. Its angular resolution is coarser than LiDAR's, and small, low-reflectivity objects are harder to detect. Radar is common in road vehicles and increasingly available in compact modules. Note that Phase 1 SensorReadings defines no radar field. A robot that uses radar reports its contribution through fused obstacle outputs, or through a clearly documented extension field.

The table explains why Phase 3 calls for fusion rather than a best sensor. The failure conditions are largely complementary: LiDAR fails in fog where radar does not, cameras fail in the dark where LiDAR does not, and ultrasonics cover the near field that the others see poorly. A design review should ask, for each environmental condition in the operating area (night, rain, glare, crowds, glass shopfronts), which sensor is still working and what the robot's perception degrades to.


2.5 Fusion and Uncertainty

Fusion combines several imperfect estimates into one better estimate, and the Kalman filter is the reference method; Phase 3 §3.1 names "Kalman filter fusion" as step four of its fusion strategy, and §2.2 names the extended Kalman filter for SLAM. The core idea fits in a one-dimensional example.

2.5.1 The Kalman filter in one dimension

Consider a single state x, such as the robot's position along a straight sidewalk, with variance P expressing how uncertain the estimate is. Each cycle has two steps.

Predict (motion model, e.g. wheel odometry reports displacement u):
    x⁻ = x + u
    P⁻ = P + Q          Q = process noise: how much uncertainty motion adds

Update (measurement z, e.g. a GNSS or SLAM position, with variance R):
    K  = P⁻ / (P⁻ + R)  Kalman gain, between 0 and 1
    x  = x⁻ + K · (z − x⁻)
    P  = (1 − K) · P⁻

The gain K decides whom to trust. If the prediction is uncertain (large P⁻) and the measurement precise (small R), K approaches 1 and the estimate moves almost to the measurement. If the measurement is noisy, K approaches 0 and the prediction dominates. The update always reduces variance, and the predict step always increases it; over time the filter settles into a rhythm that reflects how good the sensors actually are.

A worked example, with illustrative numbers: after a prediction the filter believes the robot is at x⁻ = 10.0 m with P⁻ = 4.0 m² (standard deviation 2.0 m). A measurement arrives: z = 11.0 m with R = 1.0 m² (standard deviation 1.0 m). Then K = 4.0 / (4.0 + 1.0) = 0.8, the new estimate is 10.0 + 0.8 × 1.0 = 10.8 m, and P = 0.2 × 4.0 = 0.8 m², a standard deviation of about 0.89 m. The fused result is more certain than either input alone, which is the entire point of fusion.

The quality of this arithmetic depends on the honesty of Q and R. If R is set too small for a GNSS receiver in an urban canyon, the filter will trust a multipath-displaced fix and jump sideways. Robust implementations therefore gate measurements: they compute the innovation z − x⁻ relative to its expected spread (P⁻ + R) and reject or down-weight measurements that are statistically implausible. In multiple dimensions, the same structure holds with matrices, and the extended Kalman filter linearizes non-linear models (such as turning motion) around the current estimate.

2.5.2 From filter output to position.source and position.accuracy

Once a filter combines inputs, the honest source value is fused. Reserve the single-source values for cases where one input genuinely determines the estimate, such as a robot that publishes raw RTK output directly. The harder field is accuracy. Phase 1 describes it only as "Position accuracy in meters", which leaves open whether it is a one-sigma value, a 95 % radius, or something else. These differ by a large factor.

Table 2-5. Common accuracy definitions for a horizontal position, assuming a circular Gaussian error with per-axis standard deviation σ
DefinitionMeaningRadius in terms of σValue when σ = 0.2 m (example)
1σ per axisStandard deviation of each coordinate1.00 σ0.20 m
CEP (50 %)Radius containing half of all fixes≈ 1.18 σ≈ 0.24 m
R95Radius containing 95 % of fixes≈ 2.45 σ≈ 0.49 m
2DRMSTwice the root-mean-square radial error≈ 2.83 σ≈ 0.57 m

The example is chosen to make the point concrete. Phase 3 §8 sets a performance target of position error below 0.5 m at 95 %. A robot whose filter reports σ = 0.2 m per axis meets that target only just, if its error really is Gaussian and its σ is honest. If one vendor fills accuracy with 1σ and another with R95, a fleet dashboard that compares them will rank the more conservative vendor as the worse one. Because the schema cannot resolve this, each implementation should declare the definition it uses, and a conformance review should treat a missing declaration as a defect. A sensible choice for delivery robots is the 95 % horizontal radius, since it lines up with the Phase 3 target; whatever is chosen, it should be stated in the conformance documentation and applied consistently across the fleet.

Real filters produce a 2×2 horizontal covariance, not a single σ, and the ellipse is often elongated: along-track error small, cross-track error large, or the reverse. A conservative reduction is to take the square root of the larger eigenvalue as σ before converting to the declared definition. It overstates the error in one direction, but it never understates it, which is the right bias for a figure that downstream systems may use for safety decisions.

A position block produced by a fused estimator might look like this (values are illustrative; the full RobotState appears in Chapter 3):

{
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-03-14T09:21:07.250Z",
  "version": "1.0.0",
  "position": {
    "latitude": 37.5662952,
    "longitude": 126.9779451,
    "altitude": 38.4,
    "accuracy": 0.42,
    "source": "fused"
  },
  "heading": 184.5,
  "speed": 1.2,
  "battery_level": 76
}

Reading this payload correctly requires three pieces of documentation that are not in the payload: the accuracy definition (here, say, a 95 % horizontal radius), the altitude reference (orthometric), and the timestamp's meaning (the time the pose was valid, not the time the message was sent). Section 2.7 returns to the last point.


2.6 From Detections to Obstacles

Localization answers "where am I?"; perception must also answer "what is around me, and where is it going?" Phase 3 §3.1 lays out the pipeline in six steps: preprocess raw data; detect objects per modality; associate detections across sensors; fuse them with a Kalman filter; classify; and predict trajectories.

2.6.1 The pipeline in practice

2.6.2 The obstacle object

Phase 3 §3.2 gives an example obstacle record. It is not a Phase 1 schema with a $id, but it is the shape the standard uses for obstacles, and implementations that expose perception results should follow it.

{
  "obstacle_id": "obs-001",
  "class": "pedestrian",
  "confidence": 0.95,
  "position": {"x": 5.2, "y": -1.3, "z": 0.0},
  "velocity": {"vx": 1.2, "vy": 0.3},
  "bounding_box": {"length": 0.5, "width": 0.4, "height": 1.7},
  "predicted_trajectory": [
    {"t": 1.0, "x": 6.4, "y": -1.0},
    {"t": 2.0, "x": 7.6, "y": -0.7}
  ]
}
Table 2-6. Obstacle fields and what an implementation must pin down
FieldContent in the exampleUnstated in the spec; declare it
obstacle_idTrack identifierLifetime: stable across frames for the life of the track, not globally unique. Not a UUID, so do not validate it as one.
classSemantic classThe allowed vocabulary (for example pedestrian, wheelchair, stroller, cyclist, vehicle, static); the spec gives no enum.
confidence0–1 scoreWhether it is calibrated (see 2.7) and whether it refers to existence or to class.
positionx, y, z in metresFrame (base_link or odom) and reference point (box centre or nearest point).
velocityvx, vy in m/sFrame, and whether it is absolute or relative to the robot.
bounding_boxMetric length, width, heightOrientation of the box (the example has no yaw).
predicted_trajectoryPoints at t seconds aheadThat t is an offset from the record's timestamp, and the prediction's uncertainty.

A useful consistency check on the example: velocity (1.2, 0.3) m/s applied for one second from (5.2, −1.3) gives (6.4, −1.0), and for two seconds (7.6, −0.7), exactly the predicted points. The example uses a constant-velocity prediction, and its x and y are consistent with the velocity being expressed in the same frame as the position. If the robot itself is moving and the frame is base_link, a constant-velocity prediction in that frame is only correct if the velocity is relative to the robot. This is precisely the ambiguity the table asks you to resolve.

One naming collision needs particular care. In Phase 1 camera detections, bounding_box is a pixel rectangle with integer x, y, width, height. In the Phase 3 obstacle, bounding_box is a metric 3D size with length, width, height. Both have a width, and one is pixels while the other is metres. Keep separate types for the two in code, even though the JSON key is the same.


2.7 Pitfalls

The following problems recur in robot telemetry. None of them is prevented by schema validation, because the payload is well-formed in every case; only design discipline and testing catch them.

2.7.1 Timestamp skew between sensors

Fusion assumes that measurements are compared at the times they were taken. If the camera's timestamp comes from the moment the driver received the frame, and the LiDAR's from the start of its sweep, the two can differ by tens of milliseconds. The effect is proportional to speed: at an illustrative combined speed of 2.5 m/s (robot at 1.2 m/s approaching a pedestrian at 1.3 m/s), a 40 ms skew misplaces the pedestrian by 0.1 m. That is a large fraction of the 0.3–0.5 m static-obstacle margin in Phase 3 and enough to cause association errors between sensors. A spinning LiDAR also has intra-scan skew: at 10 Hz one sweep takes 100 ms, and a robot moving at 1.5 m/s travels 0.15 m during it.

Mitigations: timestamp at acquisition in hardware where possible; synchronize sensor clocks to the robot's clock (PTP, IEEE 1588, is designed for this on a local network); record per-sensor latency and compensate; and deskew point clouds using odometry. Separately, define what the RobotState timestamp means. Phase 1 calls it the "timestamp of state capture"; set it to the time at which the published pose was valid, not the time the message was serialized. Fleet-level clock synchronization between robots and cloud is covered in Chapter 6.

2.7.2 Raw point clouds in JSON

SensorReadings allows lidar[].points as an array of {x, y, z, intensity} objects. That is useful for a debug snapshot and ruinous as a telemetry stream. As an illustrative calculation, a sensor producing 300,000 points per second, encoded as JSON objects of roughly 60–80 bytes each, generates on the order of 20 MB per second per sensor, before any overhead. The same points as four 32-bit floats are 16 bytes each, about 4.8 MB per second, and still far too much for a cellular uplink shared by a fleet. Phase 1 §6.3 already points the way: minimize payload size, use Protocol Buffers for high-frequency telemetry, and send delta updates. The camera schema shows the intended pattern: send detections and an image_url pointing to a stored frame, not the frame itself. Apply the same idea to LiDAR: publish obstacles and occupancy summaries routinely, and upload raw clouds only on request or around incidents.

2.7.3 Confidence calibration

The schema constrains confidence to 0–1, which invites reading it as a probability. Most detector outputs are not calibrated probabilities: a network may output 0.95 for detections that are right far less often than 95 % of the time, and the relationship varies between models, software versions and lighting conditions. Two consequences follow. First, thresholds tuned on one model do not transfer to a retrained model. Second, confidences from different vendors cannot be compared or averaged in a fleet dashboard. If you expose confidence, calibrate it on representative validation data (reliability diagrams and a scaling step such as temperature scaling are standard techniques), record the model version, and state whether the value is calibrated. Phase 3 §8 sets targets for detection rate and false-positive rate; those are measured against ground truth in testing (Chapter 7), not inferred from confidence scores.

2.7.4 Units and ambiguous fields

Phase 1 mixes units: speed in m/s, heading in degrees, ultrasonic[].distance_cm in centimetres, and LiDAR point coordinates with no unit stated. The IMU block has acceleration x, y, z with no unit, and a gyroscope object with fields named roll, pitch and yaw. A gyroscope measures angular rate, but those names suggest angles, and no unit is given. A consumer cannot tell whether "yaw: 0.2" means an orientation of 0.2 rad, a rate of 0.2 rad/s, or 0.2 °/s. Resolve this in your implementation profile: for example, SI units following REP-103 (m/s² for acceleration, rad/s for angular rate), with the gyroscope fields carrying rates about the body axes. Whatever you choose, document it and test it with a stationary robot (accelerometer z should read about 9.81 m/s² including gravity, or about 0 if gravity has been removed, and your documentation should say which).

2.7.5 Precision and frames revisited

Three frame-related errors from section 2.1 account for a disproportionate share of field problems and are worth restating as checks: heading published in ROS convention rather than compass convention; latitude and longitude truncated by a float32 somewhere in the pipeline; and altitude published as ellipsoidal height while documented as above sea level. Each produces valid JSON, each passes schema validation, and each misleads every consumer downstream.


Chapter Summary

Chapter 3 takes the fields discussed here and places them in the complete Phase 1 schema set, with validation code and the spec gaps that implementers must fill.



← Chapter 1: Last-Mile Delivery Robots and Where WIA ROB-010 Fits | Back to Index | Chapter 3: Phase 1 Data Format — RobotState, Package and Route Schemas →