usv_gazebo_wind_plugin.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 Brian Bingham
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 
18 #include <std_msgs/Float64.h>
19 #include <functional>
20 #include <gazebo/common/Console.hh>
22 
23 using namespace gazebo;
24 
27 {
28 }
29 
31 void UsvWindPlugin::Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
32 {
33  if (char* env_dbg = std::getenv("VRX_DEBUG"))
34  {
35  gzdbg << std::string(env_dbg) <<std::endl;
36  if (std::string(env_dbg) == "false")
37  this->debug = false;
38  }
39  else
40  {
41  gzwarn << "VRX_DEBUG environment variable not set, defaulting to true"
42  << std::endl;
43  }
44  this->world = _parent;
45  // Retrieve models' parameters from SDF
46  if (!_sdf->HasElement("wind_obj") ||
47  !_sdf->GetElement("wind_obj"))
48  {
49  gzerr << "Did not find SDF parameter wind_obj" << std::endl;
50  }
51  else
52  {
53  sdf::ElementPtr windObjSDF = _sdf->GetElement("wind_obj");
54  while (windObjSDF)
55  {
57  if (!windObjSDF->HasElement("name") ||
58  !windObjSDF->GetElement("name")->GetValue())
59  {
60  gzerr << ("Did not find SDF parameter name") << std::endl;
61  }
62  else
63  {
64  obj.modelName = windObjSDF->GetElement("name")->Get<std::string>();
65  }
66 
67  if (!windObjSDF->HasElement("link_name") ||
68  !windObjSDF->GetElement("link_name")->GetValue())
69  {
70  gzerr << ("Did not find SDF parameter link_name") << std::endl;
71  }
72  else
73  {
74  obj.linkName = windObjSDF->GetElement("link_name")->Get<std::string>();
75  }
76 
77  if (!windObjSDF->HasElement("coeff_vector") ||
78  !windObjSDF->GetElement("coeff_vector")->GetValue())
79  {
80  gzerr << ("Did not find SDF parameter coeff_vector") << std::endl;
81  }
82  else
83  {
84  obj.windCoeff = windObjSDF->GetElement("coeff_vector")->
85  Get<ignition::math::Vector3d>();
86  }
87  this->windObjs.push_back(obj);
88  gzdbg << obj.modelName << " loaded" << std::endl;
89  windObjSDF = windObjSDF->GetNextElement("wind_obj");
90  }
91  }
92 
93  if (_sdf->HasElement("wind_direction"))
94  {
95  double windAngle = _sdf->GetElement("wind_direction")->Get<double>();
96  this->windDirection.X(cos(windAngle * M_PI / 180));
97  this->windDirection.Y(sin(windAngle * M_PI / 180));
98  this->windDirection.Z(0);
99  }
100 
101  gzmsg << "Wind direction unit vector = " << this->windDirection << std::endl;
102 
103  if (_sdf->HasElement("wind_mean_velocity"))
104  {
105  this->windMeanVelocity =
106  _sdf->GetElement("wind_mean_velocity")->Get<double>();
107  }
108 
109  gzmsg << "Wind mean velocity = " << this->windMeanVelocity << std::endl;
110 
111  if (_sdf->HasElement("var_wind_gain_constants"))
112  {
113  this->gainConstant =
114  _sdf->GetElement("var_wind_gain_constants")->Get<double>();
115  }
116 
117  gzmsg << "var wind gain constants = " << this->gainConstant << std::endl;
118 
119  if (_sdf->HasElement("var_wind_time_constants"))
120  {
121  this->timeConstant =
122  _sdf->GetElement("var_wind_time_constants")->Get<double>();
123  }
124 
125  gzmsg << "var wind time constants = " << this->timeConstant << std::endl;
126 
127  if (_sdf->HasElement("update_rate"))
128  {
129  this->updateRate =
130  _sdf->GetElement("update_rate")->Get<double>();
131  }
132 
133  gzmsg << "update rate = " << this->updateRate << std::endl;
134 
135  // Setting the seed for the random generator.
136  unsigned int seed = std::random_device {}();
137  if (_sdf->HasElement("random_seed") &&
138  _sdf->GetElement("random_seed")->Get<unsigned int>() != 0)
139  {
140  seed = _sdf->GetElement("random_seed")->Get<unsigned int>();
141  }
142 
143  gzmsg << "Random seed value = " << seed << std::endl;
144  this->randGenerator.reset(new std::mt19937(seed));
145 
146  // Calculate filter constant
147  this->filterGain = this->gainConstant*sqrt(2.0*this->timeConstant);
148  gzmsg << "Var wind filter gain = " << this->filterGain << std::endl;
149 
150  // Initialize previous time and previous velocity
151 #if GAZEBO_MAJOR_VERSION >= 8
152  this->previousTime = this->world->SimTime().Double();
153 #else
154  this->previousTime = this->world->GetSimTime().Double();
155 #endif
156  this->varVel = 0;
157 
158  // Initialize ROS transport.
159  this->rosNode.reset(new ros::NodeHandle());
160  this->windSpeedPub =
161  this->rosNode->advertise<std_msgs::Float64>(this->topicWindSpeed, 100);
162  this->windDirectionPub = this->rosNode->advertise<std_msgs::Float64>(
163  this->topicWindDirection, 100);
164 
165  // Listen to the update event. This event is broadcast every
166  // simulation iteration.
167  this->updateConnection = event::Events::ConnectWorldUpdateBegin(
168  std::bind(&UsvWindPlugin::Update, this));
169 }
170 
173 {
174  // Look for the missing models if not all of them have been initialized
175  if (!this->windObjsInit)
176  {
177  for (auto& i : this->windObjs)
178  {
179 #if GAZEBO_MAJOR_VERSION >= 8
180  if ((!i.init) && (this->world->ModelByName(i.modelName)))
181  {
182 #else
183  if ((!i.init) && (this->world->GetModel(i.modelName)))
184  {
185 #endif
186  gzdbg << i.modelName << " initialized" << std::endl;
187  ++this->windObjsInitCount;
188  i.init = true;
189 #if GAZEBO_MAJOR_VERSION >= 8
190  i.model = this->world->ModelByName(i.modelName);
191 #else
192  i.model = this->world->GetModel(i.modelName);
193 #endif
194  i.link = i.model->GetLink(i.linkName);
195  if (!i.link)
196  {
197  gzdbg << i.modelName << "'s link name: " << i.linkName
198  << " is invalid" << std::endl;
199  }
200  }
201  }
202  if (windObjsInitCount == windObjs.size())
203  this->windObjsInit = true;
204  }
205 #if GAZEBO_MAJOR_VERSION >= 8
206  double currentTime = this->world->SimTime().Double();
207 #else
208  double currentTime = this->world->GetSimTime().Double();
209 #endif
210  double dT= currentTime - this->previousTime;
211  std::normal_distribution<double> dist(0, 1);
212  double randomDist = dist(*this->randGenerator);
213 
214  // Current variable wind velocity
215  this->varVel += 1.0/this->timeConstant*
216  (-1.0*this->varVel+this->filterGain/sqrt(dT)*randomDist)*dT;
217  // Current wind velocity
218  double velocity = this->varVel + this->windMeanVelocity;
219 
220  for (auto& windObj : this->windObjs)
221  {
222  // Apply the forces of the wind to all wind objects only if they have been
223  // initialized
224  if (!windObj.init || !windObj.link)
225  continue;
226 
227  // Transform wind from world coordinates to body coordinates
228 #if GAZEBO_MAJOR_VERSION >= 8
229  ignition::math::Vector3d relativeWind =
230  windObj.link->WorldPose().Rot().Inverse().RotateVector(
231  this->windDirection*velocity);
232 #else
233  ignition::math::Vector3d relativeWind =
234  windObj.link->GetWorldPose().rot.Ign().Inverse().RotateVector(
235  this->windDirection*velocity);
236 #endif
237  // Calculate apparent wind
238 #if GAZEBO_MAJOR_VERSION >= 8
239  ignition::math::Vector3d apparentWind =
240  relativeWind - windObj.link->RelativeLinearVel();
241 #else
242  ignition::math::Vector3d apparentWind = relativeWind
243  - windObj.link->GetRelativeLinearVel().Ign();
244 #endif
245 
246  // gzdbg << "Relative wind: " << relativeWind << std::endl;
247  // gzdbg << "Apparent wind: " << apparentWind << std::endl;
248 
249  // Calculate wind force - body coordinates
250  ignition::math::Vector3d windForce(
251  windObj.windCoeff.X() * relativeWind.X() * abs(relativeWind.X()),
252  windObj.windCoeff.Y() * relativeWind.Y() * abs(relativeWind.Y()),
253  -2.0 * windObj.windCoeff.Z() * relativeWind.X() * relativeWind.Y());
254 
255  // Add forces/torques to link at CG
256  windObj.link->AddRelativeForce(
257  ignition::math::Vector3d(windForce.X(), windForce.Y(), 0.0));
258  windObj.link->AddRelativeTorque(
259  ignition::math::Vector3d(0.0, 0.0, windForce.Z()));
260  }
261  // Moving the previous time one step forward.
262  this->previousTime = currentTime;
263 
264  double publishingBuffer = 1/this->updateRate;
265  if (this->updateRate >= 0)
266  {
267  publishingBuffer = 1/this->updateRate;
268  }
269  else
270  {
271  publishingBuffer = -1;
272  }
273  // Publishing the wind speed and direction
274  if ((currentTime - this->lastPublishTime > publishingBuffer) && this->debug)
275  {
276  std_msgs::Float64 windSpeedMsg;
277  std_msgs::Float64 windDirectionMsg;
278  windSpeedMsg.data = velocity;
279  windDirectionMsg.data =
280  atan2(this->windDirection[1], this->windDirection[0]) * 180 / M_PI;
281  this->windSpeedPub.publish(windSpeedMsg);
282  this->windDirectionPub.publish(windDirectionMsg);
283  this->lastPublishTime = currentTime;
284  }
285 }
286 
double windMeanVelocity
Average wind velocity.
bool debug
Bool debug set by environment var VRX_DEBUG
void publish(const boost::shared_ptr< M > &message) const
GZ_REGISTER_WORLD_PLUGIN(UsvWindPlugin)
physics::WorldPtr world
Pointer to the Gazebo world.
unsigned int windObjsInitCount
Bool to keep track if ALL of the windObjs have been initialized.
std::vector< UsvWindPlugin::WindObj > windObjs
vector of simple objects effected by the wind
std::unique_ptr< ros::NodeHandle > rosNode
ROS node handle.
double filterGain
Calculated filter gain constant.
double lastPublishTime
Last time wind speed and direction was published.
A plugin that simulates a simple wind model. It accepts the following parameters: ...
double updateRate
Update rate buffer for wind speed and direction.
ros::Publisher windSpeedPub
Publisher for wind speed.
ignition::math::Vector3d windDirection
Wind velocity unit vector in Gazebo coordinates [m/s].
double previousTime
Previous time.
std::string linkName
of the link on that model
event::ConnectionPtr updateConnection
Pointer to the update event connection.
double timeConstant
Time constant.
bool windObjsInit
Bool to keep track if ALL of the windObjs have been initialized.
double gainConstant
User specified gain constant.
virtual void Update()
Callback executed at every physics update.
std::unique_ptr< std::mt19937 > randGenerator
std::string topicWindDirection
Topic where the wind direction is published.
std::string topicWindSpeed
Topic where the wind speed is published.
double varVel
Variable velocity component.
ignition::math::Vector3d windCoeff
Wind force coefficients.
virtual void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
ros::Publisher windDirectionPub
Publisher for wind direction.


usv_gazebo_plugins
Author(s): Brian Bingham , Carlos Aguero
autogenerated on Thu May 7 2020 03:54:47