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
00035 #include <ros/ros.h>
00036 #include <nodelet/nodelet.h>
00037 #include <pluginlib/class_list_macros.h>
00038 #include <string>
00039 #include <diagnostic_updater/diagnostic_updater.h>
00040 #include "flyer_controller/controller_status.h"
00041 #include "flyer_controller/controller_cmd.h"
00042 #include "std_msgs/Bool.h"
00043 #include "starmac_msgs/OperatorCommands.h"
00044
00045 #include <sensor_msgs/Joy.h>
00046
00047 namespace flyer_controller
00048 {
00049
00050
00051 const int BTN_TRIGGER = 0;
00052 const int BTN_PROCEED = 8;
00053 const int BTN_CANCEL = 6;
00054 const int BTN_ESTOP = 11;
00055
00056 const int BTN_STANDBY_GO_OPERATIONAL = 2;
00057
00058 const int BTN_OPERATIONAL_MODE_ATTITUDE = 2;
00059 const int BTN_OPERATIONAL_MODE_HOVER = 3;
00060
00061 namespace TeleopTypes
00062 {
00063 enum TeleopStates
00064 {
00065 ERROR = 0, OFF = 1, INITIALIZE = 2, STANDBY = 3, OPERATIONAL = 4
00066 };
00067 typedef TeleopStates TeleopState;
00068
00069 }
00070
00071 using namespace TeleopTypes;
00072 using namespace std;
00073
00074 class TeleopFlyer : public nodelet::Nodelet
00075 {
00076 private:
00077 ros::NodeHandle nh;
00078 ros::NodeHandle nh_priv;
00079
00080 ros::Publisher oper_cmd_pub;
00081 ros::Publisher controller_cmd_pub;
00082 ros::Publisher motor_enable_pub;
00083 ros::Publisher estop_pub;
00084
00085 ros::Subscriber joy_sub;
00086 ros::Subscriber controller_status_sub;
00087
00088 ros::Timer republish_timer;
00089
00090 bool got_first_joy;
00091 sensor_msgs::Joy prev_joy;
00092 sensor_msgs::Joy latest_joy;
00093 ros::Time latest_joy_time;
00094
00095
00096 diagnostic_updater::Updater diag_updater;
00097
00098
00099 double joy_republish_rate;
00100 double max_interval;
00101 bool use_udp;
00102 double pitch_deadband;
00103 double roll_deadband;
00104 double yaw_deadband;
00105
00106
00107 TeleopState state;
00108 bool command_pending;
00109 string pending_command;
00110 bool lost_joystick;
00111 double last_trigger_duration;
00112 controller_status latest_controller_status;
00113 double max_joystick_dt;
00114 bool motors_on;
00115
00116 public:
00117 TeleopFlyer() :
00118 got_first_joy(false),
00119 diag_updater(),
00120 joy_republish_rate(20), max_interval(2.0),
00121 use_udp(true),
00122 pitch_deadband(0.05), roll_deadband(0.05),
00123 yaw_deadband(0.1),
00124 state(OFF), command_pending(false), pending_command(""), lost_joystick(false), last_trigger_duration(0),
00125 max_joystick_dt(0), motors_on(false)
00126 {
00127 }
00128
00129 void onInit()
00130 {
00131 nh = getMTNodeHandle();
00132 nh_priv = getMTPrivateNodeHandle();
00133
00134
00135 diag_updater.add("TeleopFlyer Status", this, &TeleopFlyer::diagnostics);
00136 diag_updater.setHardwareID("none");
00137 diag_updater.force_update();
00138
00139 nh_priv.param("joy_republish_rate", joy_republish_rate, joy_republish_rate);
00140 nh_priv.param("max_interval", max_interval, max_interval);
00141 nh_priv.param("use_udp", use_udp, use_udp);
00142 nh_priv.param("pitch_deadband", pitch_deadband, pitch_deadband);
00143 nh_priv.param("roll_deadband", roll_deadband, roll_deadband);
00144 nh_priv.param("yaw_deadband", yaw_deadband, yaw_deadband);
00145
00146
00147 oper_cmd_pub = nh_priv.advertise<starmac_msgs::OperatorCommands> ("operator_cmds", 1);
00148
00149 motor_enable_pub = nh_priv.advertise<std_msgs::Bool> ("motor_enable", 1);
00150 estop_pub = nh_priv.advertise<std_msgs::Bool> ("estop", 1);
00151
00152 ros::TransportHints thints;
00153 if (use_udp)
00154 {
00155 thints.udp();
00156 }
00157 else
00158 {
00159 thints.tcp().tcpNoDelay();
00160 }
00161 joy_sub = nh_priv.subscribe("joy", 10, &TeleopFlyer::joyCallback, this, thints);
00162 controller_status_sub = nh.subscribe("controller/status", 10, &TeleopFlyer::controllerStatusCallback, this);
00163
00164
00165 republish_timer = nh.createTimer(ros::Duration(1 / joy_republish_rate), &TeleopFlyer::republishCallback, this);
00166 }
00167
00168 std::string stateToString(TeleopState t)
00169 {
00170 switch (t)
00171 {
00172 case OFF:
00173 return "OFF";
00174 case ERROR:
00175 return "ERROR";
00176 case INITIALIZE:
00177 return "INITIALIZE";
00178 case STANDBY:
00179 return "STANDBY";
00180 case OPERATIONAL:
00181 return "OPERATIONAL";
00182 }
00183 return "Unknown";
00184 }
00185
00186 private:
00187
00188 void diagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00189 {
00190 int status;
00191 status = ((state != ERROR && !lost_joystick) ? int(diagnostic_msgs::DiagnosticStatus::OK)
00192 : int(diagnostic_msgs::DiagnosticStatus::ERROR));
00193 stat.summary(status, stateToString(state));
00194 stat.add("Command Pending", command_pending);
00195 stat.add("Pending Command", pending_command);
00196 stat.add("Lost Joystick", lost_joystick);
00197 stat.add("Trigger Duration", last_trigger_duration);
00198 stat.add("Max time between joystick messages", max_joystick_dt);
00199 }
00200
00201 void controllerStatusCallback(const controller_statusConstPtr& msg)
00202 {
00203 state = TeleopState(msg->state);
00204 latest_controller_status = *msg;
00205 }
00206
00207 void estop()
00208 {
00209 static bool issued_warning = false;
00210 std_msgs::BoolPtr estop_msg(new std_msgs::Bool);
00211 estop_msg->data = true;
00212 estop_pub.publish(estop_msg);
00213 if (not issued_warning)
00214 {
00215 ROS_WARN("E-STOP triggered");
00216 issued_warning = true;
00217 }
00218 }
00219
00220 void joyCallback(const sensor_msgs::JoyConstPtr msg)
00221 {
00222
00223 ros::Time rightnow = ros::Time::now();
00224
00225 if (msg->axes.size() == 0)
00226 {
00227
00228 NODELET_WARN_STREAM_THROTTLE(0.5, "Received joystick message with zero-size axes array, ignoring...");
00229 return;
00230 }
00231 prev_joy = latest_joy;
00232 latest_joy = *msg;
00233 if (not got_first_joy)
00234 {
00235 got_first_joy = true;
00236 ROS_INFO("Got first joystick message");
00237 }
00238 else
00239 {
00240 double dT = (rightnow - latest_joy_time).toSec();
00241 max_joystick_dt = max(max_joystick_dt, dT);
00242 if (dT > max_interval and (state == OPERATIONAL))
00243 {
00244 ROS_ERROR_STREAM("Time (" << dT << " s) between Joy messages exceeded allowable (" << max_interval << ")");
00245 lost_joystick = true;
00246 }
00247
00248 if (state == OPERATIONAL)
00249 {
00250
00251
00252 if (not motors_on and
00253 (latest_joy.axes[2] <= -0.95) and (latest_joy.axes[3] <= -0.95)
00254 )
00255 {
00256 motors_on = true;
00257 NODELET_INFO("Motors ON");
00258 }
00259
00260 if (motors_on and
00261 (latest_joy.axes[2] >= 0.95) and (latest_joy.axes[3] <= -0.95)
00262 )
00263 {
00264 motors_on = false;
00265 NODELET_INFO("Motors OFF");
00266 }
00267 }
00268 else
00269 {
00270 motors_on = false;
00271 }
00272
00273 latest_joy_time = rightnow;
00274 }
00275
00276 }
00277
00278 void republishCallback(const ros::TimerEvent& e)
00279 {
00280 ROS_DEBUG_STREAM("Timer callback triggered " << e.current_real.toSec());
00281 if (got_first_joy)
00282 {
00283 starmac_msgs::OperatorCommandsPtr opercmd_msg_ptr(new starmac_msgs::OperatorCommands);
00284
00285 double roll_in = double(-latest_joy.axes[0]);
00286 double pitch_in = double(-latest_joy.axes[1]);
00287 double yaw_in = double(-latest_joy.axes[2]);
00288 double roll_sign = (roll_in > 0) ? 1.0 : -1.0;
00289 double pitch_sign = (pitch_in > 0) ? 1.0 : -1.0;
00290 double yaw_sign = (yaw_in > 0) ? 1.0 : -1.0;
00291 opercmd_msg_ptr->roll_cmd = roll_sign * roll_in > roll_deadband ? (max(-1.0, min(1.0, roll_in)) - roll_sign
00292 * roll_deadband) / (1.0 - roll_deadband) : 0.0;
00293 opercmd_msg_ptr->pitch_cmd = pitch_sign * pitch_in > pitch_deadband ? (max(-1.0, min(1.0, pitch_in)) - pitch_sign
00294 * pitch_deadband) / (1.0 - pitch_deadband) : 0.0;
00295 opercmd_msg_ptr->alt_cmd = (min(1.0, max(-1.0, double(latest_joy.axes[3]))) + 1.0) / 2.0;
00296
00297 if (opercmd_msg_ptr->alt_cmd > 0.05)
00298 {
00299 opercmd_msg_ptr->yaw_cmd = yaw_sign * yaw_in > yaw_deadband ? (max(-1.0, min(1.0, yaw_in)) - yaw_sign
00300 * yaw_deadband) / (1.0 - yaw_deadband) : 0.0;
00301 }
00302 else
00303 {
00304 opercmd_msg_ptr->yaw_cmd = 0;
00305 }
00306 opercmd_msg_ptr->motors_on = motors_on;
00307 oper_cmd_pub.publish(opercmd_msg_ptr);
00308 }
00309 else
00310 {
00311 NODELET_WARN_STREAM_THROTTLE(10, "No joystick messages received yet - if this message recurs, check launchfile configuration");
00312
00313 return;
00314 }
00315 diag_updater.update();
00316 ros::Time now = ros::Time::now();
00317 double joy_interval = (now - latest_joy_time).toSec();
00318 bool joystick_is_recent = (not got_first_joy) or (joy_interval < max_interval);
00319 std_msgs::BoolPtr mtr_enable_msg(new std_msgs::Bool);
00320 if (lost_joystick)
00321 {
00322 estop();
00323 mtr_enable_msg->data = false;
00324 motor_enable_pub.publish(mtr_enable_msg);
00325 }
00326 else
00327 {
00328 if (joystick_is_recent)
00329 {
00330 if (state == OPERATIONAL)
00331 {
00332 mtr_enable_msg->data = motors_on;
00333 motor_enable_pub.publish(mtr_enable_msg);
00334 }
00335 else
00336 {
00337 mtr_enable_msg->data = false;
00338 motor_enable_pub.publish(mtr_enable_msg);
00339 }
00340 }
00341 else
00342 {
00343 if (got_first_joy and (state == OPERATIONAL))
00344
00345 {
00346 lost_joystick = true;
00347 ROS_ERROR_STREAM("Too large (" << joy_interval << " s) an interval between joystick messages!");
00348 mtr_enable_msg->data = false;
00349 motor_enable_pub.publish(mtr_enable_msg);
00350 }
00351 }
00352 }
00353 }
00354
00355 };
00356 PLUGINLIB_DECLARE_CLASS(flyer_controller, TeleopFlyer, flyer_controller::TeleopFlyer, nodelet::Nodelet)
00357 ;
00358
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370