Skip to content

Conversation

greganderson-vermeer
Copy link


Basic Info

Info Please fill out this column
Ticket(s) this addresses #5585
Primary OS tested on Ubuntu
Robotic platform tested on Vermeer Balehawk
Does this PR contain AI generated software? No
Was this PR description generated by AI software? No

Description of contribution in a few bullet points

  • Added iterator in for a custom height field in our point cloud iterator

Description of documentation updates required from your changes

  • If completed in a configurable method it would require new parameters, so would need to add that to default configs and documentation page
  • I added some capabilities, need to document them

Description of how this change was tested

  • No unit tests have been written or updated, but this has been tested on my physical robot platform in production for 6 weeks.

Future work that may be required in bullet points

  • I know in this form this is not going to be commonly useful and would need to be setup to be configurable for end users. (see issue description) I would be willing do the configuration setup work but guidance or direction to the best example of how this is typically handled in the nav2 Eco-system would be appreciated.

For Maintainers:

  • Check that any new parameters added are updated in docs.nav2.org
  • Check that any significant change is added to the migration guide
  • Check that any new features OR changes to existing behaviors are reflected in the tuning guide
  • Check that any new functions have Doxygen added
  • Check that any new features have test coverage
  • Check that any new plugins is added to the plugins page
  • If BT Node, Additionally: add to BT's XML index of nodes for groot, BT package's readme table, and BT library lists
  • Should this be backported to current distributions? If so, tag with backport-*.

Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #5585 (comment)

Basically: Just have the height_field be a parameter with a string type default to "z". Then you can set this in your yaml to "height" and no other code needs to change (i.e. no new iterators or changes to the check, just have iter_z use that parameterized string value)

of height checking by end users.

Signed-off-by: Greg Anderson <[email protected]>
error found when running tests.

Signed-off-by: Greg Anderson <[email protected]>
Comment on lines 142 to 149
if(use_global_height_) {
if (*iter_height >= min_height_ && *iter_height <= max_height_) {
data.push_back({p_v3_b.x(), p_v3_b.y()});
}
} else {
if (*iter_z >= min_height_ && *iter_z <= max_height_) {
data.push_back({p_v3_b.x(), p_v3_b.y()});
}
Copy link
Member

@SteveMacenski SteveMacenski Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If here when if(use_global_height_) we do the ++iter_height, then we can remove it from the for loop, which also allows us not to initialize it with z when not set. This will improve performance for users without the height element since we're not double iterating through the Z channel. The else then can also be removed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had originally tried implementing as you described, but had two problems.

  1. I couldn't find a way to initilize iter_height inside the if statement that didn't give an undeclared error for iter_height inside the for loop. This is possibly a skill issue on my part, please advise if there is a method I am unaware of.
  2. If removing the ++iter_height from the for loop and adding it to the loop body then it also needs to be incremented at the < min_range check to keep the iterators synchronized. I saw it as a potential foot gun in future development if other checks are implemented but miss incrementing the height iterator. I will defer to your judgement on that implementation.

In the last commit I pushed I duplicated the for loop with the different iterator implementations as an additional option. I'm not a fan of the code duplication but it worked and would address performance concerns.

Copy link
Member

@SteveMacenski SteveMacenski Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps something like:


  bool height_present = false;
  for(const auto & field : data_->fields) {
    if (field.name == "height") {
      height_present = true;
    }
  }

  // Reference height field
  std::string height_field{""};
  if (use_global_height_ && height_present) {
    height_field = "height";
  } else if (use_global_height_) {
    // Log error here TODO
    return false;
  }

  sensor_msgs::PointCloud2ConstIterator<float> iter_height(*data_, height_field);

  // Refill data array with PointCloud points in base frame
  for (; iter_x != iter_x.end(); ++iter_x, ++iter_y, ++iter_z) {
    // Transform point coordinates from source frame -> to base frame
    tf2::Vector3 p_v3_s(*iter_x, *iter_y, *iter_z);

    double data_height = *iter_z;
    if (use_global_height_) {
      data_height = *iter_height;
      iter_height++;
    }

    // Check range from sensor origin before transformation
    double range = p_v3_s.length();
    if (range < min_range_) {
      continue;
    }
    tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
    // Refill data array
    if (data_height >= min_height_ && data_height <= max_height_) {
      data.push_back({p_v3_b.x(), p_v3_b.y()});
    }
  }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't increment the iter_height unless use_global_height_ = true, which resolves the computation issue since the iterator doesn't do a copy of the PC data. It also removes duplication of the loop and in the loop by just replacing a locally stored version of data_height that is set as z when not using the height. Then height is incremented before any processing happens to keep it aligned.

What do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works except the iter_height object gives a run time error that the field is not found since height_field is initialized as an empty string. Since you said creating the iterator doesn't copy the PC data that shouldn't be a performance impact. And in that case I will just initialize it as the "z" field and then overwrite it to "height" for the global height case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that works!

Remove run time error and replaced with log error.

Signed-off-by: Greg Anderson <[email protected]>
Copy link

codecov bot commented Oct 7, 2025

Codecov Report

❌ Patch coverage is 66.66667% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
nav2_collision_monitor/src/pointcloud.cpp 66.66% 5 Missing ⚠️
Files with missing lines Coverage Δ
nav2_collision_monitor/src/pointcloud.cpp 78.75% <66.66%> (-3.07%) ⬇️

... and 18 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

code simplicity.

Signed-off-by: Greg Anderson <[email protected]>
Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beyond that, we just need the new parameter introduced into the configuration guide https://docs.nav2.org/configuration/packages/configuring-collision-monitor.html

Can this be removed from draft mode?

sensor_msgs::PointCloud2ConstIterator<float> iter_z(*data_, "z");

bool height_present = false;
for(const auto & field : data_->fields) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for(const auto & field : data_->fields) {
for (const auto & field : data_->fields) {

height_field = "height";
} else if (use_global_height_) {
RCLCPP_ERROR(logger_, "[%s]: 'use_global_height' parameter true but height field not in cloud",
source_name_.c_str());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
source_name_.c_str());
source_name_.c_str());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants