Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
wait_behavior_tester.cpp
1 // Copyright (c) 2020 Samsung Research
2 // Copyright (c) 2020 Sarthak Mittal
3 // Copyright (c) 2018 Intel Corporation
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License. Reserved.
16 
17 #include <string>
18 #include <random>
19 #include <tuple>
20 #include <memory>
21 #include <iostream>
22 #include <chrono>
23 #include <sstream>
24 #include <iomanip>
25 
26 #include "wait_behavior_tester.hpp"
27 #include "nav2_ros_common/tf2_factories.hpp"
28 
29 using namespace std::chrono_literals;
30 using namespace std::chrono; // NOLINT
31 
32 namespace nav2_system_tests
33 {
34 
35 WaitBehaviorTester::WaitBehaviorTester()
36 : is_active_(false),
37  initial_pose_received_(false)
38 {
39  node_ = rclcpp::Node::make_shared(
40  "wait_behavior_test",
41  rclcpp::NodeOptions().parameter_overrides(
42  {rclcpp::Parameter("use_sim_time", true)}));
43 
44  tf_buffer_ = nav2::create_transform_buffer(node_);
45  tf_listener_ = nav2::create_transform_listener(*tf_buffer_);
46 
47  client_ptr_ = rclcpp_action::create_client<Wait>(
48  node_->get_node_base_interface(),
49  node_->get_node_graph_interface(),
50  node_->get_node_logging_interface(),
51  node_->get_node_waitables_interface(),
52  "wait");
53 
54  publisher_ =
55  node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
56 
57  subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
58  "amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
59  std::bind(&WaitBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
60 }
61 
62 WaitBehaviorTester::~WaitBehaviorTester()
63 {
64  if (is_active_) {
65  deactivate();
66  }
67 }
68 
69 void WaitBehaviorTester::activate()
70 {
71  if (is_active_) {
72  throw std::runtime_error("Trying to activate while already active");
73  return;
74  }
75  rclcpp::executors::SingleThreadedExecutor executor;
76  executor.add_node(node_);
77  while (!initial_pose_received_) {
78  RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
79  sendInitialPose();
80  std::this_thread::sleep_for(100ms);
81  executor.spin_some();
82  }
83 
84  // Wait for lifecycle_manager_navigation to activate behavior_server
85  std::this_thread::sleep_for(10s);
86 
87  if (!client_ptr_) {
88  RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
89  is_active_ = false;
90  return;
91  }
92 
93  if (!client_ptr_->wait_for_action_server(10s)) {
94  RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
95  is_active_ = false;
96  return;
97  }
98 
99  RCLCPP_INFO(this->node_->get_logger(), "Wait action server is ready");
100  is_active_ = true;
101 }
102 
103 void WaitBehaviorTester::deactivate()
104 {
105  if (!is_active_) {
106  throw std::runtime_error("Trying to deactivate while already inactive");
107  }
108  is_active_ = false;
109 }
110 
111 bool WaitBehaviorTester::behaviorTest(
112  const float wait_time)
113 {
114  if (!is_active_) {
115  RCLCPP_ERROR(node_->get_logger(), "Not activated");
116  return false;
117  }
118 
119  // Sleep to let behavior server be ready for serving in multiple runs
120  std::this_thread::sleep_for(5s);
121 
122  auto start_time = node_->now();
123  auto goal_msg = Wait::Goal();
124  goal_msg.time = rclcpp::Duration(wait_time, 0.0);
125 
126  RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
127 
128  auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
129 
130  if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
131  rclcpp::FutureReturnCode::SUCCESS)
132  {
133  RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
134  return false;
135  }
136 
137  rclcpp_action::ClientGoalHandle<Wait>::SharedPtr goal_handle = goal_handle_future.get();
138  if (!goal_handle) {
139  RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
140  return false;
141  }
142 
143  // Wait for the server to be done with the goal
144  auto result_future = client_ptr_->async_get_result(goal_handle);
145 
146  RCLCPP_INFO(node_->get_logger(), "Waiting for result");
147  if (rclcpp::spin_until_future_complete(node_, result_future) !=
148  rclcpp::FutureReturnCode::SUCCESS)
149  {
150  RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
151  return false;
152  }
153 
154  rclcpp_action::ClientGoalHandle<Wait>::WrappedResult wrapped_result = result_future.get();
155 
156  switch (wrapped_result.code) {
157  case rclcpp_action::ResultCode::SUCCEEDED: break;
158  case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
159  node_->get_logger(),
160  "Goal was aborted");
161  return false;
162  case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
163  node_->get_logger(),
164  "Goal was canceled");
165  return false;
166  default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
167  return false;
168  }
169 
170  RCLCPP_INFO(node_->get_logger(), "result received");
171 
172  if ((node_->now() - start_time).seconds() < static_cast<double>(wait_time)) {
173  return false;
174  }
175 
176  return true;
177 }
178 
179 bool WaitBehaviorTester::behaviorTestCancel(
180  const float wait_time)
181 {
182  if (!is_active_) {
183  RCLCPP_ERROR(node_->get_logger(), "Not activated");
184  return false;
185  }
186 
187  // Sleep to let behavior server be ready for serving in multiple runs
188  std::this_thread::sleep_for(5s);
189 
190  auto start_time = node_->now();
191  auto goal_msg = Wait::Goal();
192  goal_msg.time = rclcpp::Duration(wait_time, 0.0);
193 
194  RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
195 
196  auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
197 
198  if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
199  rclcpp::FutureReturnCode::SUCCESS)
200  {
201  RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
202  return false;
203  }
204 
205  rclcpp_action::ClientGoalHandle<Wait>::SharedPtr goal_handle = goal_handle_future.get();
206  if (!goal_handle) {
207  RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
208  return false;
209  }
210 
211  // Wait for the server to be done with the goal
212  auto result_future = client_ptr_->async_cancel_all_goals();
213 
214  RCLCPP_INFO(node_->get_logger(), "Waiting for cancellation");
215  if (rclcpp::spin_until_future_complete(node_, result_future) !=
216  rclcpp::FutureReturnCode::SUCCESS)
217  {
218  RCLCPP_ERROR(node_->get_logger(), "get cancel result call failed :(");
219  return false;
220  }
221 
222  auto status = goal_handle_future.get()->get_status();
223 
224  switch (status) {
225  case rclcpp_action::GoalStatus::STATUS_SUCCEEDED: RCLCPP_ERROR(
226  node_->get_logger(),
227  "Goal succeeded");
228  return false;
229  case rclcpp_action::GoalStatus::STATUS_ABORTED: RCLCPP_ERROR(
230  node_->get_logger(),
231  "Goal was aborted");
232  return false;
233  case rclcpp_action::GoalStatus::STATUS_CANCELED: RCLCPP_INFO(
234  node_->get_logger(),
235  "Goal was canceled");
236  return true;
237  case rclcpp_action::GoalStatus::STATUS_CANCELING: RCLCPP_INFO(
238  node_->get_logger(),
239  "Goal is cancelling");
240  return true;
241  case rclcpp_action::GoalStatus::STATUS_EXECUTING: RCLCPP_ERROR(
242  node_->get_logger(),
243  "Goal is executing");
244  return false;
245  case rclcpp_action::GoalStatus::STATUS_ACCEPTED: RCLCPP_ERROR(
246  node_->get_logger(),
247  "Goal is processing");
248  return false;
249  default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
250  return false;
251  }
252 
253  return false;
254 }
255 
256 void WaitBehaviorTester::sendInitialPose()
257 {
258  geometry_msgs::msg::PoseWithCovarianceStamped pose;
259  pose.header.frame_id = "map";
260  pose.header.stamp = rclcpp::Time();
261  pose.pose.pose.position.x = -2.0;
262  pose.pose.pose.position.y = -0.5;
263  pose.pose.pose.position.z = 0.0;
264  pose.pose.pose.orientation.x = 0.0;
265  pose.pose.pose.orientation.y = 0.0;
266  pose.pose.pose.orientation.z = 0.0;
267  pose.pose.pose.orientation.w = 1.0;
268  for (int i = 0; i < 35; i++) {
269  pose.pose.covariance[i] = 0.0;
270  }
271  pose.pose.covariance[0] = 0.08;
272  pose.pose.covariance[7] = 0.08;
273  pose.pose.covariance[35] = 0.05;
274 
275  publisher_->publish(pose);
276  RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
277 }
278 
279 void WaitBehaviorTester::amclPoseCallback(
280  const geometry_msgs::msg::PoseWithCovarianceStamped::ConstSharedPtr)
281 {
282  initial_pose_received_ = true;
283 }
284 
285 } // namespace nav2_system_tests