Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External torque estimation, URDF refining #41

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lwr_controllers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ project(lwr_controllers)
find_package(catkin REQUIRED COMPONENTS
controller_interface
control_msgs
geometry_msgs
forward_command_controller
control_toolbox
realtime_tools
Expand All @@ -12,6 +13,7 @@ find_package(catkin REQUIRED COMPONENTS
kdl_parser
message_generation
cmake_modules
kdl_conversions
)

include_directories(include ${Boost_INCLUDE_DIR} ${catkin_INCLUDE_DIRS})
Expand All @@ -23,6 +25,7 @@ add_message_files(
PoseRPY.msg
RPY.msg
MultiPriorityTask.msg
ArmState.msg
)

generate_messages(
Expand All @@ -35,6 +38,7 @@ catkin_package(
CATKIN_DEPENDS
controller_interface
control_msgs
geometry_msgs
control_toolbox
realtime_tools
urdf
Expand All @@ -58,6 +62,7 @@ add_library(${PROJECT_NAME}
src/dynamic_sliding_mode_controller_task_space.cpp
src/one_task_inverse_dynamics_jl.cpp
src/gravity_compensation.cpp
src/arm_state_controller.cpp
)

add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_gencpp)
Expand Down
48 changes: 48 additions & 0 deletions lwr_controllers/include/lwr_controllers/arm_state_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef ARM_STATE_CONTROLLER_H
#define ARM_STATE_CONTROLLER_H

#include "KinematicChainControllerBase.h"

#include <lwr_controllers/ArmState.h>
#include <std_msgs/Float32.h>
#include <std_msgs/Bool.h>

#include <realtime_tools/realtime_publisher.h>

#include <boost/scoped_ptr.hpp>

namespace arm_state_controller
{
class ArmStateController: public controller_interface::KinematicChainControllerBase<hardware_interface::JointStateInterface>
{
public:

ArmStateController();
~ArmStateController();

bool init(hardware_interface::JointStateInterface *robot, ros::NodeHandle &n);
void starting(const ros::Time& time);
void update(const ros::Time& time, const ros::Duration& period);
void stopping(const ros::Time& time);

private:

boost::shared_ptr< realtime_tools::RealtimePublisher< lwr_controllers::ArmState > > realtime_pub_;

boost::scoped_ptr<KDL::ChainIdSolver_RNE> id_solver_;
boost::scoped_ptr<KDL::ChainJntToJacSolver> jac_solver_;
boost::scoped_ptr<KDL::ChainFkSolverPos> fk_solver_;
boost::scoped_ptr<KDL::Jacobian> jacobian_;
boost::scoped_ptr<KDL::Vector> gravity_;
boost::scoped_ptr<KDL::JntArray> joint_position_;
boost::scoped_ptr<KDL::JntArray> joint_velocity_;
boost::scoped_ptr<KDL::JntArray> joint_acceleration_;
boost::scoped_ptr<KDL::Wrenches> joint_wrenches_;
boost::scoped_ptr<KDL::JntArray> joint_effort_est_;

ros::Time last_publish_time_;
double publish_rate_;
};
}

#endif
8 changes: 7 additions & 1 deletion lwr_controllers/lwr_controllers_plugins.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<library path="lib/liblwr_controllers">


<class name="arm_state_controller/ArmStateController" type="arm_state_controller::ArmStateController" base_class_type="controller_interface::ControllerBase">
<description>
Information about external torque, Jacobian, etc.
</description>
</class>

<class name="lwr_controllers/GravityCompensation" type="lwr_controllers::GravityCompensation" base_class_type="controller_interface::ControllerBase">
<description>
Safe gravity compensation.
Expand Down
6 changes: 6 additions & 0 deletions lwr_controllers/msg/ArmState.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Header header

string[] joint_name
float32[] est_ext_torques
geometry_msgs/Wrench est_ee_wrench
geometry_msgs/Wrench est_ee_wrench_base
6 changes: 4 additions & 2 deletions lwr_controllers/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

<build_depend>angles</build_depend>
<build_depend>controller_interface</build_depend>
<build_depend>control_msgs</build_depend>
<build_depend>control_msgs</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>control_toolbox</build_depend>
<build_depend>realtime_tools</build_depend>
<build_depend>urdf</build_depend>
Expand All @@ -25,7 +26,8 @@

<run_depend>angles</run_depend>
<run_depend>controller_interface</run_depend>
<run_depend>control_msgs</run_depend>
<run_depend>control_msgs</run_depend>
<run_depend>geometry_msgs</run_depend>
<run_depend>control_toolbox</run_depend>
<run_depend>realtime_tools</run_depend>
<run_depend>urdf</run_depend>
Expand Down
121 changes: 121 additions & 0 deletions lwr_controllers/src/arm_state_controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <pluginlib/class_list_macros.h>
#include <math.h>

#include <lwr_controllers/arm_state_controller.h>
#include <kdl_conversions/kdl_msg.h>
#include <utils/pseudo_inversion.h>
#include <control_toolbox/filters.h>

namespace arm_state_controller
{
ArmStateController::ArmStateController() {}
ArmStateController::~ArmStateController() {}

bool ArmStateController::init(hardware_interface::JointStateInterface *robot, ros::NodeHandle &n)
{
KinematicChainControllerBase<hardware_interface::JointStateInterface>::init(robot, n);

// get publishing period
if (!nh_.getParam("publish_rate", publish_rate_)) {
ROS_ERROR("Parameter 'publish_rate' not set");
return false;
}

realtime_pub_.reset(new realtime_tools::RealtimePublisher<lwr_controllers::ArmState>(nh_,"arm_state",4));
realtime_pub_->msg_.est_ext_torques.resize(kdl_chain_.getNrOfJoints());

gravity_.reset(new KDL::Vector(0.0, 0.0, -9.81)); // TODO: compute from actual robot position (TF?)
id_solver_.reset(new KDL::ChainIdSolver_RNE(kdl_chain_, *gravity_));
jac_solver_.reset(new KDL::ChainJntToJacSolver(kdl_chain_));
fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(kdl_chain_));
jacobian_.reset(new KDL::Jacobian(kdl_chain_.getNrOfJoints()));
joint_position_.reset(new KDL::JntArray(kdl_chain_.getNrOfJoints()));
joint_velocity_.reset(new KDL::JntArray(kdl_chain_.getNrOfJoints()));
joint_acceleration_.reset(new KDL::JntArray(kdl_chain_.getNrOfJoints()));
joint_wrenches_.reset(new KDL::Wrenches(kdl_chain_.getNrOfJoints()));
joint_effort_est_.reset(new KDL::JntArray(kdl_chain_.getNrOfJoints()));

return true;
}

void ArmStateController::starting(const ros::Time& time)
{
last_publish_time_ = time;
for (unsigned i = 0; i < joint_handles_.size(); i++){
(*joint_position_)(i) = joint_handles_[i].getPosition();
(*joint_velocity_)(i) = joint_handles_[i].getVelocity();
(*joint_acceleration_)(i) = 0;
}
ROS_INFO("started");
}

void ArmStateController::update(const ros::Time& time, const ros::Duration& period)
{
// limit rate of publishing
if (publish_rate_ > 0.0 && last_publish_time_ + ros::Duration(1.0/publish_rate_) < time){

if (realtime_pub_->trylock()) {
// we're actually publishing, so increment time
last_publish_time_ = last_publish_time_ + ros::Duration(1.0/publish_rate_);

for (unsigned i = 0; i < joint_handles_.size(); i++) {
float acceleration = filters::exponentialSmoothing((joint_handles_[i].getPosition() - (*joint_position_)(i))/period.toSec(), joint_handles_[i].getVelocity(), 0.2);
(*joint_position_)(i) = joint_handles_[i].getPosition();
(*joint_velocity_)(i) = joint_handles_[i].getVelocity();
(*joint_acceleration_)(i) = acceleration;
}

// Compute Dynamics
int ret = id_solver_->CartToJnt(*joint_position_,
*joint_velocity_,
*joint_acceleration_,
*joint_wrenches_,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I'm reviewing still...

According to the api, this joint_wrenches_ is an input, right? Where do you update it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you are using joint_wrenches_= 0 always, so it is just to estimate the torque at the joints from the model, is that it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, I think that the class you should use is ChainDynParam, I couldn't find a forward dynamic solver.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I use the inverse dynamics solver to find the expected joint torques given the current position, velocity and acceleration of the robot. Then I subtract the expected from the measured joint torques to find the estimated external joint torques.

So joint_wrenches is input, and I set it to zero to find the expected joint torques when there is no object applying a force on the robot.

I think that the inverse dynamics solver is a higher-level solver than ChainDynParam, and is closer to what we want. Or do you see any problem with this approach?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's fine, I was just wondering that if you never consider external forces (joint_wrenhes_ = 0), perhaps there was no need to use the solver, because you are not actually solving neither a FD nor an ID problem, also because the motion is measured not planned, but the numbers are the same as in an ID problem.

So, as you wish, no problem, let me know when to merge.

Though, I'd change the var name in case we ever use it, since it is not joint wrenches as if the joint generated the wrenches, but wrenches at the segments, I believe expressed in the corresponding joint frame from this, it doesn't say that, only:
f_ext The external forces (no gravity) on the segments Output parameters:
anyways, it is zero in our case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I'm still playing with it because today I get very crappy performance out of the controller. I don't know if I changed something wrong; in the meantime I realised that I was computing the acceleration in a very wrong way 😇 so I fixed it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I might have found the reason.. I think that the numerical stability was due to using the damped pseudo-inverse of the Jacobian. Somehow the change did not make it into the git commit.

I would say that we can test it a bit more, and then merge it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

*joint_effort_est_);
if (ret < 0) {
ROS_ERROR("KDL: inverse dynamics ERROR");
realtime_pub_->unlock();
return;
}

realtime_pub_->msg_.header.stamp = time;
for (unsigned i=0; i<joint_handles_.size(); i++) {
realtime_pub_->msg_.est_ext_torques[i] = joint_handles_[i].getEffort() - (*joint_effort_est_)(i);
}

// Compute cartesian wrench on end effector
ret = jac_solver_->JntToJac(*joint_position_, *jacobian_);
if (ret < 0) {
ROS_ERROR("KDL: jacobian computation ERROR");
realtime_pub_->unlock();
return;
}

Eigen::MatrixXd jinv;
pseudo_inverse(jacobian_->data.transpose(),jinv,false);

KDL::Wrench wrench;

for (unsigned int i = 0; i < 6; i++)
for (unsigned int j = 0; j < kdl_chain_.getNrOfJoints(); j++)
wrench[i] += jinv(i,j) * realtime_pub_->msg_.est_ext_torques[j];

tf::wrenchKDLToMsg(wrench, realtime_pub_->msg_.est_ee_wrench_base);

// Transform cartesian wrench into tool reference frame
KDL::Frame tool_frame;
fk_solver_->JntToCart(*joint_position_, tool_frame);
KDL::Wrench tool_wrench = tool_frame * wrench;

tf::wrenchKDLToMsg(tool_wrench, realtime_pub_->msg_.est_ee_wrench);

realtime_pub_->unlockAndPublish();
}
}
}

void ArmStateController::stopping(const ros::Time& time)
{}

}

PLUGINLIB_EXPORT_CLASS(arm_state_controller::ArmStateController, controller_interface::ControllerBase)
12 changes: 7 additions & 5 deletions lwr_description/model/kuka_lwr.urdf.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

<!-- properties /-->
<xacro:property name="base_mass" value="2.0"/>
<xacro:property name="link_mass" value="2.0"/>
<xacro:property name="link_mass" value="2.35"/>
<xacro:property name="wrist_mass" value="1.1"/>
<xacro:property name="tip_mass" value="0.25"/>
<xacro:property name="velocity_scale" value="1"/>
<xacro:property name="effort_scale" value="1"/>

Expand Down Expand Up @@ -344,9 +346,9 @@

<link name="${name}_6_link">
<inertial>
<mass value="0.2"/>
<mass value="${wrist_mass}"/>
<origin rpy="0 0 0" xyz="0 0 0.0625"/>
<cuboid_inertia_def length="0.125" width="0.125" height="0.125" mass="0.2"/>
<cuboid_inertia_def length="0.125" width="0.125" height="0.125" mass="${wrist_mass}"/>
</inertial>

<visual>
Expand Down Expand Up @@ -385,9 +387,9 @@

<link name="${name}_7_link">
<inertial>
<mass value="0.2"/>
<mass value="${tip_mass}"/>
<origin xyz="0 0 0"/>
<cuboid_inertia_def length="1" width="1" height="1" mass="0.2"/>
<cuboid_inertia_def length="0.1" width="0.1" height="0.1" mass="${tip_mass}"/>
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 ${M_PI}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
</group>

<!-- spawn only desired controllers in current namespace -->
<node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_state_controller $(arg controllers)"/>
<node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_state_controller ArmStateController $(arg controllers)"/>
</group>

</launch>
6 changes: 6 additions & 0 deletions single_lwr_example/single_lwr_robot/config/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ lwr:
- lwr_6_joint_stiffness

## OTHER CUSTOM CONTROLLERS LEFT HERE AS EXAMPLES
ArmStateController:
type: arm_state_controller/ArmStateController
root_name: lwr_base_link
tip_name: lwr_7_link
publish_rate: 30

GravityCompensation:
type: lwr_controllers/GravityCompensation
root_name: lwr_base_link
Expand Down