88 geometry_msgs::Pose2D tmp_pose2D;
91 tmp_pose2D.theta = 0.0;
99 ROS_WARN(
"This planner has already been initialized, doing nothing.");
105 eband_local_planner::EBandPlannerConfig& config)
115 k_p_ = config.k_prop;
116 k_nu_ = config.k_damp;
149 odom_vel_.linear.x = odometry.twist.twist.linear.x;
150 odom_vel_.linear.y = odometry.twist.twist.linear.y;
154 odom_vel_.angular.z = odometry.twist.twist.angular.z;
162 const geometry_msgs::Pose& pose)
164 const double pi = 3.14159265;
165 const double t1 =
atan2(heading.linear.y, heading.linear.x);
166 const double t2 =
tf::getYaw(pose.orientation);
167 const double d = t1-t2;
178 goal_reached =
false;
180 geometry_msgs::Twist robot_cmd, bubble_diff;
181 robot_cmd.linear.x = 0.0;
182 robot_cmd.angular.z = 0.0;
184 bool command_provided =
false;
188 ROS_ERROR(
"Requesting feedforward command from not initialized planner. Please call initialize() before using this planner");
194 ROS_WARN(
"Requesting feedforward command from empty band.");
204 float distance_from_goal = -1.0f;
208 if (!command_provided) {
209 int curr_target_bubble = 1;
211 while(curr_target_bubble < ((
int)
elastic_band_.size()) - 1) {
212 curr_target_bubble++;
235 distance_from_goal = sqrtf(bubble_diff.linear.x * bubble_diff.linear.x +
236 bubble_diff.linear.y * bubble_diff.linear.y);
250 ROS_DEBUG(
"Performing in place rotation for goal (diff): %f", orientation_diff);
251 double rotation_sign = -2 * (orientation_diff < 0) + 1;
252 robot_cmd.angular.z =
259 ROS_INFO (
"TrajectoryController: Goal reached with distance %.2f, %.2f (od = %.2f)" 260 "; sending zero velocity",
261 bubble_diff.linear.x, bubble_diff.linear.y, orientation_diff);
263 robot_cmd.linear.x = 0.0;
264 robot_cmd.angular.z = 0.0;
267 command_provided =
true;
278 if (!command_provided) {
279 ROS_DEBUG(
"Goal has not been reached, performing checks to move towards goal");
282 double distance_to_next_bubble =
sqrt(
283 bubble_diff.linear.x * bubble_diff.linear.x +
284 bubble_diff.linear.y * bubble_diff.linear.y);
285 double radius_of_next_bubble = 0.7 *
elastic_band_.at(1).expansion;
286 double in_place_rotation_threshold =
288 fabs(
atan2(radius_of_next_bubble,distance_to_next_bubble));
289 ROS_DEBUG(
"In-place rotation threshold: %f(%f,%f)",
290 in_place_rotation_threshold, radius_of_next_bubble, distance_to_next_bubble);
293 if (fabs(bubble_diff.angular.z) > in_place_rotation_threshold) {
294 robot_cmd.angular.z =
k_p_ * bubble_diff.angular.z;
295 double rotation_sign = (bubble_diff.angular.z < 0) ? -1.0 : +1.0;
302 ROS_DEBUG(
"Performing in place rotation for start (diff): %f with rot vel: %f", bubble_diff.angular.z, robot_cmd.angular.z);
303 command_provided =
true;
309 if (!command_provided) {
312 double forward_sign = -2 * (bubble_diff.linear.x < 0) + 1;
317 if (distance_from_goal < 0.75
f) {
318 max_vel_lin = (max_vel_lin < 0.3) ? 0.15 : max_vel_lin / 2;
321 double linear_velocity = velocity_multiplier * max_vel_lin;
322 linear_velocity *=
cos(bubble_diff.angular.z);
330 double error = bubble_diff.angular.z;
331 double rotation_sign = -2 * (bubble_diff.angular.z < 0) + 1;
332 double angular_velocity =
k_p_ * error;
339 ROS_DEBUG(
"Selected velocity: lin: %f, ang: %f",
340 linear_velocity, angular_velocity);
342 robot_cmd.linear.x = linear_velocity;
343 robot_cmd.angular.z = angular_velocity;
344 command_provided =
true;
347 twist_cmd = robot_cmd;
348 ROS_DEBUG(
"Final command: %f, %f", twist_cmd.linear.x, twist_cmd.angular.z);
355 goal_reached =
false;
361 geometry_msgs::Twist robot_cmd, bubble_diff, control_deviation;
362 robot_cmd.linear.x = 0.0;
363 robot_cmd.linear.y = 0.0;
364 robot_cmd.linear.z = 0.0;
365 robot_cmd.angular.x = 0.0;
366 robot_cmd.angular.y = 0.0;
367 robot_cmd.angular.z = 0.0;
370 twist_cmd = robot_cmd;
371 control_deviation = robot_cmd;
376 ROS_ERROR(
"Requesting feedforward command from not initialized planner. Please call initialize() before using this planner");
383 ROS_WARN(
"Requesting feedforward command from empty band.");
393 double bubble_distance, ang_pseudo_dist;
398 bubble_distance =
sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) + (bubble_diff.linear.y * bubble_diff.linear.y) +
399 (ang_pseudo_dist * ang_pseudo_dist) );
409 control_deviation = bubble_diff;
413 abs_ctrl_dev =
sqrt( (control_deviation.linear.x * control_deviation.linear.x) +
414 (control_deviation.linear.y * control_deviation.linear.y) +
415 (ang_pseudo_dist * ang_pseudo_dist) );
418 if(scaled_radius < bubble_distance)
421 double scale_difference = scaled_radius / bubble_distance;
422 bubble_diff.linear.x *= scale_difference;
423 bubble_diff.linear.y *= scale_difference;
424 bubble_diff.angular.z *= scale_difference;
426 control_deviation = bubble_diff;
431 if(scaled_radius > bubble_distance)
437 double next_bubble_distance;
438 geometry_msgs::Twist next_bubble_diff;
443 next_bubble_distance =
sqrt( (next_bubble_diff.linear.x * next_bubble_diff.linear.x) +
444 (next_bubble_diff.linear.y * next_bubble_diff.linear.y) +
445 (ang_pseudo_dist * ang_pseudo_dist) );
447 if(scaled_radius > (bubble_distance + next_bubble_distance) )
450 control_deviation.linear.x = bubble_diff.linear.x + next_bubble_diff.linear.x;
451 control_deviation.linear.y = bubble_diff.linear.y + next_bubble_diff.linear.y;
452 control_deviation.angular.z = bubble_diff.angular.z + next_bubble_diff.angular.z;
464 double b_distance, cosine_at_bub;
465 double vec_prod, norm_vec1, norm_vec2;
466 double ang_pseudo_dist1, ang_pseudo_dist2;
472 vec_prod = - ( (bubble_diff.linear.x * next_bubble_diff.linear.x) +
473 (bubble_diff.linear.y * next_bubble_diff.linear.y) +
474 (ang_pseudo_dist1 * ang_pseudo_dist2) );
476 norm_vec1 =
sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) +
477 (bubble_diff.linear.y * bubble_diff.linear.y) +
478 (ang_pseudo_dist1 * ang_pseudo_dist1) );
480 norm_vec2 =
sqrt( (next_bubble_diff.linear.x * next_bubble_diff.linear.x) +
481 (next_bubble_diff.linear.y * next_bubble_diff.linear.y) +
482 (ang_pseudo_dist2 * ang_pseudo_dist2) );
485 cosine_at_bub = vec_prod / norm_vec1 / norm_vec2;
486 b_distance = bubble_distance * cosine_at_bub +
sqrt( scaled_radius*scaled_radius -
487 bubble_distance*bubble_distance * (1.0 - cosine_at_bub*cosine_at_bub) );
490 double scale_next_difference = b_distance / next_bubble_distance;
491 next_bubble_diff.linear.x *= scale_next_difference;
492 next_bubble_diff.linear.y *= scale_next_difference;
493 next_bubble_diff.angular.z *= scale_next_difference;
496 control_deviation.linear.x = bubble_diff.linear.x + next_bubble_diff.linear.x;
497 control_deviation.linear.y = bubble_diff.linear.y + next_bubble_diff.linear.y;
498 control_deviation.angular.z = bubble_diff.angular.z + next_bubble_diff.angular.z;
506 abs_ctrl_dev =
sqrt( (control_deviation.linear.x * control_deviation.linear.x) +
507 (control_deviation.linear.y * control_deviation.linear.y) +
508 (ang_pseudo_dist * ang_pseudo_dist) );
514 geometry_msgs::Pose2D tmp_bubble_2d, curr_bubble_2d;
515 geometry_msgs::Pose tmp_pose;
519 tmp_bubble_2d.x = curr_bubble_2d.x + control_deviation.linear.x;
520 tmp_bubble_2d.y = curr_bubble_2d.y + control_deviation.linear.y;
521 tmp_bubble_2d.theta = curr_bubble_2d.theta + control_deviation.angular.z;
523 new_bubble.
center.pose = tmp_pose;
529 const geometry_msgs::Point& goal = (--
elastic_band_.end())->center.pose.position;
530 const double dx =
elastic_band_.at(0).center.pose.position.x - goal.x;
531 const double dy =
elastic_band_.at(0).center.pose.position.y - goal.y;
532 const double dist_to_goal =
sqrt(dx*dx + dy*dy);
542 control_deviation.angular.z = vel*mult;
543 const double abs_vel = fabs(control_deviation.angular.z);
546 "Angular diff is %.2f and desired angular " 547 "vel is %.2f. Initial translation velocity " 548 "is %.2f, %.2f", angular_diff,
549 control_deviation.angular.z,
550 control_deviation.linear.x,
551 control_deviation.linear.y);
553 control_deviation.linear.x *= trans_mult;
554 control_deviation.linear.y *= trans_mult;
556 "Translation multiplier is %.2f and scaled " 557 "translational velocity is %.2f, %.2f",
558 trans_mult, control_deviation.linear.x,
559 control_deviation.linear.y);
563 "Not applying angle correction because " 564 "distance to goal is %.2f", dist_to_goal);
570 geometry_msgs::Twist desired_velocity, currbub_maxvel_dir;
571 double desvel_abs, desvel_abs_trans, currbub_maxvel_abs;
572 double scale_des_vel;
573 desired_velocity = robot_cmd;
574 currbub_maxvel_dir = robot_cmd;
577 desired_velocity.linear.x =
k_p_/
k_nu_ * control_deviation.linear.x;
578 desired_velocity.linear.y =
k_p_/
k_nu_ * control_deviation.linear.y;
579 desired_velocity.angular.z =
k_p_/
k_nu_ * control_deviation.angular.z;
584 int curr_bub_num = 0;
589 desvel_abs =
sqrt( (desired_velocity.linear.x * desired_velocity.linear.x) +
590 (desired_velocity.linear.y * desired_velocity.linear.y) +
591 (ang_pseudo_dist * ang_pseudo_dist) );
592 if(desvel_abs > currbub_maxvel_abs)
594 scale_des_vel = currbub_maxvel_abs / desvel_abs;
595 desired_velocity.linear.x *= scale_des_vel;
596 desired_velocity.linear.y *= scale_des_vel;
597 desired_velocity.angular.z *= scale_des_vel;
601 desvel_abs_trans =
sqrt( (desired_velocity.linear.x * desired_velocity.linear.x) + (desired_velocity.linear.y * desired_velocity.linear.y) );
606 desired_velocity.linear.x *= scale_des_vel;
607 desired_velocity.linear.y *= scale_des_vel;
609 desired_velocity.angular.z *= scale_des_vel;
615 scale_des_vel =
max_vel_th_ / fabs(desired_velocity.angular.z);
616 desired_velocity.angular.z *= scale_des_vel;
618 desired_velocity.linear.x *= scale_des_vel;
619 desired_velocity.linear.y *= scale_des_vel;
623 geometry_msgs::Twist acc_desired;
624 acc_desired = robot_cmd;
631 double abs_acc_trans =
sqrt( (acc_desired.linear.x*acc_desired.linear.x) + (acc_desired.linear.y*acc_desired.linear.y) );
635 acc_desired.linear.x *= scale_acc;
636 acc_desired.linear.y *= scale_acc;
638 acc_desired.angular.z *= scale_acc;
644 acc_desired.angular.z *= scale_acc;
646 acc_desired.linear.x *= scale_acc;
647 acc_desired.linear.y *= scale_acc;
668 int curr_target_bubble = 1;
675 curr_target_bubble++;
684 "Goal reached with distance %.2f, %.2f, %.2f" 685 "; sending zero velocity",
686 bubble_diff.linear.x, bubble_diff.linear.y,
687 bubble_diff.angular.z);
689 robot_cmd.linear.x = 0.0;
690 robot_cmd.linear.y = 0.0;
691 robot_cmd.angular.z = 0.0;
701 twist_cmd = robot_cmd;
710 VelDir.linear.x = 0.0;
711 VelDir.linear.y = 0.0;
712 VelDir.linear.z = 0.0;
713 VelDir.angular.x = 0.0;
714 VelDir.angular.y = 0.0;
715 VelDir.angular.z = 0.0;
718 if(target_bub_num >= ((
int) band.size() - 1))
723 double v_max_curr_bub, v_max_next_bub;
724 double bubble_distance, angle_to_pseudo_vel, delta_vel_max;
725 geometry_msgs::Twist bubble_diff;
731 ROS_ASSERT( (target_bub_num >= 0) && ((target_bub_num +1) < (
int) band.size()) );
736 bubble_distance =
sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) + (bubble_diff.linear.y * bubble_diff.linear.y) +
737 (angle_to_pseudo_vel * angle_to_pseudo_vel) );
740 VelDir.linear.x =bubble_diff.linear.x/bubble_distance;
741 VelDir.linear.y =bubble_diff.linear.y/bubble_distance;
742 VelDir.angular.z =bubble_diff.angular.z/bubble_distance;
745 if(bubble_distance > band.at(target_bub_num).expansion )
746 return v_max_curr_bub;
750 int next_bub_num = target_bub_num + 1;
751 geometry_msgs::Twist dummy_twist;
755 if(v_max_next_bub >= v_max_curr_bub)
756 return v_max_curr_bub;
761 v_max_curr_bub = v_max_next_bub + delta_vel_max;
763 return v_max_curr_bub;
770 geometry_msgs::Pose2D frame1_pose2D, frame2_pose2D, ref_frame_pose2D;
771 geometry_msgs::Pose2D frame1_pose2D_rf, frame2_pose2D_rf;
772 geometry_msgs::Twist frame_diff;
780 frame1_pose2D_rf.x = (frame1_pose2D.x - ref_frame_pose2D.x) *
cos(ref_frame_pose2D.theta) +
781 (frame1_pose2D.y - ref_frame_pose2D.y) *
sin(ref_frame_pose2D.theta);
782 frame1_pose2D_rf.y = -(frame1_pose2D.x - ref_frame_pose2D.x) *
sin(ref_frame_pose2D.theta) +
783 (frame1_pose2D.y - ref_frame_pose2D.y) *
cos(ref_frame_pose2D.theta);
784 frame1_pose2D_rf.theta = frame1_pose2D.theta - ref_frame_pose2D.theta;
787 frame2_pose2D_rf.x = (frame2_pose2D.x - ref_frame_pose2D.x) *
cos(ref_frame_pose2D.theta) +
788 (frame2_pose2D.y - ref_frame_pose2D.y) *
sin(ref_frame_pose2D.theta);
789 frame2_pose2D_rf.y = -(frame2_pose2D.x - ref_frame_pose2D.x) *
sin(ref_frame_pose2D.theta) +
790 (frame2_pose2D.y - ref_frame_pose2D.y) *
cos(ref_frame_pose2D.theta);
791 frame2_pose2D_rf.theta = frame2_pose2D.theta - ref_frame_pose2D.theta;
795 frame_diff.linear.x = frame2_pose2D_rf.x - frame1_pose2D_rf.x;
796 frame_diff.linear.y = frame2_pose2D_rf.y - frame1_pose2D_rf.y;
797 frame_diff.linear.z = 0.0;
798 frame_diff.angular.x = 0.0;
799 frame_diff.angular.y = 0.0;
800 frame_diff.angular.z = frame2_pose2D_rf.theta - frame1_pose2D_rf.theta;
810 double x1 = frame1.position.x - ref_frame.position.x;
811 double y1 = frame1.position.y - ref_frame.position.y;
812 double x2 = frame2.position.x - ref_frame.position.x;
813 double y2 = frame2.position.y - ref_frame.position.y;
814 double yaw_ref =
tf::getYaw(ref_frame.orientation);
816 double x_diff = x2 - x1;
817 double y_diff = y2 - y1;
818 double theta_diff =
atan2(y_diff, x_diff);
822 double x_final = x_diff *
cos(rotation) + y_diff *
sin(rotation);
823 double y_final = - x_diff * sin(rotation) + y_diff *
cos(rotation);
825 geometry_msgs::Twist twist_msg;
826 twist_msg.linear.x = x_final;
827 twist_msg.linear.y = y_final;
835 const geometry_msgs::Pose& frame1,
const geometry_msgs::Pose& frame2)
837 geometry_msgs::Pose2D frame1_pose2D, frame2_pose2D;
838 geometry_msgs::Twist tmp_transformed;
841 tmp_transformed = curr_twist;
848 delta_ang = frame2_pose2D.theta - frame1_pose2D.theta;
852 tmp_transformed.linear.x = curr_twist.linear.x *
cos(delta_ang) + curr_twist.linear.y *
sin(delta_ang);
853 tmp_transformed.linear.y = -curr_twist.linear.x *
sin(delta_ang) + curr_twist.linear.y *
cos(delta_ang);
855 return tmp_transformed;
861 geometry_msgs::Twist res = twist;
864 double lin_overshoot =
sqrt(res.linear.x * res.linear.x + res.linear.y * res.linear.y) /
max_vel_lin_;
865 double lin_undershoot =
min_vel_lin_ /
sqrt(res.linear.x * res.linear.x + res.linear.y * res.linear.y);
866 if (lin_overshoot > 1.0)
868 res.linear.x /= lin_overshoot;
869 res.linear.y /= lin_overshoot;
871 res.angular.z /= lin_overshoot;
875 if(lin_undershoot > 1.0)
877 res.linear.x *= lin_undershoot;
878 res.linear.y *= lin_undershoot;
886 res.angular.z *= scale;
888 res.linear.x *= scale;
889 res.linear.y *= scale;
905 ROS_DEBUG(
"Angular command %f", res.angular.z);
std::vector< Bubble > elastic_band_
bool disallow_hysteresis_
double rotation_threshold_multiplier_
geometry_msgs::Twist getFrame1ToFrame2InRefFrameNew(const geometry_msgs::Pose &frame1, const geometry_msgs::Pose &frame2, const geometry_msgs::Pose &ref_frame)
geometry_msgs::Twist transformTwistFromFrame1ToFrame2(const geometry_msgs::Twist &curr_twist, const geometry_msgs::Pose &frame1, const geometry_msgs::Pose &frame2)
double bubble_velocity_multiplier_
bool getTwist(geometry_msgs::Twist &twist_cmd, bool &goal_reached)
calculates a twist feedforward command from the current band
geometry_msgs::Twist getFrame1ToFrame2InRefFrame(const geometry_msgs::Pose &frame1, const geometry_msgs::Pose &frame2, const geometry_msgs::Pose &ref_frame)
Transforms Pose of frame 1 and 2 into reference frame and gets difference of frame 1 and 2...
bool setBand(const std::vector< Bubble > &elastic_band)
This sets the elastic_band to the trajectory controller.
#define ROS_DEBUG_THROTTLE_NAMED(rate, name,...)
double sign(double n)
defines sign of a double
static double getYaw(const Quaternion &bt_q)
void reconfigure(EBandPlannerConfig &config)
Reconfigures the parameters of the planner.
void Pose2DToPose(geometry_msgs::Pose &pose, const geometry_msgs::Pose2D pose2D)
Converts a frame of type Pose to type Pose2D (mainly -> conversion of orientation from euler angles t...
EBandTrajectoryCtrl()
Default constructor.
bool setOdometry(const nav_msgs::Odometry &odometry)
This sets the robot velocity as provided by odometry.
double min_in_place_vel_th_
double angularDiff(const geometry_msgs::Twist &heading, const geometry_msgs::Pose &pose)
geometry_msgs::Twist last_vel_
bool differential_drive_hack_
~EBandTrajectoryCtrl()
Destructor.
geometry_msgs::Twist odom_vel_
bool getTwistDifferentialDrive(geometry_msgs::Twist &twist_cmd, bool &goal_reached)
double getCircumscribedRadius(costmap_2d::Costmap2DROS &costmap)
Gets the footprint of the robot and computes the circumscribed radius for the eband approach...
double in_place_trans_vel_
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
def normalize_angle(angle)
control_toolbox::Pid pid_
double rotation_correction_threshold_
geometry_msgs::Pose ref_frame_band_
void initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros)
Initializes the elastic band class by accesing costmap and loading parameters.
double getBubbleTargetVel(const int &target_bub_num, const std::vector< Bubble > &band, geometry_msgs::Twist &VelDir)
gets the max velocity allowed within this bubble depending on size of the bubble and pose and size of...
void setVisualization(boost::shared_ptr< EBandVisualization > target_visual)
passes a reference to the eband visualization object which can be used to visualize the band optimiza...
boost::shared_ptr< EBandVisualization > target_visual_
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
geometry_msgs::Twist limitTwist(const geometry_msgs::Twist &twist)
limits the twist to the allowed range
geometry_msgs::PoseStamped center
costmap_2d::Costmap2DROS * costmap_ros_
pointer to costmap
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
double max(double a, double b)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
void PoseToPose2D(const geometry_msgs::Pose pose, geometry_msgs::Pose2D &pose2D)
Converts a frame of type Pose to type Pose2D (mainly -> conversion of orientation from quaternions to...