liftdrag_plugin.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014-2016 Open Source Robotics Foundation
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *
00016 */
00017 
00018 #include <algorithm>
00019 #include <string>
00020 
00021 #include "gazebo/common/Assert.hh"
00022 #include "gazebo/physics/physics.hh"
00023 #include "gazebo/sensors/SensorManager.hh"
00024 #include "gazebo/transport/transport.hh"
00025 #include "gazebo/msgs/msgs.hh"
00026 #include "liftdrag_plugin/liftdrag_plugin.h"
00027 
00028 using namespace gazebo;
00029 
00030 GZ_REGISTER_MODEL_PLUGIN(LiftDragPlugin)
00031 
00032 
00033 LiftDragPlugin::LiftDragPlugin() : cla(1.0), cda(0.01), cma(0.01), rho(1.2041)
00034 {
00035   this->cp = ignition::math::Vector3d (0, 0, 0);
00036   this->forward = ignition::math::Vector3d (1, 0, 0);
00037   this->upward = ignition::math::Vector3d (0, 0, 1);
00038   this->area = 1.0;
00039   this->alpha0 = 0.0;
00040   this->alpha = 0.0;
00041   this->sweep = 0.0;
00042   this->velocityStall = 0.0;
00043 
00044   // 90 deg stall
00045   this->alphaStall = 0.5*M_PI;
00046   this->claStall = 0.0;
00047 
00048   this->radialSymmetry = false;
00049 
00051   this->cdaStall = 1.0;
00052   this->cmaStall = 0.0;
00053 
00055   this->controlJointRadToCL = 4.0;
00056 }
00057 
00059 LiftDragPlugin::~LiftDragPlugin()
00060 {
00061 }
00062 
00064 void LiftDragPlugin::Load(physics::ModelPtr _model,
00065                      sdf::ElementPtr _sdf)
00066 {
00067   GZ_ASSERT(_model, "LiftDragPlugin _model pointer is NULL");
00068   GZ_ASSERT(_sdf, "LiftDragPlugin _sdf pointer is NULL");
00069   this->model = _model;
00070   this->sdf = _sdf;
00071 
00072   this->world = this->model->GetWorld();
00073   GZ_ASSERT(this->world, "LiftDragPlugin world pointer is NULL");
00074 
00075   this->physics = this->world->Physics();
00076   GZ_ASSERT(this->physics, "LiftDragPlugin physics pointer is NULL");
00077 
00078   GZ_ASSERT(_sdf, "LiftDragPlugin _sdf pointer is NULL");
00079 
00080   if (_sdf->HasElement("radial_symmetry"))
00081     this->radialSymmetry = _sdf->Get<bool>("radial_symmetry");
00082 
00083   if (_sdf->HasElement("a0"))
00084     this->alpha0 = _sdf->Get<double>("a0");
00085 
00086   if (_sdf->HasElement("cla"))
00087     this->cla = _sdf->Get<double>("cla");
00088 
00089   if (_sdf->HasElement("cda"))
00090     this->cda = _sdf->Get<double>("cda");
00091 
00092   if (_sdf->HasElement("cma"))
00093     this->cma = _sdf->Get<double>("cma");
00094 
00095   if (_sdf->HasElement("alpha_stall"))
00096     this->alphaStall = _sdf->Get<double>("alpha_stall");
00097 
00098   if (_sdf->HasElement("cla_stall"))
00099     this->claStall = _sdf->Get<double>("cla_stall");
00100 
00101   if (_sdf->HasElement("cda_stall"))
00102     this->cdaStall = _sdf->Get<double>("cda_stall");
00103 
00104   if (_sdf->HasElement("cma_stall"))
00105     this->cmaStall = _sdf->Get<double>("cma_stall");
00106 
00107   if (_sdf->HasElement("cp"))
00108     this->cp = _sdf->Get<ignition::math::Vector3d >("cp");
00109 
00110   // blade forward (-drag) direction in link frame
00111   if (_sdf->HasElement("forward"))
00112     this->forward = _sdf->Get<ignition::math::Vector3d >("forward");
00113   this->forward.Normalize();
00114 
00115   // blade upward (+lift) direction in link frame
00116   if (_sdf->HasElement("upward"))
00117     this->upward = _sdf->Get<ignition::math::Vector3d >("upward");
00118   this->upward.Normalize();
00119 
00120   if (_sdf->HasElement("area"))
00121     this->area = _sdf->Get<double>("area");
00122 
00123   if (_sdf->HasElement("air_density"))
00124     this->rho = _sdf->Get<double>("air_density");
00125 
00126   if (_sdf->HasElement("link_name"))
00127   {
00128     sdf::ElementPtr elem = _sdf->GetElement("link_name");
00129     // GZ_ASSERT(elem, "Element link_name doesn't exist!");
00130     std::string linkName = elem->Get<std::string>();
00131     this->link = this->model->GetLink(linkName);
00132     // GZ_ASSERT(this->link, "Link was NULL");
00133 
00134     if (!this->link)
00135     {
00136       gzerr << "Link with name[" << linkName << "] not found. "
00137         << "The LiftDragPlugin will not generate forces\n";
00138     }
00139     else
00140     {
00141       this->updateConnection = event::Events::ConnectWorldUpdateBegin(
00142           boost::bind(&LiftDragPlugin::OnUpdate, this));
00143     }
00144   }
00145 
00146   if (_sdf->HasElement("control_joint_name"))
00147   {
00148     std::string controlJointName = _sdf->Get<std::string>("control_joint_name");
00149     this->controlJoint = this->model->GetJoint(controlJointName);
00150     if (!this->controlJoint)
00151     {
00152       gzerr << "Joint with name[" << controlJointName << "] does not exist.\n";
00153     }
00154   }
00155 
00156   if (_sdf->HasElement("control_joint_rad_to_cl"))
00157     this->controlJointRadToCL = _sdf->Get<double>("control_joint_rad_to_cl");
00158 }
00159 
00161 void LiftDragPlugin::OnUpdate()
00162 {
00163   GZ_ASSERT(this->link, "Link was NULL");
00164   // get linear velocity at cp in inertial frame
00165   ignition::math::Vector3d vel = this->link->WorldLinearVel(this->cp);
00166   ignition::math::Vector3d velI = vel;
00167   velI.Normalize();
00168 
00169   // smoothing
00170   // double e = 0.8;
00171   // this->velSmooth = e*vel + (1.0 - e)*velSmooth;
00172   // vel = this->velSmooth;
00173 
00174   if (vel.Length() <= 0.01)
00175     return;
00176 
00177   // pose of body
00178   ignition::math::Pose3d pose = this->link->WorldPose();
00179 
00180   // rotate forward and upward vectors into inertial frame
00181   ignition::math::Vector3d forwardI = pose.Rot().RotateVector(this->forward);
00182 
00183   ignition::math::Vector3d upwardI;
00184   if (this->radialSymmetry)
00185   {
00186     // use inflow velocity to determine upward direction
00187     // which is the component of inflow perpendicular to forward direction.
00188     ignition::math::Vector3d tmp = forwardI.Cross(velI);
00189     upwardI = forwardI.Cross(tmp).Normalize();
00190   }
00191   else
00192   {
00193     upwardI = pose.Rot().RotateVector(this->upward);
00194   }
00195 
00196   // spanwiseI: a vector normal to lift-drag-plane described in inertial frame
00197   ignition::math::Vector3d spanwiseI = forwardI.Cross(upwardI).Normalize();
00198 
00199   const double minRatio = -1.0;
00200   const double maxRatio = 1.0;
00201   // check sweep (angle between velI and lift-drag-plane)
00202   double sinSweepAngle = ignition::math::clamp(
00203       spanwiseI.Dot(velI), minRatio, maxRatio);
00204 
00205   // get cos from trig identity
00206   double cosSweepAngle = 1.0 - sinSweepAngle * sinSweepAngle;
00207   this->sweep = asin(sinSweepAngle);
00208 
00209   // truncate sweep to within +/-90 deg
00210   while (fabs(this->sweep) > 0.5 * M_PI)
00211     this->sweep = this->sweep > 0 ? this->sweep - M_PI
00212                                   : this->sweep + M_PI;
00213 
00214   // angle of attack is the angle between
00215   // velI projected into lift-drag plane
00216   //  and
00217   // forward vector
00218   //
00219   // projected = spanwiseI Xcross ( vector Xcross spanwiseI)
00220   //
00221   // so,
00222   // removing spanwise velocity from vel
00223   ignition::math::Vector3d velInLDPlane = vel - vel.Dot(spanwiseI)*velI;
00224 
00225   // get direction of drag
00226   ignition::math::Vector3d dragDirection = -velInLDPlane;
00227   dragDirection.Normalize();
00228 
00229   // get direction of lift
00230   ignition::math::Vector3d liftI = spanwiseI.Cross(velInLDPlane);
00231   liftI.Normalize();
00232 
00233   // get direction of moment
00234   ignition::math::Vector3d momentDirection = spanwiseI;
00235 
00236   // compute angle between upwardI and liftI
00237   // in general, given vectors a and b:
00238   //   cos(theta) = a.Dot(b)/(a.Length()*b.Lenghth())
00239   // given upwardI and liftI are both unit vectors, we can drop the denominator
00240   //   cos(theta) = a.Dot(b)
00241   double cosAlpha = ignition::math::clamp(liftI.Dot(upwardI), minRatio, maxRatio);
00242 
00243   // Is alpha positive or negative? Test:
00244   // forwardI points toward zero alpha
00245   // if forwardI is in the same direction as lift, alpha is positive.
00246   // liftI is in the same direction as forwardI?
00247   if (liftI.Dot(forwardI) >= 0.0)
00248     this->alpha = this->alpha0 + acos(cosAlpha);
00249   else
00250     this->alpha = this->alpha0 - acos(cosAlpha);
00251 
00252   // normalize to within +/-90 deg
00253   while (fabs(this->alpha) > 0.5 * M_PI)
00254     this->alpha = this->alpha > 0 ? this->alpha - M_PI
00255                                   : this->alpha + M_PI;
00256 
00257   // compute dynamic pressure
00258   double speedInLDPlane = velInLDPlane.Length();
00259   double q = 0.5 * this->rho * speedInLDPlane * speedInLDPlane;
00260 
00261   // compute cl at cp, check for stall, correct for sweep
00262   double cl;
00263   if (this->alpha > this->alphaStall)
00264   {
00265     cl = (this->cla * this->alphaStall +
00266           this->claStall * (this->alpha - this->alphaStall))
00267          * cosSweepAngle;
00268     // make sure cl is still great than 0
00269     cl = std::max(0.0, cl);
00270   }
00271   else if (this->alpha < -this->alphaStall)
00272   {
00273     cl = (-this->cla * this->alphaStall +
00274           this->claStall * (this->alpha + this->alphaStall))
00275          * cosSweepAngle;
00276     // make sure cl is still less than 0
00277     cl = std::min(0.0, cl);
00278   }
00279   else
00280     cl = this->cla * this->alpha * cosSweepAngle;
00281 
00282   // modify cl per control joint value
00283   if (this->controlJoint)
00284   {
00285     double controlAngle = this->controlJoint->Position(0);
00286     cl = cl + this->controlJointRadToCL * controlAngle;
00288   }
00289 
00290   // compute lift force at cp
00291   ignition::math::Vector3d lift = cl * q * this->area * liftI;
00292 
00293   // compute cd at cp, check for stall, correct for sweep
00294   double cd;
00295   if (this->alpha > this->alphaStall)
00296   {
00297     cd = (this->cda * this->alphaStall +
00298           this->cdaStall * (this->alpha - this->alphaStall))
00299          * cosSweepAngle;
00300   }
00301   else if (this->alpha < -this->alphaStall)
00302   {
00303     cd = (-this->cda * this->alphaStall +
00304           this->cdaStall * (this->alpha + this->alphaStall))
00305          * cosSweepAngle;
00306   }
00307   else
00308     cd = (this->cda * this->alpha) * cosSweepAngle;
00309 
00310   // make sure drag is positive
00311   cd = fabs(cd);
00312 
00313   // drag at cp
00314   ignition::math::Vector3d drag = cd * q * this->area * dragDirection;
00315 
00316   // compute cm at cp, check for stall, correct for sweep
00317   double cm;
00318   if (this->alpha > this->alphaStall)
00319   {
00320     cm = (this->cma * this->alphaStall +
00321           this->cmaStall * (this->alpha - this->alphaStall))
00322          * cosSweepAngle;
00323     // make sure cm is still great than 0
00324     cm = std::max(0.0, cm);
00325   }
00326   else if (this->alpha < -this->alphaStall)
00327   {
00328     cm = (-this->cma * this->alphaStall +
00329           this->cmaStall * (this->alpha + this->alphaStall))
00330          * cosSweepAngle;
00331     // make sure cm is still less than 0
00332     cm = std::min(0.0, cm);
00333   }
00334   else
00335     cm = this->cma * this->alpha * cosSweepAngle;
00336 
00339   cm = 0.0;
00340 
00341   // compute moment (torque) at cp
00342   ignition::math::Vector3d moment = cm * q * this->area * momentDirection;
00343 
00344   // moment arm from cg to cp in inertial plane
00345   ignition::math::Vector3d momentArm = pose.Rot().RotateVector(
00346     this->cp - this->link->GetInertial()->CoG());
00347   // gzerr << this->cp << " : " << this->link->GetInertial()->GetCoG() << "\n";
00348 
00349   // force and torque about cg in inertial frame
00350   ignition::math::Vector3d force = lift + drag;
00351   // + moment.Cross(momentArm);
00352 
00353   ignition::math::Vector3d torque = moment;
00354   // - lift.Cross(momentArm) - drag.Cross(momentArm);
00355 
00356   // debug
00357   //
00358   // if ((this->link->GetName() == "wing_1" ||
00359   //      this->link->GetName() == "wing_2") &&
00360   //     (vel.GetLength() > 50.0 &&
00361   //      vel.GetLength() < 50.0))
00362   if (0)
00363   {
00364     gzdbg << "=============================\n";
00365     gzdbg << "sensor: [" << this->GetHandle() << "]\n";
00366     gzdbg << "Link: [" << this->link->GetName()
00367           << "] pose: [" << pose
00368           << "] dynamic pressure: [" << q << "]\n";
00369     gzdbg << "spd: [" << vel.Length()
00370           << "] vel: [" << vel << "]\n";
00371     gzdbg << "LD plane spd: [" << velInLDPlane.Length()
00372           << "] vel : [" << velInLDPlane << "]\n";
00373     gzdbg << "forward (inertial): " << forwardI << "\n";
00374     gzdbg << "upward (inertial): " << upwardI << "\n";
00375     gzdbg << "lift dir (inertial): " << liftI << "\n";
00376     gzdbg << "Span direction (normal to LD plane): " << spanwiseI << "\n";
00377     gzdbg << "sweep: " << this->sweep << "\n";
00378     gzdbg << "alpha: " << this->alpha << "\n";
00379     gzdbg << "lift: " << lift << "\n";
00380     gzdbg << "drag: " << drag << " cd: "
00381           << cd << " cda: " << this->cda << "\n";
00382     gzdbg << "moment: " << moment << "\n";
00383     gzdbg << "cp momentArm: " << momentArm << "\n";
00384     gzdbg << "force: " << force << "\n";
00385     gzdbg << "torque: " << torque << "\n";
00386   }
00387 
00388   // Correct for nan or inf
00389   force.Correct();
00390   this->cp.Correct();
00391   torque.Correct();
00392 
00393   // apply forces at cg (with torques for position shift)
00394   this->link->AddForceAtRelativePosition(force, this->cp);
00395   this->link->AddTorque(torque);
00396 }


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Thu Apr 18 2019 02:43:43