Skip to content

Commit 27ea500

Browse files
authored
Add sensor_msgs/msg/NavSatFix MessageParser (#11044)
1 parent 296e8b3 commit 27ea500

File tree

4 files changed

+251
-4
lines changed

4 files changed

+251
-4
lines changed

crates/utils/re_mcap/src/layers/ros2.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use crate::{
2-
parsers::MessageParser,
3-
parsers::ros2msg::{
1+
use crate::parsers::{
2+
MessageParser,
3+
ros2msg::{
44
sensor_msgs::{
55
CameraInfoMessageParser, CompressedImageMessageParser, ImageMessageParser,
6-
ImuMessageParser, JointStateMessageParser, PointCloud2MessageParser,
6+
ImuMessageParser, JointStateMessageParser, NavSatFixMessageParser,
7+
PointCloud2MessageParser,
78
},
89
std_msgs::StringMessageParser,
910
},
@@ -50,6 +51,7 @@ impl MessageLayer for McapRos2Layer {
5051
Box::new(CompressedImageMessageParser::new(num_rows))
5152
}
5253
"sensor_msgs/msg/PointCloud2" => Box::new(PointCloud2MessageParser::new(num_rows)),
54+
"sensor_msgs/msg/NavSatFix" => Box::new(NavSatFixMessageParser::new(num_rows)),
5355
_ => {
5456
re_log::warn_once!(
5557
"Message schema {:?} is currently not supported",

crates/utils/re_mcap/src/parsers/ros2msg/definitions/sensor_msgs.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,94 @@ pub struct JointState {
290290
/// The efforts applied in the joints.
291291
pub effort: Vec<f64>,
292292
}
293+
294+
/// Navigation Satellite fix status information.
295+
#[derive(Debug, Serialize, Deserialize)]
296+
pub struct NavSatStatus {
297+
/// Navigation satellite fix status.
298+
pub status: NavSatFixStatus,
299+
300+
/// Navigation satellite service type.
301+
pub service: NavSatService,
302+
}
303+
304+
/// Navigation satellite fix status values.
305+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
306+
#[repr(i8)]
307+
pub enum NavSatFixStatus {
308+
/// Unable to fix position.
309+
NoFix = -1,
310+
311+
/// Unaugmented fix.
312+
Fix = 0,
313+
314+
/// Satellite-based augmentation.
315+
SbasFix = 1,
316+
317+
/// Ground-based augmentation.
318+
GbasFix = 2,
319+
}
320+
321+
/// Navigation satellite service type values.
322+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
323+
#[repr(u16)]
324+
pub enum NavSatService {
325+
Gps = 1,
326+
Glonass = 2,
327+
Compass = 4,
328+
Galileo = 8,
329+
}
330+
331+
/// Position covariance type for navigation satellite fix.
332+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
333+
#[repr(u8)]
334+
pub enum CovarianceType {
335+
Unknown = 0,
336+
Approximated = 1,
337+
DiagonalKnown = 2,
338+
Known = 3,
339+
}
340+
341+
/// Navigation Satellite fix for any Global Navigation Satellite System
342+
///
343+
/// Specified using the WGS 84 reference ellipsoid.
344+
///
345+
/// `header.stamp` specifies the ROS time for this measurement (the
346+
/// corresponding satellite time may be reported using the
347+
/// `sensor_msgs/TimeReference` message).
348+
///
349+
/// `header.frame_id` is the frame of reference reported by the satellite
350+
/// receiver, usually the location of the antenna. This is a
351+
/// Euclidean frame relative to the vehicle, not a reference
352+
/// ellipsoid.
353+
#[derive(Debug, Serialize, Deserialize)]
354+
pub struct NavSatFix {
355+
/// Metadata including timestamp and coordinate frame.
356+
pub header: Header,
357+
358+
/// Satellite fix status information.
359+
pub status: NavSatStatus,
360+
361+
/// Latitude (degrees). Positive is north of equator; negative is south.
362+
pub latitude: f64,
363+
364+
/// Longitude (degrees). Positive is east of prime meridian; negative is west.
365+
pub longitude: f64,
366+
367+
/// Altitude (m). Positive is above the WGS 84 ellipsoid
368+
/// (quiet NaN if no altitude is available).
369+
pub altitude: f64,
370+
371+
/// Position covariance (m^2) defined relative to a tangential plane
372+
/// through the reported position. The components are East, North, and
373+
/// Up (ENU), in row-major order.
374+
///
375+
/// Beware: this coordinate system exhibits singularities at the poles.
376+
pub position_covariance: [f64; 9],
377+
378+
/// If the covariance of the fix is known, fill it in completely. If the
379+
/// GPS receiver provides the variance of each measurement, put them
380+
/// along the diagonal. If only Dilution of Precision is available,
381+
/// estimate an approximate covariance from that.
382+
pub position_covariance_type: CovarianceType,
383+
}

crates/utils/re_mcap/src/parsers/ros2msg/sensor_msgs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ mod compressed_image;
33
mod image;
44
mod imu;
55
mod joint_state;
6+
mod nav_sat_fix;
67
mod point_cloud_2;
78

89
pub use camera_info::*;
910
pub use compressed_image::*;
1011
pub use image::*;
1112
pub use imu::*;
1213
pub use joint_state::*;
14+
pub use nav_sat_fix::*;
1315
pub use point_cloud_2::*;
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use anyhow::Context as _;
2+
use arrow::array::{
3+
FixedSizeListArray, FixedSizeListBuilder, Float64Builder, Int8Builder, UInt8Builder,
4+
UInt16Builder,
5+
};
6+
use re_chunk::{Chunk, ChunkId};
7+
use re_log_types::TimeCell;
8+
use re_types::{
9+
ComponentDescriptor, SerializedComponentColumn, archetypes::GeoPoints, components::LatLon,
10+
};
11+
12+
use crate::parsers::{
13+
cdr,
14+
decode::{MessageParser, ParserContext},
15+
ros2msg::definitions::sensor_msgs,
16+
util::fixed_size_list_builder,
17+
};
18+
19+
/// Plugin that parses `sensor_msgs/msg/NavSatFix` messages.
20+
#[derive(Default)]
21+
pub struct NavSatFixSchemaPlugin;
22+
23+
pub struct NavSatFixMessageParser {
24+
geo_points: Vec<LatLon>,
25+
latitude: FixedSizeListBuilder<Float64Builder>,
26+
longitude: FixedSizeListBuilder<Float64Builder>,
27+
altitude: FixedSizeListBuilder<Float64Builder>,
28+
status: FixedSizeListBuilder<Int8Builder>,
29+
service: FixedSizeListBuilder<UInt16Builder>,
30+
position_covariance: FixedSizeListBuilder<Float64Builder>,
31+
position_covariance_type: FixedSizeListBuilder<UInt8Builder>,
32+
}
33+
34+
impl NavSatFixMessageParser {
35+
const ARCHETYPE_NAME: &str = "sensor_msgs.msg.NavSatFix";
36+
37+
pub fn new(num_rows: usize) -> Self {
38+
Self {
39+
geo_points: Vec::with_capacity(num_rows),
40+
latitude: fixed_size_list_builder(1, num_rows),
41+
longitude: fixed_size_list_builder(1, num_rows),
42+
altitude: fixed_size_list_builder(1, num_rows),
43+
status: fixed_size_list_builder(1, num_rows),
44+
service: fixed_size_list_builder(1, num_rows),
45+
position_covariance: fixed_size_list_builder(9, num_rows),
46+
position_covariance_type: fixed_size_list_builder(1, num_rows),
47+
}
48+
}
49+
50+
fn create_metadata_column(name: &str, array: FixedSizeListArray) -> SerializedComponentColumn {
51+
SerializedComponentColumn {
52+
list_array: array.into(),
53+
descriptor: ComponentDescriptor::partial(name)
54+
.with_archetype(Self::ARCHETYPE_NAME.into()),
55+
}
56+
}
57+
}
58+
59+
impl MessageParser for NavSatFixMessageParser {
60+
fn append(&mut self, ctx: &mut ParserContext, msg: &mcap::Message<'_>) -> anyhow::Result<()> {
61+
re_tracing::profile_function!();
62+
let sensor_msgs::NavSatFix {
63+
header,
64+
status,
65+
latitude,
66+
longitude,
67+
altitude,
68+
position_covariance,
69+
position_covariance_type,
70+
} = cdr::try_decode_message::<sensor_msgs::NavSatFix>(&msg.data)
71+
.context("Failed to decode sensor_msgs::NavSatFix message from CDR data")?;
72+
73+
// add the sensor timestamp to the context, `log_time` and `publish_time` are added automatically
74+
ctx.add_time_cell(
75+
"timestamp",
76+
TimeCell::from_timestamp_nanos_since_epoch(header.stamp.as_nanos()),
77+
);
78+
79+
// Store latitude/longitude as geographic points
80+
let geo_point = LatLon::new(latitude, longitude);
81+
self.geo_points.push(geo_point);
82+
83+
self.latitude.values().append_slice(&[latitude]);
84+
self.latitude.append(true);
85+
86+
self.longitude.values().append_slice(&[longitude]);
87+
self.longitude.append(true);
88+
89+
self.altitude.values().append_slice(&[altitude]);
90+
self.altitude.append(true);
91+
92+
self.status.values().append_slice(&[status.status as i8]);
93+
self.status.append(true);
94+
95+
self.service.values().append_slice(&[status.service as u16]);
96+
self.service.append(true);
97+
98+
self.position_covariance
99+
.values()
100+
.append_slice(&position_covariance);
101+
self.position_covariance.append(true);
102+
103+
self.position_covariance_type
104+
.values()
105+
.append_slice(&[position_covariance_type as u8]);
106+
self.position_covariance_type.append(true);
107+
108+
Ok(())
109+
}
110+
111+
fn finalize(self: Box<Self>, ctx: ParserContext) -> anyhow::Result<Vec<re_chunk::Chunk>> {
112+
re_tracing::profile_function!();
113+
let Self {
114+
geo_points,
115+
mut latitude,
116+
mut longitude,
117+
mut altitude,
118+
mut status,
119+
mut service,
120+
mut position_covariance,
121+
mut position_covariance_type,
122+
} = *self;
123+
124+
let entity_path = ctx.entity_path().clone();
125+
let timelines = ctx.build_timelines();
126+
127+
let mut chunk_components: Vec<_> = GeoPoints::update_fields()
128+
.with_positions(geo_points)
129+
.columns_of_unit_batches()?
130+
.collect();
131+
132+
chunk_components.extend([
133+
Self::create_metadata_column("latitude", latitude.finish()),
134+
Self::create_metadata_column("longitude", longitude.finish()),
135+
Self::create_metadata_column("altitude", altitude.finish()),
136+
Self::create_metadata_column("status", status.finish()),
137+
Self::create_metadata_column("service", service.finish()),
138+
Self::create_metadata_column("position_covariance", position_covariance.finish()),
139+
Self::create_metadata_column(
140+
"position_covariance_type",
141+
position_covariance_type.finish(),
142+
),
143+
]);
144+
145+
Ok(vec![Chunk::from_auto_row_ids(
146+
ChunkId::new(),
147+
entity_path.clone(),
148+
timelines.clone(),
149+
chunk_components.into_iter().collect(),
150+
)?])
151+
}
152+
}

0 commit comments

Comments
 (0)