00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "rotors_gazebo_plugins/gazebo_fw_dynamics_plugin.h"
00019
00020 #include "ConnectRosToGazeboTopic.pb.h"
00021
00022 namespace gazebo {
00023
00024 GazeboFwDynamicsPlugin::GazeboFwDynamicsPlugin()
00025 : ModelPlugin(),
00026 node_handle_(0),
00027 W_wind_speed_W_B_(0, 0, 0),
00028 delta_aileron_left_(0.0),
00029 delta_aileron_right_(0.0),
00030 delta_elevator_(0.0),
00031 delta_flap_(0.0),
00032 delta_rudder_(0.0),
00033 throttle_(0.0),
00034 pubs_and_subs_created_(false) {
00035 }
00036
00037 GazeboFwDynamicsPlugin::~GazeboFwDynamicsPlugin() {
00038 }
00039
00040 void GazeboFwDynamicsPlugin::Load(physics::ModelPtr _model,
00041 sdf::ElementPtr _sdf) {
00042 if (kPrintOnPluginLoad) {
00043 gzdbg << __FUNCTION__ << "() called." << std::endl;
00044 }
00045
00046 gzdbg << "_model = " << _model->GetName() << std::endl;
00047
00048
00049 model_ = _model;
00050 world_ = model_->GetWorld();
00051
00052 namespace_.clear();
00053
00054
00055 if (_sdf->HasElement("robotNamespace"))
00056 namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
00057 else
00058 gzerr << "[gazebo_fw_dynamics_plugin] Please specify a robotNamespace.\n";
00059
00060
00061 node_handle_ = transport::NodePtr(new transport::Node());
00062
00063
00064 node_handle_->Init();
00065
00066
00067 std::string link_name;
00068 if (_sdf->HasElement("linkName"))
00069 link_name = _sdf->GetElement("linkName")->Get<std::string>();
00070 else
00071 gzerr << "[gazebo_fw_dynamics_plugin] Please specify a linkName.\n";
00072
00073 link_ = model_->GetLink(link_name);
00074 if (link_ == NULL) {
00075 gzthrow("[gazebo_fw_dynamics_plugin] Couldn't find specified link \""
00076 << link_name << "\".");
00077 }
00078
00079
00080
00081 if (_sdf->HasElement("aeroParamsYAML")) {
00082 std::string aero_params_yaml =
00083 _sdf->GetElement("aeroParamsYAML")->Get<std::string>();
00084
00085 aero_params_.LoadAeroParamsYAML(aero_params_yaml);
00086 } else {
00087 gzwarn << "[gazebo_fw_dynamics_plugin] No aerodynamic paramaters YAML file"
00088 << " specified, using default Techpod parameters.\n";
00089 }
00090
00091
00092
00093 if (_sdf->HasElement("vehicleParamsYAML")) {
00094 std::string vehicle_params_yaml =
00095 _sdf->GetElement("vehicleParamsYAML")->Get<std::string>();
00096
00097 vehicle_params_.LoadVehicleParamsYAML(vehicle_params_yaml);
00098 } else {
00099 gzwarn << "[gazebo_fw_dynamics_plugin] No vehicle paramaters YAML file"
00100 << " specified, using default Techpod parameters.\n";
00101 }
00102
00103
00104 getSdfParam<bool>(_sdf, "isInputJoystick", is_input_joystick_,
00105 kDefaultIsInputJoystick);
00106 getSdfParam<std::string>(_sdf, "actuatorsSubTopic",
00107 actuators_sub_topic_,
00108 mav_msgs::default_topics::COMMAND_ACTUATORS);
00109 getSdfParam<std::string>(_sdf, "rollPitchYawrateThrustSubTopic",
00110 roll_pitch_yawrate_thrust_sub_topic_,
00111 mav_msgs::default_topics::
00112 COMMAND_ROLL_PITCH_YAWRATE_THRUST);
00113 getSdfParam<std::string>(_sdf, "windSpeedSubTopic",
00114 wind_speed_sub_topic_,
00115 mav_msgs::default_topics::WIND_SPEED);
00116
00117
00118
00119 this->updateConnection_ = event::Events::ConnectWorldUpdateBegin(
00120 boost::bind(&GazeboFwDynamicsPlugin::OnUpdate, this, _1));
00121 }
00122
00123 void GazeboFwDynamicsPlugin::OnUpdate(const common::UpdateInfo& _info) {
00124 if (kPrintOnUpdates) {
00125 gzdbg << __FUNCTION__ << "() called." << std::endl;
00126 }
00127
00128 if (!pubs_and_subs_created_) {
00129 CreatePubsAndSubs();
00130 pubs_and_subs_created_ = true;
00131 }
00132
00133 UpdateForcesAndMoments();
00134 }
00135
00136 void GazeboFwDynamicsPlugin::UpdateForcesAndMoments() {
00137
00138
00139
00140 ignition::math::Quaterniond W_rot_W_B = link_->WorldPose().Rot();
00141 ignition::math::Vector3d B_air_speed_W_B = W_rot_W_B.RotateVectorReverse(
00142 link_->WorldLinearVel() - W_wind_speed_W_B_);
00143 ignition::math::Vector3d B_angular_velocity_W_B = link_->RelativeAngularVel();
00144
00145
00146
00147
00148 double u = B_air_speed_W_B.X();
00149 double v = -B_air_speed_W_B.Y();
00150 double w = -B_air_speed_W_B.Z();
00151
00152 double p = B_angular_velocity_W_B.X();
00153 double q = -B_angular_velocity_W_B.Y();
00154 double r = -B_angular_velocity_W_B.Z();
00155
00156
00157
00158
00159 double V = B_air_speed_W_B.Length();
00160 double beta = (V < kMinAirSpeedThresh) ? 0.0 : asin(v / V);
00161 double alpha = (u < kMinAirSpeedThresh) ? 0.0 : atan(w / u);
00162
00163
00164 if (alpha > aero_params_.alpha_max)
00165 alpha = aero_params_.alpha_max;
00166 else if (alpha < aero_params_.alpha_min)
00167 alpha = aero_params_.alpha_min;
00168
00169
00170 const double q_bar_S = 0.5 * kAirDensity * V * V * vehicle_params_.wing_surface;
00171
00172
00173 double aileron_sum = delta_aileron_left_ + delta_aileron_right_;
00174 double aileron_diff = delta_aileron_left_ - delta_aileron_right_;
00175 double flap_sum = 2.0 * delta_flap_;
00176 double flap_diff = 0.0;
00177
00178
00179 const double drag = q_bar_S *
00180 (aero_params_.c_drag_alpha.dot(
00181 Eigen::Vector3d(1.0, alpha, alpha * alpha)) +
00182 aero_params_.c_drag_beta.dot(
00183 Eigen::Vector3d(0.0, beta, beta * beta)) +
00184 aero_params_.c_drag_delta_ail.dot(
00185 Eigen::Vector3d(0.0, aileron_sum, aileron_sum * aileron_sum)) +
00186 aero_params_.c_drag_delta_flp.dot(
00187 Eigen::Vector3d(0.0, flap_sum, flap_sum * flap_sum)));
00188
00189 const double side_force = q_bar_S *
00190 (aero_params_.c_side_force_beta.dot(
00191 Eigen::Vector2d(0.0, beta)));
00192
00193 const double lift = q_bar_S *
00194 (aero_params_.c_lift_alpha.dot(
00195 Eigen::Vector4d(1.0, alpha, alpha * alpha, alpha * alpha * alpha)) +
00196 aero_params_.c_lift_delta_ail.dot(
00197 Eigen::Vector2d(0.0, aileron_sum)) +
00198 aero_params_.c_lift_delta_flp.dot(
00199 Eigen::Vector2d(0.0, flap_sum)));
00200
00201 const Eigen::Vector3d forces_Wind(-drag, side_force, -lift);
00202
00203
00204
00205
00206 const double p_hat = (V < kMinAirSpeedThresh) ? 0.0 :
00207 p * vehicle_params_.wing_span / (2.0 * V);
00208 const double q_hat = (V < kMinAirSpeedThresh) ? 0.0 :
00209 q * vehicle_params_.chord_length / (2.0 * V);
00210 const double r_hat = (V < kMinAirSpeedThresh) ? 0.0 :
00211 r * vehicle_params_.wing_span / (2.0 * V);
00212
00213
00214 const double rolling_moment = q_bar_S * vehicle_params_.wing_span *
00215 (aero_params_.c_roll_moment_beta.dot(
00216 Eigen::Vector2d(0.0, beta)) +
00217 aero_params_.c_roll_moment_p.dot(
00218 Eigen::Vector2d(0.0, p_hat)) +
00219 aero_params_.c_roll_moment_r.dot(
00220 Eigen::Vector2d(0.0, r_hat)) +
00221 aero_params_.c_roll_moment_delta_ail.dot(
00222 Eigen::Vector2d(0.0, aileron_diff)) +
00223 aero_params_.c_roll_moment_delta_flp.dot(
00224 Eigen::Vector2d(0.0, flap_diff)));
00225
00226 const double pitching_moment = q_bar_S * vehicle_params_.chord_length *
00227 (aero_params_.c_pitch_moment_alpha.dot(
00228 Eigen::Vector2d(1.0, alpha)) +
00229 aero_params_.c_pitch_moment_q.dot(
00230 Eigen::Vector2d(0.0, q_hat)) +
00231 aero_params_.c_pitch_moment_delta_elv.dot(
00232 Eigen::Vector2d(0.0, delta_elevator_)));
00233
00234 const double yawing_moment = q_bar_S * vehicle_params_.wing_span *
00235 (aero_params_.c_yaw_moment_beta.dot(
00236 Eigen::Vector2d(0.0, beta)) +
00237 aero_params_.c_yaw_moment_r.dot(
00238 Eigen::Vector2d(0.0, r_hat)) +
00239 aero_params_.c_yaw_moment_delta_rud.dot(
00240 Eigen::Vector2d(0.0, delta_rudder_)));
00241
00242 const Eigen::Vector3d moments_Wind(rolling_moment,
00243 pitching_moment,
00244 yawing_moment);
00245
00246
00247 const double thrust = aero_params_.c_thrust.dot(
00248 Eigen::Vector3d(1.0, throttle_, throttle_ * throttle_));
00249
00250 const Eigen::Vector3d force_thrust_B = thrust * Eigen::Vector3d(
00251 cos(vehicle_params_.thrust_inclination),
00252 0.0,
00253 sin(vehicle_params_.thrust_inclination));
00254
00255
00256 double ca = cos(alpha);
00257 double sa = sin(alpha);
00258 double cb = cos(beta);
00259 double sb = sin(beta);
00260
00261 Eigen::Matrix3d R_Wind_B;
00262 R_Wind_B << ca * cb, sb, sa * cb,
00263 -sb * ca, cb, -sa * sb,
00264 -sa, 0.0, ca;
00265
00266 const Eigen::Matrix3d R_Wind_B_t = R_Wind_B.transpose();
00267
00268
00269 const Eigen::Vector3d forces_B = R_Wind_B_t * forces_Wind + force_thrust_B;
00270 const Eigen::Vector3d moments_B = R_Wind_B_t * moments_Wind;
00271
00272
00273
00274 const ignition::math::Vector3d forces =
00275 ignition::math::Vector3d (forces_B[0], -forces_B[1], -forces_B[2]);
00276 const ignition::math::Vector3d moments =
00277 ignition::math::Vector3d (moments_B[0], -moments_B[1], -moments_B[2]);
00278
00279
00280 link_->AddRelativeForce(forces);
00281 link_->AddRelativeTorque(moments);
00282 }
00283
00284 double GazeboFwDynamicsPlugin::NormalizedInputToAngle(
00285 const ControlSurface& surface, double input) {
00286 return (surface.deflection_max + surface.deflection_min) * 0.5 +
00287 (surface.deflection_max - surface.deflection_min) * 0.5 * input;
00288 }
00289
00290 void GazeboFwDynamicsPlugin::CreatePubsAndSubs() {
00291 gzdbg << __PRETTY_FUNCTION__ << " called." << std::endl;
00292
00293
00294 gazebo::transport::PublisherPtr gz_connect_ros_to_gazebo_topic_pub =
00295 node_handle_->Advertise<gz_std_msgs::ConnectRosToGazeboTopic>(
00296 "~/" + kConnectRosToGazeboSubtopic, 1);
00297 gz_std_msgs::ConnectRosToGazeboTopic connect_ros_to_gazebo_topic_msg;
00298
00299
00300
00301
00302
00303
00304 wind_speed_sub_ =
00305 node_handle_->Subscribe("~/" + namespace_ + "/" + wind_speed_sub_topic_,
00306 &GazeboFwDynamicsPlugin::WindSpeedCallback,
00307 this);
00308
00309 connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
00310 wind_speed_sub_topic_);
00311 connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
00312 wind_speed_sub_topic_);
00313 connect_ros_to_gazebo_topic_msg.set_msgtype(
00314 gz_std_msgs::ConnectRosToGazeboTopic::WIND_SPEED);
00315 gz_connect_ros_to_gazebo_topic_pub->Publish(connect_ros_to_gazebo_topic_msg,
00316 true);
00317
00318
00319
00320 if (is_input_joystick_) {
00321
00322
00323
00324
00325 roll_pitch_yawrate_thrust_sub_ =
00326 node_handle_->Subscribe("~/" + namespace_ + "/" +
00327 roll_pitch_yawrate_thrust_sub_topic_,
00328 &GazeboFwDynamicsPlugin::RollPitchYawrateThrustCallback, this);
00329
00330 connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
00331 roll_pitch_yawrate_thrust_sub_topic_);
00332 connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
00333 roll_pitch_yawrate_thrust_sub_topic_);
00334 connect_ros_to_gazebo_topic_msg.set_msgtype(
00335 gz_std_msgs::ConnectRosToGazeboTopic::ROLL_PITCH_YAWRATE_THRUST);
00336 } else {
00337
00338
00339
00340
00341 actuators_sub_ =
00342 node_handle_->Subscribe("~/" + namespace_ + "/" + actuators_sub_topic_,
00343 &GazeboFwDynamicsPlugin::ActuatorsCallback,
00344 this);
00345
00346 connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
00347 actuators_sub_topic_);
00348 connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
00349 actuators_sub_topic_);
00350 connect_ros_to_gazebo_topic_msg.set_msgtype(
00351 gz_std_msgs::ConnectRosToGazeboTopic::ACTUATORS);
00352 }
00353
00354 gz_connect_ros_to_gazebo_topic_pub->Publish(connect_ros_to_gazebo_topic_msg,
00355 true);
00356 }
00357
00358 void GazeboFwDynamicsPlugin::ActuatorsCallback(
00359 GzActuatorsMsgPtr &actuators_msg) {
00360 if (kPrintOnMsgCallback) {
00361 gzdbg << __FUNCTION__ << "() called." << std::endl;
00362 }
00363
00364 delta_aileron_left_ = NormalizedInputToAngle(vehicle_params_.aileron_left,
00365 actuators_msg->normalized(vehicle_params_.aileron_left.channel));
00366 delta_aileron_right_ = NormalizedInputToAngle(vehicle_params_.aileron_right,
00367 actuators_msg->normalized(vehicle_params_.aileron_right.channel));
00368 delta_elevator_ = NormalizedInputToAngle(vehicle_params_.elevator,
00369 actuators_msg->normalized(vehicle_params_.elevator.channel));
00370 delta_flap_ = NormalizedInputToAngle(vehicle_params_.flap,
00371 actuators_msg->normalized(vehicle_params_.flap.channel));
00372 delta_rudder_ = NormalizedInputToAngle(vehicle_params_.rudder,
00373 actuators_msg->normalized(vehicle_params_.rudder.channel));
00374
00375 throttle_ = actuators_msg->normalized(vehicle_params_.throttle_channel);
00376 }
00377
00378 void GazeboFwDynamicsPlugin::RollPitchYawrateThrustCallback(
00379 GzRollPitchYawrateThrustMsgPtr& roll_pitch_yawrate_thrust_msg) {
00380 if (kPrintOnMsgCallback) {
00381 gzdbg << __FUNCTION__ << "() called." << std::endl;
00382 }
00383
00384 delta_aileron_left_ = NormalizedInputToAngle(vehicle_params_.aileron_left,
00385 roll_pitch_yawrate_thrust_msg->roll());
00386 delta_aileron_right_ = -NormalizedInputToAngle(vehicle_params_.aileron_right,
00387 roll_pitch_yawrate_thrust_msg->roll());
00388 delta_elevator_ = NormalizedInputToAngle(vehicle_params_.elevator,
00389 roll_pitch_yawrate_thrust_msg->pitch());
00390 delta_rudder_ = NormalizedInputToAngle(vehicle_params_.rudder,
00391 roll_pitch_yawrate_thrust_msg->yaw_rate());
00392
00393 throttle_ = roll_pitch_yawrate_thrust_msg->thrust().x();
00394 }
00395
00396 void GazeboFwDynamicsPlugin::WindSpeedCallback(
00397 GzWindSpeedMsgPtr& wind_speed_msg) {
00398 if (kPrintOnMsgCallback) {
00399 gzdbg << __FUNCTION__ << "() called." << std::endl;
00400 }
00401
00402 W_wind_speed_W_B_.X() = wind_speed_msg->velocity().x();
00403 W_wind_speed_W_B_.Y() = wind_speed_msg->velocity().y();
00404 W_wind_speed_W_B_.Z() = wind_speed_msg->velocity().z();
00405 }
00406
00407 GZ_REGISTER_MODEL_PLUGIN(GazeboFwDynamicsPlugin);
00408
00409 }