@@ -140,6 +140,59 @@ class TestNode : public nav2_util::LifecycleNode
140140 pointcloud_pub_->publish (std::move (msg));
141141 }
142142
143+ void publishPointCloudForMinRange (const rclcpp::Time & stamp)
144+ {
145+ pointcloud_pub_ = this ->create_publisher <sensor_msgs::msg::PointCloud2>(
146+ POINTCLOUD_TOPIC, rclcpp::QoS (rclcpp::KeepLast (1 )).transient_local ().reliable ());
147+ pointcloud_pub_->on_activate ();
148+
149+ std::unique_ptr<sensor_msgs::msg::PointCloud2> msg =
150+ std::make_unique<sensor_msgs::msg::PointCloud2>();
151+ sensor_msgs::PointCloud2Modifier modifier (*msg);
152+
153+ msg->header .frame_id = SOURCE_FRAME_ID;
154+ msg->header .stamp = stamp;
155+
156+ modifier.setPointCloud2Fields (
157+ 3 , " x" , 1 , sensor_msgs::msg::PointField::FLOAT32,
158+ " y" , 1 , sensor_msgs::msg::PointField::FLOAT32,
159+ " z" , 1 , sensor_msgs::msg::PointField::FLOAT32);
160+ modifier.resize (4 );
161+
162+ sensor_msgs::PointCloud2Iterator<float > iter_x (*msg, " x" );
163+ sensor_msgs::PointCloud2Iterator<float > iter_y (*msg, " y" );
164+ sensor_msgs::PointCloud2Iterator<float > iter_z (*msg, " z" );
165+
166+ // Point 0: Very close to origin (0.05, 0.0, 0.15) - range ≈ 0.158,
167+ // should be filtered
168+ *iter_x = 0.05 ;
169+ *iter_y = 0.0 ;
170+ *iter_z = 0.15 ;
171+ ++iter_x; ++iter_y; ++iter_z;
172+
173+ // Point 1: Close to origin (0.15, 0.0, 0.15) - range ≈ 0.212,
174+ // should pass with min_range=0.16
175+ *iter_x = 0.15 ;
176+ *iter_y = 0.0 ;
177+ *iter_z = 0.15 ;
178+ ++iter_x; ++iter_y; ++iter_z;
179+
180+ // Point 2: At min_range threshold (0.2, 0.0, 0.15) - range ≈ 0.25,
181+ // should pass with min_range=0.16
182+ *iter_x = 0.2 ;
183+ *iter_y = 0.0 ;
184+ *iter_z = 0.15 ;
185+ ++iter_x; ++iter_y; ++iter_z;
186+
187+ // Point 3: Beyond min_range (0.5, 0.0, 0.15) - range ≈ 0.522,
188+ // should pass
189+ *iter_x = 0.5 ;
190+ *iter_y = 0.0 ;
191+ *iter_z = 0.15 ;
192+
193+ pointcloud_pub_->publish (std::move (msg));
194+ }
195+
143196 void publishRange (const rclcpp::Time & stamp, const double range)
144197 {
145198 range_pub_ = this ->create_publisher <sensor_msgs::msg::Range>(
@@ -296,6 +349,8 @@ class Tester : public ::testing::Test
296349public:
297350 Tester ();
298351 ~Tester ();
352+ std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
353+ std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
299354
300355protected:
301356 // Data sources creation routine
@@ -319,10 +374,6 @@ class Tester : public ::testing::Test
319374 std::shared_ptr<PointCloudWrapper> pointcloud_;
320375 std::shared_ptr<RangeWrapper> range_;
321376 std::shared_ptr<PolygonWrapper> polygon_;
322-
323- private:
324- std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
325- std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
326377}; // Tester
327378
328379Tester::Tester ()
@@ -741,6 +792,62 @@ TEST_F(Tester, testIgnoreTimeShift)
741792 checkPolygon (data);
742793}
743794
795+ TEST_F (Tester, testPointCloudMinRange)
796+ {
797+ rclcpp::Time curr_time = test_node_->now ();
798+
799+ // Create PointCloud object with min_range = 0.2
800+ test_node_->declare_parameter (
801+ std::string (POINTCLOUD_NAME) + " .topic" , rclcpp::ParameterValue (POINTCLOUD_TOPIC));
802+ test_node_->set_parameter (
803+ rclcpp::Parameter (std::string (POINTCLOUD_NAME) + " .topic" , POINTCLOUD_TOPIC));
804+ test_node_->declare_parameter (
805+ std::string (POINTCLOUD_NAME) + " .min_height" , rclcpp::ParameterValue (0.1 ));
806+ test_node_->set_parameter (
807+ rclcpp::Parameter (std::string (POINTCLOUD_NAME) + " .min_height" , 0.1 ));
808+ test_node_->declare_parameter (
809+ std::string (POINTCLOUD_NAME) + " .max_height" , rclcpp::ParameterValue (1.0 ));
810+ test_node_->set_parameter (
811+ rclcpp::Parameter (std::string (POINTCLOUD_NAME) + " .max_height" , 1.0 ));
812+ test_node_->declare_parameter (
813+ std::string (POINTCLOUD_NAME) + " .min_range" , rclcpp::ParameterValue (0.16 ));
814+ test_node_->set_parameter (
815+ rclcpp::Parameter (std::string (POINTCLOUD_NAME) + " .min_range" , 0.16 ));
816+
817+ pointcloud_ = std::make_shared<PointCloudWrapper>(
818+ test_node_, POINTCLOUD_NAME, tf_buffer_,
819+ BASE_FRAME_ID, GLOBAL_FRAME_ID,
820+ TRANSFORM_TOLERANCE, DATA_TIMEOUT, true );
821+ pointcloud_->configure ();
822+
823+ sendTransforms (curr_time);
824+
825+ // Publish pointcloud data with points at various ranges
826+ test_node_->publishPointCloudForMinRange (curr_time);
827+
828+ // Wait until pointcloud receives the data
829+ ASSERT_TRUE (waitPointCloud (500ms));
830+
831+ // Check PointCloud data - should only contain points with range >= min_range (0.16)
832+ std::vector<nav2_collision_monitor::Point> data;
833+ pointcloud_->getData (curr_time, data);
834+
835+ // Should have 3 points: first point (range ≈ 0.158) filtered out, remaining 3 pass
836+ ASSERT_EQ (data.size (), 3u );
837+
838+ // Point 1: (0.15 + 0.1, 0.0 + 0.1) = (0.25, 0.1) - range ≈ 0.212, passes
839+ EXPECT_NEAR (data[0 ].x , 0.25 , EPSILON);
840+ EXPECT_NEAR (data[0 ].y , 0.1 , EPSILON);
841+
842+ // Point 2: (0.2 + 0.1, 0.0 + 0.1) = (0.3, 0.1) - range ≈ 0.25, passes
843+ EXPECT_NEAR (data[1 ].x , 0.3 , EPSILON);
844+ EXPECT_NEAR (data[1 ].y , 0.1 , EPSILON);
845+
846+ // Point 3: (0.5 + 0.1, 0.0 + 0.1) = (0.6, 0.1) - range ≈ 0.522, passes
847+ EXPECT_NEAR (data[2 ].x , 0.6 , EPSILON);
848+ EXPECT_NEAR (data[2 ].y , 0.1 , EPSILON);
849+ }
850+
744851int main (int argc, char ** argv)
745852{
746853 // Initialize the system
0 commit comments