move_basic.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-21, Ubiquity Robotics
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  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  *
30  */
31 
32 #include <ros/ros.h>
33 #include <tf/transform_datatypes.h>
35 #include <tf2_ros/buffer.h>
38 #include <geometry_msgs/PoseStamped.h>
39 #include <geometry_msgs/Twist.h>
40 #include <geometry_msgs/Vector3.h>
41 #include <nav_msgs/Path.h>
42 #include <std_msgs/Float32.h>
43 #include <std_msgs/Bool.h>
44 #include <move_base_msgs/MoveBaseAction.h>
45 
47 #include <dynamic_reconfigure/server.h>
50 #include <move_basic/MovebasicConfig.h>
51 
52 #include <string>
53 
55 
56 class MoveBasic {
57  private:
60 
66 
67  std::unique_ptr<MoveBaseActionServer> actionServer;
68  std::unique_ptr<CollisionChecker> collision_checker;
69  std::unique_ptr<ObstaclePoints> obstacle_points;
70 
73 
79 
84 
85  double lateralKp;
86  double lateralKi;
87  double lateralKd;
88 
91  double minSideDist;
94  bool stop;
95 
99  tf2::Vector3 forwardLeft;
100  tf2::Vector3 forwardRight;
101 
106  std::string baseFrame;
107 
108  dynamic_reconfigure::Server<move_basic::MovebasicConfig> dr_srv;
109 
110  void dynamicReconfigCallback(move_basic::MovebasicConfig& config, uint32_t);
111  void stopCallback(const std_msgs::Bool::ConstPtr& msg);
112  void goalCallback(const geometry_msgs::PoseStamped::ConstPtr &msg);
113  void executeAction(const move_base_msgs::MoveBaseGoalConstPtr& goal);
114  void drawLine(double x0, double y0, double x1, double y1);
115  void sendCmd(double angular, double linear);
116  void abortGoal(const std::string msg);
117 
118  bool getTransform(const std::string& from, const std::string& to,
119  tf2::Transform& tf);
120  bool transformPose(const std::string& from, const std::string& to,
121  const tf2::Transform& in, tf2::Transform& out);
122 
123  public:
124  MoveBasic();
125 
126  void run();
127 
128  bool moveLinear(tf2::Transform& goalInDriving,
129  const std::string& drivingFrame);
130  bool rotate(double requestedYaw,
131  const std::string& drivingFrame);
132 
134 };
135 
136 
137 // Radians to degrees
138 
139 static double rad2deg(double rad)
140 {
141  return rad * 180.0 / M_PI;
142 }
143 
144 // Get the sign of a number
145 
146 static int sign(double n)
147 {
148  return (n <0 ? -1 : 1);
149 }
150 
151 // Adjust angle to be between -PI and PI
152 
153 static void normalizeAngle(double& angle)
154 {
155  if (angle < -M_PI) {
156  angle += 2 * M_PI;
157  }
158  if (angle > M_PI) {
159  angle -= 2 * M_PI;
160  }
161 }
162 
163 
164 // retreive the 3 DOF we are interested in from a Transform
165 
166 static void getPose(const tf2::Transform& tf, double& x, double& y, double& yaw)
167 {
168  tf2::Vector3 trans = tf.getOrigin();
169  x = trans.x();
170  y = trans.y();
171 
172  double roll, pitch;
173  tf.getBasis().getRPY(roll, pitch, yaw);
174 }
175 
176 
177 // Constructor
178 
179 MoveBasic::MoveBasic(): tfBuffer(ros::Duration(3.0)),
181 {
182  ros::NodeHandle nh("~");
183 
184  // Velocity parameters
185  nh.param<double>("min_turning_velocity", minTurningVelocity, 0.18);
186  nh.param<double>("max_turning_velocity", maxTurningVelocity, 1.0);
187  nh.param<double>("max_lateral_velocity", maxLateralVelocity, 0.5);
188  nh.param<double>("max_linear_velocity", maxLinearVelocity, 0.5);
189  nh.param<double>("min_linear_velocity", minLinearVelocity, 0.1);
190  nh.param<double>("linear_acceleration", linearAcceleration, 0.1);
191  nh.param<double>("turning_acceleration", turningAcceleration, 0.2);
192 
193  // Within tolerance, goal is successfully reached
194  nh.param<double>("angular_tolerance", angularTolerance, 0.05);
195  nh.param<double>("linear_tolerance", linearTolerance, 0.05);
196 
197  // PID parameters for lateral control
198  nh.param<double>("lateral_kp", lateralKp, 0.0);
199  nh.param<double>("lateral_ki", lateralKi, 0.0);
200  nh.param<double>("lateral_kd", lateralKd, 3.0);
201 
202  // how long to wait after moving to be sure localization is accurate
203  nh.param<double>("localization_latency", localizationLatency, 0.5);
204 
205  // how long robot can be driving away from the goal
206  nh.param<double>("runaway_timeout", runawayTimeoutSecs, 1.0);
207 
208  // how long to wait for an obstacle to disappear
209  nh.param<double>("obstacle_wait_threshold", obstacleWaitThreshold, 60.0);
210 
211  // Minimum distance to maintain in front
212  nh.param<double>("forward_obstacle_threshold", forwardObstacleThreshold, 0.5);
213 
214  // Minimum distance to maintain at each side
215  nh.param<double>("min_side_dist", minSideDist, 0.3);
216 
217  nh.param<std::string>("preferred_planning_frame",
219  nh.param<std::string>("alternate_planning_frame",
220  alternatePlanningFrame, "odom");
221  nh.param<std::string>("preferred_driving_frame",
222  preferredDrivingFrame, "map");
223  nh.param<std::string>("alternate_driving_frame",
224  alternateDrivingFrame, "odom");
225  nh.param<std::string>("base_frame", baseFrame, "base_footprint");
226 
227  stop = false;
228 
229  dynamic_reconfigure::Server<move_basic::MovebasicConfig>::CallbackType f;
230  f = boost::bind(&MoveBasic::dynamicReconfigCallback, this, _1, _2);
231  dr_srv.setCallback(f);
232 
233  cmdPub = ros::Publisher(nh.advertise<geometry_msgs::Twist>("/cmd_vel", 1));
234  pathPub = ros::Publisher(nh.advertise<nav_msgs::Path>("/plan", 1));
235 
237  ros::Publisher(nh.advertise<geometry_msgs::Vector3>("/obstacle_distance", 1));
238  errorPub =
239  ros::Publisher(nh.advertise<geometry_msgs::Vector3>("/lateral_error", 1));
240 
241  goalSub = nh.subscribe("/move_base_simple/goal", 1,
242  &MoveBasic::goalCallback, this);
243 
244  stopSub = nh.subscribe("/move_base/stop", 1,
245  &MoveBasic::stopCallback, this);
246 
247  ros::NodeHandle actionNh("");
248 
249  actionServer.reset(new MoveBaseActionServer(actionNh, "move_base",
250  boost::bind(&MoveBasic::executeAction, this, _1)));
251 
252  actionServer->start();
253  goalPub = actionNh.advertise<move_base_msgs::MoveBaseActionGoal>(
254  "/move_base/goal", 1);
255 
256  obstacle_points.reset(new ObstaclePoints(nh, tfBuffer));
258 
259  ROS_INFO("Move Basic ready");
260 }
261 
262 
263 // Lookup the specified transform, returns true on success
264 
265 bool MoveBasic::getTransform(const std::string& from, const std::string& to,
267 {
268  try {
269  geometry_msgs::TransformStamped tfs =
270  tfBuffer.lookupTransform(to, from, ros::Time(0));
271  tf2::fromMsg(tfs.transform, tf);
272  return true;
273  }
274  catch (tf2::TransformException &ex) {
275  return false;
276  }
277 }
278 
279 // Transform a pose from one frame to another
280 
281 bool MoveBasic::transformPose(const std::string& from, const std::string& to,
282  const tf2::Transform& in, tf2::Transform& out)
283 {
285  if (!getTransform(from, to, tf)) {
286  return false;
287  }
288  out = tf * in;
289  return true;
290 }
291 
292 // Dynamic reconfigure
293 
294 void MoveBasic::dynamicReconfigCallback(move_basic::MovebasicConfig& config, uint32_t){
295  minTurningVelocity = config.min_turning_velocity;
296  maxTurningVelocity = config.max_turning_velocity;
297  maxLateralVelocity = config.max_lateral_velocity;
298  turningAcceleration = config.turning_acceleration;
299  maxLinearVelocity = config.max_linear_velocity;
300  minLinearVelocity = config.min_linear_velocity;
301  linearAcceleration = config.linear_acceleration;
302 
303  angularTolerance = config.angular_tolerance;
304  linearTolerance = config.linear_tolerance;
305 
306  lateralKp = config.lateral_kp;
307  lateralKi = config.lateral_ki;
308  lateralKd = config.lateral_kd;
309 
310  localizationLatency = config.localization_latency;
311  runawayTimeoutSecs = config.runaway_timeout;
312 
313  minSideDist = config.min_side_dist;
314  obstacleWaitThreshold = config.obstacle_wait_threshold;
315  forwardObstacleThreshold = config.forward_obstacle_threshold;
316 
317  ROS_WARN("Parameter change detected");
318 }
319 
320 // Stop robot in place and save last state
321 
322 void MoveBasic::stopCallback(const std_msgs::Bool::ConstPtr& msg)
323 {
324  stop = msg->data;
325  if (stop) ROS_WARN("MoveBasic: Robot is forced to stop!");
326 }
327 
328 // Called when a simple goal message is received
329 
330 void MoveBasic::goalCallback(const geometry_msgs::PoseStamped::ConstPtr &msg)
331 {
332  ROS_INFO("MoveBasic: Received simple goal");
333 
334  move_base_msgs::MoveBaseActionGoal actionGoal;
335  actionGoal.header.stamp = ros::Time::now();
336  actionGoal.goal.target_pose = *msg;
337 
338  // Send the goal to the action server
339  goalPub.publish(actionGoal);
340 }
341 
342 
343 // Abort goal and print message
344 
345 void MoveBasic::abortGoal(const std::string msg)
346 {
347  actionServer->setAborted(move_base_msgs::MoveBaseResult(), msg);
348  ROS_ERROR("%s", msg.c_str());
349 }
350 
351 
352 // Called when an action goal is received
353 
354 void MoveBasic::executeAction(const move_base_msgs::MoveBaseGoalConstPtr& msg)
355 {
356  /*
357  Plan a path that involves rotating to face the goal, going straight towards it,
358  and then rotating for the final orientation.
359 
360  It is assumed that we are dealing with imperfect localization data:
361  map->base_link is accurate but may be delayed and is at a slow rate
362  odom->base_link is frequent, but drifts, particularly after rotating
363  To counter these issues, we plan in the map frame, and wait localizationLatency
364  after each step, and execute in the odom frame.
365  */
366 
367  tf2::Transform goal;
368  tf2::fromMsg(msg->target_pose.pose, goal);
369  std::string frameId = msg->target_pose.header.frame_id;
370 
371  // Needed for RobotCommander
372  if (frameId[0] == '/')
373  frameId = frameId.substr(1);
374 
375  double x, y, yaw;
376  getPose(goal, x, y, yaw);
377 
378  ROS_INFO("MoveBasic: Received goal %f %f %f %s", x, y, rad2deg(yaw), frameId.c_str());
379 
380  bool do_final_rotation = true;
381  if (std::isnan(yaw)) {
382  ROS_WARN("MoveBasic: Received a goal with invalid orientation, will go to it but not do final turn");
383  do_final_rotation = false;
384  }
385 
386  // The pose of the robot planning frame MUST be known initially, and may or may not
387  // be known after that.
388  // The pose of the robot in the driving frame MUST be known at all times.
389  // An empty planning frame means to use what ever frame the goal is specified in.
390  double goalYaw;
391  std::string planningFrame;
392  if (preferredPlanningFrame == "") {
393  planningFrame = frameId;
394  goalInPlanning = goal;
395  ROS_INFO("Planning in goal frame: %s\n", planningFrame.c_str());
396  }
397  else if (!transformPose(frameId, preferredPlanningFrame, goal, goalInPlanning)) {
398  ROS_WARN("MoveBasic: Will attempt to plan in %s frame", alternatePlanningFrame.c_str());
399  if (!transformPose(frameId, alternatePlanningFrame, goal,
400  goalInPlanning)) {
401  abortGoal("MoveBasic: No localization available for planning");
402  return;
403  }
404  planningFrame = alternatePlanningFrame;
405  goalYaw = yaw;
406  }
407  else {
408  planningFrame = preferredPlanningFrame;
409  }
410 
411  getPose(goalInPlanning, x, y, goalYaw);
412  ROS_INFO("MoveBasic: Goal in %s %f %f %f", planningFrame.c_str(),
413  x, y, rad2deg(goalYaw));
414 
415  // Publish our planned path
416  nav_msgs::Path path;
417  geometry_msgs::PoseStamped p0, p1;
418  path.header.frame_id = frameId;
419  p0.pose.position.x = x;
420  p0.pose.position.y = y;
421  p0.header.frame_id = frameId;
422  path.poses.push_back(p0);
423 
424  tf2::Transform poseFrameId;
425  if (!getTransform(baseFrame, frameId, poseFrameId)) {
426  abortGoal("MoveBasic: Cannot determine robot pose in goal frame");
427  return;
428  }
429  getPose(poseFrameId, x, y, yaw);
430  p1.pose.position.x = x;
431  p1.pose.position.y = y;
432  p1.header.frame_id = frameId;
433  path.poses.push_back(p1);
434 
435  pathPub.publish(path);
436 
437  std::string drivingFrame;
438  tf2::Transform goalInDriving;
439  tf2::Transform currentDrivingBase;
440  // Should be at time of goal message
441  if (!getTransform(preferredDrivingFrame, baseFrame, currentDrivingBase)) {
442  ROS_WARN("MoveBasic: %s not available, attempting to drive using %s frame",
445  baseFrame, currentDrivingBase)) {
446  abortGoal("MoveBasic: Cannot determine robot pose in driving frame");
447  return;
448  }
449  else {
450  drivingFrame = alternateDrivingFrame;
451  }
452  }
453  else {
454  drivingFrame = preferredDrivingFrame;
455  }
456 
457  if (!transformPose(frameId, drivingFrame, goal, goalInDriving)) {
458  abortGoal("MoveBasic: Cannot determine goal pose in driving frame");
459  return;
460  }
461 
462  tf2::Transform goalInBase = currentDrivingBase * goalInDriving;
463  {
464  double x, y, yaw;
465  getPose(goalInBase, x, y, yaw);
466  ROS_INFO("MoveBasic: Goal in %s %f %f %f", baseFrame.c_str(),
467  x, y, rad2deg(yaw));
468  }
469 
470  tf2::Vector3 linear = goalInBase.getOrigin();
471  linear.setZ(0);
472  double dist = linear.length();
473 
474  if (!transformPose(frameId, baseFrame, goal, goalInBase)) {
475  ROS_WARN("MoveBasic: Cannot determine robot pose for rotation");
476  return;
477  }
478 
479  if (dist > linearTolerance) {
480 
481  // Initial rotation to face the goal
482  double requestedYaw = atan2(linear.y(), linear.x());
483  if (std::abs(requestedYaw) > angularTolerance) {
484  if (!rotate(requestedYaw, drivingFrame)) {
485  return;
486  }
487  }
488  sleep(localizationLatency);
489 
490  // Do linear portion of the goal
491  if (!moveLinear(goalInDriving, drivingFrame)) {
492  return;
493  }
494  sleep(localizationLatency);
495 
496  // Final rotation as specified in goal
497  if (do_final_rotation) {
498  double finalYaw = goalYaw - (yaw + requestedYaw);
499  if (std::abs(finalYaw) > angularTolerance) {
500  if (!rotate(finalYaw, drivingFrame)) {
501  return;
502  }
503  }
504 
505  sleep(localizationLatency);
506  }
507  }
508 
509  actionServer->setSucceeded();
510 }
511 
512 
513 // Send a motion command
514 
515 void MoveBasic::sendCmd(double angular, double linear)
516 {
517  if (stop) {
518  angular = 0;
519  linear = 0;
520  }
521  geometry_msgs::Twist msg;
522  msg.angular.z = angular;
523  msg.linear.x = linear;
524 
525  cmdPub.publish(msg);
526 }
527 
528 
529 // Main loop
530 
532 {
533  ros::Rate r(20);
534 
535  while (ros::ok()) {
536  ros::spinOnce();
537  collision_checker->min_side_dist = minSideDist;
538  forwardObstacleDist = collision_checker->obstacle_dist(true,
541  forwardLeft,
542  forwardRight);
543  geometry_msgs::Vector3 msg;
544  msg.x = forwardObstacleDist;
545  msg.y = leftObstacleDist;
546  msg.z = rightObstacleDist;
548  r.sleep();
549  }
550 }
551 
552 
553 // Rotate relative to current orientation
554 
555 bool MoveBasic::rotate(double yaw, const std::string& drivingFrame)
556 {
557  tf2::Transform poseDriving;
558  if (!getTransform(baseFrame, drivingFrame, poseDriving)) {
559  abortGoal("MoveBasic: Cannot determine robot pose for rotation");
560  return false;
561  }
562 
563  double x, y, currentYaw;
564  getPose(poseDriving, x, y, currentYaw);
565  double requestedYaw = currentYaw + yaw;
566  normalizeAngle(requestedYaw);
567  ROS_INFO("MoveBasic: Requested rotation %f", rad2deg(requestedYaw));
568 
569  int oscillations = 0;
570  double prevAngleRemaining = 0;
571 
572  bool done = false;
573  ros::Rate r(50);
574 
575  while (!done && ros::ok()) {
576  ros::spinOnce();
577  r.sleep();
578 
579  double x, y, currentYaw;
580  tf2::Transform poseDriving;
581  if (!getTransform(baseFrame, drivingFrame, poseDriving)) {
582  abortGoal("MoveBasic: Cannot determine robot pose for rotation");
583  return false;
584  }
585  getPose(poseDriving, x, y, currentYaw);
586 
587  double angleRemaining = requestedYaw - currentYaw;
588  normalizeAngle(angleRemaining);
589 
590  double obstacle = collision_checker->obstacle_angle(angleRemaining > 0);
591  double remaining = std::min(std::abs(angleRemaining), std::abs(obstacle));
592  double velocity = std::max(minTurningVelocity,
593  std::min(remaining, std::min(maxTurningVelocity,
594  std::sqrt(2.0 * turningAcceleration *remaining))));
595 
596  if (sign(prevAngleRemaining) != sign(angleRemaining)) {
597  oscillations++;
598  }
599  prevAngleRemaining = angleRemaining;
600 
601  if (actionServer->isPreemptRequested()) {
602  ROS_INFO("MoveBasic: Stopping rotation due to preempt");
603  sendCmd(0, 0);
604  actionServer->setPreempted();
605  return false;
606  }
607 
608  if (std::abs(angleRemaining) < angularTolerance || oscillations > 2) {
609  ROS_INFO("MoveBasic: Done rotation, error %f degrees", rad2deg(angleRemaining));
610  velocity = 0;
611  done = true;
612  }
613 
614  bool counterwise = (angleRemaining < 0.0);
615  if (counterwise) {
616  velocity = -velocity;
617  }
618 
619  sendCmd(velocity, 0);
620  ROS_DEBUG("Angle remaining: %f, Angular velocity: %f", rad2deg(angleRemaining), velocity);
621  }
622  return done;
623 }
624 
625 // Move forward specified distance
626 
628  const std::string& drivingFrame)
629 {
630  tf2::Transform poseDriving;
631  if (!getTransform(drivingFrame, baseFrame, poseDriving)) {
632  abortGoal("MoveBasic: Cannot determine robot pose for linear");
633  return false;
634  }
635  tf2::Transform goalInBase = poseDriving * goalInDriving;
636  tf2::Vector3 remaining = goalInBase.getOrigin();
637 
638  remaining.setZ(0);
639  double requestedDistance = remaining.length();
640 
641  bool pausingForObstacle = false;
642  ros::Time obstacleTime;
643  ros::Duration runawayTimeout(runawayTimeoutSecs);
644  ros::Time last = ros::Time::now();
645 
646  // For lateral control
647  double lateralIntegral = 0.0;
648  double lateralError = 0.0;
649  double prevLateralError = 0.0;
650  double lateralDiff = 0.0;
651 
652  bool done = false;
653  ros::Rate r(50);
654 
655  while (!done && ros::ok()) {
656  ros::spinOnce();
657  r.sleep();
658 
659  if (!getTransform(drivingFrame, baseFrame, poseDriving)) {
660  ROS_WARN("MoveBasic: Cannot determine robot pose for linear");
661  return false;
662  }
663  goalInBase = poseDriving * goalInDriving;
664  remaining = goalInBase.getOrigin();
665  double distRemaining = sqrt(remaining.x() * remaining.x() + remaining.y() * remaining.y());
666 
667  // PID lateral control to keep robot on path
668  double rotation = 0.0;
669  lateralError = remaining.y();
670  lateralDiff = lateralError - prevLateralError;
671  prevLateralError = lateralError;
672  lateralIntegral += lateralError;
673  rotation = (lateralKp * lateralError) + (lateralKi * lateralIntegral) +
674  (lateralKd * lateralDiff);
675  // Clamp rotation
676  rotation = std::max(-maxLateralVelocity, std::min(maxLateralVelocity,
677  rotation));
678  ROS_DEBUG("MoveBasic: %f L %f, R %f %f %f %f %f \n",
680  remaining.x(), remaining.y(), lateralError,
681  rotation);
682 
683  // Publish messages for PID tuning
684  geometry_msgs::Vector3 pid_debug;
685  pid_debug.x = remaining.x();
686  pid_debug.y = lateralError;
687  pid_debug.z = rotation;
688  errorPub.publish(pid_debug);
689 
690  // Collision Avoidance
691  double obstacleDist = forwardObstacleDist;
692  if (requestedDistance < 0.0) {
693  obstacleDist = collision_checker->obstacle_dist(false,
696  forwardLeft,
697  forwardRight);
698  }
699 
700  double velocity = std::max(minLinearVelocity,
701  std::min(std::min(std::abs(obstacleDist), std::abs(distRemaining)),
702  std::min(maxLinearVelocity, std::sqrt(2.0 * linearAcceleration *
703  std::min(std::abs(obstacleDist), std::abs(distRemaining))))));
704 
705  bool obstacleDetected = (obstacleDist < forwardObstacleThreshold);
706  if (obstacleDetected) {
707  velocity = 0;
708  if (!pausingForObstacle) {
709  ROS_INFO("MoveBasic: PAUSING for OBSTACLE");
710  obstacleTime = ros::Time::now();
711  pausingForObstacle = true;
712  }
713  else {
714  ROS_INFO("MoveBasic: Still waiting for obstacle at %f meters!", obstacleDist);
715  ros::Duration waitTime = ros::Time::now() - obstacleTime;
716  if (waitTime.toSec() > obstacleWaitThreshold) {
717  abortGoal("MoveBasic: Aborting due to obstacle");
718  return false;
719  }
720  }
721  }
722 
723  if (!obstacleDetected && pausingForObstacle) {
724  ROS_INFO("MoveBasic: Resuming after obstacle has gone");
725  pausingForObstacle = false;
726  }
727 
728  // Abort Checks
729  if (actionServer->isPreemptRequested()) {
730  ROS_INFO("MoveBasic: Stopping move due to preempt");
731  actionServer->setPreempted();
732  sendCmd(0, 0);
733  return false;
734  }
735 
736  /* Since we are dealing with imperfect localization we should make
737  * sure we are at least runawayTimeout driving away from the goal*/
738  double angleRemaining = std::atan2(remaining.y(), remaining.x());
739  if (std::cos(angleRemaining) < 0) {
740  if (ros::Time::now() - last > runawayTimeout) {
741  abortGoal("MoveBasic: Moving away from goal");
742  sendCmd(0, 0);
743  return false;
744  }
745  }
746  else {
747  // Only update time when moving towards the goal
748  last = ros::Time::now();
749  }
750 
751  /* Finish Check */
752 
753  if (distRemaining < linearTolerance) {
754  ROS_INFO("MoveBasic: Done linear, error: x: %f meters, y: %f meters", remaining.x(), remaining.y());
755  velocity = 0;
756  done = true;
757  }
758 
759  sendCmd(rotation, velocity);
760  ROS_DEBUG("Distance remaining: %f, Linear velocity: %f", distRemaining, velocity);
761  }
762 
763  return done;
764 }
765 
766 
767 int main(int argc, char ** argv) {
768  ros::init(argc, argv, "move_basic");
769  MoveBasic mb_node;
770  mb_node.run();
771 
772  return 0;
773 }
int main(int argc, char **argv)
Definition: move_basic.cpp:767
bool moveLinear(tf2::Transform &goalInDriving, const std::string &drivingFrame)
Definition: move_basic.cpp:627
std::unique_ptr< CollisionChecker > collision_checker
Definition: move_basic.cpp:68
void executeAction(const move_base_msgs::MoveBaseGoalConstPtr &goal)
Definition: move_basic.cpp:354
std::unique_ptr< ObstaclePoints > obstacle_points
Definition: move_basic.cpp:69
void getRPY(tf2Scalar &roll, tf2Scalar &pitch, tf2Scalar &yaw, unsigned int solution_number=1) const
double linearAcceleration
Definition: move_basic.cpp:82
TF2SIMD_FORCE_INLINE Matrix3x3 & getBasis()
void publish(const boost::shared_ptr< M > &message) const
f
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ros::Publisher errorPub
Definition: move_basic.cpp:65
double maxTurningVelocity
Definition: move_basic.cpp:75
double minSideDist
Definition: move_basic.cpp:91
std::string preferredPlanningFrame
Definition: move_basic.cpp:102
ros::Publisher pathPub
Definition: move_basic.cpp:63
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
actionlib::QueuedActionServer< move_base_msgs::MoveBaseAction > MoveBaseActionServer
Definition: move_basic.cpp:54
float leftObstacleDist
Definition: move_basic.cpp:97
double lateralKd
Definition: move_basic.cpp:87
std::unique_ptr< MoveBaseActionServer > actionServer
Definition: move_basic.cpp:67
static int sign(double n)
Definition: move_basic.cpp:146
ros::Subscriber stopSub
Definition: move_basic.cpp:59
TFSIMD_FORCE_INLINE const tfScalar & y() const
ros::Publisher goalPub
Definition: move_basic.cpp:61
#define ROS_WARN(...)
tf2::Vector3 forwardLeft
Definition: move_basic.cpp:99
double obstacleWaitThreshold
Definition: move_basic.cpp:89
ros::Publisher cmdPub
Definition: move_basic.cpp:62
void run()
Definition: move_basic.cpp:531
void dynamicReconfigCallback(move_basic::MovebasicConfig &config, uint32_t)
Definition: move_basic.cpp:294
double lateralKp
Definition: move_basic.cpp:85
double angularTolerance
Definition: move_basic.cpp:77
tf2_ros::Buffer tfBuffer
Definition: move_basic.cpp:71
double minTurningVelocity
Definition: move_basic.cpp:74
TF2SIMD_FORCE_INLINE Vector3 & getOrigin()
double maxLinearVelocity
Definition: move_basic.cpp:80
#define ROS_INFO(...)
double turningAcceleration
Definition: move_basic.cpp:76
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ros::Publisher obstacleDistPub
Definition: move_basic.cpp:64
bool getTransform(const std::string &from, const std::string &to, tf2::Transform &tf)
Definition: move_basic.cpp:265
static void normalizeAngle(double &angle)
Definition: move_basic.cpp:153
float forwardObstacleDist
Definition: move_basic.cpp:96
void drawLine(double x0, double y0, double x1, double y1)
void fromMsg(const A &, B &b)
ros::Subscriber goalSub
Definition: move_basic.cpp:58
double linearTolerance
Definition: move_basic.cpp:83
ROSCPP_DECL bool ok()
std::string preferredDrivingFrame
Definition: move_basic.cpp:104
std::string baseFrame
Definition: move_basic.cpp:106
void goalCallback(const geometry_msgs::PoseStamped::ConstPtr &msg)
Definition: move_basic.cpp:330
float rightObstacleDist
Definition: move_basic.cpp:98
tf2::Transform goalInPlanning
Definition: move_basic.cpp:133
TFSIMD_FORCE_INLINE const tfScalar & x() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::string alternatePlanningFrame
Definition: move_basic.cpp:103
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
tf2::Vector3 forwardRight
Definition: move_basic.cpp:100
double maxLateralVelocity
Definition: move_basic.cpp:78
void abortGoal(const std::string msg)
Definition: move_basic.cpp:345
dynamic_reconfigure::Server< move_basic::MovebasicConfig > dr_srv
Definition: move_basic.cpp:108
static double rad2deg(double rad)
Definition: move_basic.cpp:139
bool sleep()
double lateralKi
Definition: move_basic.cpp:86
static void getPose(const tf2::Transform &tf, double &x, double &y, double &yaw)
Definition: move_basic.cpp:166
double localizationLatency
Definition: move_basic.cpp:92
std::string alternateDrivingFrame
Definition: move_basic.cpp:105
void sendCmd(double angular, double linear)
Definition: move_basic.cpp:515
bool rotate(double requestedYaw, const std::string &drivingFrame)
Definition: move_basic.cpp:555
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
static Time now()
tf2_ros::TransformListener listener
Definition: move_basic.cpp:72
void stopCallback(const std_msgs::Bool::ConstPtr &msg)
Definition: move_basic.cpp:322
double minLinearVelocity
Definition: move_basic.cpp:81
double runawayTimeoutSecs
Definition: move_basic.cpp:93
double forwardObstacleThreshold
Definition: move_basic.cpp:90
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
bool transformPose(const std::string &from, const std::string &to, const tf2::Transform &in, tf2::Transform &out)
Definition: move_basic.cpp:281
#define ROS_DEBUG(...)


move_basic
Author(s): Jim Vaughan
autogenerated on Fri Mar 26 2021 02:46:58