twist_recovery.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 
40 #include <tf/transform_datatypes.h>
41 #include <tf2/utils.h>
42 
43 // register as a RecoveryBehavior plugin
45 
46 namespace gm=geometry_msgs;
47 namespace cmap=costmap_2d;
48 namespace blp=base_local_planner;
49 using std::vector;
50 using std::max;
51 
52 namespace twist_recovery
53 {
54 
56  global_costmap_(NULL), local_costmap_(NULL), tf_(NULL), initialized_(false)
57 {}
58 
60 {
61  delete world_model_;
62 }
63 
64 void TwistRecovery::initialize (std::string name, tf2_ros::Buffer* tf,
65  cmap::Costmap2DROS* global_cmap, cmap::Costmap2DROS* local_cmap)
66 {
68  name_ = name;
69  tf_ = tf;
70  local_costmap_ = local_cmap;
71  global_costmap_ = global_cmap;
73 
74  pub_ = nh_.advertise<gm::Twist>("cmd_vel", 10);
75  ros::NodeHandle private_nh("~/" + name);
76 
77  {
78  bool found=true;
79  found = found && private_nh.getParam("linear_x", base_frame_twist_.linear.x);
80  found = found && private_nh.getParam("linear_y", base_frame_twist_.linear.y);
81  found = found && private_nh.getParam("angular_z", base_frame_twist_.angular.z);
82  if (!found) {
83  ROS_FATAL_STREAM ("Didn't find twist parameters in " << private_nh.getNamespace());
84  ros::shutdown();
85  }
86  }
87 
88  private_nh.param("duration", duration_, 1.0);
89  private_nh.param("linear_speed_limit", linear_speed_limit_, 0.3);
90  private_nh.param("angular_speed_limit", angular_speed_limit_, 1.0);
91  private_nh.param("linear_acceleration_limit", linear_acceleration_limit_, 4.0);
92  private_nh.param("angular_acceleration_limit", angular_acceleration_limit_, 3.2);
93  private_nh.param("controller_frequency", controller_frequency_, 20.0);
94  private_nh.param("simulation_inc", simulation_inc_, 1/controller_frequency_);
95 
96  ROS_INFO_STREAM_NAMED ("top", "Initialized twist recovery with twist " <<
97  base_frame_twist_ << " and duration " << duration_);
98 
99  initialized_ = true;
100 }
101 
102 gm::Twist scaleTwist (const gm::Twist& twist, const double scale)
103 {
104  gm::Twist t;
105  t.linear.x = twist.linear.x * scale;
106  t.linear.y = twist.linear.y * scale;
107  t.angular.z = twist.angular.z * scale;
108  return t;
109 }
110 
111 gm::Pose2D forwardSimulate (const gm::Pose2D& p, const gm::Twist& twist, const double t=1.0)
112 {
113  gm::Pose2D p2;
114  p2.x = p.x + twist.linear.x*t;
115  p2.y = p.y + twist.linear.y*t;
116  p2.theta = p.theta + twist.angular.z*t;
117  return p2;
118 }
119 
121 double TwistRecovery::normalizedPoseCost (const gm::Pose2D& pose) const
122 {
123  const double c = world_model_->footprintCost(pose.x, pose.y, pose.theta, local_costmap_->getRobotFootprint(), 0.0, 0.0);
124  return c < 0 ? 1e9 : c;
125 }
126 
127 
132 double TwistRecovery::nonincreasingCostInterval (const gm::Pose2D& current, const gm::Twist& twist) const
133 {
134  double cost = normalizedPoseCost(current);
135  double t; // Will hold the first time that is invalid
136  for (t=simulation_inc_; t<=duration_; t+=simulation_inc_) {
137  const double next_cost = normalizedPoseCost(forwardSimulate(current, twist, t));
138  if (next_cost > cost) {
139  ROS_DEBUG_STREAM_NAMED ("cost", "Cost at " << t << " and pose " << forwardSimulate(current, twist, t)
140  << " is " << next_cost << " which is greater than previous cost " << cost);
141  break;
142  }
143  cost = next_cost;
144  }
145 
146  return t-simulation_inc_;
147 }
148 
149 double linearSpeed (const gm::Twist& twist)
150 {
151  return sqrt(twist.linear.x*twist.linear.x + twist.linear.y*twist.linear.y);
152 }
153 
154 double angularSpeed (const gm::Twist& twist)
155 {
156  return fabs(twist.angular.z);
157 }
158 
159 // Scale twist so we can stop in the given time, and so it's within the max velocity
160 gm::Twist TwistRecovery::scaleGivenAccelerationLimits (const gm::Twist& twist, const double time_remaining) const
161 {
162  const double linear_speed = linearSpeed(twist);
163  const double angular_speed = angularSpeed(twist);
164  const double linear_acc_scaling = linear_speed/(time_remaining*linear_acceleration_limit_);
165  const double angular_acc_scaling = angular_speed/(time_remaining*angular_acceleration_limit_);
166  const double acc_scaling = max(linear_acc_scaling, angular_acc_scaling);
167  const double linear_vel_scaling = linear_speed/linear_speed_limit_;
168  const double angular_vel_scaling = angular_speed/angular_speed_limit_;
169  const double vel_scaling = max(linear_vel_scaling, angular_vel_scaling);
170  return scaleTwist(twist, max(1.0, max(acc_scaling, vel_scaling)));
171 }
172 
173 // Get pose in local costmap frame
175 {
176  gm::PoseStamped p;
178  gm::Pose2D pose;
179  pose.x = p.pose.position.x;
180  pose.y = p.pose.position.y;
181  pose.theta = tf2::getYaw(p.pose.orientation);
182  return pose;
183 }
184 
186 {
188 
189  // Figure out how long we can safely run the behavior
190  const gm::Pose2D& current = getCurrentLocalPose();
191 
192  const double d = nonincreasingCostInterval(current, base_frame_twist_);
194  ROS_INFO_NAMED ("top", "Applying (%.2f, %.2f, %.2f) for %.2f seconds", base_frame_twist_.linear.x,
195  base_frame_twist_.linear.y, base_frame_twist_.angular.z, d);
196 
197  // We'll now apply this twist open-loop for d seconds (scaled so we can guarantee stopping at the end)
198  for (double t=0; t<d; t+=1/controller_frequency_) {
200  r.sleep();
201  }
202 }
203 
204 
205 } // namespace twist_recovery
206 
d
void runBehavior()
Run the behavior.
#define ROS_INFO_NAMED(name,...)
#define ROS_DEBUG_STREAM_NAMED(name, args)
geometry_msgs::Twist scaleGivenAccelerationLimits(const geometry_msgs::Twist &twist, const double time_remaining) const
tf2_ros::Buffer * tf_
#define ROS_INFO_STREAM_NAMED(name, args)
gm::Pose2D forwardSimulate(const gm::Pose2D &p, const gm::Twist &twist, const double t=1.0)
base_local_planner::CostmapModel * world_model_
geometry_msgs::TransformStamped t
geometry_msgs::Twist base_frame_twist_
costmap_2d::Costmap2DROS * global_costmap_
void publish(const boost::shared_ptr< M > &message) const
double angularSpeed(const gm::Twist &twist)
double linearSpeed(const gm::Twist &twist)
#define ROS_FATAL_STREAM(args)
TwistRecovery()
Doesn&#39;t do anything: initialize is where the actual work happens.
gm::Twist scaleTwist(const gm::Twist &twist, const double scale)
bool getRobotPose(geometry_msgs::PoseStamped &global_pose) const
double normalizedPoseCost(const geometry_msgs::Pose2D &pose) const
Return the cost of a pose, modified so that -1 does not equal infinity; instead 1e9 does...
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
double nonincreasingCostInterval(const geometry_msgs::Pose2D &current, const geometry_msgs::Twist &twist) const
bool sleep()
double getYaw(const A &a)
costmap_2d::Costmap2DROS * local_costmap_
virtual double footprintCost(const geometry_msgs::Point &position, const std::vector< geometry_msgs::Point > &footprint, double inscribed_radius, double circumscribed_radius)
ROSCPP_DECL void shutdown()
Costmap2D * getCostmap()
#define ROS_ASSERT(cond)
std::vector< geometry_msgs::Point > getRobotFootprint()
double max(double a, double b)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void initialize(std::string n, tf2_ros::Buffer *tf, costmap_2d::Costmap2DROS *global_costmap, costmap_2d::Costmap2DROS *local_costmap)
Initialize the parameters of the behavior.
geometry_msgs::Pose2D getCurrentLocalPose() const


twist_recovery
Author(s): Bhaskara Marthi
autogenerated on Sat Aug 27 2022 02:54:24