00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "flyer_controller/control_mode.h"
00035 #include "flyer_controller/hover_modes.h"
00036
00037
00038 #include "flyer_controller/control_mode_autosequence_info.h"
00039 #include "flyer_controller/Autosequence.h"
00040 #include "flyer_controller/GetAutosequence.h"
00041
00042 namespace flyer_controller
00043 {
00044
00045 const int BTN_PROCEED = 8;
00046 const int BTN_PAUSE = 7;
00047
00048 struct autosequence_point
00049 {
00050 hover_point point;
00051 bool pause;
00052 };
00053
00054 typedef vector<autosequence_point> autosequence;
00055
00056 namespace AutosequenceTypes
00057 {
00058 enum WaypointUpdateStates
00059 {
00060 WAITING_PROCEED = 0, MOVING = 1, PAUSED = 2, IDLE = 3
00061 };
00062 typedef WaypointUpdateStates WaypointUpdateState;
00063 }
00064
00065 class ControlModeAutosequence : public HoverMode
00066 {
00067 private:
00068
00069 double waypoint_update_rate;
00070 double reached_tolerance;
00071 double reached_tolerance_yaw;
00072 double waypoint_speed;
00073 double max_waypoint_lead;
00074
00075 ros::Publisher autosequence_info_pub;
00076
00077 ros::ServiceServer get_autosequence_srv;
00078
00079 ros::Timer waypoint_update_timer;
00080
00081 bool executing;
00082 string current_autosequence;
00083 unsigned int current_point;
00084 AutosequenceTypes::WaypointUpdateState wp_update_state;
00085 hover_point segment_start;
00086 hover_point segment_end;
00087 bool proceed_commanded;
00088 bool pause_commanded;
00089 bool cancel_commanded;
00090 control_mode_autosequence_info autosequence_info_msg;
00091
00092 public:
00093 ControlModeAutosequence() :
00094 HoverMode("autosequence"), waypoint_update_rate(10), reached_tolerance(0.05), reached_tolerance_yaw(5.0),
00095 waypoint_speed(0.05), max_waypoint_lead(0.1), executing(false), current_autosequence(""), current_point(0),
00096 wp_update_state(AutosequenceTypes::IDLE), proceed_commanded(false), pause_commanded(false),
00097 cancel_commanded(false)
00098 {
00099
00100 }
00101
00102 void onInit()
00103 {
00104 HoverMode::onInit();
00105 nh_priv.param("waypoint_update_rate", waypoint_update_rate, waypoint_update_rate);
00106 nh_priv.param("reached_tolerance", reached_tolerance, reached_tolerance);
00107 nh_priv.param("reached_tolerance_yaw", reached_tolerance_yaw, reached_tolerance_yaw);
00108 nh_priv.param("waypoint_speed", waypoint_speed, waypoint_speed);
00109 nh_priv.param("max_waypoint_lead", max_waypoint_lead, max_waypoint_lead);
00110
00111 autosequence_info_pub = nh_priv.advertise<control_mode_autosequence_info> ("autosequence_info", 10);
00112 get_autosequence_srv = nh_priv.advertiseService("get_autosequence",
00113 &ControlModeAutosequence::get_autosequence_callback, this);
00114 }
00115
00116 private:
00117 map<string, autosequence> autosequences;
00118
00119 bool autosequence_exists(const string autosequence_name)
00120 {
00121 map<string, autosequence>::iterator it;
00122 it = autosequences.find(autosequence_name);
00123 return (not (it == autosequences.end()));
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 bool parseControlModeCmdDerived(const string cmd)
00148 {
00149 vector < string > words;
00150 boost::split(words, cmd, boost::is_any_of(" \t\n,"), boost::token_compress_on);
00151 int nw = words.size();
00152
00153 if (words[0] == "define" and words[1] == "autosequence")
00154 {
00155 string autosequence_name = words[2];
00156 if (autosequence_exists(autosequence_name))
00157 {
00158 NODELET_WARN_STREAM("Autosequence '" << autosequence_name << "' exists and will be redefined.");
00159 }
00160 int i = 3;
00161 autosequence new_autosequence;
00162 bool fail = false;
00163 while ((i < nw) and not fail)
00164 {
00165 bool pause = false;
00166 if ((i < nw - 1) and words[i + 1] == "pause")
00167 {
00168 pause = true;
00169 }
00170 autosequence_point new_autosequence_point;
00171 if (hover_point_exists(words[i]))
00172 {
00173 NODELET_DEBUG_STREAM("Adding point " << words[i] << " to autosequence");
00174 new_autosequence_point.point = hover_points[words[i]];
00175 new_autosequence_point.pause = pause;
00176 new_autosequence.push_back(new_autosequence_point);
00177 if (pause)
00178 i += 2;
00179 else
00180 i++;
00181 }
00182 else
00183 {
00184 NODELET_ERROR_STREAM("Unknown hover point '" << words[i] << "'.");
00185 fail = true;
00186 }
00187 }
00188 if (!fail)
00189 {
00190 autosequences[autosequence_name] = new_autosequence;
00191 NODELET_INFO_STREAM("Completed autosequence definition for '" << autosequence_name << "' with "
00192 << new_autosequence.size() << " points");
00193
00194 }
00195 else
00196 {
00197 NODELET_ERROR("Autosequence definition failed");
00198 }
00199
00200 }
00201 else if (words[0] == "execute" and words[1] == "autosequence")
00202 {
00203 if (nw == 3)
00204 {
00205 if (autosequence_exists(words[2]))
00206 {
00207 if (not executing)
00208 {
00209 start_autosequence(words[2]);
00210 }
00211 else
00212 {
00213 NODELET_ERROR("Autosequence already executing");
00214 }
00215 }
00216 else
00217 {
00218 NODELET_ERROR_STREAM("Unknown autosequence '" << words[2] << "'");
00219 }
00220 }
00221 else
00222 {
00223 NODELET_ERROR("Invalid command");
00224 }
00225 }
00226 else if (words[0] == "proceed")
00227 {
00228 if (executing and ((wp_update_state == AutosequenceTypes::WAITING_PROCEED) or (wp_update_state
00229 == AutosequenceTypes::PAUSED)))
00230 {
00231 proceed_commanded = true;
00232 }
00233 else
00234 {
00235 NODELET_ERROR("Invalid command");
00236 }
00237 }
00238 else if (words[0] == "pause")
00239 {
00240 if (executing and (wp_update_state == AutosequenceTypes::MOVING))
00241 {
00242 pause_commanded = true;
00243 }
00244 else
00245 {
00246 NODELET_ERROR("Invalid command");
00247 }
00248
00249 }
00250 else if (words[0] == "cancel")
00251 {
00252 if (executing)
00253 {
00254 NODELET_WARN_STREAM("Cancelling autosequence by operator request");
00255 cancel_commanded = true;
00256 }
00257 else
00258 {
00259 NODELET_ERROR("Invalid command");
00260 }
00261 }
00262 else
00263 {
00264 return false;
00265 }
00266 return true;
00267 }
00268
00269 void start_autosequence(const string& autosequence_name)
00270 {
00271 NODELET_INFO("Starting autosequence - press PROCEED on joystick");
00272
00273 executing = true;
00274 wp_update_state = AutosequenceTypes::WAITING_PROCEED;
00275 current_autosequence = autosequence_name;
00276 current_point = 0;
00277
00278 segment_start.north = latest_state.pose.pose.position.x;
00279 segment_start.east = latest_state.pose.pose.position.y;
00280 segment_end = autosequences[autosequence_name][current_point].point;
00281
00282 NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00283 waypoint_update_timer = nh.createTimer(ros::Duration(1 / waypoint_update_rate),
00284 &ControlModeAutosequence::updateWaypointCallback, this);
00285 }
00286
00287 void cancel_autosequence()
00288 {
00289 executing = false;
00290 cancel_commanded = false;
00291 wp_update_state = AutosequenceTypes::IDLE;
00292 current_autosequence = "";
00293 current_point = 0;
00294 waypoint_update_timer.stop();
00295 }
00296
00297 void proceed_autosequence()
00298 {
00299 NODELET_INFO("Proceeding");
00300 proceed_commanded = false;
00301 wp_update_state = AutosequenceTypes::MOVING;
00302 NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00303 }
00304
00305 void pause_autosequence()
00306 {
00307 NODELET_INFO("Pausing (operator commanded)");
00308 wp_update_state = AutosequenceTypes::PAUSED;
00309 pause_commanded = false;
00310 }
00311
00312 void complete_autosequence()
00313 {
00314 NODELET_INFO("Autosequence complete");
00315 cancel_autosequence();
00316 }
00317
00318 void updateWaypointCallback(const ros::TimerEvent& event)
00319 {
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 }
00371
00372 void do_reached_point()
00373 {
00374 NODELET_DEBUG_STREAM("Reached " << segment_end.name);
00375 set_hover_point(segment_end, false);
00376 if (current_point < autosequences[current_autosequence].size() - 1)
00377 {
00378
00379 segment_start = segment_end;
00380 segment_end = autosequences[current_autosequence][current_point + 1].point;
00381
00382 if (autosequences[current_autosequence][current_point].pause)
00383 {
00384 wp_update_state = AutosequenceTypes::PAUSED;
00385 NODELET_INFO("Pausing (per autosequence definition) - press PROCEED button");
00386 NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00387 }
00388 else
00389 {
00390 NODELET_DEBUG_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00391
00392 }
00393 current_point++;
00394 }
00395 else
00396 {
00397 complete_autosequence();
00398 }
00399
00400 }
00401
00402 bool reached_point(const hover_point& point)
00403 {
00404 double north_err;
00405 double east_err;
00406 double yaw_err;
00407 get_current_error_to_point(point, north_err, east_err, yaw_err);
00408 double error_norm = sqrt(north_err * north_err + east_err * east_err);
00409 bool reached = (error_norm <= reached_tolerance and (fabs(angles::to_degrees(yaw_err)) < reached_tolerance_yaw));
00410
00411 return reached;
00412 }
00413
00414 double norm2(double x1, double x2)
00415 {
00416 return sqrt(x1 * x1 + x2 * x2);
00417 }
00418
00419 void calc_waypoint_location(hover_point& new_point, const double dt)
00420 {
00421
00422
00423
00424 double delta_north = segment_end.north - segment_start.north;
00425 double delta_east = segment_end.east - segment_start.east;
00426
00427 double norm_delta = norm2(delta_north, delta_east);
00428 double dir_north = 0;
00429 double dir_east = 0;
00430 if (norm_delta > 0.001)
00431 {
00432 dir_north = delta_north / norm_delta;
00433 dir_east = delta_east / norm_delta;
00434 }
00435
00436
00437 new_point.north = north_cmd + dir_north * dt * waypoint_speed;
00438 new_point.east = east_cmd + dir_east * dt * waypoint_speed;
00439 new_point.north_vel = dir_north * waypoint_speed;
00440 new_point.east_vel = dir_east * waypoint_speed;
00441 double norm_now = norm2(new_point.north - segment_start.north, new_point.east - segment_start.east);
00442
00443 if (norm_now > norm_delta)
00444 {
00445 new_point.north = segment_end.north;
00446 new_point.east = segment_end.east;
00447 }
00448
00449 if (not isnan(segment_end.yaw))
00450 {
00451 new_point.yaw = segment_end.yaw;
00452 }
00453 else
00454 {
00455 new_point.yaw = yaw_cmd;
00456 }
00457 }
00458
00459 bool get_autosequence_callback(flyer_controller::GetAutosequence::Request& req,
00460 flyer_controller::GetAutosequence::Response& resp)
00461 {
00462 if (autosequence_exists(req.autosequence_name))
00463 {
00464 resp.found = true;
00465 resp.autosequence.name = req.autosequence_name;
00466 resp.autosequence.num_points = autosequences[req.autosequence_name].size();
00467 for (int i = 0; i < resp.autosequence.num_points; i++)
00468 {
00469 autosequence_point cur_pt = autosequences[req.autosequence_name][i];
00470 flyer_controller::AutosequencePoint new_ap;
00471 new_ap.pause = cur_pt.pause;
00472 new_ap.hover_point.name = cur_pt.point.name;
00473 new_ap.hover_point.x = cur_pt.point.north;
00474 new_ap.hover_point.y = cur_pt.point.east;
00475 new_ap.hover_point.vx = cur_pt.point.north_vel;
00476 new_ap.hover_point.vy = cur_pt.point.east_vel;
00477 new_ap.hover_point.yaw = cur_pt.point.yaw;
00478 resp.autosequence.points.push_back(new_ap);
00479 }
00480 }
00481 else
00482 {
00483 resp.found = false;
00484 }
00485 return true;
00486 }
00487
00488 void reportStatusTimerCallback(const ros::TimerEvent& e)
00489 {
00490 HoverMode::reportStatusTimerCallback(e);
00491 control_mode_autosequence_infoPtr autosequence_info_msg(new control_mode_autosequence_info);
00492 autosequence_info_msg->current_autosequence = current_autosequence;
00493 autosequence_info_msg->current_point = current_point;
00494 autosequence_info_msg->header.stamp = e.current_real;
00495 switch (wp_update_state)
00496 {
00497 case AutosequenceTypes::IDLE:
00498 autosequence_info_msg->status = control_mode_autosequence_info::IDLE;
00499 break;
00500 case AutosequenceTypes::PAUSED:
00501 autosequence_info_msg->status = control_mode_autosequence_info::PAUSED;
00502 break;
00503 case AutosequenceTypes::WAITING_PROCEED:
00504 autosequence_info_msg->status = control_mode_autosequence_info::WAITING_PROCEED;
00505 break;
00506 case AutosequenceTypes::MOVING:
00507 autosequence_info_msg->status = control_mode_autosequence_info::MOVING;
00508 break;
00509 }
00510
00511 autosequence_info_msg->defined_autosequences.clear();
00512 for (map<string, autosequence>::iterator iter = autosequences.begin(); iter != autosequences.end(); ++iter)
00513 {
00514 autosequence_info_msg->defined_autosequences.push_back(iter->first);
00515 }
00516 autosequence_info_pub.publish(autosequence_info_msg);
00517
00518 }
00519
00520 };
00521
00522 PLUGINLIB_DECLARE_CLASS(flyer_controller, ControlModeAutosequence, flyer_controller::ControlModeAutosequence, nodelet::Nodelet)
00523 ;
00524
00525 }