17 #include "nav2_behaviors/plugins/assisted_teleop.hpp"
18 #include "nav2_ros_common/node_utils.hpp"
19 #include "nav2_util/geometry_utils.hpp"
21 namespace nav2_behaviors
23 AssistedTeleop::AssistedTeleop()
24 : TimedBehavior<AssistedTeleopAction>(),
25 feedback_(std::make_shared<AssistedTeleopAction::Feedback>())
28 void AssistedTeleop::onConfigure()
30 auto node = node_.lock();
32 throw std::runtime_error{
"Failed to lock node"};
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"));
41 vel_sub_ = std::make_unique<nav2_util::TwistSubscriber>(
44 [&](
const geometry_msgs::msg::Twist::ConstSharedPtr & msg) {
45 teleop_twist_.twist = *msg;
46 }, [&](
const geometry_msgs::msg::TwistStamped::ConstSharedPtr & msg) {
50 preempt_teleop_sub_ = node->create_subscription<std_msgs::msg::Empty>(
53 &AssistedTeleop::preemptTeleopCallback,
54 this, std::placeholders::_1));
57 ResultStatus AssistedTeleop::onRun(
const std::shared_ptr<const AssistedTeleopAction::Goal> command)
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,
""};
65 void AssistedTeleop::onActionCompletion(std::shared_ptr<AssistedTeleopActionResult>)
67 teleop_twist_ = geometry_msgs::msg::TwistStamped();
68 preempt_teleop_ =
false;
73 feedback_->current_teleop_duration = elapsed_time_;
74 action_server_->publish_feedback(feedback_);
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};
85 if (preempt_teleop_) {
87 return ResultStatus{Status::SUCCEEDED, AssistedTeleopActionResult::NONE,
""};
90 geometry_msgs::msg::PoseStamped current_pose;
91 if (!nav2_util::getCurrentPose(
92 current_pose, *tf_, local_frame_, robot_base_frame_,
93 transform_tolerance_))
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};
100 geometry_msgs::msg::Pose projected_pose = current_pose.pose;
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_)
106 projected_pose = projectPose(projected_pose, teleop_twist_.twist, simulation_time_step_);
108 if (!local_collision_checker_->isCollisionFree(projected_pose)) {
109 if (time == simulation_time_step_) {
110 RCLCPP_DEBUG_STREAM_THROTTLE(
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;
120 RCLCPP_DEBUG_STREAM_THROTTLE(
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;
133 vel_pub_->publish(std::move(scaled_twist));
135 return ResultStatus{Status::RUNNING, AssistedTeleopActionResult::NONE,
""};
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)
143 geometry_msgs::msg::Pose projected_pose = pose;
145 double theta = tf2::getYaw(pose.orientation);
147 projected_pose.position.x += projection_time * (
148 twist.linear.x * cos(theta) -
149 twist.linear.y * sin(theta));
151 projected_pose.position.y += projection_time * (
152 twist.linear.x * sin(theta) +
153 twist.linear.y * cos(theta));
155 double new_theta = theta + projection_time * twist.angular.z;
156 projected_pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis(new_theta);
158 return projected_pose;
161 void AssistedTeleop::preemptTeleopCallback(
const std_msgs::msg::Empty::ConstSharedPtr &)
163 preempt_teleop_ =
true;
168 #include "pluginlib/class_list_macros.hpp"
An action server behavior for assisted teleop.
Abstract interface for behaviors to adhere to with pluginlib.