@@ -38,9 +38,7 @@ class IsWithinPathTrackingBoundsConditionTestFixture : public ::testing::Test
3838 // Create the blackboard that will be shared by all of the nodes in the tree
3939 config_->blackboard = BT::Blackboard::create ();
4040 // Put items on the blackboard
41- config_->blackboard ->set (
42- " node" ,
43- node_);
41+ config_->blackboard ->set (" node" , node_);
4442 config_->blackboard ->set <std::chrono::milliseconds>(
4543 " bt_loop_duration" ,
4644 std::chrono::milliseconds (10 ));
@@ -49,7 +47,7 @@ class IsWithinPathTrackingBoundsConditionTestFixture : public ::testing::Test
4947 " IsWithinPathTrackingBounds" );
5048
5149 tracking_feedback_pub_ = node_->create_publisher <nav2_msgs::msg::TrackingFeedback>(
52- " / tracking_feedback" ,
50+ " tracking_feedback" ,
5351 rclcpp::SystemDefaultsQoS ());
5452 tracking_feedback_pub_->on_activate ();
5553 }
@@ -64,6 +62,15 @@ class IsWithinPathTrackingBoundsConditionTestFixture : public ::testing::Test
6462 executor_.reset ();
6563 }
6664
65+ void publishAndSpin (float error_value)
66+ {
67+ nav2_msgs::msg::TrackingFeedback msg;
68+ msg.tracking_error = error_value;
69+ tracking_feedback_pub_->publish (msg);
70+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
71+ executor_->spin_some ();
72+ }
73+
6774protected:
6875 static nav2::LifecycleNode::SharedPtr node_;
6976 static rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
@@ -81,129 +88,175 @@ std::shared_ptr<BT::BehaviorTreeFactory> IsWithinPathTrackingBoundsConditionTest
8188nav2::Publisher<nav2_msgs::msg::TrackingFeedback>::SharedPtr
8289IsWithinPathTrackingBoundsConditionTestFixture::tracking_feedback_pub_ = nullptr ;
8390
84- TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_behavior_within_bounds )
91+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_symmetric_bounds )
8592{
93+ // Test with equal bounds for left and right sides
8694 std::string xml_txt =
8795 R"(
8896 <root BTCPP_format="4">
8997 <BehaviorTree ID="MainTree">
90- <IsWithinPathTrackingBounds max_error ="1.0"/>
98+ <IsWithinPathTrackingBounds max_error_left="1.0" max_error_right ="1.0"/>
9199 </BehaviorTree>
92100 </root>)" ;
93101
94102 auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
95103
96- // Test case 1: Error is within bounds (should return SUCCESS)
97- nav2_msgs::msg::TrackingFeedback tracking_feedback_msg;
98- tracking_feedback_msg.tracking_error = 0.5 ;
99- tracking_feedback_pub_->publish (tracking_feedback_msg);
100- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
101- executor_->spin_some ();
104+ publishAndSpin (0.5 );
102105 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
103-
104- // Test case 2: Error is exactly at the boundary (should return SUCCESS)
105- tracking_feedback_msg.tracking_error = 1.0 ;
106- tracking_feedback_pub_->publish (tracking_feedback_msg);
107- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
108- executor_->spin_some ();
106+ publishAndSpin (-0.5 );
109107 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
110-
111- // Test case 3: Error exceeds bounds (should return FAILURE)
112- tracking_feedback_msg.tracking_error = 1.5 ;
113- tracking_feedback_pub_->publish (tracking_feedback_msg);
114- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
115- executor_->spin_some ();
108+ publishAndSpin (1.0 );
109+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
110+ publishAndSpin (-1.0 );
111+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
112+ publishAndSpin (1.5 );
116113 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
114+ publishAndSpin (-1.5 );
115+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
116+ publishAndSpin (0.0 );
117+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
118+ }
117119
118- // Test case 4: Zero error (should return SUCCESS)
119- tracking_feedback_msg.tracking_error = 0.0 ;
120- tracking_feedback_pub_->publish (tracking_feedback_msg);
121- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
122- executor_->spin_some ();
120+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_asymmetric_bounds)
121+ {
122+ // Test with different bounds for left and right sides
123+ std::string xml_txt =
124+ R"(
125+ <root BTCPP_format="4">
126+ <BehaviorTree ID="MainTree">
127+ <IsWithinPathTrackingBounds max_error_left="2.0" max_error_right="0.5"/>
128+ </BehaviorTree>
129+ </root>)" ;
130+
131+ auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
132+ publishAndSpin (1.5 );
133+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
134+ publishAndSpin (-0.3 );
135+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
136+ publishAndSpin (2.0 );
137+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
138+ publishAndSpin (-0.5 );
123139 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
140+ publishAndSpin (2.5 );
141+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
142+ publishAndSpin (-0.8 );
143+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
124144}
125145
126- TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_behavior_different_max_error )
146+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_left_side_only )
127147{
148+ // Test with very restrictive right bound
128149 std::string xml_txt =
129150 R"(
130151 <root BTCPP_format="4">
131152 <BehaviorTree ID="MainTree">
132- <IsWithinPathTrackingBounds max_error="0.2 "/>
153+ <IsWithinPathTrackingBounds max_error_left="5.0" max_error_right="0.0 "/>
133154 </BehaviorTree>
134155 </root>)" ;
135156
136157 auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
137158
138- // Test case 1: Error is within smaller bounds (should return SUCCESS)
139- nav2_msgs::msg::TrackingFeedback tracking_feedback_msg;
140- tracking_feedback_msg.tracking_error = 0.1 ;
141- tracking_feedback_pub_->publish (tracking_feedback_msg);
142- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
143- executor_->spin_some ();
159+ publishAndSpin (4.9 );
160+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
161+ publishAndSpin (5.0 );
144162 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
163+ publishAndSpin (5.1 );
164+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
165+ publishAndSpin (-0.001 );
166+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
167+ publishAndSpin (0.0 );
168+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
169+ }
145170
146- // Test case 2: Error exceeds smaller bounds (should return FAILURE)
147- tracking_feedback_msg.tracking_error = 0.3 ;
148- tracking_feedback_pub_->publish (tracking_feedback_msg);
149- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
150- executor_->spin_some ();
171+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_right_side_only)
172+ {
173+ // Test with very restrictive left bound
174+ std::string xml_txt =
175+ R"(
176+ <root BTCPP_format="4">
177+ <BehaviorTree ID="MainTree">
178+ <IsWithinPathTrackingBounds max_error_left="0.0" max_error_right="5.0"/>
179+ </BehaviorTree>
180+ </root>)" ;
181+
182+ auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
183+
184+ publishAndSpin (-4.9 );
185+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
186+ publishAndSpin (-5.0 );
187+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
188+ publishAndSpin (-5.1 );
189+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
190+ publishAndSpin (0.001 );
151191 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
192+ publishAndSpin (0.0 );
193+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
152194}
153195
154- TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_behavior_large_error_values )
196+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_very_tight_bounds )
155197{
198+ // Test with very small bounds
156199 std::string xml_txt =
157200 R"(
158201 <root BTCPP_format="4">
159202 <BehaviorTree ID="MainTree">
160- <IsWithinPathTrackingBounds max_error="5.0 "/>
203+ <IsWithinPathTrackingBounds max_error_left="0.1" max_error_right="0.1 "/>
161204 </BehaviorTree>
162205 </root>)" ;
163206
164207 auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
165208
166- // Test case 1: Large error within bounds (should return SUCCESS)
167- nav2_msgs::msg::TrackingFeedback tracking_feedback_msg;
168- tracking_feedback_msg.tracking_error = 4.9 ;
169- tracking_feedback_pub_->publish (tracking_feedback_msg);
170- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
171- executor_->spin_some ();
209+ publishAndSpin (0.05 );
172210 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
211+ publishAndSpin (-0.05 );
212+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
213+ publishAndSpin (0.15 );
214+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
215+ publishAndSpin (-0.15 );
216+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
217+ }
218+
219+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_no_feedback_received)
220+ {
221+ // Test behavior when no feedback has been received yet
222+ std::string xml_txt =
223+ R"(
224+ <root BTCPP_format="4">
225+ <BehaviorTree ID="MainTree">
226+ <IsWithinPathTrackingBounds max_error_left="1.0" max_error_right="1.0"/>
227+ </BehaviorTree>
228+ </root>)" ;
173229
174- // Test case 2: Very large error exceeding bounds (should return FAILURE)
175- tracking_feedback_msg.tracking_error = 10.0 ;
176- tracking_feedback_pub_->publish (tracking_feedback_msg);
230+ // Create a fresh tree without publishing any feedback
231+ auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
232+
233+ // Should return FAILURE when no feedback received
234+ // Note: This test creates a new condition node, so last_error_ will be at max()
177235 std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
178236 executor_->spin_some ();
179237 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
180238}
181239
182- TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_behavior_edge_cases )
240+ TEST_F (IsWithinPathTrackingBoundsConditionTestFixture, test_sign_convention )
183241{
242+ // Verify sign convention: positive = left, negative = right
184243 std::string xml_txt =
185244 R"(
186245 <root BTCPP_format="4">
187246 <BehaviorTree ID="MainTree">
188- <IsWithinPathTrackingBounds max_error="0 .0"/>
247+ <IsWithinPathTrackingBounds max_error_left="1.0" max_error_right="2 .0"/>
189248 </BehaviorTree>
190249 </root>)" ;
191250
192251 auto tree = factory_->createTreeFromText (xml_txt, config_->blackboard );
193252
194- // Test case 1: Zero max_error with zero tracking error (should return SUCCESS)
195- nav2_msgs::msg::TrackingFeedback tracking_feedback_msg;
196- tracking_feedback_msg.tracking_error = 0.0 ;
197- tracking_feedback_pub_->publish (tracking_feedback_msg);
198- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
199- executor_->spin_some ();
253+ publishAndSpin (0.9 );
200254 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
201-
202- // Test case 2: Zero max_error with any positive tracking error (should return FAILURE)
203- tracking_feedback_msg.tracking_error = 0.001 ;
204- tracking_feedback_pub_->publish (tracking_feedback_msg);
205- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
206- executor_->spin_some ();
255+ publishAndSpin (1.5 );
256+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
257+ publishAndSpin (-1.5 );
258+ EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::SUCCESS);
259+ publishAndSpin (-2.5 );
207260 EXPECT_EQ (tree.tickOnce (), BT::NodeStatus::FAILURE);
208261}
209262
0 commit comments