Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/schema/v1/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ Each 0.x `calibrated_sensor` row becomes a `sensor` row, keeping its token. The

Labels are `manual` unless 0.x marks them as autolabel (`provenance` = model names). `instance.nbr_annotations` and its first / last annotation are computed over its 3D boxes and 2D labels; 0.x tools count them differently (some write 0 for 2D labels). Categories without `index` get their position in `category.json`, as the 0.x devkit reads them (all set or none). `surface_ann` rows become `object_ann` rows without an instance, with `bbox` computed from the mask. 0.x visibility `unavailable` (or any unknown level) becomes `visibility_token: null`, and the aliases `v0-40`, `v40-60`, `v60-80`, `v80-100` map to `none`, `partial`, `most`, `full`.

`vehicle_state` rows get `source: vehicle_interface` (where the 0.x converter reads them) and shift `FORWARD`/`HIGH` becomes `DRIVE`; `additional_info.speed` is dropped and the velocities are `null`. The 0.x `traffic_light` table (`primitive_id`) and `traffic_light_instance_map` table (`traffic_light_linestring_id`, which wins if both list a lamp) link a lamp instance to its lanelet2 way (`type=traffic_light`) and have no states: the way becomes that instance's `map_element` (`type: way`), and the 1.0 `traffic_light` table stays empty. Source LiDARs of a concatenation have no frames of their own in 0.x: they take the concatenated channel's format and `fields`, and `frame_count` is the number of concatenated frames whose `.info` file lists points from them.
`vehicle_state` rows get `source: vehicle_interface` (where the 0.x converter reads them) and shift `FORWARD`/`HIGH` becomes `DRIVE`; `additional_info.speed` is dropped and the velocities are `null`. 0.x `ego_pose.acceleration` is dropped too: it held raw IMU readings whose frame and gravity sign vary by vehicle, and 1.0 `acceleration` is gravity-free; `acceleration` and `imu` come from the backfill. The 0.x `traffic_light` table (`primitive_id`) and `traffic_light_instance_map` table (`traffic_light_linestring_id`, which wins if both list a lamp) link a lamp instance to its lanelet2 way (`type=traffic_light`) and have no states: the way becomes that instance's `map_element` (`type: way`), and the 1.0 `traffic_light` table stays empty. Source LiDARs of a concatenation have no frames of their own in 0.x: they take the concatenated channel's format and `fields`, and `frame_count` is the number of concatenated frames whose `.info` file lists points from them.

1.0 requires some values that 0.x never stored. They are filled with these placeholders (`V0Converter.FALLBACKS`), which keep the dataset loadable but say nothing about it. In particular, `vehicle.model == "unknown"` means the vehicle dimensions are placeholders and must not be used, and `"unknown"` map IDs mean the map is not identified:

Expand Down
5 changes: 4 additions & 1 deletion docs/schema/v1/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,17 @@ ego_pose {
"rotation": <[float;4]> -- Orientation as quaternion (w, x, y, z).
"timestamp": <int> -- Unix timestamp in microseconds.
"twist": <option[[float;6]]> -- (vx, vy, vz, yaw_rate, pitch_rate, roll_rate) in the vehicle frame.
"acceleration": <option[[float;3]]> -- (ax, ay, az) in the vehicle frame, as an IMU measures it: gravity included (az ≈ +9.8 m/s² at rest).
"acceleration": <option[[float;3]]> -- (ax, ay, az) in the vehicle frame [m/s²], without gravity: the localization estimate, what Autoware feeds the planner.
"imu": <option[[float;6]]> -- (ax, ay, az, wx, wy, wz): the raw IMU in the vehicle frame, specific force with gravity (az ≈ +9.8 m/s² at rest) and angular velocity [rad/s].
"geocoordinate": <option[[float;3]]> -- (latitude, longitude, altitude).
"source": <enum["localization", "post_processed", "gnss_ins"]> -- Where the pose came from.
"frame": <str> -- Coordinate frame, e.g. "map".
"covariance": <option[[float;36]]> -- 6×6 pose covariance, row-major.
}
```

An `ego_pose` sits at a sample time. `twist`, `acceleration`, `imu`, `geocoordinate` and `covariance` hold the latest message at or before `timestamp`, best effort; the pose itself is interpolated at `timestamp`.

### Sensor

- Filename: `sensor.json`
Expand Down
5 changes: 4 additions & 1 deletion t4_devkit/schema/v1/convert_v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,10 @@ def convert_ego_pose(self, record: Record) -> Record:
"rotation": record["rotation"],
"timestamp": record["timestamp"],
"twist": record.get("twist"),
"acceleration": record.get("acceleration"),
# 0.x acceleration is a raw IMU reading whose frame and gravity sign vary by
# vehicle; 1.0 acceleration is gravity-free. Both come from the backfill.
"acceleration": None,
"imu": None,
"geocoordinate": record.get("geocoordinate"),
"covariance": None,
"source": fallbacks["source"],
Expand Down
9 changes: 8 additions & 1 deletion t4_devkit/schema/v1/ego_pose.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,25 @@ class EgoPose(SchemaBase):
rotation (Quaternion): Orientation in `frame`, given as quaternion [w, x, y, z].
timestamp (int): Unix time stamp [us].
twist (Vector6 | None): (vx, vy, vz, yaw_rate, pitch_rate, roll_rate) in the vehicle frame.
acceleration (Vector3 | None): (ax, ay, az) in the vehicle frame [m/s^2].
acceleration (Vector3 | None): (ax, ay, az) in the vehicle frame [m/s^2], without gravity:
the localization estimate, what Autoware feeds the planner.
imu (Vector6 | None): (ax, ay, az, wx, wy, wz): the raw IMU in the vehicle frame, specific
force with gravity (az ≈ +9.8 m/s^2 at rest) and angular velocity [rad/s].
geocoordinate (Vector3 | None): (latitude, longitude, altitude).
source (EgoPoseSource): Where the pose came from.
frame (str): Coordinate frame of the pose, e.g. "map".
covariance (list[float] | None): 6x6 pose covariance, row-major.

`twist`, `acceleration`, `imu`, `geocoordinate` and `covariance` hold the latest message at
or before `timestamp`, best effort; the pose itself is interpolated at `timestamp`.
"""

translation: Vector3 = field(converter=Vector3)
rotation: Quaternion = field(converter=to_quaternion)
timestamp: int = field(validator=validators.instance_of(int))
twist: Vector6 | None = field(converter=converters.optional(Vector6))
acceleration: Vector3 | None = field(converter=converters.optional(Vector3))
imu: Vector6 | None = field(converter=converters.optional(Vector6))
geocoordinate: Vector3 | None = field(converter=converters.optional(Vector3))
source: EgoPoseSource = field(converter=EgoPoseSource)
frame: str = field(validator=(validators.instance_of(str), impossible_empty()))
Expand Down
5 changes: 5 additions & 0 deletions t4_devkit/schema/v1/migrate_v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ def migrate(
self.notes.append(
"provenance.rosbag.record_start / record_end are the first / last sample times"
)
if any(record.get("acceleration") for record in self._load_v0("ego_pose")):
self.notes.append(
"ego_pose.acceleration dropped: 0.x stored raw IMU readings, whose frame and "
"gravity sign vary by vehicle; the backfill restores acceleration and imu"
)
manifest_info = self._manifest_info(dataset_id, version)
manifest_info.update(fields)
manifest_info["migration_notes"] = self.notes + list(fields.get("migration_notes", []))
Expand Down
5 changes: 5 additions & 0 deletions tests/sample/t4dataset_v1/annotation/ego_pose.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"timestamp": 1704067200000000,
"twist": null,
"acceleration": null,
"imu": null,
"geocoordinate": null,
"source": "localization",
"frame": "map",
Expand All @@ -36,6 +37,7 @@
"timestamp": 1704067200100000,
"twist": null,
"acceleration": null,
"imu": null,
"geocoordinate": null,
"source": "localization",
"frame": "map",
Expand All @@ -57,6 +59,7 @@
"timestamp": 1704067200000000,
"twist": null,
"acceleration": null,
"imu": null,
"geocoordinate": null,
"source": "localization",
"frame": "map",
Expand All @@ -78,6 +81,7 @@
"timestamp": 1704067200100000,
"twist": null,
"acceleration": null,
"imu": null,
"geocoordinate": null,
"source": "localization",
"frame": "map",
Expand All @@ -99,6 +103,7 @@
"timestamp": 1704067200200000,
"twist": null,
"acceleration": null,
"imu": null,
"geocoordinate": null,
"source": "localization",
"frame": "map",
Expand Down
1 change: 1 addition & 0 deletions tests/sample/t4dataset_v1/make_sample_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def link(tokens: list[str], i: int) -> dict:
"timestamp": timestamps[i],
"twist": None,
"acceleration": None,
"imu": None,
"geocoordinate": None,
"source": "localization",
"frame": "map",
Expand Down
2 changes: 1 addition & 1 deletion tests/sample/t4dataset_v1/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"ego_pose": {
"path": "annotation/ego_pose.json",
"sha256": "41c24c1c135773c2037e63f8aafe9080e2345eedd8a6ec71872d5ef7cabf6ce2"
"sha256": "c797549026aa60e7e5aa5578511754d62de75c52fc9f079fd7c914796a1f6c79"
},
"sensor": {
"path": "annotation/sensor.json",
Expand Down
17 changes: 17 additions & 0 deletions tests/schema/v1/test_migrate_v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,20 @@ def test_migrate_with_backfilled_metadata(tmp_path: Path) -> None:
assert vehicles[0]["model"] == "j6_gen2"
reports = sanity_check(output_root.parent.as_posix(), revision="1").reports
assert not [report.id for report in reports if report.is_failed()]


def test_migrate_drops_v0_acceleration(tmp_path: Path) -> None:
"""0.x `ego_pose.acceleration` (a raw IMU reading) is dropped, with a note."""
sample = SampleCopy(tmp_path, SAMPLE_V0, name="v0")
sample.edit(
"ego_pose", lambda records: [dict(r, acceleration=[0.0, 0.0, -9.8]) for r in records]
)
output_root = tmp_path / "t4dataset" / "1"
with pytest.warns(UserWarning): # the sample's fractional intensity stays float32
manifest = V0Migrator(sample.root, output_root).migrate("t4dataset", 1, keep_images=True)

poses = json.loads((output_root / "annotation" / "ego_pose.json").read_text())
assert all(pose["acceleration"] is None and pose["imu"] is None for pose in poses)
assert any(
note.startswith("ego_pose.acceleration dropped") for note in manifest.migration_notes
)
1 change: 1 addition & 0 deletions tests/schema/v1/test_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def _other_lidar_block(record: dict, records: list[dict]) -> None:
"frame-without-file": ("sample_data", 0, _set(("filename",), None), TypeError),
"frame-without-sample": ("sample_data", -1, _set(("sample_token",), None), TypeError),
"covariance-length": ("ego_pose", 0, _set(("covariance",), [0.0] * 35), ValueError),
"imu-length": ("ego_pose", 0, _set(("imu",), [0.0] * 3), ValueError),
"annotation-type": ("sample_annotation", 0, _set(("annotation_type",), "human"), ValueError),
"confidence-range": ("sample_annotation", 0, _set(("confidence",), 1.5), ValueError),
"instance-index-range": ("instance", 0, _set(("index",), 2**15), ValueError),
Expand Down
Loading