latched_stop_rotate_controller.cpp
Go to the documentation of this file.
1 /*
2  * latched_stop_rotate_controller.cpp
3  *
4  * Created on: Apr 16, 2012
5  * Author: tkruse
6  */
7 
9 
10 #include <cmath>
11 
12 #include <Eigen/Core>
13 
14 #include <angles/angles.h>
15 #include <nav_msgs/Odometry.h>
16 
19 
20 namespace base_local_planner {
21 
23 
24 void LatchedStopRotateController::initialize(const std::string& name) {
25  ros::NodeHandle private_nh("~/" + name);
26  std::string param_name;
27  private_nh.searchParam("latch_xy_goal_tolerance", param_name);
28  private_nh.param(param_name, latch_xy_goal_tolerance_, false);
29  rotating_to_goal_ = false;
30  }
31 
33 
34 
41  tf::Stamped<tf::Pose> global_pose) {
42  double xy_goal_tolerance = planner_util->getCurrentLimits().xy_goal_tolerance;
43 
44  //we assume the global goal is the last point in the global plan
45  tf::Stamped<tf::Pose> goal_pose;
46  if ( ! planner_util->getGoal(goal_pose)) {
47  return false;
48  }
49 
50  double goal_x = goal_pose.getOrigin().getX();
51  double goal_y = goal_pose.getOrigin().getY();
52 
53  //check to see if we've reached the goal position
55  base_local_planner::getGoalPositionDistance(global_pose, goal_x, goal_y) <= xy_goal_tolerance) {
56  xy_tolerance_latch_ = true;
57  return true;
58  }
59  return false;
60 }
61 
62 
68  OdometryHelperRos& odom_helper,
69  tf::Stamped<tf::Pose> global_pose) {
70  double xy_goal_tolerance = planner_util->getCurrentLimits().xy_goal_tolerance;
71  double rot_stopped_vel = planner_util->getCurrentLimits().rot_stopped_vel;
72  double trans_stopped_vel = planner_util->getCurrentLimits().trans_stopped_vel;
73 
74  //copy over the odometry information
75  nav_msgs::Odometry base_odom;
76  odom_helper.getOdom(base_odom);
77 
78  //we assume the global goal is the last point in the global plan
79  tf::Stamped<tf::Pose> goal_pose;
80  if ( ! planner_util->getGoal(goal_pose)) {
81  return false;
82  }
83 
84  double goal_x = goal_pose.getOrigin().getX();
85  double goal_y = goal_pose.getOrigin().getY();
86 
88 
89  //check to see if we've reached the goal position
91  base_local_planner::getGoalPositionDistance(global_pose, goal_x, goal_y) <= xy_goal_tolerance) {
92  //if the user wants to latch goal tolerance, if we ever reach the goal location, we'll
93  //just rotate in place
95  ROS_DEBUG("Goal position reached (check), stopping and turning in place");
96  xy_tolerance_latch_ = true;
97  }
98  double goal_th = tf::getYaw(goal_pose.getRotation());
99  double angle = base_local_planner::getGoalOrientationAngleDifference(global_pose, goal_th);
100  //check to see if the goal orientation has been reached
101  if (fabs(angle) <= limits.yaw_goal_tolerance) {
102  //make sure that we're actually stopped before returning success
103  if (base_local_planner::stopped(base_odom, rot_stopped_vel, trans_stopped_vel)) {
104  return true;
105  }
106  }
107  }
108  return false;
109 }
110 
112  const tf::Stamped<tf::Pose>& robot_vel,
113  geometry_msgs::Twist& cmd_vel,
114  Eigen::Vector3f acc_lim,
115  double sim_period,
116  boost::function<bool (Eigen::Vector3f pos,
117  Eigen::Vector3f vel,
118  Eigen::Vector3f vel_samples)> obstacle_check) {
119 
120  //slow down with the maximum possible acceleration... we should really use the frequency that we're running at to determine what is feasible
121  //but we'll use a tenth of a second to be consistent with the implementation of the local planner.
122  double vx = sign(robot_vel.getOrigin().x()) * std::max(0.0, (fabs(robot_vel.getOrigin().x()) - acc_lim[0] * sim_period));
123  double vy = sign(robot_vel.getOrigin().y()) * std::max(0.0, (fabs(robot_vel.getOrigin().y()) - acc_lim[1] * sim_period));
124 
125  double vel_yaw = tf::getYaw(robot_vel.getRotation());
126  double vth = sign(vel_yaw) * std::max(0.0, (fabs(vel_yaw) - acc_lim[2] * sim_period));
127 
128  //we do want to check whether or not the command is valid
129  double yaw = tf::getYaw(global_pose.getRotation());
130  bool valid_cmd = obstacle_check(Eigen::Vector3f(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw),
131  Eigen::Vector3f(robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw),
132  Eigen::Vector3f(vx, vy, vth));
133 
134  //if we have a valid command, we'll pass it on, otherwise we'll command all zeros
135  if(valid_cmd){
136  ROS_DEBUG_NAMED("latched_stop_rotate", "Slowing down... using vx, vy, vth: %.2f, %.2f, %.2f", vx, vy, vth);
137  cmd_vel.linear.x = vx;
138  cmd_vel.linear.y = vy;
139  cmd_vel.angular.z = vth;
140  return true;
141  }
142  ROS_WARN("Stopping cmd in collision");
143  cmd_vel.linear.x = 0.0;
144  cmd_vel.linear.y = 0.0;
145  cmd_vel.angular.z = 0.0;
146  return false;
147 }
148 
150  const tf::Stamped<tf::Pose>& global_pose,
151  const tf::Stamped<tf::Pose>& robot_vel,
152  double goal_th,
153  geometry_msgs::Twist& cmd_vel,
154  Eigen::Vector3f acc_lim,
155  double sim_period,
157  boost::function<bool (Eigen::Vector3f pos,
158  Eigen::Vector3f vel,
159  Eigen::Vector3f vel_samples)> obstacle_check) {
160  double yaw = tf::getYaw(global_pose.getRotation());
161  double vel_yaw = tf::getYaw(robot_vel.getRotation());
162  cmd_vel.linear.x = 0;
163  cmd_vel.linear.y = 0;
164  double ang_diff = angles::shortest_angular_distance(yaw, goal_th);
165 
166  double v_theta_samp = std::min(limits.max_rot_vel, std::max(limits.min_rot_vel, fabs(ang_diff)));
167 
168  //take the acceleration limits of the robot into account
169  double max_acc_vel = fabs(vel_yaw) + acc_lim[2] * sim_period;
170  double min_acc_vel = fabs(vel_yaw) - acc_lim[2] * sim_period;
171 
172  v_theta_samp = std::min(std::max(fabs(v_theta_samp), min_acc_vel), max_acc_vel);
173 
174  //we also want to make sure to send a velocity that allows us to stop when we reach the goal given our acceleration limits
175  double max_speed_to_stop = sqrt(2 * acc_lim[2] * fabs(ang_diff));
176  v_theta_samp = std::min(max_speed_to_stop, fabs(v_theta_samp));
177 
178  v_theta_samp = std::min(limits.max_rot_vel, std::max(limits.min_rot_vel, v_theta_samp));
179 
180  if (ang_diff < 0) {
181  v_theta_samp = - v_theta_samp;
182  }
183 
184  //we still want to lay down the footprint of the robot and check if the action is legal
185  bool valid_cmd = obstacle_check(Eigen::Vector3f(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw),
186  Eigen::Vector3f(robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw),
187  Eigen::Vector3f( 0.0, 0.0, v_theta_samp));
188 
189  if (valid_cmd) {
190  ROS_DEBUG_NAMED("dwa_local_planner", "Moving to desired goal orientation, th cmd: %.2f, valid_cmd: %d", v_theta_samp, valid_cmd);
191  cmd_vel.angular.z = v_theta_samp;
192  return true;
193  }
194  ROS_WARN("Rotation cmd in collision");
195  cmd_vel.angular.z = 0.0;
196  return false;
197 
198 }
199 
201  Eigen::Vector3f acc_lim,
202  double sim_period,
203  LocalPlannerUtil* planner_util,
204  OdometryHelperRos& odom_helper_,
205  tf::Stamped<tf::Pose> global_pose,
206  boost::function<bool (Eigen::Vector3f pos,
207  Eigen::Vector3f vel,
208  Eigen::Vector3f vel_samples)> obstacle_check) {
209  //we assume the global goal is the last point in the global plan
210  tf::Stamped<tf::Pose> goal_pose;
211  if ( ! planner_util->getGoal(goal_pose)) {
212  ROS_ERROR("Could not get goal pose");
213  return false;
214  }
215 
217 
218  //if the user wants to latch goal tolerance, if we ever reach the goal location, we'll
219  //just rotate in place
221  ROS_INFO("Goal position reached, stopping and turning in place");
222  xy_tolerance_latch_ = true;
223  }
224  //check to see if the goal orientation has been reached
225  double goal_th = tf::getYaw(goal_pose.getRotation());
226  double angle = base_local_planner::getGoalOrientationAngleDifference(global_pose, goal_th);
227  if (fabs(angle) <= limits.yaw_goal_tolerance) {
228  //set the velocity command to zero
229  cmd_vel.linear.x = 0.0;
230  cmd_vel.linear.y = 0.0;
231  cmd_vel.angular.z = 0.0;
232  rotating_to_goal_ = false;
233  } else {
234  ROS_DEBUG("Angle: %f Tolerance: %f", angle, limits.yaw_goal_tolerance);
235  tf::Stamped<tf::Pose> robot_vel;
236  odom_helper_.getRobotVel(robot_vel);
237  nav_msgs::Odometry base_odom;
238  odom_helper_.getOdom(base_odom);
239 
240  //if we're not stopped yet... we want to stop... taking into account the acceleration limits of the robot
241  if ( ! rotating_to_goal_ && !base_local_planner::stopped(base_odom, limits.rot_stopped_vel, limits.trans_stopped_vel)) {
242  if ( ! stopWithAccLimits(
243  global_pose,
244  robot_vel,
245  cmd_vel,
246  acc_lim,
247  sim_period,
248  obstacle_check)) {
249  ROS_INFO("Error when stopping.");
250  return false;
251  }
252  ROS_DEBUG("Stopping...");
253  }
254  //if we're stopped... then we want to rotate to goal
255  else {
256  //set this so that we know its OK to be moving
257  rotating_to_goal_ = true;
258  if ( ! rotateToGoal(
259  global_pose,
260  robot_vel,
261  goal_th,
262  cmd_vel,
263  acc_lim,
264  sim_period,
265  limits,
266  obstacle_check)) {
267  ROS_INFO("Error when rotating.");
268  return false;
269  }
270  ROS_DEBUG("Rotating...");
271  }
272  }
273 
274  return true;
275 
276 }
277 
278 
279 } /* namespace base_local_planner */
bool getGoal(tf::Stamped< tf::Pose > &goal_pose)
void getRobotVel(tf::Stamped< tf::Pose > &robot_vel)
double getGoalPositionDistance(const tf::Stamped< tf::Pose > &global_pose, double goal_x, double goal_y)
return squared distance to check if the goal position has been achieved
static double getYaw(const Quaternion &bt_q)
bool isGoalReached(LocalPlannerUtil *planner_util, OdometryHelperRos &odom_helper, tf::Stamped< tf::Pose > global_pose)
void getOdom(nav_msgs::Odometry &base_odom)
#define ROS_WARN(...)
bool stopped(const nav_msgs::Odometry &base_odom, const double &rot_stopped_velocity, const double &trans_stopped_velocity)
Check whether the robot is stopped or not.
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
#define ROS_DEBUG_NAMED(name,...)
bool computeVelocityCommandsStopRotate(geometry_msgs::Twist &cmd_vel, Eigen::Vector3f acc_lim, double sim_period, LocalPlannerUtil *planner_util, OdometryHelperRos &odom_helper, tf::Stamped< tf::Pose > global_pose, boost::function< bool(Eigen::Vector3f pos, Eigen::Vector3f vel, Eigen::Vector3f vel_samples)> obstacle_check)
#define ROS_INFO(...)
bool stopWithAccLimits(const tf::Stamped< tf::Pose > &global_pose, const tf::Stamped< tf::Pose > &robot_vel, geometry_msgs::Twist &cmd_vel, Eigen::Vector3f acc_lim, double sim_period, boost::function< bool(Eigen::Vector3f pos, Eigen::Vector3f vel, Eigen::Vector3f vel_samples)> obstacle_check)
Stop the robot taking into account acceleration limits.
bool searchParam(const std::string &key, std::string &result) const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
bool rotateToGoal(const tf::Stamped< tf::Pose > &global_pose, const tf::Stamped< tf::Pose > &robot_vel, double goal_th, geometry_msgs::Twist &cmd_vel, Eigen::Vector3f acc_lim, double sim_period, base_local_planner::LocalPlannerLimits &limits, boost::function< bool(Eigen::Vector3f pos, Eigen::Vector3f vel, Eigen::Vector3f vel_samples)> obstacle_check)
Once a goal position is reached... rotate to the goal orientation.
Helper class implementing infrastructure code many local planner implementations may need...
#define ROS_ERROR(...)
def shortest_angular_distance(from_angle, to_angle)
double getGoalOrientationAngleDifference(const tf::Stamped< tf::Pose > &global_pose, double goal_th)
return angle difference to goal to check if the goal orientation has been achieved ...
#define ROS_DEBUG(...)
bool isPositionReached(LocalPlannerUtil *planner_util, tf::Stamped< tf::Pose > global_pose)


base_local_planner
Author(s): Eitan Marder-Eppstein, Eric Perko, contradict@gmail.com
autogenerated on Thu Jan 21 2021 04:05:49