27 #include "ConnectGazeboToRosTopic.pb.h" 37 gzdbg << __FUNCTION__ <<
"() called." << std::endl;
51 if (_sdf->HasElement(
"robotNamespace"))
52 namespace_ = _sdf->GetElement(
"robotNamespace")->Get<std::string>();
54 gzerr <<
"[gazebo_wind_plugin] Please specify a robotNamespace.\n";
57 node_handle_ = gazebo::transport::NodePtr(
new transport::Node());
62 if (_sdf->HasElement(
"xyzOffset"))
63 xyz_offset_ = _sdf->GetElement(
"xyzOffset")->Get<ignition::math::Vector3d >();
65 gzerr <<
"[gazebo_wind_plugin] Please specify a xyzOffset.\n";
78 getSdfParam<ignition::math::Vector3d >(_sdf,
"windDirection",
wind_direction_,
83 if (!use_custom_static_wind_field_) {
84 gzdbg <<
"[gazebo_wind_plugin] Using user-defined constant wind field and gusts.\n";
91 getSdfParam<double>(_sdf,
"windGustStart", wind_gust_start, wind_gust_start);
92 getSdfParam<double>(_sdf,
"windGustDuration", wind_gust_duration,
101 wind_direction_.Normalize();
102 wind_gust_direction_.Normalize();
104 wind_gust_end_ = common::Time(wind_gust_start + wind_gust_duration);
106 gzdbg <<
"[gazebo_wind_plugin] Using custom wind field from text file.\n";
108 std::string custom_wind_field_path;
109 getSdfParam<std::string>(_sdf,
"customWindFieldPath", custom_wind_field_path,
110 custom_wind_field_path);
116 gzthrow(
"[gazebo_wind_plugin] Couldn't find specified link \"" << link_name_
128 gzdbg << __FUNCTION__ <<
"() called." << std::endl;
137 common::Time now =
world_->SimTime();
139 ignition::math::Vector3d wind_velocity(0.0, 0.0, 0.0);
149 ignition::math::Vector3d wind_gust(0.0, 0.0, 0.0);
180 ignition::math::Vector3d link_position =
link_->WorldPose().Pos();
184 std::size_t x_inf = floor((link_position.X() -
min_x_) /
res_x_);
185 std::size_t y_inf = floor((link_position.Y() -
min_y_) /
res_y_);
189 if (x_inf ==
n_x_ - 1u) {
192 if (y_inf ==
n_y_ - 1u) {
198 std::size_t x_sup = x_inf + 1u;
199 std::size_t y_sup = y_inf + 1u;
203 constexpr
unsigned int n_vertices = 8;
204 std::size_t idx_x[n_vertices] = {x_inf, x_inf, x_sup, x_sup, x_inf, x_inf, x_sup, x_sup};
205 std::size_t idx_y[n_vertices] = {y_inf, y_inf, y_inf, y_inf, y_sup, y_sup, y_sup, y_sup};
209 constexpr
unsigned int n_columns = 4;
210 float vertical_factors_columns[n_columns];
211 for (std::size_t i = 0u; i < n_columns; ++i) {
212 vertical_factors_columns[i] = (
213 link_position.Z() -
bottom_z_[idx_x[2u * i] + idx_y[2u * i] *
n_x_]) /
218 float vertical_factors_min = std::min(std::min(std::min(
219 vertical_factors_columns[0], vertical_factors_columns[1]),
220 vertical_factors_columns[2]), vertical_factors_columns[3]);
221 float vertical_factors_max = std::max(std::max(std::max(
222 vertical_factors_columns[0], vertical_factors_columns[1]),
223 vertical_factors_columns[2]), vertical_factors_columns[3]);
226 if (x_inf >= 0u && y_inf >= 0u && vertical_factors_max >= 0u &&
227 x_sup <= (
n_x_ - 1u) && y_sup <= (
n_y_ - 1u) && vertical_factors_min <= 1u) {
234 for (std::size_t i = 0u; i < n_columns; ++i) {
235 if (vertical_factors_columns[i] < 0u) {
237 idx_z[2u * i + 1u] = 1u;
238 }
else if (vertical_factors_columns[i] >= 1u) {
247 idx_z[2u * i + 1u] = j + 1u;
255 ignition::math::Vector3d wind_at_vertices[n_vertices];
256 for (std::size_t i = 0u; i < n_vertices; ++i) {
257 wind_at_vertices[i].X() =
u_[idx_x[i] + idx_y[i] *
n_x_ + idx_z[i] *
n_x_ *
n_y_];
258 wind_at_vertices[i].Y() =
v_[idx_x[i] + idx_y[i] *
n_x_ + idx_z[i] *
n_x_ *
n_y_];
259 wind_at_vertices[i].Z() =
w_[idx_x[i] + idx_y[i] *
n_x_ + idx_z[i] *
n_x_ *
n_y_];
264 constexpr
unsigned int n_points_interp_z = 8;
265 constexpr
unsigned int n_points_interp_x = 4;
266 constexpr
unsigned int n_points_interp_y = 2;
267 double interpolation_points[n_points_interp_x + n_points_interp_y + n_points_interp_z];
268 for (std::size_t i = 0u; i < n_points_interp_x + n_points_interp_y + n_points_interp_z; ++i) {
269 if (i < n_points_interp_z) {
270 interpolation_points[i] = (
273 }
else if (i >= n_points_interp_z && i < n_points_interp_x + n_points_interp_z) {
274 interpolation_points[i] =
min_x_ +
res_x_ * idx_x[2u * (i - n_points_interp_z)];
276 interpolation_points[i] =
min_y_ +
res_y_ * idx_y[4u * (i - n_points_interp_z - n_points_interp_x)];
282 link_position, wind_at_vertices, interpolation_points);
302 gazebo::transport::PublisherPtr connect_gazebo_to_ros_topic_pub =
303 node_handle_->Advertise<gz_std_msgs::ConnectGazeboToRosTopic>(
306 gz_std_msgs::ConnectGazeboToRosTopic connect_gazebo_to_ros_topic_msg;
315 connect_gazebo_to_ros_topic_msg.set_gazebo_topic(
"~/" +
namespace_ +
"/" +
316 wind_force_pub_topic_);
317 connect_gazebo_to_ros_topic_msg.set_ros_topic(
namespace_ +
"/" +
318 wind_force_pub_topic_);
319 connect_gazebo_to_ros_topic_msg.set_msgtype(
320 gz_std_msgs::ConnectGazeboToRosTopic::WRENCH_STAMPED);
321 connect_gazebo_to_ros_topic_pub->Publish(connect_gazebo_to_ros_topic_msg,
330 connect_gazebo_to_ros_topic_msg.set_gazebo_topic(
"~/" +
namespace_ +
"/" +
331 wind_speed_pub_topic_);
332 connect_gazebo_to_ros_topic_msg.set_ros_topic(
namespace_ +
"/" +
333 wind_speed_pub_topic_);
334 connect_gazebo_to_ros_topic_msg.set_msgtype(
335 gz_std_msgs::ConnectGazeboToRosTopic::WIND_SPEED);
336 connect_gazebo_to_ros_topic_pub->Publish(connect_gazebo_to_ros_topic_msg,
342 fin.open(custom_wind_field_path);
344 std::string data_name;
347 while (fin >> data_name) {
349 if (data_name ==
"min_x:") {
351 }
else if (data_name ==
"min_y:") {
353 }
else if (data_name ==
"n_x:") {
355 }
else if (data_name ==
"n_y:") {
357 }
else if (data_name ==
"res_x:") {
359 }
else if (data_name ==
"res_y:") {
361 }
else if (data_name ==
"vertical_spacing_factors:") {
362 while (fin >> data) {
364 if (fin.peek() ==
'\n')
break;
366 }
else if (data_name ==
"bottom_z:") {
367 while (fin >> data) {
369 if (fin.peek() ==
'\n')
break;
371 }
else if (data_name ==
"top_z:") {
372 while (fin >> data) {
374 if (fin.peek() ==
'\n')
break;
376 }
else if (data_name ==
"u:") {
377 while (fin >> data) {
379 if (fin.peek() ==
'\n')
break;
381 }
else if (data_name ==
"v:") {
382 while (fin >> data) {
384 if (fin.peek() ==
'\n')
break;
386 }
else if (data_name ==
"w:") {
387 while (fin >> data) {
389 if (fin.peek() ==
'\n')
break;
394 std::string restOfLine;
395 getline(fin, restOfLine);
396 gzerr <<
" [gazebo_wind_plugin] Invalid data name '" << data_name << restOfLine <<
397 "' in custom wind field text file. Ignoring data on next line.\n";
398 fin.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
402 gzdbg <<
"[gazebo_wind_plugin] Successfully read custom wind field from text file.\n";
404 gzerr <<
"[gazebo_wind_plugin] Could not open custom wind field text file.\n";
410 double position, ignition::math::Vector3d * values,
double* points)
const {
411 ignition::math::Vector3d value = values[0] + (values[1] - values[0]) /
412 (points[1] - points[0]) * (position - points[0]);
417 double* position, ignition::math::Vector3d * values,
double* points)
const {
419 position[0], &(values[0]), &(points[0])),
421 position[0], &(values[2]), &(points[2])) };
423 position[1], intermediate_values, &(points[4]));
428 ignition::math::Vector3d link_position, ignition::math::Vector3d * values,
double* points)
const {
429 double position[3] = {link_position.X(),link_position.Y(),link_position.Z()};
431 position[2], &(values[0]), &(points[0])),
433 position[2], &(values[2]), &(points[2])),
435 position[2], &(values[4]), &(points[4])),
437 position[2], &(values[6]), &(points[6])) };
439 &(position[0]), intermediate_values, &(points[8]));
double wind_force_variance_
ignition::math::Vector3d BilinearInterpolation(double *position, ignition::math::Vector3d *values, double *points) const
Bilinear interpolation.
common::Time wind_gust_start_
event::ConnectionPtr update_connection_
Pointer to the update event connection.
void OnUpdate(const common::UpdateInfo &)
Called when the world is updated.
double wind_gust_force_variance_
virtual ~GazeboWindPlugin()
std::vector< float > vertical_spacing_factors_
static constexpr double kDefaultWindGustStart
double wind_gust_force_mean_
common::Time wind_gust_end_
bool pubs_and_subs_created_
Flag that is set to true once CreatePubsAndSubs() is called, used to prevent CreatePubsAndSubs() from...
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
Load the plugin.
ignition::math::Vector3d wind_direction_
bool use_custom_static_wind_field_
Variables for custom wind field generation.
std::vector< float > top_z_
static constexpr double kDefaultWindGustDuration
gazebo::transport::NodePtr node_handle_
ignition::math::Vector3d wind_gust_direction_
gz_mav_msgs::WindSpeed wind_speed_msg_
Gazebo message for sending wind speed data.
static const bool kPrintOnPluginLoad
ignition::math::Vector3d xyz_offset_
gazebo::transport::PublisherPtr wind_force_pub_
ignition::math::Vector3d LinearInterpolation(double position, ignition::math::Vector3d *values, double *points) const
Functions for trilinear interpolation of wind field at aircraft position.
This gazebo plugin simulates wind acting on a model.
std::string wind_force_pub_topic_
void CreatePubsAndSubs()
Creates all required publishers and subscribers, incl. routing of messages to/from ROS if required...
ignition::math::Vector3d TrilinearInterpolation(ignition::math::Vector3d link_position, ignition::math::Vector3d *values, double *points) const
Trilinear interpolation.
double wind_speed_variance_
static const bool kPrintOnUpdates
std::string wind_speed_pub_topic_
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
static const std::string kConnectGazeboToRosSubtopic
std::vector< float > bottom_z_
gz_geometry_msgs::WrenchStamped wrench_stamped_msg_
Gazebo message for sending wind data.
gazebo::transport::PublisherPtr wind_speed_pub_
void ReadCustomWindField(std::string &custom_wind_field_path)
Reads wind data from a text file and saves it.