gazebo_fw_dynamics_plugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Pavel Vechersky, ASL, ETH Zurich, Switzerland
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // MODULE HEADER
19 
20 #include "ConnectRosToGazeboTopic.pb.h"
21 
22 namespace gazebo {
23 
25  : ModelPlugin(),
26  node_handle_(0),
27  W_wind_speed_W_B_(0, 0, 0),
28  delta_aileron_left_(0.0),
29  delta_aileron_right_(0.0),
30  delta_elevator_(0.0),
31  delta_flap_(0.0),
32  delta_rudder_(0.0),
33  throttle_(0.0),
34  pubs_and_subs_created_(false) {
35 }
36 
38 }
39 
40 void GazeboFwDynamicsPlugin::Load(physics::ModelPtr _model,
41  sdf::ElementPtr _sdf) {
42  if (kPrintOnPluginLoad) {
43  gzdbg << __FUNCTION__ << "() called." << std::endl;
44  }
45 
46  gzdbg << "_model = " << _model->GetName() << std::endl;
47 
48  // Store the pointer to the model.
49  model_ = _model;
50  world_ = model_->GetWorld();
51 
52  namespace_.clear();
53 
54  // Get the robot namespace.
55  if (_sdf->HasElement("robotNamespace"))
56  namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
57  else
58  gzerr << "[gazebo_fw_dynamics_plugin] Please specify a robotNamespace.\n";
59 
60  // Create the node handle.
61  node_handle_ = transport::NodePtr(new transport::Node());
62 
63  // Initialise with default namespace (typically /gazebo/default/).
64  node_handle_->Init();
65 
66  // Get the link name.
67  std::string link_name;
68  if (_sdf->HasElement("linkName"))
69  link_name = _sdf->GetElement("linkName")->Get<std::string>();
70  else
71  gzerr << "[gazebo_fw_dynamics_plugin] Please specify a linkName.\n";
72  // Get the pointer to the link.
73  link_ = model_->GetLink(link_name);
74  if (link_ == NULL) {
75  gzthrow("[gazebo_fw_dynamics_plugin] Couldn't find specified link \""
76  << link_name << "\".");
77  }
78 
79  // Get the path to fixed-wing aerodynamics parameters YAML file. If not
80  // provided, default Techpod parameters are used.
81  if (_sdf->HasElement("aeroParamsYAML")) {
82  std::string aero_params_yaml =
83  _sdf->GetElement("aeroParamsYAML")->Get<std::string>();
84 
85  aero_params_.LoadAeroParamsYAML(aero_params_yaml);
86  } else {
87  gzwarn << "[gazebo_fw_dynamics_plugin] No aerodynamic paramaters YAML file"
88  << " specified, using default Techpod parameters.\n";
89  }
90 
91  // Get the path to fixed-wing vehicle parameters YAML file. If not provided,
92  // default Techpod parameters are used.
93  if (_sdf->HasElement("vehicleParamsYAML")) {
94  std::string vehicle_params_yaml =
95  _sdf->GetElement("vehicleParamsYAML")->Get<std::string>();
96 
97  vehicle_params_.LoadVehicleParamsYAML(vehicle_params_yaml);
98  } else {
99  gzwarn << "[gazebo_fw_dynamics_plugin] No vehicle paramaters YAML file"
100  << " specified, using default Techpod parameters.\n";
101  }
102 
103  // Get the rest of the sdf parameters.
104  getSdfParam<bool>(_sdf, "isInputJoystick", is_input_joystick_,
106  getSdfParam<std::string>(_sdf, "actuatorsSubTopic",
109  getSdfParam<std::string>(_sdf, "rollPitchYawrateThrustSubTopic",
113  getSdfParam<std::string>(_sdf, "windSpeedSubTopic",
116 
117  // Listen to the update event. This event is broadcast every
118  // simulation iteration.
119  this->updateConnection_ = event::Events::ConnectWorldUpdateBegin(
120  boost::bind(&GazeboFwDynamicsPlugin::OnUpdate, this, _1));
121 }
122 
123 void GazeboFwDynamicsPlugin::OnUpdate(const common::UpdateInfo& _info) {
124  if (kPrintOnUpdates) {
125  gzdbg << __FUNCTION__ << "() called." << std::endl;
126  }
127 
128  if (!pubs_and_subs_created_) {
130  pubs_and_subs_created_ = true;
131  }
132 
134 }
135 
137  // Express the air speed and angular velocity in the body frame.
138  // B denotes body frame and W world frame ... e.g., W_rot_W_B denotes
139  // rotation of B wrt. W expressed in W.
140  ignition::math::Quaterniond W_rot_W_B = link_->WorldPose().Rot();
141  ignition::math::Vector3d B_air_speed_W_B = W_rot_W_B.RotateVectorReverse(
142  link_->WorldLinearVel() - W_wind_speed_W_B_);
143  ignition::math::Vector3d B_angular_velocity_W_B = link_->RelativeAngularVel();
144 
145  // Traditionally, fixed-wing aerodynamics use NED (North-East-Down) frame,
146  // but since our model's body frame is in North-West-Up frame we rotate the
147  // linear and angular velocities by 180 degrees around the X axis.
148  double u = B_air_speed_W_B.X();
149  double v = -B_air_speed_W_B.Y();
150  double w = -B_air_speed_W_B.Z();
151 
152  double p = B_angular_velocity_W_B.X();
153  double q = -B_angular_velocity_W_B.Y();
154  double r = -B_angular_velocity_W_B.Z();
155 
156  // Compute the angle of attack (alpha) and the sideslip angle (beta). To
157  // avoid division by zero, there is a minimum air speed threshold below which
158  // alpha and beta are zero.
159  double V = B_air_speed_W_B.Length();
160  double beta = (V < kMinAirSpeedThresh) ? 0.0 : asin(v / V);
161  double alpha = (u < kMinAirSpeedThresh) ? 0.0 : atan(w / u);
162 
163  // Bound the angle of attack.
164  if (alpha > aero_params_.alpha_max)
165  alpha = aero_params_.alpha_max;
166  else if (alpha < aero_params_.alpha_min)
167  alpha = aero_params_.alpha_min;
168 
169  // Pre-compute the common component in the force and moment calculations.
170  const double q_bar_S = 0.5 * kAirDensity * V * V * vehicle_params_.wing_surface;
171 
172  // Combine some of the control surface deflections.
173  double aileron_sum = delta_aileron_left_ + delta_aileron_right_;
174  double aileron_diff = delta_aileron_left_ - delta_aileron_right_;
175  double flap_sum = 2.0 * delta_flap_;
176  double flap_diff = 0.0;
177 
178  // Compute the forces in the wind frame.
179  const double drag = q_bar_S *
181  Eigen::Vector3d(1.0, alpha, alpha * alpha)) +
183  Eigen::Vector3d(0.0, beta, beta * beta)) +
185  Eigen::Vector3d(0.0, aileron_sum, aileron_sum * aileron_sum)) +
187  Eigen::Vector3d(0.0, flap_sum, flap_sum * flap_sum)));
188 
189  const double side_force = q_bar_S *
191  Eigen::Vector2d(0.0, beta)));
192 
193  const double lift = q_bar_S *
195  Eigen::Vector4d(1.0, alpha, alpha * alpha, alpha * alpha * alpha)) +
197  Eigen::Vector2d(0.0, aileron_sum)) +
199  Eigen::Vector2d(0.0, flap_sum)));
200 
201  const Eigen::Vector3d forces_Wind(-drag, side_force, -lift);
202 
203  // Non-dimensionalize the angular rates for inclusion in the computation of
204  // moments. To avoid division by zero, there is a minimum air speed threshold
205  // below which the values are zero.
206  const double p_hat = (V < kMinAirSpeedThresh) ? 0.0 :
207  p * vehicle_params_.wing_span / (2.0 * V);
208  const double q_hat = (V < kMinAirSpeedThresh) ? 0.0 :
209  q * vehicle_params_.chord_length / (2.0 * V);
210  const double r_hat = (V < kMinAirSpeedThresh) ? 0.0 :
211  r * vehicle_params_.wing_span / (2.0 * V);
212 
213  // Compute the moments in the wind frame.
214  const double rolling_moment = q_bar_S * vehicle_params_.wing_span *
216  Eigen::Vector2d(0.0, beta)) +
218  Eigen::Vector2d(0.0, p_hat)) +
220  Eigen::Vector2d(0.0, r_hat)) +
222  Eigen::Vector2d(0.0, aileron_diff)) +
224  Eigen::Vector2d(0.0, flap_diff)));
225 
226  const double pitching_moment = q_bar_S * vehicle_params_.chord_length *
228  Eigen::Vector2d(1.0, alpha)) +
230  Eigen::Vector2d(0.0, q_hat)) +
232  Eigen::Vector2d(0.0, delta_elevator_)));
233 
234  const double yawing_moment = q_bar_S * vehicle_params_.wing_span *
236  Eigen::Vector2d(0.0, beta)) +
238  Eigen::Vector2d(0.0, r_hat)) +
240  Eigen::Vector2d(0.0, delta_rudder_)));
241 
242  const Eigen::Vector3d moments_Wind(rolling_moment,
243  pitching_moment,
244  yawing_moment);
245 
246  // Compute the thrust force in the body frame.
247  const double thrust = aero_params_.c_thrust.dot(
248  Eigen::Vector3d(1.0, throttle_, throttle_ * throttle_));
249 
250  const Eigen::Vector3d force_thrust_B = thrust * Eigen::Vector3d(
252  0.0,
254 
255  // Compute the transform between the body frame and the wind frame.
256  double ca = cos(alpha);
257  double sa = sin(alpha);
258  double cb = cos(beta);
259  double sb = sin(beta);
260 
261  Eigen::Matrix3d R_Wind_B;
262  R_Wind_B << ca * cb, sb, sa * cb,
263  -sb * ca, cb, -sa * sb,
264  -sa, 0.0, ca;
265 
266  const Eigen::Matrix3d R_Wind_B_t = R_Wind_B.transpose();
267 
268  // Transform all the forces and moments into the body frame
269  const Eigen::Vector3d forces_B = R_Wind_B_t * forces_Wind + force_thrust_B;
270  const Eigen::Vector3d moments_B = R_Wind_B_t * moments_Wind;
271 
272  // Once again account for the difference between our body frame orientation
273  // and the traditional aerodynamics frame.
274  const ignition::math::Vector3d forces =
275  ignition::math::Vector3d (forces_B[0], -forces_B[1], -forces_B[2]);
276  const ignition::math::Vector3d moments =
277  ignition::math::Vector3d (moments_B[0], -moments_B[1], -moments_B[2]);
278 
279  // Apply the calculated forced and moments to the main body link.
280  link_->AddRelativeForce(forces);
281  link_->AddRelativeTorque(moments);
282 }
283 
285  const ControlSurface& surface, double input) {
286  return (surface.deflection_max + surface.deflection_min) * 0.5 +
287  (surface.deflection_max - surface.deflection_min) * 0.5 * input;
288 }
289 
291  gzdbg << __PRETTY_FUNCTION__ << " called." << std::endl;
292 
293  // Create temporary "ConnectRosToGazeboTopic" publisher and message
294  gazebo::transport::PublisherPtr gz_connect_ros_to_gazebo_topic_pub =
295  node_handle_->Advertise<gz_std_msgs::ConnectRosToGazeboTopic>(
296  "~/" + kConnectRosToGazeboSubtopic, 1);
297  gz_std_msgs::ConnectRosToGazeboTopic connect_ros_to_gazebo_topic_msg;
298 
299  // ============================================ //
300  // ==== WIND SPEED MSG SETUP (ROS->GAZEBO) ==== //
301  // ============================================ //
302 
303  // Wind speed subscriber (Gazebo).
305  node_handle_->Subscribe("~/" + namespace_ + "/" + wind_speed_sub_topic_,
307  this);
308 
309  connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
311  connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
313  connect_ros_to_gazebo_topic_msg.set_msgtype(
314  gz_std_msgs::ConnectRosToGazeboTopic::WIND_SPEED);
315  gz_connect_ros_to_gazebo_topic_pub->Publish(connect_ros_to_gazebo_topic_msg,
316  true);
317 
318  // If we are using a joystick for control inputs then subscribe to the
319  // RollPitchYawrateThrust msgs, otherwise subscribe to the Actuator msgs.
320  if (is_input_joystick_) {
321  // ========================================================= //
322  // === ROLL_PITCH_YAWRATE_THRUST MSG SETUP (ROS->GAZEBO) === //
323  // ========================================================= //
324 
326  node_handle_->Subscribe("~/" + namespace_ + "/" +
329 
330  connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
332  connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
334  connect_ros_to_gazebo_topic_msg.set_msgtype(
335  gz_std_msgs::ConnectRosToGazeboTopic::ROLL_PITCH_YAWRATE_THRUST);
336  } else {
337  // ============================================ //
338  // ===== ACTUATORS MSG SETUP (ROS->GAZEBO) ==== //
339  // ============================================ //
340 
342  node_handle_->Subscribe("~/" + namespace_ + "/" + actuators_sub_topic_,
344  this);
345 
346  connect_ros_to_gazebo_topic_msg.set_ros_topic(namespace_ + "/" +
348  connect_ros_to_gazebo_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
350  connect_ros_to_gazebo_topic_msg.set_msgtype(
351  gz_std_msgs::ConnectRosToGazeboTopic::ACTUATORS);
352  }
353 
354  gz_connect_ros_to_gazebo_topic_pub->Publish(connect_ros_to_gazebo_topic_msg,
355  true);
356 }
357 
359  GzActuatorsMsgPtr &actuators_msg) {
360  if (kPrintOnMsgCallback) {
361  gzdbg << __FUNCTION__ << "() called." << std::endl;
362  }
363 
365  actuators_msg->normalized(vehicle_params_.aileron_left.channel));
367  actuators_msg->normalized(vehicle_params_.aileron_right.channel));
369  actuators_msg->normalized(vehicle_params_.elevator.channel));
371  actuators_msg->normalized(vehicle_params_.flap.channel));
373  actuators_msg->normalized(vehicle_params_.rudder.channel));
374 
375  throttle_ = actuators_msg->normalized(vehicle_params_.throttle_channel);
376 }
377 
379  GzRollPitchYawrateThrustMsgPtr& roll_pitch_yawrate_thrust_msg) {
380  if (kPrintOnMsgCallback) {
381  gzdbg << __FUNCTION__ << "() called." << std::endl;
382  }
383 
385  roll_pitch_yawrate_thrust_msg->roll());
387  roll_pitch_yawrate_thrust_msg->roll());
389  roll_pitch_yawrate_thrust_msg->pitch());
391  roll_pitch_yawrate_thrust_msg->yaw_rate());
392 
393  throttle_ = roll_pitch_yawrate_thrust_msg->thrust().x();
394 }
395 
397  GzWindSpeedMsgPtr& wind_speed_msg) {
398  if (kPrintOnMsgCallback) {
399  gzdbg << __FUNCTION__ << "() called." << std::endl;
400  }
401 
402  W_wind_speed_W_B_.X() = wind_speed_msg->velocity().x();
403  W_wind_speed_W_B_.Y() = wind_speed_msg->velocity().y();
404  W_wind_speed_W_B_.Z() = wind_speed_msg->velocity().z();
405 }
406 
408 
409 } // namespace gazebo
void CreatePubsAndSubs()
Creates all required publishers and subscribers, incl. routing of messages to/from ROS if required...
physics::LinkPtr link_
Pointer to the link.
std::string actuators_sub_topic_
Topic name for actuator commands.
void LoadVehicleParamsYAML(const std::string &yaml_path)
Eigen::Vector2d c_roll_moment_delta_flp
transport::NodePtr node_handle_
Handle for the Gazebo node.
static constexpr char WIND_SPEED[]
static const std::string kConnectRosToGazeboSubtopic
Definition: common.h:57
static constexpr bool kDefaultIsInputJoystick
static constexpr double kAirDensity
void ActuatorsCallback(GzActuatorsMsgPtr &actuators_msg)
Processes the actuator commands.
double NormalizedInputToAngle(const ControlSurface &surface, double input)
Convert control surface input that is normalized in range [-1, 1] to a physical deflection angle valu...
static constexpr char COMMAND_ROLL_PITCH_YAWRATE_THRUST[]
double throttle_
Throttle input, in range from 0 to 1.
event::ConnectionPtr updateConnection_
Pointer to the update event connection.
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
Called when the plugin is first created, and after the world has been loaded. This function should no...
gazebo::transport::SubscriberPtr wind_speed_sub_
Subscriber ror receiving wind speed readings.
double delta_aileron_left_
Left aileron deflection [rad].
static constexpr char COMMAND_ACTUATORS[]
ignition::math::Vector3d W_wind_speed_W_B_
Most current wind speed reading [m/s].
void OnUpdate(const common::UpdateInfo &)
This gets called by the world update start event.
std::string roll_pitch_yawrate_thrust_sub_topic_
Topic name for roll_pitch_yawrate_thrust commands.
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
FWVehicleParameters vehicle_params_
The physical properties of the aircraft.
Eigen::Vector2d c_roll_moment_delta_ail
Eigen::Vector2d c_pitch_moment_delta_elv
INLINE Rall1d< T, V, S > asin(const Rall1d< T, V, S > &x)
static const bool kPrintOnPluginLoad
Definition: common.h:41
std::string namespace_
Transport namespace.
physics::ModelPtr model_
Pointer to the model.
void LoadAeroParamsYAML(const std::string &yaml_path)
void UpdateForcesAndMoments()
Calculates the forces and moments to be applied to the fixed-wing body.
gazebo::transport::SubscriberPtr actuators_sub_
Subscriber for receiving actuator commands.
static const bool kPrintOnUpdates
Definition: common.h:42
double delta_rudder_
Rudder deflection [rad].
Eigen::Vector2d c_yaw_moment_delta_rud
double delta_flap_
Flap deflection [rad].
void WindSpeedCallback(GzWindSpeedMsgPtr &wind_speed_msg)
Processes the wind speed readings.
void RollPitchYawrateThrustCallback(GzRollPitchYawrateThrustMsgPtr &roll_pitch_yawrate_thrust_msg)
Process the roll_pitch_yawrate_thrust commands.
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
bool is_input_joystick_
Are the input commands coming from a joystick (as opposed to a remote control via HIL interface...
physics::WorldPtr world_
Pointer to the world.
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
FWAerodynamicParameters aero_params_
The aerodynamic properties of the aircraft.
std::string wind_speed_sub_topic_
Topic name for wind speed readings.
Eigen::Vector2d c_pitch_moment_alpha
gazebo::transport::SubscriberPtr roll_pitch_yawrate_thrust_sub_
Subscriber for receiving roll_pitch_yawrate_thrust commands.
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
static const bool kPrintOnMsgCallback
Definition: common.h:43
static constexpr double kMinAirSpeedThresh
double delta_elevator_
Elevator deflection [rad].
bool pubs_and_subs_created_
Flag that is set to true once CreatePubsAndSubs() is called, used to prevent CreatePubsAndSubs() from...
double delta_aileron_right_
Right aileron deflection [rad].


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03