You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've searched other issues and no duplicate issues were found.
I'm convinced that this is not my fault but a bug.
Description
RingOutlierFilterComponent::set_up_pointcloud_format() in autoware_pointcloud_preprocessor never sets PointCloud2::row_step on the output cloud it constructs. Every field except row_step is set (header.frame_id, height, width, is_bigendian, is_dense, fields), so the output message is published with row_step == 0 (its default-constructed value) regardless of input.
This node is the last stage of the standard lidar preprocessing pipeline (crop_box_filter_self → crop_box_filter_mirror → distortion_corrector_node → ring_outlier_filter → e.g. pointcloud_before_sync), so every downstream consumer of its output receives a cloud with an invalid row_step. The recently-added generic PointCloud2 validation in the shared Filter base class (#11853, tracked under #11858) correctly flags this on every downstream node that happens to validate its input, but the validation warning's own text says this becomes a hard error starting July 2026 — at which point every pipeline downstream of ring_outlier_filter will start rejecting clouds outright.
#11855 already fixed the equivalent row_step/width recalculation for the concatenation node (autoware::pointcloud_preprocessor::PointCloudConcatenationComponent), but that fix only covers clouds that pass through multi-source concatenation. A single-lidar setup (common in simulation integrations, e.g. one lidar wired straight through a topic_tools::RelayNode instead of the concatenation node) never touches that fix, so ring_outlier_filter's own bug reaches consumers unmodified.
Expected behavior
ring_outlier_filter's output PointCloud2 should have row_step == width * point_step (for the unorganized, height == 1 clouds this node always produces), matching the invariant the new validator in filter.hpp enforces.
Actual behavior
row_step is always 0 on ring_outlier_filter's output, for every input. Downstream nodes (e.g. crop_box_filter instances in both perception's obstacle-segmentation pipeline and localization's NDT preprocessing pipeline) log, once per received message:
Invalid PointCloud: row_step mismatch. Expected: <width * point_step> (width <W> * point_step <P>), Got: 0. Frame: 'base_link', Stamp: <t>. Please fill in the `cloud->row_step` field accordingly. This will be an ERROR starting in 2026 July
Steps to reproduce
Launch any lidar pipeline that routes through autoware::pointcloud_preprocessor::RingOutlierFilterComponent (the standard common_sensor_launch/nebula_node_container.launch.py chain used by, e.g., awsim_sensor_kit_launch/launch/lidar.launch.xml).
Subscribe to any node downstream of ring_outlier_filter that validates incoming PointCloud2 messages via the shared Filter base class (e.g. any crop_box_filter instance).
Observe the row_step mismatch ... Got: 0 warning on every message, indefinitely.
Reproduced against ghcr.io/autowarefoundation/autoware:universe-devel-cuda-jazzy in a CARLA-based single-lidar simulation integration; traced to source against autoware_universe@cdc0792965be82577a310eb363bf877c5c2d070e (current main), so the bug is present at main as of this report, not specific to that image build.
(height is always 1 here, so row_step and data.size() coincide; the simpler equivalent formatted_points.row_step = static_cast<uint32_t>(formatted_points.data.size()); also works and matches the pattern already used in CropBoxFilterComponent's own output construction.)
Additional context
Cross-checked that this is not a CARLA-side issue: CARLA's own native PointCloud2 publisher sets row_step = width * point_step correctly, and CropBoxFilterComponent's own output construction (the two upstream crop_box_filter_self/crop_box_filter_mirror stages in the same pipeline) also correctly recomputes row_step. ring_outlier_filter is the only stage in the chain that drops it.
Checklist
Description
RingOutlierFilterComponent::set_up_pointcloud_format()inautoware_pointcloud_preprocessornever setsPointCloud2::row_stepon the output cloud it constructs. Every field exceptrow_stepis set (header.frame_id,height,width,is_bigendian,is_dense,fields), so the output message is published withrow_step == 0(its default-constructed value) regardless of input.This node is the last stage of the standard lidar preprocessing pipeline (
crop_box_filter_self→crop_box_filter_mirror→distortion_corrector_node→ring_outlier_filter→ e.g.pointcloud_before_sync), so every downstream consumer of its output receives a cloud with an invalidrow_step. The recently-added genericPointCloud2validation in the sharedFilterbase class (#11853, tracked under #11858) correctly flags this on every downstream node that happens to validate its input, but the validation warning's own text says this becomes a hard error starting July 2026 — at which point every pipeline downstream ofring_outlier_filterwill start rejecting clouds outright.#11855 already fixed the equivalent
row_step/widthrecalculation for the concatenation node (autoware::pointcloud_preprocessor::PointCloudConcatenationComponent), but that fix only covers clouds that pass through multi-source concatenation. A single-lidar setup (common in simulation integrations, e.g. one lidar wired straight through atopic_tools::RelayNodeinstead of the concatenation node) never touches that fix, soring_outlier_filter's own bug reaches consumers unmodified.Expected behavior
ring_outlier_filter's outputPointCloud2should haverow_step == width * point_step(for the unorganized,height == 1clouds this node always produces), matching the invariant the new validator infilter.hppenforces.Actual behavior
row_stepis always0onring_outlier_filter's output, for every input. Downstream nodes (e.g.crop_box_filterinstances in both perception's obstacle-segmentation pipeline and localization's NDT preprocessing pipeline) log, once per received message:Steps to reproduce
autoware::pointcloud_preprocessor::RingOutlierFilterComponent(the standardcommon_sensor_launch/nebula_node_container.launch.pychain used by, e.g.,awsim_sensor_kit_launch/launch/lidar.launch.xml).ring_outlier_filter's output feeds a downstream consumer directly (or via a plain relay) rather than throughPointCloudConcatenationComponent(whoserow_steprecalculation from fix(autoware_pointcloud_preprocessor): recalculate row_step and width after concatenation #11855 would otherwise mask this).ring_outlier_filterthat validates incomingPointCloud2messages via the sharedFilterbase class (e.g. anycrop_box_filterinstance).row_step mismatch ... Got: 0warning on every message, indefinitely.Reproduced against
ghcr.io/autowarefoundation/autoware:universe-devel-cuda-jazzyin a CARLA-based single-lidar simulation integration; traced to source againstautoware_universe@cdc0792965be82577a310eb363bf877c5c2d070e(currentmain), so the bug is present atmainas of this report, not specific to that image build.Versions
autoware_universe@cdc0792965be82577a310eb363bf877c5c2d070e(main)ghcr.io/autowarefoundation/autoware:universe-devel-cuda-jazzyPossible causes
sensing/autoware_pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_node.cpp,RingOutlierFilterComponent::set_up_pointcloud_format()(currently lines 381-400):Suggested fix, right after
widthis computed:(
heightis always1here, sorow_stepanddata.size()coincide; the simpler equivalentformatted_points.row_step = static_cast<uint32_t>(formatted_points.data.size());also works and matches the pattern already used inCropBoxFilterComponent's own output construction.)Additional context
PointCloud2publisher setsrow_step = width * point_stepcorrectly, andCropBoxFilterComponent's own output construction (the two upstreamcrop_box_filter_self/crop_box_filter_mirrorstages in the same pipeline) also correctly recomputesrow_step.ring_outlier_filteris the only stage in the chain that drops it.ring_outlier_filter).