virtual_force_publisher.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, JSK, The University of Tokyo.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Kei Okada */
36 
37 #include <boost/scoped_ptr.hpp>
38 #include <ros/ros.h>
39 #include <urdf/model.h>
40 #include <kdl/tree.hpp>
41 #include <kdl/chainjnttojacsolver.hpp>
43 #include <tf_conversions/tf_kdl.h>
44 #include <geometry_msgs/WrenchStamped.h>
45 #include <sensor_msgs/JointState.h>
46 #include <tf/transform_listener.h>
47 #include <Eigen/Core>
48 #include <Eigen/Geometry>
49 
51 
53 
55  {
56  private:
60  boost::scoped_ptr<KDL::ChainJntToJacSolver> jnt_to_jac_solver_;
63  std::string root, tip;
64 
66  std::map<std::string, ros::Time> last_publish_time_;
67  double t_const_;
70  public:
71 
73  {
74  ros::NodeHandle n_tilde("~");
76 
77  // subscribe to joint state
78  joint_state_sub_ = n.subscribe("joint_states", 1, &VirtualForcePublisher::callbackJointState, this);
79  wrench_stamped_pub_ = n.advertise<geometry_msgs::WrenchStamped>("wrench", 1);
80 
81  // set publish frequency
82  double publish_freq;
83  n_tilde.param("publish_frequency", publish_freq, 50.0);
84  publish_interval_ = ros::Duration(1.0/std::max(publish_freq,1.0));
85 
86  //set time constant of low pass filter
87  n_tilde.param("time_constant", t_const_, 0.3);
88  // set root and tip
89  n_tilde.param("root", root, std::string("torso_lift_link"));
90  n_tilde.param("tip", tip, std::string("l_gripper_tool_frame"));
91 
92  // load robot model
93  urdf::Model robot_model;
94  robot_model.initParam("robot_description");
95 
96  KDL::Tree kdl_tree;
97  kdl_parser::treeFromUrdfModel(robot_model, kdl_tree);
98  kdl_tree.getChain(root, tip, chain_);
99  jnt_to_jac_solver_.reset(new KDL::ChainJntToJacSolver(chain_));
100 
101  jnt_pos_.resize(chain_.getNrOfJoints());
102  jacobian_.resize(chain_.getNrOfJoints());
103 
104  for (size_t i=0; i<chain_.getNrOfSegments(); i++){
105  if (chain_.getSegment(i).getJoint().getType() != KDL::Joint::None){
106  std::cerr << "kdl_chain(" << i << ") " << chain_.getSegment(i).getJoint().getName().c_str() << std::endl;
107  }
108  }
109  }
111 
113  {
114  std::map<std::string, double> joint_name_position;
115  if (state->name.size() != state->position.size()){
116  ROS_ERROR("Robot state publisher received an invalid joint state vector");
117  return;
118  }
119 
120  // determine least recently published joint
121  ros::Time last_published = ros::Time::now();
122  for (unsigned int i=0; i<state->name.size(); i++) {
123  ros::Time t = last_publish_time_[state->name[i]];
124  last_published = (t < last_published) ? t : last_published;
125  }
126 
127  if (state->header.stamp >= last_published + publish_interval_){
128  // get joint positions from state message
129  std::map<std::string, double> joint_positions;
130  std::map<std::string, double> joint_efforts;
131  for (unsigned int i=0; i<state->name.size(); i++) {
132  joint_positions.insert(make_pair(state->name[i], state->position[i]));
133  joint_efforts.insert(make_pair(state->name[i], state->effort[i]));
134  }
135 
136  KDL::JntArray tau;
137  KDL::Wrench F;
138  Eigen::Matrix<double,Eigen::Dynamic,6> jac_t;
139  Eigen::Matrix<double,6,Eigen::Dynamic> jac_t_pseudo_inv;
140  tf::StampedTransform transform;
141  KDL::Wrench F_pub;
142  tf::Vector3 tf_force;
143  tf::Vector3 tf_torque;
144 
145  tau.resize(chain_.getNrOfJoints());
146 
147  //getPositions;
148  for (size_t i=0, j=0; i<chain_.getNrOfSegments(); i++){
149  if (chain_.getSegment(i).getJoint().getType() == KDL::Joint::None)
150  continue;
151 
152  // check
153  std::string joint_name = chain_.getSegment(i).getJoint().getName();
154  if ( joint_positions.find(joint_name) == joint_positions.end() ) {
155  ROS_ERROR("Joint '%s' is not found in joint state vector", joint_name.c_str());
156  }
157 
158  // set position
159  jnt_pos_(j) = joint_positions[joint_name];
160  tau(j) = joint_efforts[joint_name];
161  j++;
162  }
163 
164  jnt_to_jac_solver_->JntToJac(jnt_pos_, jacobian_);
165  jac_t = jacobian_.data.transpose();
166  if ( jacobian_.columns() >= jacobian_.rows() ) {
167  jac_t_pseudo_inv =(jac_t.transpose() * jac_t).inverse() * jac_t.transpose();
168  } else {
169  jac_t_pseudo_inv =jac_t.transpose() * ( jac_t * jac_t.transpose() ).inverse();
170  }
171 #if 1
172  {
173  ROS_INFO("jac_t# jac_t : ");
174  Eigen::Matrix<double,6,6> mat_i = mat_i = jac_t_pseudo_inv * jac_t;
175  for (unsigned int i = 0; i < 6; i++) {
176  std::stringstream ss;
177  for (unsigned int j=0; j<6; j++)
178  ss << std::fixed << std::setw(8) << std::setprecision(4) << mat_i(j,i) << " ";
179  ROS_INFO_STREAM(ss.str());
180  }
181  }
182 #endif
183  // f = - inv(jt) * effort
184  for (unsigned int j=0; j<6; j++)
185  {
186  F(j) = 0;
187  for (unsigned int i = 0; i < jnt_pos_.rows(); i++)
188  {
189  F(j) += -1 * jac_t_pseudo_inv(j, i) * tau(i);
190  }
191  }
192 
193  //low pass filter
194  F += (F_pre_ - F) * exp(-1.0 / t_const_);
195  for (unsigned int j=0; j<6; j++){
196  F_pre_(j) = 0;
197  }
198  F_pre_ += F;
199 
200  //tf transformation
201  tf::vectorKDLToTF(F.force, tf_force);
202  tf::vectorKDLToTF(F.torque, tf_torque);
203  try{
204  listener_.waitForTransform( tip, root, state->header.stamp, ros::Duration(1.0));
205  listener_.lookupTransform( tip, root, state->header.stamp , transform);
206  }
207  catch (tf::TransformException ex){
208  ROS_ERROR("%s",ex.what());
209  ros::Duration(1.0).sleep();
210  }
211  for (unsigned int j=0; j<3; j++){
212  F_pub.force[j] = transform.getBasis()[j].dot(tf_force);
213  F_pub.torque[j] = transform.getBasis()[j].dot(tf_torque);
214  }
215 
216  geometry_msgs::WrenchStamped msg;
217  msg.header.stamp = state->header.stamp;
218  msg.header.frame_id = tip;
219  // http://code.ros.org/lurker/message/20110107.151127.7177af06.nl.html
220  //tf::WrenchKDLToMsg(F,msg.wrench);
221  msg.wrench.force.x = F_pub.force[0];
222  msg.wrench.force.y = F_pub.force[1];
223  msg.wrench.force.z = F_pub.force[2];
224  msg.wrench.torque.x = F_pub.torque[0];
225  msg.wrench.torque.y = F_pub.torque[1];
226  msg.wrench.torque.z = F_pub.torque[2];
227  wrench_stamped_pub_.publish(msg);
228 
229  {
230  ROS_INFO("jacobian : ");
231  for (unsigned int i = 0; i < jnt_pos_.rows(); i++) {
232  std::stringstream ss;
233  for (unsigned int j=0; j<6; j++)
234  ss << std::fixed << std::setw(8) << std::setprecision(4) << jacobian_(j,i) << " ";
235  ROS_INFO_STREAM(ss.str());
236  }
237  ROS_INFO("effort : ");
238  std::stringstream sstau;
239  for (unsigned int i = 0; i < tau.rows(); i++) {
240  sstau << std::fixed << std::setw(8) << std::setprecision(4) << tau(i) << " ";
241  }
242  ROS_INFO_STREAM(sstau.str());
243  ROS_INFO("force : ");
244  std::stringstream ssf;
245  for (unsigned int j = 0; j < 6; j++) {
246  ssf << std::fixed << std::setw(8) << std::setprecision(4) << F(j) << " ";
247  }
248  ROS_INFO_STREAM(ssf.str());
249  }
250 
251  // store publish time in joint map
252  for (unsigned int i=0; i<state->name.size(); i++)
253  last_publish_time_[state->name[i]] = state->header.stamp;
254  }
255  }
256  };
257 };
258 
259 using namespace virtual_force_publisher;
260 
261 int main (int argc, char ** argv) {
262 
263  // Initialize ros
264  ros::init(argc, argv, "virtual_force_publisher");
265 
267 
268  ros::spin();
269 
270  return 0;
271 }
boost::shared_ptr< sensor_msgs::JointState const > JointStateConstPtr
const Segment & getSegment(unsigned int nr) const
void publish(const boost::shared_ptr< M > &message) const
bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
unsigned int rows() const
void resize(unsigned int newNrOfColumns)
void vectorKDLToTF(const KDL::Vector &k, tf::Vector3 &t)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
TFSIMD_FORCE_INLINE Matrix3x3 & getBasis()
bool sleep() const
unsigned int getNrOfSegments() const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
boost::scoped_ptr< KDL::ChainJntToJacSolver > jnt_to_jac_solver_
Vector torque
double z() const
ROSCPP_DECL void spin(Spinner &spinner)
unsigned int columns() const
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
void callbackJointState(const JointStateConstPtr &state)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Eigen::Matrix< double, 6, Eigen::Dynamic > data
const std::string & getName() const
std::map< std::string, ros::Time > last_publish_time_
double y() const
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TFSIMD_FORCE_INLINE Quaternion inverse(const Quaternion &q)
double x() const
int main(int argc, char **argv)
const Joint & getJoint() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
unsigned int getNrOfJoints() const
bool initParam(const std::string &param)
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
Vector force
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
void resize(unsigned int newSize)
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
#define ROS_INFO_STREAM(args)
static Time now()
#define ROS_ERROR(...)
unsigned int rows() const
const JointType & getType() const


virtual_force_publisher
Author(s): Kei Okada
autogenerated on Tue Feb 6 2018 03:45:47