🚚 WIA Delivery Robot Standard Ebook | Chapter 2 of 8
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.
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.
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.
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:
map → odom → base_link. base_link is rigidly attached to the robot. odom is a world-fixed frame in which the pose drifts over time but never jumps, which suits local control. map is a world-fixed frame in which the pose is globally consistent but may jump when localization corrects itself, which suits global planning and reporting.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.
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)
| Property | Phase 1 heading | ROS yaw (REP-103, ENU) |
|---|---|---|
| Zero direction | North | East |
| Positive rotation | Clockwise (seen from above) | Counter-clockwise (seen from above) |
| Unit | Degrees | Radians |
| Range | 0 to 360 (schema) | Commonly −π to π |
| Robot facing east | 90 | 0 |
| Robot facing north | 0 | π/2 |
| Robot facing south-west | 225 | −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.
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.
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.
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.
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.
| Tier | Mechanism | Typical accuracy | Main failure condition | position.source |
|---|---|---|---|---|
| GNSS (primary) | Code pseudoranges from multiple satellites | 1–5 m, open sky | Urban canyons, tunnels, indoors, multipath | gps |
| RTK-GPS (enhanced) | Carrier phase plus base-station corrections | 1–10 cm with fixed solution | Loss of correction link, loss of fix, obstructed sky | rtk-gps |
| Dead reckoning (fallback) | Wheel odometry plus IMU integration | Unbounded drift; degrades with distance and time | Wheel slip, sensor bias, long outages | No 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".
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.
Phase 3 §2.2 outlines SLAM as six steps. Each step has a characteristic failure, and knowing them helps interpret what a robot reports.
odom frame from the globally consistent map frame.| Map type | Content | Strength | Typical use on a delivery robot |
|---|---|---|---|
| Occupancy grid | 2D (or 3D voxel) cells, each occupied, free or unknown, often stored as a probability | Directly usable for collision checking and planning | Local costmaps, indoor floor plans, obstacle inflation |
| Feature map | Sparse set of distinctive landmarks with positions | Compact; efficient for localization and loop closure | Re-localizing along a known route; visual SLAM |
| Semantic map | Objects and regions labelled by type (tree, building, crosswalk) | Carries meaning that rules can use | Knowing 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.
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.
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.
| Sensor | Range | Field of view | Weather/lighting | Update rate | Relative cost | SensorReadings field |
|---|---|---|---|---|---|---|
| LiDAR | 0.1–100 m | 360° | Poor in rain/fog | 10–20 Hz | High | lidar[] (points x, y, z, intensity) |
| Camera | 0.5–50 m | 60–120° | Poor in dark/glare | 30–60 Hz | Low | cameras[] (image_url, detections) |
| Ultrasonic | 0.02–5 m | 15–30° | Excellent | 10–40 Hz | Very low | ultrasonic[] (distance_cm) |
| Radar | 1–200 m | 15–120° | Excellent | 10–20 Hz | Medium | None 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.
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.
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.
position.source and position.accuracyOnce 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.
| Definition | Meaning | Radius in terms of σ | Value when σ = 0.2 m (example) |
|---|---|---|---|
| 1σ per axis | Standard deviation of each coordinate | 1.00 σ | 0.20 m |
| CEP (50 %) | Radius containing half of all fixes | ≈ 1.18 σ | ≈ 0.24 m |
| R95 | Radius containing 95 % of fixes | ≈ 2.45 σ | ≈ 0.49 m |
| 2DRMS | Twice 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.
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.
base_link) and timestamps become critical. Association is often solved as an assignment problem with gating on distance.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}
]
}
| Field | Content in the example | Unstated in the spec; declare it |
|---|---|---|
obstacle_id | Track identifier | Lifetime: stable across frames for the life of the track, not globally unique. Not a UUID, so do not validate it as one. |
class | Semantic class | The allowed vocabulary (for example pedestrian, wheelchair, stroller, cyclist, vehicle, static); the spec gives no enum. |
confidence | 0–1 score | Whether it is calibrated (see 2.7) and whether it refers to existence or to class. |
position | x, y, z in metres | Frame (base_link or odom) and reference point (box centre or nearest point). |
velocity | vx, vy in m/s | Frame, and whether it is absolute or relative to the robot. |
bounding_box | Metric length, width, height | Orientation of the box (the example has no yaw). |
predicted_trajectory | Points at t seconds ahead | That 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.
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.
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.
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.
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.
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).
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.
heading is 0 = North, clockwise, degrees; ROS yaw is 0 = East, counter-clockwise, radians. Use heading_deg = (90 − yaw_deg) mod 360, normalize to [0, 360), and test the cardinal directions.source: "fused", and accuracy must carry a declared definition, preferably a 95 % horizontal radius to match the Phase 3 target.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 →