ppovb5fc7/gazebo/plugins/RandomVelocityPlugin.cc

182 lines
5.9 KiB
C++

/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <ignition/math/Rand.hh>
#include <gazebo/common/Events.hh>
#include <gazebo/common/Assert.hh>
#include <gazebo/physics/Model.hh>
#include <gazebo/physics/Link.hh>
#include "RandomVelocityPluginPrivate.hh"
#include "RandomVelocityPlugin.hh"
using namespace gazebo;
GZ_REGISTER_MODEL_PLUGIN(RandomVelocityPlugin)
/////////////////////////////////////////////////
RandomVelocityPlugin::RandomVelocityPlugin()
: dataPtr(new RandomVelocityPluginPrivate)
{
}
/////////////////////////////////////////////////
RandomVelocityPlugin::~RandomVelocityPlugin()
{
delete this->dataPtr;
}
/////////////////////////////////////////////////
void RandomVelocityPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
{
GZ_ASSERT(_model, "Model pointer is null");
// Make sure the link has been specified
if (!_sdf->HasElement("link"))
{
gzerr << "<link> element missing from RandomVelocity plugin. "
<< "The plugin will not function.\n";
return;
}
// Get the link;
this->dataPtr->link = _model->GetLink(_sdf->Get<std::string>("link"));
if (!this->dataPtr->link)
{
gzerr << "Unable to find link[" << _sdf->Get<std::string>("link") << "] "
<< "in model[" << _model->GetName() << "]. The RandomVelocity plugin "
<< "will not function.\n";
return;
}
// Get x clamping values
if (_sdf->HasElement("min_x"))
this->dataPtr->xRange.X(_sdf->Get<double>("min_x"));
if (_sdf->HasElement("max_x"))
this->dataPtr->xRange.Y(_sdf->Get<double>("max_x"));
// Make sure min <= max
//
// Analysis:
// min_x max_x | result_X result_Y
// ----------------------------------
// 0: 0 0 | 0 0
// 1: 1 0 | 0 1
// 2: 0 1 | 0 1
//
// Line 1 above is the error case, and can be handled different ways:
// a: Throw an exception
// b: Set both min and max values to the same value (either min_x or
// max_x)
// c: Fix it by swapping the values
// d: Do nothing, which would:
// i. First clamp the value to <= max_x
// ii. Second clamp the value to >= min_x
// iii. The result would always be the value of min_x
//
// We've opted for option c, which seems the most resonable.
ignition::math::Vector2d tmp = this->dataPtr->xRange;
this->dataPtr->xRange.X(std::min(tmp.X(), tmp.Y()));
this->dataPtr->xRange.Y(std::max(tmp.X(), tmp.Y()));
// Get y clamping values
if (_sdf->HasElement("min_y"))
this->dataPtr->yRange.X(_sdf->Get<double>("min_y"));
if (_sdf->HasElement("max_y"))
this->dataPtr->yRange.Y(_sdf->Get<double>("max_y"));
// Make sure min <= max
tmp = this->dataPtr->yRange;
this->dataPtr->yRange.X(std::min(tmp.X(), tmp.Y()));
this->dataPtr->yRange.Y(std::max(tmp.X(), tmp.Y()));
// Get z clamping values
if (_sdf->HasElement("min_z"))
this->dataPtr->zRange.X(_sdf->Get<double>("min_z"));
if (_sdf->HasElement("max_z"))
this->dataPtr->zRange.Y(_sdf->Get<double>("max_z"));
// Make sure min <= max
tmp = this->dataPtr->zRange;
this->dataPtr->zRange.X(std::min(tmp.X(), tmp.Y()));
this->dataPtr->zRange.Y(std::max(tmp.X(), tmp.Y()));
// Set the initial velocity, if present
if (_sdf->HasElement("initial_velocity"))
{
this->dataPtr->velocity =
_sdf->Get<ignition::math::Vector3d>("initial_velocity");
}
// Set the velocity factor
if (_sdf->HasElement("velocity_factor"))
this->dataPtr->velocityFactor = _sdf->Get<double>("velocity_factor");
// Set the update period
if (_sdf->HasElement("update_period"))
this->dataPtr->updatePeriod = _sdf->Get<double>("update_period");
// Connect to the world update signal
this->dataPtr->updateConnection = event::Events::ConnectWorldUpdateBegin(
std::bind(&RandomVelocityPlugin::Update, this, std::placeholders::_1));
}
/////////////////////////////////////////////////
void RandomVelocityPlugin::Reset()
{
this->dataPtr->prevUpdate.Set(0, 0);
}
/////////////////////////////////////////////////
void RandomVelocityPlugin::Update(const common::UpdateInfo &_info)
{
GZ_ASSERT(this->dataPtr->link, "<link> in RandomVelocity plugin is null");
// Short-circuit in case the link is invalid.
if (!this->dataPtr->link)
return;
// Change direction when enough time has elapsed
if (_info.simTime - this->dataPtr->prevUpdate > this->dataPtr->updatePeriod)
{
// Get a random velocity value.
this->dataPtr->velocity.Set(
ignition::math::Rand::DblUniform(-1, 1),
ignition::math::Rand::DblUniform(-1, 1),
ignition::math::Rand::DblUniform(-1, 1));
// Apply scaling factor
this->dataPtr->velocity.Normalize();
this->dataPtr->velocity *= this->dataPtr->velocityFactor;
// Clamp X value
this->dataPtr->velocity.X(ignition::math::clamp(this->dataPtr->velocity.X(),
this->dataPtr->xRange.X(), this->dataPtr->xRange.Y()));
// Clamp Y value
this->dataPtr->velocity.Y(ignition::math::clamp(this->dataPtr->velocity.Y(),
this->dataPtr->yRange.X(), this->dataPtr->yRange.Y()));
// Clamp Z value
this->dataPtr->velocity.Z(ignition::math::clamp(this->dataPtr->velocity.Z(),
this->dataPtr->zRange.X(), this->dataPtr->zRange.Y()));
this->dataPtr->prevUpdate = _info.simTime;
}
// Apply velocity
this->dataPtr->link->SetLinearVel(this->dataPtr->velocity);
}