Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
assisted_teleop.cpp
1 // Copyright (c) 2022 Joshua Wallace
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <utility>
16 
17 #include "nav2_behaviors/plugins/assisted_teleop.hpp"
18 #include "nav2_ros_common/node_utils.hpp"
19 #include "nav2_util/geometry_utils.hpp"
20 
21 namespace nav2_behaviors
22 {
23 AssistedTeleop::AssistedTeleop()
24 : TimedBehavior<AssistedTeleopAction>(),
25  feedback_(std::make_shared<AssistedTeleopAction::Feedback>())
26 {}
27 
28 void AssistedTeleop::onConfigure()
29 {
30  auto node = node_.lock();
31  if (!node) {
32  throw std::runtime_error{"Failed to lock node"};
33  }
34 
35  // set up parameters
36  projection_time_ = node->declare_or_get_parameter("projection_time", 1.0);
37  simulation_time_step_ = node->declare_or_get_parameter("simulation_time_step", 0.1);
38  std::string cmd_vel_teleop = node->declare_or_get_parameter(
39  "cmd_vel_teleop", std::string("cmd_vel_teleop"));
40 
41  vel_sub_ = std::make_unique<nav2_util::TwistSubscriber>(
42  node,
43  cmd_vel_teleop,
44  [&](const geometry_msgs::msg::Twist::ConstSharedPtr & msg) {
45  teleop_twist_.twist = *msg;
46  }, [&](const geometry_msgs::msg::TwistStamped::ConstSharedPtr & msg) {
47  teleop_twist_ = *msg;
48  });
49 
50  preempt_teleop_sub_ = node->create_subscription<std_msgs::msg::Empty>(
51  "preempt_teleop",
52  std::bind(
53  &AssistedTeleop::preemptTeleopCallback,
54  this, std::placeholders::_1));
55 }
56 
57 ResultStatus AssistedTeleop::onRun(const std::shared_ptr<const AssistedTeleopAction::Goal> command)
58 {
59  preempt_teleop_ = false;
60  command_time_allowance_ = command->time_allowance;
61  end_time_ = this->clock_->now() + command_time_allowance_;
62  return ResultStatus{Status::SUCCEEDED, AssistedTeleopActionResult::NONE, ""};
63 }
64 
65 void AssistedTeleop::onActionCompletion(std::shared_ptr<AssistedTeleopActionResult>/*result*/)
66 {
67  teleop_twist_ = geometry_msgs::msg::TwistStamped();
68  preempt_teleop_ = false;
69 }
70 
71 ResultStatus AssistedTeleop::onCycleUpdate()
72 {
73  feedback_->current_teleop_duration = elapsed_time_;
74  action_server_->publish_feedback(feedback_);
75 
76  rclcpp::Duration time_remaining = end_time_ - this->clock_->now();
77  if (time_remaining.seconds() < 0.0 && command_time_allowance_.seconds() > 0.0) {
78  std::string error_msg = "Exceeded time allowance before reaching the " + behavior_name_ +
79  "goal - Exiting " + behavior_name_;
80  RCLCPP_WARN_STREAM(logger_, error_msg.c_str());
81  return ResultStatus{Status::FAILED, AssistedTeleopActionResult::TIMEOUT, error_msg};
82  }
83 
84  // user states that teleop was successful
85  if (preempt_teleop_) {
86  stopRobot();
87  return ResultStatus{Status::SUCCEEDED, AssistedTeleopActionResult::NONE, ""};
88  }
89 
90  geometry_msgs::msg::PoseStamped current_pose;
91  if (!nav2_util::getCurrentPose(
92  current_pose, *tf_, local_frame_, robot_base_frame_,
93  transform_tolerance_))
94  {
95  std::string error_msg = "Current robot pose is not available for " + behavior_name_;
96  RCLCPP_ERROR_STREAM(logger_, error_msg.c_str());
97  return ResultStatus{Status::FAILED, AssistedTeleopActionResult::TF_ERROR, error_msg};
98  }
99 
100  geometry_msgs::msg::Pose projected_pose = current_pose.pose;
101 
102  auto scaled_twist = std::make_unique<geometry_msgs::msg::TwistStamped>(teleop_twist_);
103  for (double time = simulation_time_step_; time < projection_time_;
104  time += simulation_time_step_)
105  {
106  projected_pose = projectPose(projected_pose, teleop_twist_.twist, simulation_time_step_);
107 
108  if (!local_collision_checker_->isCollisionFree(projected_pose)) {
109  if (time == simulation_time_step_) {
110  RCLCPP_DEBUG_STREAM_THROTTLE(
111  logger_,
112  *clock_,
113  1000,
114  behavior_name_.c_str() << " collided on first time step, setting velocity to zero");
115  scaled_twist->twist.linear.x = 0.0f;
116  scaled_twist->twist.linear.y = 0.0f;
117  scaled_twist->twist.angular.z = 0.0f;
118  break;
119  } else {
120  RCLCPP_DEBUG_STREAM_THROTTLE(
121  logger_,
122  *clock_,
123  1000,
124  behavior_name_.c_str() << " collision approaching in " << time << " seconds");
125  double scale_factor = time / projection_time_;
126  scaled_twist->twist.linear.x *= scale_factor;
127  scaled_twist->twist.linear.y *= scale_factor;
128  scaled_twist->twist.angular.z *= scale_factor;
129  break;
130  }
131  }
132  }
133  vel_pub_->publish(std::move(scaled_twist));
134 
135  return ResultStatus{Status::RUNNING, AssistedTeleopActionResult::NONE, ""};
136 }
137 
138 geometry_msgs::msg::Pose AssistedTeleop::projectPose(
139  const geometry_msgs::msg::Pose & pose,
140  const geometry_msgs::msg::Twist & twist,
141  double projection_time)
142 {
143  geometry_msgs::msg::Pose projected_pose = pose;
144 
145  double theta = tf2::getYaw(pose.orientation);
146 
147  projected_pose.position.x += projection_time * (
148  twist.linear.x * cos(theta) -
149  twist.linear.y * sin(theta));
150 
151  projected_pose.position.y += projection_time * (
152  twist.linear.x * sin(theta) +
153  twist.linear.y * cos(theta));
154 
155  double new_theta = theta + projection_time * twist.angular.z;
156  projected_pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis(new_theta);
157 
158  return projected_pose;
159 }
160 
161 void AssistedTeleop::preemptTeleopCallback(const std_msgs::msg::Empty::ConstSharedPtr &)
162 {
163  preempt_teleop_ = true;
164 }
165 
166 } // namespace nav2_behaviors
167 
168 #include "pluginlib/class_list_macros.hpp"
An action server behavior for assisted teleop.
Abstract interface for behaviors to adhere to with pluginlib.
Definition: behavior.hpp:41