25 #include "assisted_teleop_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 AssistedTeleopBehaviorTester::AssistedTeleopBehaviorTester()
36 initial_pose_received_(false)
38 node_ = rclcpp::Node::make_shared(
"assisted_teleop_behavior_test");
40 tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
41 tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
43 client_ptr_ = rclcpp_action::create_client<AssistedTeleop>(
44 node_->get_node_base_interface(),
45 node_->get_node_graph_interface(),
46 node_->get_node_logging_interface(),
47 node_->get_node_waitables_interface(),
51 node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>(
"initialpose", 10);
54 node_->create_publisher<std_msgs::msg::Empty>(
"preempt_teleop", 10);
57 node_->create_publisher<geometry_msgs::msg::TwistStamped>(
"cmd_vel_teleop", 10);
59 subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
60 "amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
61 std::bind(&AssistedTeleopBehaviorTester::amclPoseCallback,
this, std::placeholders::_1));
63 filtered_vel_sub_ = node_->create_subscription<geometry_msgs::msg::TwistStamped>(
65 rclcpp::SystemDefaultsQoS(),
66 std::bind(&AssistedTeleopBehaviorTester::filteredVelCallback,
this, std::placeholders::_1));
68 std::string costmap_topic =
"/local_costmap/costmap_raw";
69 std::string footprint_topic =
"/local_costmap/published_footprint";
71 costmap_sub_ = std::make_shared<nav2_costmap_2d::CostmapSubscriber>(
75 footprint_sub_ = std::make_shared<nav2_costmap_2d::FootprintSubscriber>(
80 collision_checker_ = std::make_unique<nav2_costmap_2d::CostmapTopicCollisionChecker>(
85 stamp_ = node_->now();
86 executor_.add_node(node_);
89 AssistedTeleopBehaviorTester::~AssistedTeleopBehaviorTester()
96 void AssistedTeleopBehaviorTester::activate()
99 throw std::runtime_error(
"Trying to activate while already active");
103 while (!initial_pose_received_) {
104 RCLCPP_WARN(node_->get_logger(),
"Initial pose not received");
106 std::this_thread::sleep_for(100ms);
107 executor_.spin_some();
111 std::this_thread::sleep_for(10s);
114 RCLCPP_ERROR(node_->get_logger(),
"Action client not initialized");
119 if (!client_ptr_->wait_for_action_server(10s)) {
120 RCLCPP_ERROR(node_->get_logger(),
"Action server not available after waiting");
125 RCLCPP_INFO(this->node_->get_logger(),
"Assisted Teleop action server is ready");
129 void AssistedTeleopBehaviorTester::deactivate()
132 throw std::runtime_error(
"Trying to deactivate while already inactive");
137 bool AssistedTeleopBehaviorTester::defaultAssistedTeleopTest(
142 RCLCPP_ERROR(node_->get_logger(),
"Not activated");
146 RCLCPP_INFO(node_->get_logger(),
"Sending goal");
148 auto goal_handle_future = client_ptr_->async_send_goal(nav2_msgs::action::AssistedTeleop::Goal());
150 if (executor_.spin_until_future_complete(goal_handle_future) !=
151 rclcpp::FutureReturnCode::SUCCESS)
153 RCLCPP_ERROR(node_->get_logger(),
"send goal call failed :(");
157 rclcpp_action::ClientGoalHandle<AssistedTeleop>::SharedPtr goal_handle = goal_handle_future.get();
159 RCLCPP_ERROR(node_->get_logger(),
"Goal was rejected by server");
164 auto result_future = client_ptr_->async_get_result(goal_handle);
169 auto start_time = std::chrono::system_clock::now();
170 while (rclcpp::ok()) {
171 geometry_msgs::msg::TwistStamped cmd_vel = geometry_msgs::msg::TwistStamped();
172 cmd_vel.twist.linear.x = lin_vel;
173 cmd_vel.twist.angular.z = ang_vel;
174 cmd_vel_pub_->publish(cmd_vel);
180 auto current_time = std::chrono::system_clock::now();
181 if (current_time - start_time > 25s) {
182 RCLCPP_ERROR(node_->get_logger(),
"Exceeded Timeout");
186 executor_.spin_some();
190 auto preempt_msg = std_msgs::msg::Empty();
191 preempt_pub_->publish(preempt_msg);
193 RCLCPP_INFO(node_->get_logger(),
"Waiting for result");
194 if (executor_.spin_until_future_complete(result_future) !=
195 rclcpp::FutureReturnCode::SUCCESS)
197 RCLCPP_ERROR(node_->get_logger(),
"get result call failed :(");
201 rclcpp_action::ClientGoalHandle<AssistedTeleop>::WrappedResult
202 wrapped_result = result_future.get();
204 switch (wrapped_result.code) {
205 case rclcpp_action::ResultCode::SUCCEEDED:
break;
206 case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
210 case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
212 "Goal was canceled");
214 default: RCLCPP_ERROR(node_->get_logger(),
"Unknown result code");
218 RCLCPP_INFO(node_->get_logger(),
"result received");
220 geometry_msgs::msg::PoseStamped current_pose;
221 if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_,
"odom")) {
222 RCLCPP_ERROR(node_->get_logger(),
"Current robot pose is not available.");
226 if (!collision_checker_->isCollisionFree(current_pose.pose)) {
227 RCLCPP_ERROR(node_->get_logger(),
"Ended in collision");
234 void AssistedTeleopBehaviorTester::sendInitialPose()
236 geometry_msgs::msg::PoseWithCovarianceStamped pose;
237 pose.header.frame_id =
"map";
238 pose.header.stamp = stamp_;
239 pose.pose.pose.position.x = -2.0;
240 pose.pose.pose.position.y = -0.5;
241 pose.pose.pose.position.z = 0.0;
242 pose.pose.pose.orientation.x = 0.0;
243 pose.pose.pose.orientation.y = 0.0;
244 pose.pose.pose.orientation.z = 0.0;
245 pose.pose.pose.orientation.w = 1.0;
246 for (
int i = 0; i < 35; i++) {
247 pose.pose.covariance[i] = 0.0;
249 pose.pose.covariance[0] = 0.08;
250 pose.pose.covariance[7] = 0.08;
251 pose.pose.covariance[35] = 0.05;
253 initial_pose_pub_->publish(pose);
254 RCLCPP_INFO(node_->get_logger(),
"Sent initial pose");
257 void AssistedTeleopBehaviorTester::amclPoseCallback(
258 const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
260 initial_pose_received_ =
true;
263 void AssistedTeleopBehaviorTester::filteredVelCallback(
264 geometry_msgs::msg::TwistStamped::SharedPtr msg)
266 if (msg->twist.linear.x == 0.0f) {