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 <string>
00035 #include <vector>
00036 #include <map>
00037 #include <algorithm>
00038 #include <boost/algorithm/string.hpp>
00039 #include "flyer_controller/control_mode.h"
00040 #include "flyer_controller/control_mode_hover_info.h"
00041 #include "flyer_controller/control_utils.h"
00042 #include "flyer_controller/pid.h"
00043
00044
00045 #include <angles/angles.h>
00046
00047 using std::string;
00048 using std::vector;
00049 using std::map;
00050 using std::max;
00051 using std::min;
00052 using angles::to_degrees;
00053 using angles::from_degrees;
00054
00055 const double GRAVITY = 9.81;
00056
00057 namespace flyer_controller
00058 {
00059
00060 struct hover_point
00061 {
00062 string name;
00063 double north;
00064 double east;
00065 double north_vel;
00066 double east_vel;
00067 double yaw;
00068 };
00069
00070 class HoverMode : public ControlMode
00071 {
00072 protected:
00073
00074 double max_alt_cmd;
00075 double min_alt_cmd;
00076
00077
00078
00079 double KP;
00080 double KI;
00081 double KD;
00082 double Ilimit;
00083 bool direct_thrust_control;
00084 double alt_KP;
00085 double alt_KI;
00086 double alt_KD;
00087 double alt_Ilimit;
00088 double mass;
00089 double north_cmd_max;
00090 double north_cmd_min;
00091 double east_cmd_max;
00092 double east_cmd_min;
00093
00094
00095 ros::Publisher info_pub;
00096
00097
00098
00099 string mode_name_;
00100 control_mode_output control_out;
00101 double yaw_cmd;
00102 flyer_controller::Pid north_pid;
00103 flyer_controller::Pid east_pid;
00104 flyer_controller::Pid alt_pid;
00105 double north_cmd;
00106 double east_cmd;
00107 double alt_cmd;
00108 double north_vel_cmd;
00109 double east_vel_cmd;
00110 double north_err;
00111 double east_err;
00112 double alt_err;
00113 double north_vel_err;
00114 double east_vel_err;
00115 map<string, hover_point> hover_points;
00116 hover_point current_hover_point;
00117 double alt_override;
00118 double yaw_override;
00119 bool yaw_override_active;
00120 ros::Time last_time;
00121 bool first;
00122
00123 public:
00124
00125 HoverMode(string mode_name) :
00126
00127 max_alt_cmd(1.5), min_alt_cmd(0.0), KP(12), KI(1),
00128 KD(8),
00129 Ilimit(2),
00130 direct_thrust_control(false), alt_KP(2), alt_KI(1), alt_KD(2),
00131 alt_Ilimit(5),
00132 mass(1.3),
00133 mode_name_(mode_name), yaw_cmd(0), north_cmd(0), east_cmd(0), alt_cmd(0), north_vel_cmd(0), east_vel_cmd(0),
00134 north_err(0), east_err(0), north_vel_err(0), east_vel_err(0), alt_override(9999), yaw_override(0),
00135 yaw_override_active(false), first(true)
00136 {
00137
00138 }
00139
00140 void onInit()
00141 {
00142 NODELET_INFO("ControlModeHover onInit() called");
00143 ControlMode::onInit();
00144
00145 nh_priv.param("max_alt_cmd", max_alt_cmd, max_alt_cmd);
00146 nh_priv.param("min_alt_cmd", min_alt_cmd, min_alt_cmd);
00147 nh_priv.param("KP", KP, KP);
00148 nh_priv.param("KI", KI, KI);
00149 nh_priv.param("KD", KD, KD);
00150 nh_priv.param("Ilimit", Ilimit, Ilimit);
00151 nh_priv.param("direct_thrust_control", direct_thrust_control, direct_thrust_control);
00152 nh_priv.param("alt_KP", alt_KP, alt_KP);
00153 nh_priv.param("alt_KI", alt_KI, alt_KI);
00154 nh_priv.param("alt_KD", alt_KD, alt_KD);
00155 nh_priv.param("alt_Ilimit", alt_Ilimit, alt_Ilimit);
00156 nh_priv.param("mass", mass, mass);
00157 nh_priv.param("north_cmd_max", north_cmd_max, north_cmd_max);
00158 nh_priv.param("north_cmd_min", north_cmd_min, north_cmd_min);
00159 nh_priv.param("east_cmd_max", east_cmd_max, east_cmd_max);
00160 nh_priv.param("east_cmd_min", east_cmd_min, east_cmd_min);
00161
00162
00163
00164
00165
00166
00167 set_gains(KP, KI, KD, Ilimit);
00168
00169 if (direct_thrust_control)
00170 alt_pid.initPid(alt_KP, alt_KI, alt_KD, alt_Ilimit, -alt_Ilimit);
00171
00172 requestRegistration(mode_name_);
00173 control_out.control_mode = mode_name_;
00174 control_out.motors_on = false;
00175 }
00176
00177 private:
00178
00179
00180
00181 bool parseControlModeCmd(const string cmd)
00182 {
00183 vector<string> words;
00184 boost::split(words, cmd, boost::is_any_of(" "));
00185 int nw = words.size();
00186 if (nw > 0)
00187 {
00188 if (words[0] == "mode")
00189 {
00190 parse_mode(words);
00191 }
00192 else if (words[0] == "define")
00193
00194
00195 {
00196 if (words[1] == "hover_point")
00197 {
00198 parse_define_hover_point(words);
00199 }
00200 else
00201 {
00202 return false;
00203 }
00204 }
00205 else if (words[0] == "set")
00206 {
00207 if (nw > 1)
00208 {
00209 if (words[1] == "hover_point")
00210 {
00211 parse_set_hover_point(words);
00212
00213 }
00214 else if (words[1] == "gains")
00215 {
00216 parse_set_gains(words);
00217 }
00218 }
00219 else
00220 {
00221 return false;
00222 }
00223 }
00224 else if (words[0] == "alt_override")
00225 {
00226 if (nw == 2)
00227 {
00228 alt_override = atof(words[1].c_str());
00229 NODELET_INFO_STREAM("alt_override set to " << alt_override);
00230 }
00231 else
00232 {
00233 NODELET_ERROR_STREAM("Invalid command '" << cmd << "'");
00234 }
00235 }
00236 else if (words[0] == "yaw_override")
00237 {
00238 if (nw == 2)
00239 {
00240 if (words[1] == "off" and yaw_override_active)
00241 {
00242 yaw_override_active = false;
00243 NODELET_INFO("yaw_override OFF");
00244 }
00245 else
00246 {
00247 yaw_override_active = true;
00248 yaw_override = atof(words[1].c_str());
00249 yaw_cmd = yaw_override;
00250 NODELET_INFO_STREAM("yaw_override set to " << yaw_override);
00251 }
00252 }
00253 else
00254 {
00255 NODELET_ERROR_STREAM("Invalid command '" << cmd << "'");
00256 }
00257 }
00258 else
00259 {
00260 return false;
00261 }
00262 }
00263 return true;
00264 }
00265
00266 protected:
00267
00268
00269
00270
00271 virtual bool parseControlModeCmdDerived(const string cmd)
00272 {
00273 return false;
00274 }
00275
00276 private:
00277 void controlModeCmdCallback(const control_mode_cmdConstPtr& msg)
00278 {
00279 NODELET_DEBUG_STREAM("Heard command: " << msg->cmd);
00280 if (!parseControlModeCmd(msg->cmd))
00281 {
00282 if (!parseControlModeCmdDerived(msg->cmd))
00283 {
00284 NODELET_ERROR_STREAM("Unrecognized command: " << msg->cmd);
00285 }
00286 }
00287 }
00288
00289
00290 protected:
00291 void outputControl()
00292 {
00293
00294 bool do_calcs = false;
00295 bool do_publish = false;
00296 ros::Time now_time = ros::Time::now();
00297 ros::Duration dt;
00298 if (first)
00299 {
00300 first = false;
00301 last_time = now_time;
00302 return;
00303 }
00304 else if (state_updated)
00305 {
00306 dt = now_time - last_time;
00307 last_time = now_time;
00308 }
00309 static int prev_trigger = 0;
00310 control_out.header.stamp = now_time;
00311
00312 switch (state)
00313 {
00314 case ControlModeTypes::STANDBY:
00315 do_calcs = (got_first_joy and got_first_state);
00316 do_publish = true;
00317 break;
00318 case ControlModeTypes::ACTIVE:
00319 do_calcs = state_updated;
00320 do_publish = true;
00321 break;
00322 default:
00323 break;
00324 }
00325
00326 if (do_calcs)
00327 {
00328
00329
00330
00331
00332 double current_yaw, current_pitch, current_roll;
00333 double current_vx, current_vy, current_vz;
00334 odom_msg_to_ypr(boost::make_shared<nav_msgs::Odometry>(latest_state), current_yaw, current_pitch, current_roll);
00335 odom_msg_to_lin_vel(boost::make_shared<nav_msgs::Odometry>(latest_state), current_vx, current_vy, current_vz);
00336 state_updated = false;
00337 get_current_lateral_position_errors(north_err, east_err, alt_err);
00338 north_vel_err = current_vx - north_vel_cmd;
00339 east_vel_err = current_vy - east_vel_cmd;
00340 if (latest_opercmd.motors_on and prev_trigger == 0)
00341 {
00342 north_pid.reset();
00343 east_pid.reset();
00344 if (direct_thrust_control)
00345 alt_pid.reset();
00346 }
00347 north_pid.updatePid(north_err, north_vel_err, dt);
00348 east_pid.updatePid(east_err, east_vel_err, dt);
00349 if (direct_thrust_control)
00350 alt_pid.updatePid(alt_err, dt);
00351 double tilt_north_cmd = north_pid.getCurrentCmd();
00352 double tilt_east_cmd = east_pid.getCurrentCmd();
00353
00354 double cos_yaw = cos(current_yaw);
00355 double sin_yaw = sin(current_yaw);
00356 control_out.roll_cmd = tilt_east_cmd * cos_yaw - tilt_north_cmd * sin_yaw;
00357 control_out.pitch_cmd = -tilt_east_cmd * sin_yaw - tilt_north_cmd * cos_yaw;
00358 prev_trigger = latest_opercmd.motors_on;
00359 control_out.direct_yaw_rate_commands = false;
00360 control_out.yaw_cmd = yaw_cmd;
00361 control_out.yaw_rate_cmd = 0;
00362 control_out.direct_thrust_commands = direct_thrust_control;
00363 if (direct_thrust_control)
00364 {
00365 control_out.alt_cmd = 0.0;
00366 control_out.thrust_cmd = GRAVITY * mass + alt_pid.getCurrentCmd();
00367 }
00368 else
00369 {
00370 control_out.alt_cmd = min(alt_override, min_alt_cmd + (max_alt_cmd - min_alt_cmd) * latest_opercmd.alt_cmd);
00371 }
00372 }
00373
00374 control_out.motors_on = (got_first_joy and (latest_opercmd.motors_on));
00375 if (do_publish)
00376 {
00377 control_out.control_mode = mode_name_;
00378 output_pub.publish(control_out);
00379 }
00380
00381 }
00382
00383 protected:
00384 void get_current_lateral_position_errors(double &north_err, double &east_err, double &alt_err)
00385 {
00386 double current_x, current_y, current_z;
00387 odom_msg_to_xyz(boost::make_shared<nav_msgs::Odometry>(latest_state), current_x, current_y, current_z);
00388 north_err = current_x - north_cmd;
00389 east_err = current_y - east_cmd;
00390 alt_err = -current_z - alt_cmd;
00391 }
00392
00393 void get_current_lateral_position(double ¤t_x, double ¤t_y)
00394 {
00395 double current_z;
00396 odom_msg_to_xyz(boost::make_shared<nav_msgs::Odometry>(latest_state), current_x, current_y, current_z);
00397 }
00398
00399 void get_current_error_to_point(const hover_point& point, double &north_err, double &east_err, double &yaw_err)
00400 {
00401 double current_x, current_y, current_z;
00402 odom_msg_to_xyz(boost::make_shared<nav_msgs::Odometry>(latest_state), current_x, current_y, current_z);
00403 north_err = current_x - point.north;
00404 east_err = current_y - point.east;
00405 get_current_yaw_error(point.yaw, yaw_err);
00406 }
00407
00408 void get_current_yaw_error(const double yaw_cmd, double &yaw_err)
00409 {
00410 if (not isnan(yaw_cmd))
00411 {
00412 double current_yaw, current_pitch, current_roll;
00413 odom_msg_to_ypr(boost::make_shared<nav_msgs::Odometry>(latest_state), current_yaw, current_pitch, current_roll);
00414 yaw_err = angles::shortest_angular_distance(current_yaw, angles::from_degrees(yaw_cmd));
00415 }
00416 else
00417 {
00418 yaw_err = 0.0;
00419 }
00420 }
00421
00422 protected:
00423 void reportStatusTimerCallback(const ros::TimerEvent& e)
00424 {
00425 control_mode_status msg;
00426
00427 msg.state = state;
00428 msg.info = info;
00429 msg.header.stamp = e.current_real;
00430 ready = (got_first_joy and got_first_state);
00431
00432 msg.ready = ready;
00433 control_mode_status_pub.publish(msg);
00434
00435 if ((state == ControlModeTypes::STANDBY) or (state == ControlModeTypes::ACTIVE))
00436 {
00437 control_mode_hover_info info_msg;
00438 info_msg.header.stamp = e.current_real;
00439 info_msg.hover_point = current_hover_point.name;
00440
00441 info_msg.north_cmd = north_cmd;
00442 info_msg.east_cmd = east_cmd;
00443 info_msg.north_vel_cmd = north_vel_cmd;
00444 info_msg.east_vel_cmd = east_vel_cmd;
00445 info_msg.yaw_cmd = yaw_cmd;
00446 info_msg.alt_override = alt_override;
00447
00448 info_msg.north_err = north_err;
00449 info_msg.east_err = east_err;
00450 info_msg.north_vel_err = north_vel_err;
00451 info_msg.east_vel_err = east_vel_err;
00452 double yaw_err;
00453 get_current_yaw_error(yaw_cmd, yaw_err);
00454 info_msg.yaw_err = yaw_err;
00455
00456 info_pub.publish(info_msg);
00457 }
00458 diag_updater.update();
00459 }
00460
00461 private:
00462
00463 void parse_mode(const vector<string> &words)
00464 {
00465 int nw = words.size();
00466 if (nw == 2)
00467 {
00468 string newmode = words[1];
00469 if (newmode == "idle")
00470 {
00471 state = ControlModeTypes::IDLE;
00472 info = "";
00473 }
00474 else if (newmode == "standby")
00475 {
00476 info = "";
00477 info_pub = nh_priv.advertise<control_mode_hover_info> ("info", 10);
00478 state = ControlModeTypes::STANDBY;
00479 }
00480 else if (newmode == "active")
00481 {
00482 if (state == ControlModeTypes::STANDBY)
00483 {
00484 state = ControlModeTypes::ACTIVE;
00485 double current_yaw, current_pitch, current_roll;
00486 double current_x, current_y, current_z;
00487 odom_msg_to_ypr(boost::make_shared<nav_msgs::Odometry>(latest_state), current_yaw, current_pitch,
00488 current_roll);
00489 odom_msg_to_xyz(boost::make_shared<nav_msgs::Odometry>(latest_state), current_x, current_y, current_z);
00490 hover_point point_here;
00491 point_here.yaw = to_degrees(current_yaw);
00492 point_here.north = current_x;
00493 point_here.east = current_y;
00494 point_here.east_vel = 0;
00495 point_here.north_vel = 0;
00496 point_here.name = "_hover_mode_entry";
00497 set_hover_point(point_here, true);
00498 alt_override = 9999;
00499 info = "";
00500 }
00501 }
00502 else
00503 {
00504 NODELET_ERROR("Unknown mode");
00505 }
00506 }
00507 else
00508 {
00509 NODELET_ERROR("Invalid command");
00510 }
00511 }
00512
00513 void parse_define_hover_point(const vector<string> &words)
00514 {
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 int nw = words.size();
00525 if (not ((nw == 5) or (nw == 7) or (nw == 8)))
00526 {
00527 NODELET_ERROR("Invalid command");
00528 }
00529 else
00530 {
00531 string point_name = words[2];
00532 if (hover_point_exists(point_name))
00533 {
00534 NODELET_WARN_STREAM("hover_point '" << point_name << "' already exists and will be redefined");
00535 }
00536 hover_points[point_name].name = point_name;
00537 double north = atof(words[3].c_str());
00538 double east = atof(words[4].c_str());
00539 if (not hover_point_within_bounds(north, east))
00540 NODELET_WARN_STREAM("Hover point " << point_name << " has out-of-bounds coordinates. Point will be defined but cannot be used.");
00541 hover_points[point_name].north = north;
00542 hover_points[point_name].east = east;
00543 if ((nw == 7) or (nw == 8))
00544
00545 {
00546 hover_points[point_name].north_vel = atof(words[5].c_str());
00547 hover_points[point_name].east_vel = atof(words[6].c_str());
00548 if (nw == 7)
00549 {
00550 hover_points[point_name].yaw = NAN;
00551 NODELET_DEBUG_STREAM(
00552 "New hover_point defined: name='" << point_name << "' north="
00553 << hover_points[point_name].north << " east=" << hover_points[point_name].east
00554 << " north_vel=" << hover_points[point_name].north_vel << " east_vel="
00555 << hover_points[point_name].east_vel << ". Yaw unspecified.");
00556 }
00557 else if (nw == 8)
00558 {
00559 hover_points[point_name].yaw = atof(words[7].c_str());
00560 NODELET_DEBUG_STREAM(
00561 "New hover_point defined: name='" << point_name << "' north="
00562 << hover_points[point_name].north << " east=" << hover_points[point_name].east
00563 << " north_vel=" << hover_points[point_name].north_vel << " east_vel="
00564 << hover_points[point_name].east_vel << " yaw=" << hover_points[point_name].yaw);
00565 }
00566 }
00567 else
00568 {
00569 hover_points[point_name].north_vel = 0;
00570 hover_points[point_name].east_vel = 0;
00571 hover_points[point_name].yaw = NAN;
00572 NODELET_DEBUG_STREAM(
00573 "New hover_point defined: name='" << point_name << "' north="
00574 << hover_points[point_name].north << " east=" << hover_points[point_name].east
00575 << " north_vel=" << hover_points[point_name].north_vel << " east_vel="
00576 << hover_points[point_name].east_vel << ". Yaw unspecified.");
00577 }
00578 }
00579 }
00580
00581 protected:
00582 bool hover_point_within_bounds(const double north, const double east)
00583 {
00584 return ((north >= north_cmd_min) and (north <= north_cmd_max)
00585 and (east >= east_cmd_min) and (east <= east_cmd_max));
00586 }
00587
00588 bool hover_point_exists(const string point_name)
00589 {
00590 map<string, hover_point>::iterator it;
00591 it = hover_points.find(point_name);
00592 return (not (it == hover_points.end()));
00593 }
00594
00595 void set_gains(double KP, double KI, double KD, double Ilimit)
00596 {
00597 north_pid.initPid(KP, KI, KD, Ilimit, -Ilimit);
00598 east_pid.initPid(KP, KI, KD, Ilimit, -Ilimit);
00599 }
00600
00601
00602
00603 void parse_set_gains(const vector<string> &words)
00604 {
00605 int nw = words.size();
00606 if (nw == 6)
00607 {
00608 double KP_new = atof(words[2].c_str());
00609 double KI_new = atof(words[3].c_str());
00610 double KD_new = atof(words[4].c_str());
00611 double Ilimit_new = atof(words[5].c_str());
00612
00613 KP = KP_new;
00614 KI = KI_new;
00615 KD = KD_new;
00616 Ilimit = Ilimit_new;
00617 set_gains(KP, KI, KD, Ilimit);
00618 NODELET_INFO("Set new gains: KP=%f, KI=%f, KD=%f, Ilimit=%f", KP, KI, KD, Ilimit);
00619 }
00620 else
00621 {
00622 NODELET_ERROR("Invalid command");
00623 }
00624 }
00625
00626 void parse_set_hover_point(const vector<string> &words)
00627 {
00628 int nw = words.size();
00629 if (nw == 3)
00630 {
00631 string point_name = words[2];
00632 if (hover_point_exists(point_name))
00633 {
00634 set_hover_point(hover_points[point_name]);
00635 }
00636 else
00637 {
00638 NODELET_ERROR("Invalid hover_point name");
00639 }
00640 }
00641 else
00642 {
00643 NODELET_ERROR("Invalid command");
00644 }
00645 }
00646
00647 void set_hover_point(const hover_point& point, bool reset = false)
00648 {
00649 if (hover_point_within_bounds(point.north, point.east))
00650 {
00651 north_cmd = point.north;
00652 east_cmd = point.east;
00653 north_vel_cmd = point.north_vel;
00654 east_vel_cmd = point.east_vel;
00655 if (reset)
00656 {
00657 north_pid.reset();
00658 east_pid.reset();
00659 }
00660 current_hover_point = point;
00661
00662
00663
00664 if (not isnan(point.yaw))
00665 {
00666 yaw_cmd = point.yaw;
00667
00668 }
00669 else
00670 {
00671
00672 }
00673
00674 }
00675 else
00676 {
00677 NODELET_ERROR("Cannot set hover point to %f, %f (out of bounds)", point.north, point.east);
00678 }
00679 }
00680
00681 };
00682
00683 }