This commit is contained in:
stelzo 2024-05-21 13:34:25 +02:00
parent d7d51e0cc2
commit b5fc791776
6 changed files with 47 additions and 49 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ros_pointcloud2" name = "ros_pointcloud2"
version = "0.5.0-rc.2" version = "0.5.0-rc.3"
edition = "2021" edition = "2021"
authors = ["Christopher Sieh <stelzo@steado.de>"] authors = ["Christopher Sieh <stelzo@steado.de>"]
description = "Customizable conversions for working with sensor_msgs/PointCloud2." description = "Customizable conversions for working with sensor_msgs/PointCloud2."
@ -32,10 +32,10 @@ rust-version = "1.63"
[dependencies] [dependencies]
rosrust_msg = { version = "0.1", optional = true } rosrust_msg = { version = "0.1", optional = true }
rosrust = { version = "0.9.11", optional = true } rosrust = { version = "0.9.11", optional = true }
r2r = { version = "0.8.4", optional = true } r2r = { version = "0.9", optional = true }
rayon = { version = "1", optional = true } rayon = { version = "1", optional = true }
nalgebra = { version = "0.32.5", optional = true, default-features = false } nalgebra = { version = "0.32", optional = true, default-features = false }
rpcl2-derive = { version = "0.2.0", optional = true } rpcl2-derive = { version = "0.2", optional = true }
memoffset = { version = "0.9", optional = true } memoffset = { version = "0.9", optional = true }
sensor_msgs = { version = "*", optional = true } sensor_msgs = { version = "*", optional = true }

View File

@ -7,7 +7,7 @@
ros_pointcloud2 uses its own type for the message `PointCloud2Msg` to keep the library framework agnostic. ROS1 and ROS2 are supported with feature flags. ros_pointcloud2 uses its own type for the message `PointCloud2Msg` to keep the library framework agnostic. ROS1 and ROS2 are supported with feature flags.
Get started with the example below, check out the other use cases in the `examples` folder or see the [Documentation](https://docs.rs/ros_pointcloud2/0.5.0-rc.1/) for a complete guide. Get started with the example below, check out the other use cases in the `examples` folder or see the [Documentation](https://docs.rs/ros_pointcloud2/0.5.0-rc.3/) for a complete guide.
## Quickstart ## Quickstart
@ -57,9 +57,9 @@ You can use `rosrust` and `r2r` by enabling the respective feature:
```toml ```toml
[dependencies] [dependencies]
ros_pointcloud2 = { version = "*", features = ["r2r_msg", "derive"]} ros_pointcloud2 = { version = "*", features = ["r2r_msg"]}
# or # or
ros_pointcloud2 = { version = "*", features = ["rosrust_msg", "derive"]} ros_pointcloud2 = { version = "*", features = ["rosrust_msg"]}
``` ```
### rclrs (ros2_rust) ### rclrs (ros2_rust)
@ -68,7 +68,7 @@ Features do not work properly with `rcrls` because the messages are linked exter
```toml ```toml
[dependencies] [dependencies]
ros_pointcloud2 = { git = "https://github.com/stelzo/ros_pointcloud2", tag = "v0.5.0-rc.1_rclrs" } ros_pointcloud2 = { git = "https://github.com/stelzo/ros_pointcloud2", tag = "v0.5.0-rc.3_rclrs" }
``` ```
Also, indicate the following dependencies to your linker inside the `package.xml` of your package. Also, indicate the following dependencies to your linker inside the `package.xml` of your package.
@ -84,32 +84,21 @@ Please open an issue or PR if you need other integrations.
## Performance ## Performance
This library offers a speed up when compared to PointCloudLibrary (PCL) conversions but the specific factor depends heavily on the use case and system. This library offers a speed up when compared to PointCloudLibrary (PCL) conversions but the specific factor depends heavily on the use case and system.
The `_vec` conversions are on average ~6x faster than PCL while the single core iteration `_iter` functions are around ~2x faster. See [this repository](https://github.com/stelzo/ros_pcl_conv_bench) for a detailed benchmark.
Parallelization with `_par_iter` gives a ~9x speed up compared to an OpenMP accelerated PCL pipeline.
The results are measured on an Intel i7-14700 with benchmarks from [this repository](https://github.com/stelzo/ros_pcl_conv_bench).
For minimizing the conversion overhead in general, always use the functions that best fit your use case. For minimizing the conversion overhead in general, always use the functions that best fit your use case.
## `no_std` Environments ### License
The `_iter` conversions are compatible with `#[no_std]` environments if an allocator is provided. This is due to the fact that names for point fields do not have a maximum length, and PointCloud2 data vectors can have arbitrary sizes. Use `default-features = false` to disable std for this crate. Only `nalgebra` can be added as an additional feature in this case. <sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>
## License <br>
Licensed under either of <sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) be dual licensed as above, without any additional terms or conditions.
</sub>
at your option.
### type-layout
For compatibility reasons, a patched version of `type-layout` is included in this repository. The original crate can be found [here](https://crates.io/crates/type-layout). After the patch is applied on the original `type-layout` crate ([PR](https://github.com/LPGhatguy/type-layout/pull/9)), the local dependency will be changed to the original crate.
`type-layout` is licensed under MIT or Apache-2.0 and Copyright by Lucien Greathouse. The changes are highlighted in the diff of the PR.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

View File

@ -319,9 +319,16 @@ where
return Err(MsgConversionError::DataLengthMismatch); return Err(MsgConversionError::DataLengthMismatch);
} }
let last_offset = offsets.last().expect("Dimensionality is 0."); let last_offset = match offsets.last() {
Some(offset) => *offset,
None => return Err(MsgConversionError::DataLengthMismatch),
};
let last_pdata = match pdata.last() {
Some(pdata) => pdata,
None => return Err(MsgConversionError::DataLengthMismatch),
};
let last_pdata = pdata.last().expect("Dimensionality is 0.");
let size_with_last_pdata = last_offset + last_pdata.1.size(); let size_with_last_pdata = last_offset + last_pdata.1.size();
if size_with_last_pdata > point_step_size { if size_with_last_pdata > point_step_size {
return Err(MsgConversionError::DataLengthMismatch); return Err(MsgConversionError::DataLengthMismatch);
@ -496,4 +503,4 @@ mod test {
let first_right = right.next(); let first_right = right.next();
assert!(first_right.is_none()); assert!(first_right.is_none());
} }
} }

View File

@ -11,11 +11,11 @@
//! - [`try_into_iter`](PointCloud2Msg::try_into_iter) //! - [`try_into_iter`](PointCloud2Msg::try_into_iter)
//! //!
//! These feature predictable performance but they do not scale well with large clouds. Learn more about that in the [performance section](https://github.com/stelzo/ros_pointcloud2?tab=readme-ov-file#performance) of the repository. //! These feature predictable performance but they do not scale well with large clouds. Learn more about that in the [performance section](https://github.com/stelzo/ros_pointcloud2?tab=readme-ov-file#performance) of the repository.
//! The iterators are useful when your conversions are more complex than a simple copy or you the cloud is small enough. //! The iterators are useful when your conversions are more complex than a simple copy or the cloud is small enough.
//! //!
//! When the cloud is getting larger or you are doing a lot of processing per point, switch to the parallel iterators. //! When the cloud is getting larger or you are doing a lot of processing per point, switch to the parallel iterators.
//! - [`try_into_par_iter`](PointCloud2Msg::try_into_par_iter) requires `rayon` feature //! - [`try_into_par_iter`](PointCloud2Msg::try_into_par_iter) requires `rayon` feature
//! - [`try_from_par_iter`](PointCloud2Msg::try_from_par_iter) requires `rayon` + `derive` feature //! - [`try_from_par_iter`](PointCloud2Msg::try_from_par_iter) requires `rayon` feature
//! //!
//! For ROS interoperability, there are integrations avialable with feature flags. If you miss a message type, please open an issue or a PR. //! For ROS interoperability, there are integrations avialable with feature flags. If you miss a message type, please open an issue or a PR.
//! See the [`ros`] module for more information on how to integrate more libraries. //! See the [`ros`] module for more information on how to integrate more libraries.
@ -56,10 +56,10 @@
//! - r2r_msg — Integration for the ROS2 library [r2r](https://github.com/sequenceplanner/r2r). //! - r2r_msg — Integration for the ROS2 library [r2r](https://github.com/sequenceplanner/r2r).
//! - rosrust_msg — Integration with the [rosrust](https://github.com/adnanademovic/rosrust) library for ROS1 message types. //! - rosrust_msg — Integration with the [rosrust](https://github.com/adnanademovic/rosrust) library for ROS1 message types.
//! - (rclrs_msg) — Integration for ROS2 [rclrs](https://github.com/ros2-rust/ros2_rust) but it currently needs [this workaround](https://github.com/stelzo/ros_pointcloud2?tab=readme-ov-file#rclrs-ros2_rust). //! - (rclrs_msg) — Integration for ROS2 [rclrs](https://github.com/ros2-rust/ros2_rust) but it currently needs [this workaround](https://github.com/stelzo/ros_pointcloud2?tab=readme-ov-file#rclrs-ros2_rust).
//! - derive *(enabled by default)* — Enables the `_vec` functions and offers helpful custom point derive macros for the [`PointConvertible`] trait. //! - derive — Offers implementations for the [`PointConvertible`] trait needed for custom points.
//! - rayon — Parallel iterator support for `_par_iter` functions. [`PointCloud2Msg::try_from_par_iter`] additionally needs the 'derive' feature. //! - rayon — Parallel iterator support for `_par_iter` functions.
//! - nalgebra — Predefined points offer a nalgebra typed getter for coordinates (e.g. [`xyz`](points::PointXYZ::xyz)). //! - nalgebra — Predefined points offer a nalgebra typed getter for coordinates (e.g. [`xyz`](points::PointXYZ::xyz)).
//! - std *(enabled by default)* — Use the standard library. `no_std` only works standalone or with the 'nalgebra' feature. //! - std *(enabled by default)* — Omit this feature to use this library in no_std environments. ROS integrations and 'rayon' will not work with no_std.
//! //!
//! # Custom Points //! # Custom Points
//! Implement [`PointConvertible`] for your point with the `derive` feature or manually. //! Implement [`PointConvertible`] for your point with the `derive` feature or manually.
@ -125,10 +125,11 @@
//! ``` //! ```
#![crate_type = "lib"] #![crate_type = "lib"]
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(html_root_url = "https://docs.rs/ros_pointcloud2/0.5.0-rc.2")] #![doc(html_root_url = "https://docs.rs/ros_pointcloud2/0.5.0-rc.3")]
#![warn(clippy::print_stderr)] #![warn(clippy::print_stderr)]
#![warn(clippy::print_stdout)] #![warn(clippy::print_stdout)]
#![warn(clippy::unwrap_used)] #![warn(clippy::unwrap_used)]
#![warn(clippy::expect_used)]
#![warn(clippy::cargo)] #![warn(clippy::cargo)]
#![warn(clippy::std_instead_of_core)] #![warn(clippy::std_instead_of_core)]
#![warn(clippy::alloc_instead_of_core)] #![warn(clippy::alloc_instead_of_core)]
@ -474,7 +475,7 @@ fn ordered_field_names<const N: usize, C: PointConvertible<N>>() -> Vec<String>
name, name,
ty: _, ty: _,
size: _, size: _,
} => name.to_string(), } => name.as_ref().into(),
_ => unreachable!("Fields must be filtered before."), _ => unreachable!("Fields must be filtered before."),
}) })
.collect() .collect()
@ -492,12 +493,13 @@ impl PointCloud2Msg {
let field_names = ordered_field_names::<N, C>(); let field_names = ordered_field_names::<N, C>();
debug_assert!(field_names.len() == N); debug_assert!(field_names.len() == N);
let layout = KnownLayoutInfo::try_from(C::layout())?; let target_layout = KnownLayoutInfo::try_from(C::layout())?;
debug_assert!(field_names.len() <= layout.fields.len()); debug_assert!(field_names.len() <= target_layout.fields.len());
debug_assert!(self.fields.len() <= target_layout.fields.len());
let mut offset: u32 = 0; let mut offset: u32 = 0;
let mut field_counter = 0; let mut field_counter = 0;
for f in layout.fields.iter() { for f in target_layout.fields.iter() {
match f { match f {
PointField::Field { PointField::Field {
datatype, datatype,
@ -913,13 +915,13 @@ pub trait PointConvertible<const N: usize>:
fn layout() -> LayoutDescription; fn layout() -> LayoutDescription;
} }
#[derive(Debug)] #[derive(Debug, Clone)]
enum PointField { enum PointField {
Padding(u32), Padding(u32),
Field { size: u32, datatype: u8, count: u32 }, Field { size: u32, datatype: u8, count: u32 },
} }
#[derive(Debug)] #[derive(Debug, Clone)]
struct KnownLayoutInfo { struct KnownLayoutInfo {
fields: Vec<PointField>, fields: Vec<PointField>,
} }
@ -1445,4 +1447,4 @@ impl FromBytes for u8 {
fn from_le_bytes(bytes: PointDataBuffer) -> Self { fn from_le_bytes(bytes: PointDataBuffer) -> Self {
Self::from_le_bytes([bytes[0]]) Self::from_le_bytes([bytes[0]])
} }
} }

View File

@ -817,4 +817,4 @@ impl PointConvertible<6> for PointXYZNormal {
LayoutField::padding(8), LayoutField::padding(8),
]) ])
} }
} }

View File

@ -11,4 +11,4 @@ pub use crate::ros::*;
pub use rayon::prelude::*; pub use rayon::prelude::*;
#[cfg(feature = "derive")] #[cfg(feature = "derive")]
pub use rpcl2_derive::*; pub use rpcl2_derive::*;