Skip to content

Commit 9af4d28

Browse files
greganderson-vermeerRBT22
authored andcommitted
Backporting custom height point field into Jazzy. (ros-navigation#5646)
* Summary commit of all changes for adding custom pointcloud field height. (ros-navigation#5586) Doing this to clear out unsigned commits from history. Signed-off-by: Greg Anderson <107634795+greganderson-vermeer@users.noreply.github.com> * Corrected parameter declaration methods that aren't part of Jazzy. Fixed parameter typo from some manual merging in pointcloud.cpp Signed-off-by: Greg Anderson <107634795+greganderson-vermeer@users.noreply.github.com> --------- Signed-off-by: Greg Anderson <107634795+greganderson-vermeer@users.noreply.github.com>
1 parent abf5d1a commit 9af4d28

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed

nav2_collision_monitor/include/nav2_collision_monitor/pointcloud.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ class PointCloud : public Source
9797
double min_height_, max_height_;
9898
// Minimum range from sensor origin to filter out close points
9999
double min_range_;
100+
/**Changes height check from "z" field to "height" field for pipelines utilizing
101+
* ground contouring
102+
*/
103+
bool use_global_height_;
100104

101105
/// @brief Latest data obtained from pointcloud
102106
sensor_msgs::msg::PointCloud2::ConstSharedPtr data_;

nav2_collision_monitor/params/collision_monitor_params.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,5 @@ collision_monitor:
9898
topic: "/intel_realsense_r200_depth/points"
9999
min_height: 0.1
100100
max_height: 0.5
101+
use_global_height: False
101102
enabled: True

nav2_collision_monitor/src/pointcloud.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,35 @@ bool PointCloud::getData(
8888
sensor_msgs::PointCloud2ConstIterator<float> iter_y(*data_, "y");
8989
sensor_msgs::PointCloud2ConstIterator<float> iter_z(*data_, "z");
9090

91+
bool height_present = false;
92+
for (const auto & field : data_->fields) {
93+
if (field.name == "height") {
94+
height_present = true;
95+
}
96+
}
97+
98+
// Reference height field
99+
std::string height_field{"z"};
100+
if (use_global_height_ && height_present) {
101+
height_field = "height";
102+
} else if (use_global_height_) {
103+
RCLCPP_ERROR(logger_, "[%s]: 'use_global_height' parameter true but height field not in cloud",
104+
source_name_.c_str());
105+
return false;
106+
}
107+
sensor_msgs::PointCloud2ConstIterator<float> iter_height(*data_, height_field);
108+
91109
// Refill data array with PointCloud points in base frame
92110
for (; iter_x != iter_x.end(); ++iter_x, ++iter_y, ++iter_z) {
93111
// Transform point coordinates from source frame -> to base frame
94112
tf2::Vector3 p_v3_s(*iter_x, *iter_y, *iter_z);
95113

114+
double data_height = *iter_z;
115+
if (use_global_height_) {
116+
data_height = *iter_height;
117+
++iter_height;
118+
}
119+
96120
// Check range from sensor origin before transformation
97121
double range = p_v3_s.length();
98122
if (range < min_range_) {
@@ -102,7 +126,7 @@ bool PointCloud::getData(
102126
tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
103127

104128
// Refill data array
105-
if (p_v3_b.z() >= min_height_ && p_v3_b.z() <= max_height_) {
129+
if (data_height >= min_height_ && data_height <= max_height_) {
106130
data.push_back({p_v3_b.x(), p_v3_b.y()});
107131
}
108132
}
@@ -127,6 +151,9 @@ void PointCloud::getParameters(std::string & source_topic)
127151
nav2_util::declare_parameter_if_not_declared(
128152
node, source_name_ + ".min_range", rclcpp::ParameterValue(0.0));
129153
min_range_ = node->get_parameter(source_name_ + ".min_range").as_double();
154+
nav2_util::declare_parameter_if_not_declared(
155+
node, source_name_ + ".use_global_height", rclcpp::ParameterValue(false));
156+
use_global_height_ = node->get_parameter(source_name_ + ".use_global_height").as_bool();
130157
}
131158

132159
void PointCloud::dataCallback(sensor_msgs::msg::PointCloud2::ConstSharedPtr msg)

nav2_collision_monitor/test/collision_monitor_node_test.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class Tester : public ::testing::Test
162162
void setPolygonVelocityVectors(
163163
const std::string & polygon_name,
164164
const std::vector<std::string> & polygons);
165+
void setGlobalHeightParams(const std::string & source_name, const double min_height);
165166

166167
// Setting TF chains
167168
void sendTransforms(const rclcpp::Time & stamp);
@@ -172,6 +173,9 @@ class Tester : public ::testing::Test
172173
// Main topic/data working routines
173174
void publishScan(const double dist, const rclcpp::Time & stamp);
174175
void publishPointCloud(const double dist, const rclcpp::Time & stamp);
176+
void publishPointCloudWithHeight(
177+
const double dist, const double height,
178+
const rclcpp::Time & stamp);
175179
void publishRange(const double dist, const rclcpp::Time & stamp);
176180
void publishPolygon(const double dist, const rclcpp::Time & stamp);
177181
void publishCmdVel(const double x, const double y, const double tw);
@@ -491,6 +495,8 @@ void Tester::addSource(
491495
source_name + ".max_height", rclcpp::ParameterValue(1.0));
492496
cm_->set_parameter(
493497
rclcpp::Parameter(source_name + ".max_height", 1.0));
498+
cm_->declare_parameter(
499+
source_name + ".use_global_height", rclcpp::ParameterValue(false));
494500
} else if (type == RANGE) {
495501
cm_->declare_parameter(
496502
source_name + ".type", rclcpp::ParameterValue("range"));
@@ -547,6 +553,12 @@ void Tester::setPolygonVelocityVectors(
547553
cm_->set_parameter(rclcpp::Parameter(polygon_name + ".velocity_polygons", polygons));
548554
}
549555

556+
void Tester::setGlobalHeightParams(const std::string & source_name, const double min_height)
557+
{
558+
cm_->set_parameter(rclcpp::Parameter(source_name + ".use_global_height", true));
559+
cm_->set_parameter(rclcpp::Parameter(source_name + ".min_height", min_height));
560+
}
561+
550562
void Tester::sendTransforms(const rclcpp::Time & stamp)
551563
{
552564
std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster =
@@ -654,6 +666,45 @@ void Tester::publishPointCloud(const double dist, const rclcpp::Time & stamp)
654666
pointcloud_pub_->publish(std::move(msg));
655667
}
656668

669+
void Tester::publishPointCloudWithHeight(
670+
const double dist, const double height,
671+
const rclcpp::Time & stamp)
672+
{
673+
std::unique_ptr<sensor_msgs::msg::PointCloud2> msg =
674+
std::make_unique<sensor_msgs::msg::PointCloud2>();
675+
sensor_msgs::PointCloud2Modifier modifier(*msg);
676+
677+
msg->header.frame_id = SOURCE_FRAME_ID;
678+
msg->header.stamp = stamp;
679+
680+
modifier.setPointCloud2Fields(
681+
4, "x", 1, sensor_msgs::msg::PointField::FLOAT32,
682+
"y", 1, sensor_msgs::msg::PointField::FLOAT32,
683+
"z", 1, sensor_msgs::msg::PointField::FLOAT32,
684+
"height", 1, sensor_msgs::msg::PointField::FLOAT32);
685+
modifier.resize(2);
686+
687+
sensor_msgs::PointCloud2Iterator<float> iter_x(*msg, "x");
688+
sensor_msgs::PointCloud2Iterator<float> iter_y(*msg, "y");
689+
sensor_msgs::PointCloud2Iterator<float> iter_z(*msg, "z");
690+
sensor_msgs::PointCloud2Iterator<float> iter_height(*msg, "height");
691+
692+
// Point 0: (dist, 0.01, 0.2, height)
693+
*iter_x = dist;
694+
*iter_y = 0.01;
695+
*iter_z = 0.2;
696+
*iter_height = height;
697+
++iter_x; ++iter_y; ++iter_z; ++iter_height;
698+
699+
// Point 1: (dist, -0.01, 0.2, height)
700+
*iter_x = dist;
701+
*iter_y = -0.01;
702+
*iter_z = 0.2;
703+
*iter_height = height;
704+
705+
pointcloud_pub_->publish(std::move(msg));
706+
}
707+
657708
void Tester::publishRange(const double dist, const rclcpp::Time & stamp)
658709
{
659710
std::unique_ptr<sensor_msgs::msg::Range> msg =
@@ -1656,6 +1707,64 @@ TEST_F(Tester, testVelocityPolygonStop)
16561707
cm_->stop();
16571708
}
16581709

1710+
TEST_F(Tester, testVelocityPolygonStopGlobalHeight)
1711+
{
1712+
// Set Collision Monitor parameters.
1713+
// Add velocity polygon with 2 sub polygon:
1714+
// 1. Forward: 0 -> 0.5 m/s
1715+
// 2. Backward: 0 -> -0.5 m/s
1716+
setCommonParameters();
1717+
addPolygon("VelocityPolygon", VELOCITY_POLYGON, 1.0, "stop");
1718+
addPolygonVelocitySubPolygon("VelocityPolygon", "Forward", 0.0, 0.5, 0.0, 1.0, 4.0);
1719+
addPolygonVelocitySubPolygon("VelocityPolygon", "Backward", -0.5, 0.0, 0.0, 1.0, 2.0);
1720+
setPolygonVelocityVectors("VelocityPolygon", {"Forward", "Backward"});
1721+
addSource(POINTCLOUD_NAME, POINTCLOUD);
1722+
setGlobalHeightParams(POINTCLOUD_NAME, 0.5);
1723+
setVectors({"VelocityPolygon"}, {POINTCLOUD_NAME});
1724+
1725+
cm_->set_parameter(
1726+
rclcpp::Parameter("source_timeout", 2.0));
1727+
1728+
rclcpp::Time curr_time = cm_->now();
1729+
// Start Collision Monitor node
1730+
cm_->start();
1731+
// Check that robot stops when source is enabled
1732+
sendTransforms(curr_time);
1733+
1734+
// 1. Obstacle is in Forward velocity polygon and below global height
1735+
publishPointCloudWithHeight(3.0, 0.4, curr_time);
1736+
ASSERT_FALSE(waitData(std::hypot(3.0, 0.01), 500ms, curr_time));
1737+
publishCmdVel(0.4, 0.0, 0.1);
1738+
ASSERT_TRUE(waitCmdVel(500ms));
1739+
ASSERT_NEAR(cmd_vel_out_->linear.x, 0.4, EPSILON);
1740+
ASSERT_NEAR(cmd_vel_out_->linear.y, 0.0, EPSILON);
1741+
ASSERT_NEAR(cmd_vel_out_->angular.z, 0.1, EPSILON);
1742+
1743+
// 2. Obstacle is in Forward velocity polygon and above global height
1744+
publishPointCloudWithHeight(3.0, 0.6, curr_time);
1745+
ASSERT_TRUE(waitData(std::hypot(3.0, 0.01), 500ms, curr_time));
1746+
publishCmdVel(0.4, 0.0, 0.1);
1747+
ASSERT_TRUE(waitCmdVel(500ms));
1748+
ASSERT_NEAR(cmd_vel_out_->linear.x, 0.0, EPSILON);
1749+
ASSERT_NEAR(cmd_vel_out_->linear.y, 0.0, EPSILON);
1750+
ASSERT_NEAR(cmd_vel_out_->angular.z, 0.0, EPSILON);
1751+
ASSERT_TRUE(waitActionState(500ms));
1752+
ASSERT_EQ(action_state_->action_type, STOP);
1753+
ASSERT_EQ(action_state_->polygon_name, "VelocityPolygon");
1754+
1755+
// 3. Pointcloud without height field, invalid source.
1756+
publishPointCloud(2.5, curr_time);
1757+
ASSERT_FALSE(waitData(std::hypot(2.5, 0.01), 100ms, curr_time));
1758+
publishCmdVel(3.0, 3.0, 3.0);
1759+
ASSERT_FALSE(waitCmdVel(500ms));
1760+
ASSERT_TRUE(waitActionState(500ms));
1761+
ASSERT_EQ(action_state_->action_type, STOP);
1762+
ASSERT_EQ(action_state_->polygon_name, "invalid source");
1763+
1764+
// Stop Collision Monitor node
1765+
cm_->stop();
1766+
}
1767+
16591768
TEST_F(Tester, testSourceAssociatedToPolygon)
16601769
{
16611770
// Set Collision Monitor parameters:

0 commit comments

Comments
 (0)