462 lines
13 KiB
C++
462 lines
13 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 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.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
||
|
// pulled in by anybody (e.g., Boost).
|
||
|
#include <Winsock2.h>
|
||
|
#endif
|
||
|
|
||
|
#include "gazebo/transport/Node.hh"
|
||
|
#include "gazebo/transport/Subscriber.hh"
|
||
|
#include "gazebo/physics/Model.hh"
|
||
|
#include "gazebo/physics/World.hh"
|
||
|
#include "gazebo/physics/Joint.hh"
|
||
|
#include "gazebo/physics/Link.hh"
|
||
|
#include "gazebo/physics/PhysicsEngine.hh"
|
||
|
|
||
|
#include "gazebo/physics/JointControllerPrivate.hh"
|
||
|
#include "gazebo/physics/JointController.hh"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
using namespace physics;
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
JointController::JointController(ModelPtr _model)
|
||
|
: dataPtr(new JointControllerPrivate)
|
||
|
{
|
||
|
this->dataPtr->model = _model;
|
||
|
|
||
|
if (this->dataPtr->model && this->dataPtr->model->GetWorld())
|
||
|
{
|
||
|
this->dataPtr->node = transport::NodePtr(new transport::Node());
|
||
|
this->dataPtr->node->Init(this->dataPtr->model->GetWorld()->GetName());
|
||
|
|
||
|
this->dataPtr->jointCmdSub = this->dataPtr->node->Subscribe(
|
||
|
std::string("~/") + this->dataPtr->model->GetName() + "/joint_cmd",
|
||
|
&JointController::OnJointCmd, this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gzwarn << "Unable to get world name. "
|
||
|
<< "JointController will not receive commands via messages\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
JointController::~JointController()
|
||
|
{
|
||
|
delete this->dataPtr;
|
||
|
this->dataPtr = NULL;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void JointController::AddJoint(JointPtr _joint)
|
||
|
{
|
||
|
this->dataPtr->joints[_joint->GetScopedName()] = _joint;
|
||
|
this->dataPtr->posPids[_joint->GetScopedName()].Init(
|
||
|
1, 0.1, 0.01, 1, -1, 1000, -1000);
|
||
|
this->dataPtr->velPids[_joint->GetScopedName()].Init(
|
||
|
1, 0.1, 0.01, 1, -1, 1000, -1000);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void JointController::RemoveJoint(Joint *_joint)
|
||
|
{
|
||
|
if (_joint)
|
||
|
{
|
||
|
this->dataPtr->joints.erase(_joint->GetScopedName());
|
||
|
this->dataPtr->posPids.erase(_joint->GetScopedName());
|
||
|
this->dataPtr->velPids.erase(_joint->GetScopedName());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void JointController::Reset()
|
||
|
{
|
||
|
// Reset setpoints and feed-forward.
|
||
|
this->dataPtr->positions.clear();
|
||
|
this->dataPtr->velocities.clear();
|
||
|
this->dataPtr->forces.clear();
|
||
|
|
||
|
std::map<std::string, common::PID>::iterator iter;
|
||
|
|
||
|
for (iter = this->dataPtr->posPids.begin();
|
||
|
iter != this->dataPtr->posPids.end(); ++iter)
|
||
|
{
|
||
|
iter->second.Reset();
|
||
|
}
|
||
|
|
||
|
for (iter = this->dataPtr->velPids.begin();
|
||
|
iter != this->dataPtr->velPids.end(); ++iter)
|
||
|
{
|
||
|
iter->second.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void JointController::Update()
|
||
|
{
|
||
|
common::Time currTime = this->dataPtr->model->GetWorld()->GetSimTime();
|
||
|
common::Time stepTime = currTime - this->dataPtr->prevUpdateTime;
|
||
|
this->dataPtr->prevUpdateTime = currTime;
|
||
|
|
||
|
// Skip the update step if SimTime appears to have gone backward.
|
||
|
// Negative update time wreaks havok on the integrators.
|
||
|
// This happens when World::ResetTime is called.
|
||
|
// TODO: fix this when World::ResetTime is improved
|
||
|
if (stepTime > 0)
|
||
|
{
|
||
|
if (!this->dataPtr->forces.empty())
|
||
|
{
|
||
|
std::map<std::string, double>::iterator iter;
|
||
|
for (iter = this->dataPtr->forces.begin();
|
||
|
iter != this->dataPtr->forces.end(); ++iter)
|
||
|
{
|
||
|
this->dataPtr->joints[iter->first]->SetForce(0, iter->second);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!this->dataPtr->positions.empty())
|
||
|
{
|
||
|
std::map<std::string, double>::iterator iter;
|
||
|
|
||
|
for (iter = this->dataPtr->positions.begin();
|
||
|
iter != this->dataPtr->positions.end(); ++iter)
|
||
|
{
|
||
|
double cmd = this->dataPtr->posPids[iter->first].Update(
|
||
|
this->dataPtr->joints[iter->first]->GetAngle(0).Radian() -
|
||
|
iter->second, stepTime);
|
||
|
this->dataPtr->joints[iter->first]->SetForce(0, cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!this->dataPtr->velocities.empty())
|
||
|
{
|
||
|
std::map<std::string, double>::iterator iter;
|
||
|
|
||
|
for (iter = this->dataPtr->velocities.begin();
|
||
|
iter != this->dataPtr->velocities.end(); ++iter)
|
||
|
{
|
||
|
double cmd = this->dataPtr->velPids[iter->first].Update(
|
||
|
this->dataPtr->joints[iter->first]->GetVelocity(0) - iter->second,
|
||
|
stepTime);
|
||
|
this->dataPtr->joints[iter->first]->SetForce(0, cmd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* enable below if we want to set position kinematically
|
||
|
if (this->dataPtr->positions.size() > 0)
|
||
|
{
|
||
|
std::map<std::string, JointPtr>::iterator iter;
|
||
|
for (iter = this->dataPtr->joints.begin();
|
||
|
iter != this->dataPtr->joints.end(); ++iter)
|
||
|
{
|
||
|
if (this->dataPtr->positions.find(iter->first) ==
|
||
|
this->dataPtr->positions.end())
|
||
|
{
|
||
|
this->dataPtr->positions[iter->first] =
|
||
|
iter->second->GetAngle(0).Radian();
|
||
|
}
|
||
|
}
|
||
|
this->SetJointPositions(this->dataPtr->positions);
|
||
|
this->dataPtr->positions.clear();
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void JointController::OnJointCmd(ConstJointCmdPtr &_msg)
|
||
|
{
|
||
|
std::map<std::string, JointPtr>::iterator iter;
|
||
|
iter = this->dataPtr->joints.find(_msg->name());
|
||
|
if (iter != this->dataPtr->joints.end())
|
||
|
{
|
||
|
if (_msg->has_reset() && _msg->reset())
|
||
|
{
|
||
|
if (this->dataPtr->forces.find(_msg->name()) !=
|
||
|
this->dataPtr->forces.end())
|
||
|
{
|
||
|
this->dataPtr->forces.erase(this->dataPtr->forces.find(_msg->name()));
|
||
|
}
|
||
|
|
||
|
if (this->dataPtr->positions.find(_msg->name()) !=
|
||
|
this->dataPtr->positions.end())
|
||
|
{
|
||
|
this->dataPtr->positions.erase(
|
||
|
this->dataPtr->positions.find(_msg->name()));
|
||
|
}
|
||
|
|
||
|
if (this->dataPtr->velocities.find(_msg->name()) !=
|
||
|
this->dataPtr->velocities.end())
|
||
|
{
|
||
|
this->dataPtr->velocities.erase(
|
||
|
this->dataPtr->velocities.find(_msg->name()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_msg->has_force())
|
||
|
this->dataPtr->forces[_msg->name()] = _msg->force();
|
||
|
|
||
|
if (_msg->has_position())
|
||
|
{
|
||
|
if (_msg->position().has_target())
|
||
|
{
|
||
|
if (!this->SetPositionTarget(_msg->name(), _msg->position().target()))
|
||
|
{
|
||
|
gzerr << "Unable to set position target for joint["
|
||
|
<< _msg->name() << "]. Joint is not found.\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_p_gain())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetPGain(
|
||
|
_msg->position().p_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_i_gain())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetIGain(
|
||
|
_msg->position().i_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_d_gain())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetDGain(
|
||
|
_msg->position().d_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_i_max())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetIMax(_msg->position().i_max());
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_i_min())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetIMin(_msg->position().i_min());
|
||
|
}
|
||
|
|
||
|
if (_msg->position().has_limit())
|
||
|
{
|
||
|
this->dataPtr->posPids[_msg->name()].SetCmdMax(
|
||
|
_msg->position().limit());
|
||
|
this->dataPtr->posPids[_msg->name()].SetCmdMin(
|
||
|
-_msg->position().limit());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_msg->has_velocity())
|
||
|
{
|
||
|
if (_msg->velocity().has_target())
|
||
|
{
|
||
|
if (!this->SetVelocityTarget(_msg->name(), _msg->velocity().target()))
|
||
|
{
|
||
|
gzerr << "Unable to set velocity target for joint["
|
||
|
<< _msg->name() << "]. Joint is not found.\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_p_gain())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetPGain(
|
||
|
_msg->velocity().p_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_i_gain())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetIGain(
|
||
|
_msg->velocity().i_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_d_gain())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetDGain(
|
||
|
_msg->velocity().d_gain());
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_i_max())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetIMax(_msg->velocity().i_max());
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_i_min())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetIMin(_msg->velocity().i_min());
|
||
|
}
|
||
|
|
||
|
if (_msg->velocity().has_limit())
|
||
|
{
|
||
|
this->dataPtr->velPids[_msg->name()].SetCmdMax(
|
||
|
_msg->velocity().limit());
|
||
|
this->dataPtr->velPids[_msg->name()].SetCmdMin(
|
||
|
-_msg->velocity().limit());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
gzerr << "Unable to find joint[" << _msg->name() << "]\n";
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void JointController::SetJointPosition(const std::string & _name,
|
||
|
double _position, int _index)
|
||
|
{
|
||
|
std::map<std::string, JointPtr>::iterator jiter =
|
||
|
this->dataPtr->joints.find(_name);
|
||
|
|
||
|
if (jiter != this->dataPtr->joints.end())
|
||
|
this->SetJointPosition(jiter->second, _position, _index);
|
||
|
else
|
||
|
gzwarn << "SetJointPosition [" << _name << "] not found\n";
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void JointController::SetJointPositions(
|
||
|
const std::map<std::string, double> & _jointPositions)
|
||
|
{
|
||
|
// go through all joints in this model and update each one
|
||
|
// for each joint update, recursively update all children
|
||
|
std::map<std::string, JointPtr>::iterator iter;
|
||
|
std::map<std::string, double>::const_iterator jiter;
|
||
|
|
||
|
for (iter = this->dataPtr->joints.begin();
|
||
|
iter != this->dataPtr->joints.end(); ++iter)
|
||
|
{
|
||
|
// First try name without scope, i.e. joint_name
|
||
|
jiter = _jointPositions.find(iter->second->GetName());
|
||
|
|
||
|
if (jiter == _jointPositions.end())
|
||
|
{
|
||
|
// Second try name with scope, i.e. model_name::joint_name
|
||
|
jiter = _jointPositions.find(iter->second->GetScopedName());
|
||
|
if (jiter == _jointPositions.end())
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
this->SetJointPosition(iter->second, jiter->second);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void JointController::SetJointPosition(
|
||
|
JointPtr _joint, double _position, int _index)
|
||
|
{
|
||
|
_joint->SetPosition(_index, _position);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
common::Time JointController::GetLastUpdateTime() const
|
||
|
{
|
||
|
return this->dataPtr->prevUpdateTime;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, JointPtr> JointController::GetJoints() const
|
||
|
{
|
||
|
return this->dataPtr->joints;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, common::PID> JointController::GetPositionPIDs() const
|
||
|
{
|
||
|
return this->dataPtr->posPids;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, common::PID> JointController::GetVelocityPIDs() const
|
||
|
{
|
||
|
return this->dataPtr->velPids;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, double> JointController::GetForces() const
|
||
|
{
|
||
|
return this->dataPtr->forces;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, double> JointController::GetPositions() const
|
||
|
{
|
||
|
return this->dataPtr->positions;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::map<std::string, double> JointController::GetVelocities() const
|
||
|
{
|
||
|
return this->dataPtr->velocities;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void JointController::SetPositionPID(const std::string &_jointName,
|
||
|
const common::PID &_pid)
|
||
|
{
|
||
|
std::map<std::string, JointPtr>::iterator iter;
|
||
|
iter = this->dataPtr->joints.find(_jointName);
|
||
|
|
||
|
if (iter != this->dataPtr->joints.end())
|
||
|
this->dataPtr->posPids[_jointName] = _pid;
|
||
|
else
|
||
|
gzerr << "Unable to find joint with name[" << _jointName << "]\n";
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
bool JointController::SetPositionTarget(const std::string &_jointName,
|
||
|
double _target)
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (this->dataPtr->posPids.find(_jointName) !=
|
||
|
this->dataPtr->posPids.end())
|
||
|
{
|
||
|
this->dataPtr->positions[_jointName] = _target;
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void JointController::SetVelocityPID(const std::string &_jointName,
|
||
|
const common::PID &_pid)
|
||
|
{
|
||
|
std::map<std::string, JointPtr>::iterator iter;
|
||
|
iter = this->dataPtr->joints.find(_jointName);
|
||
|
|
||
|
if (iter != this->dataPtr->joints.end())
|
||
|
this->dataPtr->velPids[_jointName] = _pid;
|
||
|
else
|
||
|
gzerr << "Unable to find joint with name[" << _jointName << "]\n";
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
bool JointController::SetVelocityTarget(const std::string &_jointName,
|
||
|
double _target)
|
||
|
{
|
||
|
bool result = false;
|
||
|
|
||
|
if (this->dataPtr->velPids.find(_jointName) !=
|
||
|
this->dataPtr->velPids.end())
|
||
|
{
|
||
|
this->dataPtr->velocities[_jointName] = _target;
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|