diff --git a/franka_description/robots/panda_arm.urdf.xacro b/franka_description/robots/panda_arm.urdf.xacro
index d5b8d0061..490c941ba 100644
--- a/franka_description/robots/panda_arm.urdf.xacro
+++ b/franka_description/robots/panda_arm.urdf.xacro
@@ -4,6 +4,7 @@
+
@@ -44,13 +45,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
#include
#include
#include
@@ -29,6 +30,8 @@ namespace franka_gazebo {
* ### transmission_interface/SimpleTransmission
* - hardware_interface/JointStateInterface
* - hardware_interface/EffortJointInterface
+ * - hardware_interface/PositionJointInterface
+ * - hardware_interface/VelocityJointInterface
*
* ### franka_hw/FrankaStateInterface
* ### franka_hw/FrankaModelInterface
@@ -94,8 +97,14 @@ class FrankaHWSim : public gazebo_ros_control::RobotHWSim {
gazebo::physics::ModelPtr robot_;
std::map> joints_;
+ enum ControlMethod { EFFORT, POSITION, VELOCITY };
+ std::map joint_control_methods_;
+ std::map pid_controllers_;
+
hardware_interface::JointStateInterface jsi_;
hardware_interface::EffortJointInterface eji_;
+ hardware_interface::PositionJointInterface pji_;
+ hardware_interface::VelocityJointInterface vji_;
franka_hw::FrankaStateInterface fsi_;
franka_hw::FrankaModelInterface fmi_;
@@ -112,6 +121,8 @@ class FrankaHWSim : public gazebo_ros_control::RobotHWSim {
void initJointStateHandle(const std::shared_ptr& joint);
void initEffortCommandHandle(const std::shared_ptr& joint);
+ void initPositionCommandHandle(const std::shared_ptr& joint);
+ void initVelocityCommandHandle(const std::shared_ptr& joint);
void initFrankaStateHandle(const std::string& robot,
const urdf::Model& urdf,
const transmission_interface::TransmissionInfo& transmission);
diff --git a/franka_gazebo/include/franka_gazebo/joint.h b/franka_gazebo/include/franka_gazebo/joint.h
index 92ae7337c..99d587b79 100644
--- a/franka_gazebo/include/franka_gazebo/joint.h
+++ b/franka_gazebo/include/franka_gazebo/joint.h
@@ -1,6 +1,7 @@
#pragma once
#include
+#include
#include
#include
#include
@@ -35,6 +36,10 @@ struct Joint {
/// http://docs.ros.org/en/diamondback/api/urdf/html/classurdf_1_1Joint.html
int type;
+ /// Joint limits @see
+ /// https://docs.ros.org/en/diamondback/api/urdf/html/classurdf_1_1JointLimits.html
+ joint_limits_interface::JointLimits limits;
+
/// The axis of rotation/translation of this joint in local coordinates
Eigen::Vector3d axis;
diff --git a/franka_gazebo/launch/panda.launch b/franka_gazebo/launch/panda.launch
index 8cf57e5b2..c8d0c4ef6 100644
--- a/franka_gazebo/launch/panda.launch
+++ b/franka_gazebo/launch/panda.launch
@@ -12,6 +12,7 @@
+
@@ -42,6 +43,7 @@
gazebo:=true
hand:=$(arg use_gripper)
arm_id:=$(arg arm_id)
+ transmission:=$(arg transmission)
xyz:='$(arg x) $(arg y) $(arg z)'
rpy:='$(arg roll) $(arg pitch) $(arg yaw)'">
diff --git a/franka_gazebo/src/franka_hw_sim.cpp b/franka_gazebo/src/franka_hw_sim.cpp
index b2bf83162..3afa0bbd5 100644
--- a/franka_gazebo/src/franka_hw_sim.cpp
+++ b/franka_gazebo/src/franka_hw_sim.cpp
@@ -10,7 +10,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -76,6 +78,7 @@ bool FrankaHWSim::initSim(const std::string& robot_namespace,
return false;
}
joint->type = urdf_joint->type;
+ joint_limits_interface::getJointLimits(urdf_joint, joint->limits);
joint->axis = Eigen::Vector3d(urdf_joint->axis.x, urdf_joint->axis.y, urdf_joint->axis.z);
// Get a handle to the underlying Gazebo Joint
@@ -105,9 +108,37 @@ bool FrankaHWSim::initSim(const std::string& robot_namespace,
ROS_INFO_STREAM_NAMED("franka_hw_sim", "Found transmission interface of joint '"
<< joint->name << "': " << k_interface);
if (k_interface == "hardware_interface/EffortJointInterface") {
+ this->joint_control_methods_.emplace(joint->name, EFFORT);
+
initEffortCommandHandle(joint);
continue;
}
+ if (k_interface == "hardware_interface/PositionJointInterface") {
+ this->joint_control_methods_.emplace(joint->name, POSITION);
+
+ // Initiate position motion generator (PID controller)
+ const ros::NodeHandle posPidGainsNh(robot_namespace +
+ "/motion_generators/position/gains/" + joint->name);
+ control_toolbox::Pid pid;
+ this->pid_controllers_.emplace(joint->name, pid);
+ this->pid_controllers_[joint->name].init(posPidGainsNh);
+
+ initPositionCommandHandle(joint);
+ continue;
+ }
+ if (k_interface == "hardware_interface/VelocityJointInterface") {
+ this->joint_control_methods_.emplace(joint->name, VELOCITY);
+
+ // Initiate velocity motion generator (PID controller)
+ const ros::NodeHandle velPidGainsNh(robot_namespace +
+ "/motion_generators/velocity/gains/" + joint->name);
+ control_toolbox::Pid pid;
+ this->pid_controllers_.emplace(joint->name, pid);
+ this->pid_controllers_[joint->name].init(velPidGainsNh);
+
+ initVelocityCommandHandle(joint);
+ continue;
+ }
}
if (transmission.type_ == "franka_hw/FrankaStateInterface") {
@@ -142,6 +173,8 @@ bool FrankaHWSim::initSim(const std::string& robot_namespace,
// After all handles have been assigned to interfaces, register them
registerInterface(&this->eji_);
+ registerInterface(&this->pji_);
+ registerInterface(&this->vji_);
registerInterface(&this->jsi_);
registerInterface(&this->fsi_);
registerInterface(&this->fmi_);
@@ -162,6 +195,16 @@ void FrankaHWSim::initEffortCommandHandle(const std::shared_ptrjsi_.getHandle(joint->name), &joint->command));
}
+void FrankaHWSim::initPositionCommandHandle(const std::shared_ptr& joint) {
+ this->pji_.registerHandle(
+ hardware_interface::JointHandle(this->jsi_.getHandle(joint->name), &joint->command));
+}
+
+void FrankaHWSim::initVelocityCommandHandle(const std::shared_ptr& joint) {
+ this->vji_.registerHandle(
+ hardware_interface::JointHandle(this->jsi_.getHandle(joint->name), &joint->command));
+}
+
void FrankaHWSim::initFrankaStateHandle(
const std::string& robot,
const urdf::Model& urdf,
@@ -302,26 +345,63 @@ void FrankaHWSim::readSim(ros::Time time, ros::Duration period) {
this->updateRobotState(time);
}
-void FrankaHWSim::writeSim(ros::Time /*time*/, ros::Duration /*period*/) {
+void FrankaHWSim::writeSim(ros::Time /*time*/, ros::Duration period) {
auto g = this->model_->gravity(this->robot_state_);
for (auto& pair : this->joints_) {
auto joint = pair.second;
auto command = joint->command;
-
- // Check if this joint is affected by gravity compensation
- std::string prefix = this->arm_id_ + "_joint";
- if (pair.first.rfind(prefix, 0) != std::string::npos) {
- int i = std::stoi(pair.first.substr(prefix.size())) - 1;
- command += g.at(i);
+ auto& effort = command;
+
+ // Retrieve effort control command
+ switch (joint_control_methods_[joint->name]) {
+ case EFFORT: {
+ // Check if this joint is affected by gravity compensation
+ std::string prefix = this->arm_id_ + "_joint";
+ if (pair.first.rfind(prefix, 0) != std::string::npos) {
+ int i = std::stoi(pair.first.substr(prefix.size())) - 1;
+ command += g.at(i);
+ }
+ effort = command;
+ } break;
+ case POSITION: {
+ // Use position motion generator
+ double error;
+ const double jointLowerLimit_ = joint->limits.min_position;
+ const double jointUpperLimit_ = joint->limits.max_position;
+ switch (joint->type) {
+ case urdf::Joint::REVOLUTE:
+ angles::shortest_angular_distance_with_limits(
+ joint->position, command, jointLowerLimit_, jointUpperLimit_, error);
+ break;
+ case urdf::Joint::CONTINUOUS:
+ error = angles::shortest_angular_distance(joint->position, command);
+ break;
+ default:
+ error = command - joint->position;
+ }
+ const double effortLimit_ = joint->limits.max_effort;
+ effort =
+ boost::algorithm::clamp(pid_controllers_[joint->name].computeCommand(error, period),
+ -effortLimit_, effortLimit_);
+ } break;
+ case VELOCITY: {
+ // Use velocity motion generator
+ const double error = command - joint->velocity;
+ const double effortLimit_ = joint->limits.max_effort;
+ effort =
+ boost::algorithm::clamp(pid_controllers_[joint->name].computeCommand(error, period),
+ -effortLimit_, effortLimit_);
+ } break;
}
- if (std::isnan(command)) {
+ // Send control effort control command
+ if (std::isnan(effort)) {
ROS_WARN_STREAM_NAMED("franka_hw_sim",
"Command for " << joint->name << "is NaN, won't send to robot");
continue;
}
- joint->handle->SetForce(0, command);
+ joint->handle->SetForce(0, effort);
}
}