00001 #include <goto_crossing/crossing_goer.h>
00002
00003 namespace goto_crossing
00004 {
00005
00006 CrossingGoer::CrossingGoer() :
00007 kp_v_(0.1),
00008 kp_w_(0.2),
00009 ki_v_(0),
00010 ki_w_(0),
00011 min_linear_velocity_(0),
00012 max_linear_velocity_(0),
00013 min_angular_velocity_(0),
00014 max_angular_velocity_(0),
00015 reach_distance_(0.1),
00016 dtheta_force_left_(0),
00017 threshold_w_only_(0.35),
00018 max_sum_v_(10),
00019 max_sum_w_(30),
00020 last_t_(ros::Time::now()),
00021 sum_v_(0),
00022 sum_w_(0)
00023 {
00024 ros::NodeHandle private_nh("~");
00025 private_nh.getParam("kp_v", kp_v_);
00026 private_nh.getParam("kp_w", kp_w_);
00027 private_nh.getParam("ki_v", ki_v_);
00028 private_nh.getParam("ki_w", ki_w_);
00029 private_nh.getParam("min_linear_velocity", min_linear_velocity_);
00030 private_nh.getParam("max_linear_velocity", max_linear_velocity_);
00031 private_nh.getParam("min_angular_velocity", min_angular_velocity_);
00032 private_nh.getParam("max_angular_velocity", max_angular_velocity_);
00033 private_nh.getParam("reach_distance", reach_distance_);
00034 private_nh.getParam("dtheta_force_left", dtheta_force_left_);
00035 private_nh.getParam("threshold_w_only", threshold_w_only_);
00036 private_nh.getParam("max_sum_v", max_sum_v_);
00037 private_nh.getParam("max_sum_w", max_sum_w_);
00038
00039 twist_publisher_ = private_nh.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00040 goal_reached_publisher_ = private_nh.advertise<std_msgs::Bool>("goal_reached", 1);
00041
00042 reset_integral_server_ = private_nh.advertiseService("reset_integrals", &CrossingGoer::callback_resetIntegrals, this);
00043 }
00044
00045
00046
00047
00048
00049
00050
00051
00052 bool CrossingGoer::goto_crossing(const lama_msgs::Crossing& crossing, geometry_msgs::Twist& twist)
00053 {
00054 geometry_msgs::Point goal;
00055
00056
00057 bool can_reach = (crossing.frontiers.size() >= 3);
00058
00059 if (crossing.frontiers.size() == 0)
00060 {
00061
00062 goal.x = crossing.radius;
00063 }
00064 else if (crossing.frontiers.size() == 1)
00065 {
00066
00067
00068
00069
00070 goal.x = std::cos(crossing.frontiers[0].angle) * crossing.radius;
00071 goal.y = std::sin(crossing.frontiers[0].angle) * crossing.radius;
00072 }
00073 else if (crossing.frontiers.size() == 2)
00074 {
00075
00076 double dtheta0 = angles::normalize_angle(crossing.frontiers[0].angle);
00077 double dtheta1 = angles::normalize_angle(crossing.frontiers[1].angle);
00078
00079 if (std::abs(dtheta0) < std::abs(dtheta1))
00080 {
00081
00082
00083
00084 goal.x = std::cos(dtheta0) * crossing.radius;
00085 goal.y = std::sin(dtheta0) * crossing.radius;
00086 }
00087 else
00088 {
00089
00090
00091
00092 goal.x = std::cos(dtheta1) * crossing.radius;
00093 goal.y = std::sin(dtheta1) * crossing.radius;
00094 }
00095 }
00096 else
00097 {
00098
00099 goal.x = crossing.center.x;
00100 goal.y = crossing.center.y;
00101 }
00102 ROS_DEBUG("goal: (%.3f, %.3f)", goal.x, goal.y);
00103 return goToGoal(goal, twist) && can_reach;
00104 }
00105
00106
00107
00108
00109
00110 void CrossingGoer::callback_goto_crossing(const lama_msgs::Crossing& crossing)
00111 {
00112
00113 geometry_msgs::Twist twist;
00114 bool goal_reached = goto_crossing(crossing, twist);
00115
00116 twist_publisher_.publish(twist);
00117 std_msgs::Bool goal_reached_msg;
00118 goal_reached_msg.data = goal_reached;
00119 goal_reached_publisher_.publish(goal_reached_msg);
00120 }
00121
00122 bool CrossingGoer::callback_resetIntegrals(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res)
00123 {
00124 resetIntegrals();
00125 return true;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135 bool CrossingGoer::goToGoal(const geometry_msgs::Point& goal, geometry_msgs::Twist& twist)
00136 {
00137
00138 ros::NodeHandle private_nh("~");
00139 private_nh.getParamCached("kp_v", kp_v_);
00140 private_nh.getParamCached("kp_w", kp_w_);
00141 private_nh.getParamCached("ki_v", ki_v_);
00142 private_nh.getParamCached("ki_w", ki_w_);
00143 private_nh.getParamCached("min_linear_velocity", min_linear_velocity_);
00144 private_nh.getParamCached("max_linear_velocity", max_linear_velocity_);
00145 private_nh.getParamCached("min_angular_velocity", min_angular_velocity_);
00146 private_nh.getParamCached("max_angular_velocity", max_angular_velocity_);
00147 private_nh.getParamCached("reach_distance", reach_distance_);
00148 private_nh.getParamCached("dtheta_force_left", dtheta_force_left_);
00149 private_nh.getParamCached("threshold_w_only", threshold_w_only_);
00150 private_nh.getParamCached("max_sum_v", max_sum_v_);
00151 private_nh.getParamCached("max_sum_w", max_sum_w_);
00152
00153 double distance = std::sqrt(goal.x * goal.x + goal.y * goal.y);
00154
00155 if (distance < reach_distance_)
00156 {
00157 ROS_DEBUG("%s: Goal (%f, %f) reached", ros::this_node::getName().c_str(), goal.x, goal.y);
00158 twist = geometry_msgs::Twist();
00159
00160 return true;
00161 }
00162
00163 double dtheta = std::atan2(goal.y, goal.x);
00164
00165 if (std::abs(dtheta) > threshold_w_only_)
00166 {
00167
00168 ROS_DEBUG("%s: Goal angle too large, just turning...", ros::this_node::getName().c_str());
00169 distance = 0.0;
00170 }
00171
00172 if ((M_PI - dtheta_force_left_ < dtheta) && (dtheta < M_PI))
00173 {
00174
00175 dtheta -= 2 * M_PI;
00176 }
00177
00178
00179 const ros::Time t = ros::Time::now();
00180 const double dt = (t - last_t_).toSec();
00181 sum_v_ += distance * dt;
00182 sum_w_ += dtheta * dt;
00183
00184
00185 if (sum_v_ < -max_sum_v_)
00186 {
00187 sum_v_ = -max_sum_v_;
00188 }
00189 else if (sum_v_ > max_sum_v_)
00190 {
00191 sum_v_ = max_sum_v_;
00192 }
00193 if (sum_w_ < -max_sum_w_)
00194 {
00195 sum_w_ = -max_sum_w_;
00196 }
00197 else if (sum_w_ > max_sum_w_)
00198 {
00199 sum_w_ = max_sum_w_;
00200 }
00201
00202
00203
00204 double vx = kp_v_ * distance + ki_v_ * sum_v_;
00205 double wz = kp_w_ * dtheta + ki_w_ * sum_w_;
00206
00207
00208
00209 const double vx_throttle_dtheta = std::max(std::min(1.0, 1.0 - std::abs(dtheta) / threshold_w_only_), 0.0);
00210 vx = vx * vx_throttle_dtheta;
00211
00212
00213 if ((ki_v_ < 1e-10) && (vx < min_linear_velocity_) &&
00214 (std::abs(distance) > 1e-10) && (std::abs(wz) < min_angular_velocity_))
00215 {
00216 vx = min_linear_velocity_;
00217 }
00218 if ((ki_w_ < 1e-10) && (wz > 0) && (wz < min_angular_velocity_) && (vx < min_linear_velocity_))
00219 {
00220 wz = min_angular_velocity_;
00221 }
00222 else if ((ki_w_ < 1e-10) && (wz < 0) && (wz > -min_angular_velocity_) && (vx < min_linear_velocity_))
00223 {
00224 wz = -min_angular_velocity_;
00225 }
00226
00227
00228 if (max_linear_velocity_ > 1e-10)
00229 {
00230
00231 if (vx > max_linear_velocity_)
00232 {
00233 vx = max_linear_velocity_;
00234 }
00235 }
00236 if (max_angular_velocity_ > 1e-10)
00237 {
00238
00239 if (wz > max_angular_velocity_)
00240 {
00241 wz = max_angular_velocity_;
00242 }
00243 else if (wz < -max_angular_velocity_)
00244 {
00245 wz = -max_angular_velocity_;
00246 }
00247 }
00248
00249 ROS_DEBUG("distance to goal: %f, dtheta to goal: %f, twist: (%f, %f)",
00250 distance, dtheta, vx, wz);
00251
00252 ROS_DEBUG_NAMED("superdebug", "sum_v_: %f", sum_v_);
00253 ROS_DEBUG_NAMED("superdebug", "sum_w_: %f", sum_w_);
00254
00255 twist.linear.x = vx;
00256 twist.angular.z = wz;
00257
00258 last_t_ = t;
00259 return false;
00260 }
00261
00262 }