25 #include "drive_on_heading_behavior_tester.hpp"
26 #include "nav2_util/geometry_utils.hpp"
28 using namespace std::chrono_literals;
29 using namespace std::chrono;
31 namespace nav2_system_tests
34 DriveOnHeadingBehaviorTester::DriveOnHeadingBehaviorTester()
36 initial_pose_received_(false)
38 rclcpp::NodeOptions options;
39 options.parameter_overrides({{
"use_sim_time",
true}});
40 node_ = rclcpp::Node::make_shared(
"DriveOnHeading_behavior_test", options);
42 tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
43 tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
45 client_ptr_ = rclcpp_action::create_client<DriveOnHeading>(
46 node_->get_node_base_interface(),
47 node_->get_node_graph_interface(),
48 node_->get_node_logging_interface(),
49 node_->get_node_waitables_interface(),
53 node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>(
"initialpose", 10);
55 subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
56 "amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
57 std::bind(&DriveOnHeadingBehaviorTester::amclPoseCallback,
this, std::placeholders::_1));
59 stamp_ = node_->now();
62 DriveOnHeadingBehaviorTester::~DriveOnHeadingBehaviorTester()
69 void DriveOnHeadingBehaviorTester::activate()
72 throw std::runtime_error(
"Trying to activate while already active");
76 while (!initial_pose_received_) {
77 RCLCPP_WARN(node_->get_logger(),
"Initial pose not received");
79 std::this_thread::sleep_for(100ms);
80 rclcpp::spin_some(node_);
84 std::this_thread::sleep_for(10s);
87 RCLCPP_ERROR(node_->get_logger(),
"Action client not initialized");
92 if (!client_ptr_->wait_for_action_server(10s)) {
93 RCLCPP_ERROR(node_->get_logger(),
"Action server not available after waiting");
98 RCLCPP_INFO(this->node_->get_logger(),
"DriveOnHeading action server is ready");
102 void DriveOnHeadingBehaviorTester::deactivate()
105 throw std::runtime_error(
"Trying to deactivate while already inactive");
110 bool DriveOnHeadingBehaviorTester::defaultDriveOnHeadingBehaviorTest(
111 const DriveOnHeading::Goal goal_msg,
112 const double tolerance)
115 RCLCPP_ERROR(node_->get_logger(),
"Not activated");
120 std::this_thread::sleep_for(5s);
122 RCLCPP_INFO(this->node_->get_logger(),
"Sending goal");
124 geometry_msgs::msg::PoseStamped initial_pose;
125 if (!nav2_util::getCurrentPose(initial_pose, *tf_buffer_,
"odom")) {
126 RCLCPP_ERROR(node_->get_logger(),
"Current robot pose is not available.");
129 RCLCPP_INFO(node_->get_logger(),
"Found current robot pose");
131 auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
133 if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
134 rclcpp::FutureReturnCode::SUCCESS)
136 RCLCPP_ERROR(node_->get_logger(),
"send goal call failed :(");
140 rclcpp_action::ClientGoalHandle<DriveOnHeading>::SharedPtr goal_handle = goal_handle_future.get();
142 RCLCPP_ERROR(node_->get_logger(),
"Goal was rejected by server");
147 auto result_future = client_ptr_->async_get_result(goal_handle);
149 RCLCPP_INFO(node_->get_logger(),
"Waiting for result");
150 if (rclcpp::spin_until_future_complete(node_, result_future) !=
151 rclcpp::FutureReturnCode::SUCCESS)
153 RCLCPP_ERROR(node_->get_logger(),
"get result call failed :(");
157 rclcpp_action::ClientGoalHandle<DriveOnHeading>::WrappedResult wrapped_result =
160 switch (wrapped_result.code) {
161 case rclcpp_action::ResultCode::SUCCEEDED:
break;
162 case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
166 case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
168 "Goal was canceled");
170 default: RCLCPP_ERROR(node_->get_logger(),
"Unknown result code");
174 RCLCPP_INFO(node_->get_logger(),
"result received");
176 geometry_msgs::msg::PoseStamped current_pose;
177 if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_,
"odom")) {
178 RCLCPP_ERROR(node_->get_logger(),
"Current robot pose is not available.");
182 double dist = nav2_util::geometry_utils::euclidean_distance(initial_pose, current_pose);
184 if (fabs(dist) > fabs(goal_msg.target.x) + tolerance) {
187 "Distance from goal is %lf (tolerance %lf)",
188 fabs(dist - goal_msg.target.x), tolerance);
195 void DriveOnHeadingBehaviorTester::sendInitialPose()
197 geometry_msgs::msg::PoseWithCovarianceStamped pose;
198 pose.header.frame_id =
"map";
199 pose.header.stamp = stamp_;
200 pose.pose.pose.position.x = -2.0;
201 pose.pose.pose.position.y = -0.5;
202 pose.pose.pose.position.z = 0.0;
203 pose.pose.pose.orientation.x = 0.0;
204 pose.pose.pose.orientation.y = 0.0;
205 pose.pose.pose.orientation.z = 0.0;
206 pose.pose.pose.orientation.w = 1.0;
207 for (
int i = 0; i < 35; i++) {
208 pose.pose.covariance[i] = 0.0;
210 pose.pose.covariance[0] = 0.08;
211 pose.pose.covariance[7] = 0.08;
212 pose.pose.covariance[35] = 0.05;
214 publisher_->publish(pose);
215 RCLCPP_INFO(node_->get_logger(),
"Sent initial pose");
218 void DriveOnHeadingBehaviorTester::amclPoseCallback(
219 const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
221 initial_pose_received_ =
true;