hybrid_force_controller.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2008, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 #include <boost/thread.hpp>
00036 #include <boost/shared_ptr.hpp>
00037 #include <boost/scoped_ptr.hpp>
00038 #include <boost/foreach.hpp>
00039 
00040 #include <Eigen/Core>
00041 #include <Eigen/Geometry>
00042 #include <Eigen/LU>
00043 
00044 #include <kdl/chainfksolver.hpp>
00045 #include <kdl/chainfksolverpos_recursive.hpp>
00046 #include <kdl/chain.hpp>
00047 #include <kdl/chainjnttojacsolver.hpp>
00048 #include <kdl/frames.hpp>
00049 
00050 #include <ros/ros.h>
00051 
00052 #include <std_msgs/Bool.h>
00053 #include <geometry_msgs/PoseStamped.h>
00054 #include <geometry_msgs/TwistStamped.h>
00055 #include <geometry_msgs/WrenchStamped.h>
00056 #include <pr2_manipulation_controllers/JTTaskControllerState.h>
00057 
00058 #include <pluginlib/class_list_macros.h>
00059 #include <angles/angles.h>
00060 #include <control_toolbox/pid.h>
00061 #include <eigen_conversions/eigen_kdl.h>
00062 #include <eigen_conversions/eigen_msg.h>
00063 #include <pr2_controller_interface/controller.h>
00064 #include <pr2_mechanism_model/chain.h>
00065 #include <realtime_tools/realtime_publisher.h>
00066 #include <tf/transform_listener.h>
00067 #include <tf_conversions/tf_eigen.h>
00068 
00069 #include <rosrt/rosrt.h>
00070 
00071 #include <filters/filter_chain.h>
00072 #include <hrl_pr2_force_ctrl/HybridCartesianGains.h>
00073 
00074 using namespace pr2_manipulation_controllers;
00075 
00076 namespace hrl_pr2_force_ctrl {
00077 
00078 template <int Joints>
00079 struct Kin
00080 {
00081   typedef Eigen::Matrix<double, Joints, 1> JointVec;
00082   typedef Eigen::Matrix<double, 6, Joints> Jacobian;
00083 
00084   Kin(const KDL::Chain &kdl_chain) :
00085     fk_solver_(kdl_chain), jac_solver_(kdl_chain),
00086     kdl_q(Joints), kdl_J(Joints)
00087   {
00088   }
00089   ~Kin()
00090   {
00091   }
00092 
00093   void fk(const JointVec &q, Eigen::Affine3d &x)
00094   {
00095     kdl_q.data = q;
00096     KDL::Frame kdl_x;
00097     fk_solver_.JntToCart(kdl_q, kdl_x);
00098     tf::transformKDLToEigen(kdl_x, x);
00099   }
00100   void jac(const JointVec &q, Jacobian &J)
00101   {
00102     kdl_q.data = q;
00103     jac_solver_.JntToJac(kdl_q, kdl_J);
00104     J = kdl_J.data;
00105   }
00106 
00107   KDL::ChainFkSolverPos_recursive fk_solver_;
00108   KDL::ChainJntToJacSolver jac_solver_;
00109   KDL::JntArray kdl_q;
00110   KDL::Jacobian kdl_J;
00111 };
00112 
00113 class HybridForceController : public pr2_controller_interface::Controller
00114 {
00115 public:
00116   // Ensure 128-bit alignment for Eigen
00117   // See also http://eigen.tuxfamily.org/dox/StructHavingEigenMembers.html
00118   EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
00119 private:
00120   enum { Joints = 7 };
00121   typedef Eigen::Matrix<double, Joints, 1> JointVec;
00122   typedef Eigen::Matrix<double, 6, 1> CartVec;
00123   typedef Eigen::Matrix<double, 6, Joints> Jacobian;
00124   typedef pr2_manipulation_controllers::JTTaskControllerState StateMsg;
00125 public:
00126   HybridForceController();
00127   ~HybridForceController();
00128 
00129   bool init(pr2_mechanism_model::RobotState *robot, ros::NodeHandle &n);
00130   void starting();
00131   void update();
00132 
00133   Eigen::Affine3d x_desi_, x_desi_filtered_;
00134   CartVec wrench_desi_;
00135 
00136   ros::NodeHandle node_;
00137   ros::Subscriber sub_gains_;
00138   ros::Subscriber sub_posture_;
00139   ros::Subscriber sub_pose_;
00140   ros::Subscriber sub_force_; // khawkins
00141   ros::Subscriber sub_max_force_; // khawkins
00142   ros::Subscriber sub_ft_zero_; // khawkins
00143   ros::Subscriber sub_ft_params_; // khawkins
00144   tf::TransformListener tf_;
00145 
00146   rosrt::Publisher<StateMsg> pub_state_;
00147   rosrt::Publisher<geometry_msgs::PoseStamped> pub_x_, pub_x_desi_;
00148   rosrt::Publisher<geometry_msgs::Twist> pub_xd_, pub_xd_desi_;
00149   rosrt::Publisher<geometry_msgs::Twist> pub_x_err_, pub_wrench_;
00150   rosrt::Publisher<std_msgs::Float64MultiArray> pub_tau_;
00151   rosrt::Publisher<std_msgs::Float64MultiArray> pub_qdot_; // khawkins
00152   rosrt::Publisher<geometry_msgs::WrenchStamped> pub_sensor_ft_; // khawkins
00153   rosrt::Publisher<geometry_msgs::WrenchStamped> pub_sensor_raw_ft_; // khawkins
00154   rosrt::Publisher<geometry_msgs::WrenchStamped> pub_f_cmd_, pub_f_err_; // khawkins
00155   rosrt::Publisher<geometry_msgs::WrenchStamped> pub_k_effective_; // khawkins
00156 
00157   std::string root_name_, tip_name_;
00158   ros::Time last_time_;
00159   int loop_count_;
00160   pr2_mechanism_model::RobotState *robot_state_;
00161 
00162   pr2_mechanism_model::Chain chain_;
00163   boost::scoped_ptr<Kin<Joints> > kin_;
00164   Eigen::Matrix<double,6,1> Kp, Kd;  //aleeper
00165   Eigen::Matrix<double,6,6> St;  //aleeper
00166   bool use_tip_frame_; // aleeper
00167   Eigen::Matrix<double,6,1> Kfp, Kfi, Kfi_max, force_selector, motion_selector;  // khawkins
00168   double pose_command_filter_;
00169   double vel_saturation_trans_, vel_saturation_rot_;
00170   JointVec saturation_;
00171   JointVec joint_dd_ff_;
00172   double joint_vel_filter_;
00173   double jacobian_inverse_damping_;
00174   JointVec q_posture_;
00175   double k_posture_;
00176   bool use_posture_;
00177 
00178   // Minimum resolutions
00179   double res_force_, res_position_;
00180   double res_torque_, res_orientation_;
00181 
00182   Eigen::Affine3d last_pose_;
00183   CartVec last_wrench_;
00184   double last_stiffness_, last_compliance_;
00185   double last_Dx_, last_Df_;
00186 
00187 
00188   JointVec qdot_filtered_;
00189 
00190   // force/torque khawkins
00191   pr2_hardware_interface::AnalogIn *analog_in_;
00192   std::string force_torque_frame_;
00193   CartVec F_sensor_zero_;
00194   double gripper_mass_;
00195   Eigen::Vector3d gripper_com_;
00196   Eigen::Affine3d ft_transform_;
00197   CartVec F_des_, F_max_, F_integ_, K_effective_, F_err_last_;
00198   bool zero_wrench_;
00199 
00200   // filters khawkins
00201   std::vector<boost::shared_ptr<filters::FilterChain<double> > > force_filter_, qdot_filter_, xdot_filter_;
00202 
00203   void setGains(const hrl_pr2_force_ctrl::HybridCartesianGains::ConstPtr &msg) // khawkins
00204   {
00205     
00206     // Store gains...
00207     if (msg->p_gains.size() == 6)
00208       for (size_t i = 0; i < 6; ++i)
00209         Kp[i] = msg->p_gains[i];
00210     if (msg->d_gains.size() == 6)
00211       for (size_t i = 0; i < 6; ++i)
00212         Kd[i] = msg->d_gains[i];
00213 
00214     // Store force gains... khawkins
00215     if (msg->fp_gains.size() == 6)
00216       for (size_t i = 0; i < 6; ++i)
00217         Kfp[i] = msg->fp_gains[i];
00218     if (msg->fi_gains.size() == 6)
00219       for (size_t i = 0; i < 6; ++i)
00220         Kfi[i] = msg->fi_gains[i];
00221     if (msg->fi_max_gains.size() == 6)
00222       for (size_t i = 0; i < 6; ++i)
00223         Kfi_max[i] = msg->fi_max_gains[i];
00224 
00225     // Store selector matricies khawkins
00226     if (msg->force_selector.size() == 6)
00227         for (size_t i = 0; i < msg->force_selector.size(); ++i)
00228             if(msg->force_selector[i]) {
00229                 force_selector[i] = 1;
00230                 motion_selector[i] = 0;
00231             } else {
00232                 force_selector[i] = 0;
00233                 motion_selector[i] = 1;
00234             }
00235 
00236     // Store frame information
00237     if(!msg->header.frame_id.compare(root_name_))
00238     {
00239       use_tip_frame_ = false;
00240       ROS_INFO("New gains in root frame [%s]: %.1lf, %.1lf, %.1lf %.1lf, %.1lf, %.1lf",
00241                root_name_.c_str(), Kp[0], Kp[1], Kp[2], Kp[3], Kp[4], Kp[5]);
00242       St.setIdentity();
00243     }
00244     else if(!msg->header.frame_id.compare(tip_name_))
00245     {
00246       use_tip_frame_ = true;
00247       ROS_INFO("New gains in tip frame [%s]: %.1lf, %.1lf, %.1lf %.1lf, %.1lf, %.1lf",
00248                tip_name_.c_str(), Kp[0], Kp[1], Kp[2], Kp[3], Kp[4], Kp[5]);
00249       
00250     }
00251     else
00252     {
00253       use_tip_frame_ = false;
00254       
00255       geometry_msgs::PoseStamped in_root;
00256       in_root.pose.orientation.w = 1.0;
00257       in_root.header.frame_id = msg->header.frame_id;
00258 
00259       try {
00260         tf_.waitForTransform(root_name_, msg->header.frame_id, msg->header.stamp, ros::Duration(0.1));
00261         tf_.transformPose(root_name_, in_root, in_root);
00262       }
00263       catch (const tf::TransformException &ex)
00264       {
00265         ROS_ERROR("Failed to transform: %s", ex.what());
00266         return;
00267       }
00268       
00269       Eigen::Affine3d t;
00270       
00271       tf::poseMsgToEigen(in_root.pose, t);
00272 
00273       St << 
00274           t(0,0),t(0,1),t(0,2),0,0,0,
00275           t(1,0),t(1,1),t(1,2),0,0,0,
00276           t(2,0),t(2,1),t(2,2),0,0,0,
00277           0,0,0,t(0,0),t(0,1),t(0,2),
00278           0,0,0,t(1,0),t(1,1),t(1,2),
00279           0,0,0,t(2,0),t(2,1),t(2,2);
00280     
00281       St.transposeInPlace();
00282   
00283       ROS_INFO("New gains in arbitrary frame [%s]: %.1lf, %.1lf, %.1lf %.1lf, %.1lf, %.1lf",
00284              msg->header.frame_id.c_str(), Kp[0], Kp[1], Kp[2], Kp[3], Kp[4], Kp[5]);
00285     }
00286   }
00287 
00288   void zeroFTSensor(const std_msgs::Bool::ConstPtr &msg) {
00289     zero_wrench_ = true;
00290     ROS_INFO("Sensor Zeroed");
00291   }
00292 
00293   void setFTSensorParams(const std_msgs::Float64MultiArray::ConstPtr &msg) // khawkins
00294   {
00295     if ((int)msg->data.size() == 1) {
00296       gripper_mass_ = msg->data[0];
00297     }
00298     else if ((int)msg->data.size() == 4) {
00299       gripper_mass_ = msg->data[0];
00300       gripper_com_[0] = msg->data[1];
00301       gripper_com_[1] = msg->data[2];
00302       gripper_com_[2] = msg->data[3];
00303     }
00304     else
00305     {
00306       ROS_ERROR("ft_params message had the wrong size: %d", (int)msg->data.size());
00307       return;
00308     }
00309   }
00310 
00311   void commandPosture(const std_msgs::Float64MultiArray::ConstPtr &msg)
00312   {
00313     if (msg->data.size() == 0) {
00314       use_posture_ = false;
00315       ROS_INFO("Posture turned off");
00316     }
00317     else if ((int)msg->data.size() != q_posture_.size()) {
00318       ROS_ERROR("Posture message had the wrong size: %d", (int)msg->data.size());
00319       return;
00320     }
00321     else
00322     {
00323       use_posture_ = true;
00324       for (int j = 0; j < Joints; ++j)
00325         q_posture_[j] = msg->data[j];
00326     }
00327   }
00328 
00329   void commandPose(const geometry_msgs::PoseStamped::ConstPtr &command)
00330   {
00331     geometry_msgs::PoseStamped in_root;
00332     try {
00333       tf_.waitForTransform(root_name_, command->header.frame_id, command->header.stamp, ros::Duration(0.1));
00334       tf_.transformPose(root_name_, *command, in_root);
00335     }
00336     catch (const tf::TransformException &ex)
00337     {
00338       ROS_ERROR("Failed to transform: %s", ex.what());
00339       return;
00340     }
00341 
00342     tf::poseMsgToEigen(in_root.pose, x_desi_);
00343   }
00344 
00345   void commandForce(const geometry_msgs::WrenchStamped::ConstPtr &msg)
00346   {
00347     F_des_ << msg->wrench.force.x, msg->wrench.force.y, msg->wrench.force.z, 
00348               msg->wrench.torque.x, msg->wrench.torque.y, msg->wrench.torque.z;
00349     if(msg->header.frame_id == root_name_)
00350       return;
00351 
00352     geometry_msgs::PoseStamped in_root;
00353     in_root.pose.orientation.w = 1.0;
00354     in_root.header.frame_id = msg->header.frame_id;
00355 
00356     try {
00357       tf_.waitForTransform(root_name_, msg->header.frame_id, msg->header.stamp, ros::Duration(0.1));
00358       tf_.transformPose(root_name_, in_root, in_root);
00359     }
00360     catch (const tf::TransformException &ex)
00361     {
00362       ROS_ERROR("Failed to transform: %s", ex.what());
00363       return;
00364     }
00365     
00366     Eigen::Affine3d t;
00367     
00368     tf::poseMsgToEigen(in_root.pose, t);
00369 
00370     F_des_.head<3>() = t.linear() * F_des_.head<3>();
00371     F_des_.tail<3>() = t.linear() * F_des_.tail<3>();
00372   }
00373 
00374   void commandMaxForce(const geometry_msgs::WrenchStamped::ConstPtr &msg)
00375   {
00376     F_max_ << msg->wrench.force.x, msg->wrench.force.y, msg->wrench.force.z, 
00377               msg->wrench.torque.x, msg->wrench.torque.y, msg->wrench.torque.z;
00378   }
00379 
00380 };
00381 
00382 
00383 HybridForceController::HybridForceController()
00384   : robot_state_(NULL), use_posture_(false)
00385 {}
00386 
00387 HybridForceController::~HybridForceController()
00388 {
00389   sub_gains_.shutdown();
00390   sub_posture_.shutdown();
00391   sub_pose_.shutdown();
00392 
00393   // khawkins
00394   sub_force_.shutdown();
00395   sub_max_force_.shutdown();
00396   sub_ft_zero_.shutdown();
00397   sub_ft_params_.shutdown();
00398 }
00399 
00400 
00401 bool HybridForceController::init(pr2_mechanism_model::RobotState *robot_state, ros::NodeHandle &n)
00402 {
00403   rosrt::init();
00404   node_ = n;
00405 
00406   ROS_INFO_STREAM("JTTask controller compiled at " << __TIME__ );
00407   // get name of root and tip from the parameter server
00408   // std::string tip_name; // aleeper: Should use the class member instead!
00409   if (!node_.getParam("root_name", root_name_)){
00410     ROS_ERROR("HybridForceController: No root name found on parameter server (namespace: %s)",
00411               node_.getNamespace().c_str());
00412     return false;
00413   }
00414   if (!node_.getParam("tip_name", tip_name_)){
00415     ROS_ERROR("HybridForceController: No tip name found on parameter server (namespace: %s)",
00416               node_.getNamespace().c_str());
00417     return false;
00418   }
00419 
00420   // test if we got robot pointer
00421   assert(robot_state);
00422   robot_state_ = robot_state;
00423 
00424   // Chain of joints
00425   if (!chain_.init(robot_state_, root_name_, tip_name_))
00426     return false;
00427   if (!chain_.allCalibrated())
00428   {
00429     ROS_ERROR("Not all joints in the chain are calibrated (namespace: %s)", node_.getNamespace().c_str());
00430     return false;
00431   }
00432 
00433 
00434   // Kinematics
00435   KDL::Chain kdl_chain;
00436   chain_.toKDL(kdl_chain);
00437   kin_.reset(new Kin<Joints>(kdl_chain));
00438 
00439   // Cartesian gains
00440   double kp_trans, kd_trans, kp_rot, kd_rot;
00441   if (!node_.getParam("cart_gains/trans/p", kp_trans) ||
00442       !node_.getParam("cart_gains/trans/d", kd_trans))
00443   {
00444     ROS_ERROR("P and D translational gains not specified (namespace: %s)", node_.getNamespace().c_str());
00445     return false;
00446   }
00447   if (!node_.getParam("cart_gains/rot/p", kp_rot) ||
00448       !node_.getParam("cart_gains/rot/d", kd_rot))
00449   {
00450     ROS_ERROR("P and D rotational gains not specified (namespace: %s)", node_.getNamespace().c_str());
00451     return false;
00452   }
00453   Kp << kp_trans, kp_trans, kp_trans,  kp_rot, kp_rot, kp_rot;
00454   Kd << kd_trans, kd_trans, kd_trans,  kd_rot, kd_rot, kd_rot;
00455 
00456   // aleeper
00457   use_tip_frame_ = false;
00458   if (!node_.getParam("use_tip_frame", use_tip_frame_)){
00459     ROS_WARN("HybridForceController: use_tip_frame was not specified, assuming 'false': %s)",
00460               node_.getNamespace().c_str());
00461   }
00462   St.setIdentity();
00463 
00464   // Force desired khawkins
00465   F_des_.setZero();
00466   F_integ_.setZero();
00467   K_effective_.setZero();
00468 
00469   double f_trans_max, f_rot_max;
00470   node_.param("force_trans_max", f_trans_max, 9999.0);
00471   node_.param("force_rot_max", f_rot_max, 9999.0);
00472   F_max_ << f_trans_max, f_trans_max, f_trans_max,  f_rot_max, f_rot_max, f_rot_max;
00473 
00474   // Force gains khawkins
00475   double kfp_trans, kfp_rot, kfi_trans, kfi_rot, kfi_max_trans, kfi_max_rot;
00476   if (!node_.getParam("force_gains/trans/p", kfp_trans) ||
00477       !node_.getParam("force_gains/trans/i", kfi_trans) ||
00478       !node_.getParam("force_gains/trans/i_max", kfi_max_trans))
00479   {
00480     ROS_ERROR("P and I translational force gains not specified (namespace: %s)", node_.getNamespace().c_str());
00481     return false;
00482   }
00483   if (!node_.getParam("force_gains/rot/p", kfp_rot) ||
00484       !node_.getParam("force_gains/rot/i", kfi_rot) ||
00485       !node_.getParam("force_gains/rot/i_max", kfi_max_rot))
00486   {
00487     ROS_ERROR("P and I rotational force gains not specified (namespace: %s)", node_.getNamespace().c_str());
00488     return false;
00489   }
00490   Kfp << kfp_trans, kfp_trans, kfp_trans,  kfp_rot, kfp_rot, kfp_rot;
00491   Kfi << kfi_trans, kfi_trans, kfi_trans,  kfi_rot, kfi_rot, kfi_rot;
00492   Kfi_max << kfi_max_trans, kfi_max_trans, kfi_max_trans,  kfi_max_rot, kfi_max_rot, kfi_max_rot;
00493   motion_selector = CartVec::Ones();
00494   force_selector = CartVec::Zero(); 
00495   force_filter_.resize(6);
00496   for(int i=0;i<6;i++) {
00497     force_filter_[i].reset(new filters::FilterChain<double>("double"));
00498     force_filter_[i]->configure("force_filter", node_);
00499     ros::Duration(0.2).sleep();
00500   }
00501   qdot_filter_.resize(Joints);
00502   for(int i=0;i<Joints;i++) {
00503     ros::Duration(0.2).sleep();
00504     qdot_filter_[i].reset(new filters::FilterChain<double>("double"));
00505     qdot_filter_[i]->configure("qdot_filter", node_);
00506   }
00507   xdot_filter_.resize(6);
00508   for(int i=0;i<6;i++) {
00509     ros::Duration(0.2).sleep();
00510     xdot_filter_[i].reset(new filters::FilterChain<double>("double"));
00511     xdot_filter_[i]->configure("xdot_filter", node_);
00512   }
00513 
00514   node_.param("pose_command_filter", pose_command_filter_, 1.0);
00515 
00516   // Velocity saturation
00517   node_.param("vel_saturation_trans", vel_saturation_trans_, 0.0);
00518   node_.param("vel_saturation_rot", vel_saturation_rot_, 0.0);
00519 
00520   node_.param("jacobian_inverse_damping", jacobian_inverse_damping_, 0.0);
00521   node_.param("joint_vel_filter", joint_vel_filter_, 1.0);
00522 
00523   // Joint gains
00524   for (int i = 0; i < Joints; ++i)
00525     node_.param("joint_feedforward/" + chain_.getJoint(i)->joint_->name, joint_dd_ff_[i], 0.0);
00526   for (int i = 0; i < Joints; ++i)
00527     node_.param("saturation/" + chain_.getJoint(i)->joint_->name, saturation_[i], 0.0);
00528 
00529   // Posture gains
00530   node_.param("k_posture", k_posture_, 1.0);
00531 
00532   node_.param("resolution/force", res_force_, 0.01);
00533   node_.param("resolution/position", res_position_, 0.001);
00534   node_.param("resolution/torque", res_torque_, 0.01);
00535   node_.param("resolution/orientation", res_orientation_, 0.001);
00536 
00537   // force/torque sensor khawkins
00538   zero_wrench_ = true;
00539   node_.param("gripper_params/mass", gripper_mass_, 1.02074);
00540   node_.param("gripper_params/com_pos_x", gripper_com_[0], -0.00126);
00541   node_.param("gripper_params/com_pos_y", gripper_com_[1], 0.001760);
00542   node_.param("gripper_params/com_pos_z", gripper_com_[2], -0.08532);
00543   std::string analog_in_name;
00544   if (!node_.getParam("force_torque_analog_in", analog_in_name))
00545   {
00546     ROS_ERROR("HybridForceController: No \"analog_in_name\" found on parameter namespace: %s",
00547               node_.getNamespace().c_str());
00548     return false;
00549   }
00550   pr2_hardware_interface::HardwareInterface* hw = robot_state_->model_->hw_;  
00551   analog_in_ = hw->getAnalogIn(analog_in_name);
00552   if (analog_in_ == NULL)
00553   {
00554     ROS_ERROR("HybridForceController: Cannot find AnalogIn named \"%s\"",
00555               analog_in_name.c_str());
00556     BOOST_FOREACH(const pr2_hardware_interface::AnalogInMap::value_type &v, hw->analog_ins_)
00557     {
00558       ROS_INFO("AnalogIn : %s", v.first.c_str());
00559     }
00560     return false;
00561   }
00562   ROS_INFO("HybridForceController: Using AnalogIn named \"%s\"", analog_in_name.c_str());
00563   if (!node_.getParam("force_torque_frame", force_torque_frame_))
00564   {
00565     ROS_ERROR("HybridForceController: No \"force_torque_frame\" found on parameter namespace: %s",
00566               node_.getNamespace().c_str());
00567     return false;
00568   }
00569   try {
00570     tf::StampedTransform ft_stf;
00571     tf_.waitForTransform(tip_name_, force_torque_frame_, ros::Time(0), ros::Duration(1.0));
00572     tf_.lookupTransform(force_torque_frame_, tip_name_, ros::Time(0), ft_stf);
00573     tf::TransformTFToEigen(ft_stf, ft_transform_);
00574   }
00575   catch (const tf::TransformException &ex)
00576   {
00577     ROS_ERROR("Failed to transform: %s", ex.what());
00578     return false;
00579   }
00580 
00581   sub_gains_ = node_.subscribe("gains", 5, &HybridForceController::setGains, this);
00582   sub_posture_ = node_.subscribe("command_posture", 5, &HybridForceController::commandPosture, this);
00583   sub_pose_ = node_.subscribe("command_pose", 1, &HybridForceController::commandPose, this);
00584   // khawkins
00585   sub_force_ = node_.subscribe("command_force", 1, &HybridForceController::commandForce, this);
00586   sub_max_force_ = node_.subscribe("command_max_force", 1, &HybridForceController::commandMaxForce, this); 
00587   sub_ft_zero_ = node_.subscribe("ft_zero", 5, &HybridForceController::zeroFTSensor, this);
00588   sub_ft_params_ = node_.subscribe("ft_params", 5, &HybridForceController::setFTSensorParams, this);
00589 
00590   StateMsg state_template;
00591   state_template.header.frame_id = root_name_;
00592   state_template.x.header.frame_id = root_name_;
00593   state_template.x_desi.header.frame_id = root_name_;
00594   state_template.x_desi_filtered.header.frame_id = root_name_;
00595   state_template.tau_pose.resize(Joints);
00596   state_template.tau_posture.resize(Joints);
00597   state_template.tau.resize(Joints);
00598   state_template.J.layout.dim.resize(2);
00599   state_template.J.data.resize(6*Joints);
00600   state_template.N.layout.dim.resize(2);
00601   state_template.N.data.resize(Joints*Joints);
00602   pub_state_.initialize(node_.advertise<StateMsg>("state", 10), 10, state_template);
00603 
00604   geometry_msgs::PoseStamped pose_template;
00605   pose_template.header.frame_id = root_name_;
00606   pub_x_.initialize(node_.advertise<geometry_msgs::PoseStamped>("state/x", 10),
00607                     10, pose_template);
00608   pub_x_desi_.initialize(node_.advertise<geometry_msgs::PoseStamped>("state/x_desi", 10),
00609                          10, pose_template);
00610   pub_x_err_.initialize(node_.advertise<geometry_msgs::Twist>("x_err", 10),
00611                         10, geometry_msgs::Twist());
00612   pub_xd_.initialize(node_.advertise<geometry_msgs::Twist>("state/xd", 10),
00613                      10, geometry_msgs::Twist());
00614   pub_xd_desi_.initialize(node_.advertise<geometry_msgs::Twist>("state/xd_desi", 10),
00615                           10, geometry_msgs::Twist());
00616   pub_wrench_.initialize(node_.advertise<geometry_msgs::Twist>("state/wrench", 10),
00617                          10, geometry_msgs::Twist());
00618   pub_sensor_ft_.initialize(node_.advertise<geometry_msgs::WrenchStamped>("sensor_ft", 10),
00619                             10, geometry_msgs::WrenchStamped());
00620   pub_sensor_raw_ft_.initialize(node_.advertise<geometry_msgs::WrenchStamped>("sensor_raw_ft", 10),
00621                                 10, geometry_msgs::WrenchStamped());
00622   pub_f_cmd_.initialize(node_.advertise<geometry_msgs::WrenchStamped>("f_cmd", 10),
00623                                 10, geometry_msgs::WrenchStamped());
00624   pub_f_err_.initialize(node_.advertise<geometry_msgs::WrenchStamped>("f_err", 10),
00625                                 10, geometry_msgs::WrenchStamped());
00626   pub_k_effective_.initialize(node_.advertise<geometry_msgs::WrenchStamped>("k_effective", 10),
00627                                 10, geometry_msgs::WrenchStamped());
00628 
00629   std_msgs::Float64MultiArray joints_template;
00630   joints_template.layout.dim.resize(1);
00631   joints_template.layout.dim[0].size = Joints;
00632   joints_template.layout.dim[0].stride = 1;
00633   joints_template.data.resize(7);
00634   pub_tau_.initialize(node_.advertise<std_msgs::Float64MultiArray>("state/tau", 10),
00635                       10, joints_template);
00636   pub_qdot_.initialize(node_.advertise<std_msgs::Float64MultiArray>("qd", 10),
00637                        10, joints_template);
00638 
00639   return true;
00640 }
00641 
00642 void HybridForceController::starting()
00643 {
00644   //Kp << 800.0, 800.0, 800.0,   80.0, 80.0, 80.0;
00645   //Kd << 12.0, 12.0, 12.0,   0.0, 0.0, 0.0;
00646 
00647   JointVec q;
00648   chain_.getPositions(q);
00649   kin_->fk(q, x_desi_);
00650   x_desi_filtered_ = x_desi_;
00651   last_pose_ = x_desi_;
00652   q_posture_ = q;
00653   qdot_filtered_.setZero();
00654   last_wrench_.setZero();
00655   F_err_last_.setZero();
00656 
00657   last_stiffness_ = 0;
00658   last_compliance_ = 0;
00659   last_Dx_ = 0;
00660   last_Df_ = 0;
00661 
00662   loop_count_ = 0;
00663 
00664   F_integ_.setZero();
00665   //zero_wrench_ = true; //khawkins
00666 }
00667 
00668 
00669 static void computePoseError(const Eigen::Affine3d &xact, const Eigen::Affine3d &xdes, Eigen::Matrix<double,6,1> &err)
00670 {
00671   err.head<3>() = xact.translation() - xdes.translation();
00672   err.tail<3>()   = 0.5 * (xdes.linear().col(0).cross(xact.linear().col(0)) +
00673                           xdes.linear().col(1).cross(xact.linear().col(1)) +
00674                           xdes.linear().col(2).cross(xact.linear().col(2)));
00675 }
00676 
00677 void HybridForceController::update()
00678 {
00679   // get time
00680   ros::Time time = robot_state_->getTime();
00681   ros::Duration dt = time - last_time_;
00682   last_time_ = time;
00683   ++loop_count_;
00684 
00685   // ======== Measures current arm state
00686 
00687   JointVec q;
00688   chain_.getPositions(q);
00689 
00690   Eigen::Affine3d x;
00691   kin_->fk(q, x);
00692 
00693   Jacobian J;
00694   kin_->jac(q, J);
00695 
00696 
00697   /*
00698   JointVec qdot_raw;
00699   chain_.getVelocities(qdot_raw);
00700   for (int i = 0; i < Joints; ++i)
00701     qdot_filtered_[i] += joint_vel_filter_ * (qdot_raw[i] - qdot_filtered_[i]);
00702   JointVec qdot = qdot_filtered_;
00703   */
00704 
00705   // filter qdot using Savitzky-Golay differentiation
00706   JointVec qdot;
00707   double in_qdot, out_qdot;
00708   for(int i=0;i<Joints;i++) {
00709     in_qdot = q[i];
00710     qdot_filter_[i]->update(in_qdot, out_qdot);
00711     qdot[i] = out_qdot;
00712   }
00713   qdot = qdot / dt.toSec();
00714   if(loop_count_ < 100)
00715     qdot.setZero();
00716 
00717   // low pass filter on xdot
00718   CartVec xdot = J * qdot;
00719   double in_xdot, out_xdot;
00720   for(int i=0;i<6;i++) {
00721     in_xdot = xdot[i];
00722     xdot_filter_[i]->update(in_xdot, out_xdot);
00723     xdot[i] = out_xdot;
00724   }
00725 
00726   // ======== Controls to the current pose setpoint
00727 
00728   {
00729     Eigen::Vector3d p0(x_desi_filtered_.translation());
00730     Eigen::Vector3d p1(x_desi_.translation());
00731     Eigen::Quaterniond q0(x_desi_filtered_.linear());
00732     Eigen::Quaterniond q1(x_desi_.linear());
00733     q0.normalize();
00734     q1.normalize();
00735 
00736     tf::Quaternion tf_q0(q0.x(), q0.y(), q0.z(), q0.w());
00737     tf::Quaternion tf_q1(q1.x(), q1.y(), q1.z(), q1.w());
00738     tf::Quaternion tf_q = tf_q0.slerp(tf_q1, pose_command_filter_);
00739 
00740     Eigen::Vector3d p = p0 + pose_command_filter_ * (p1 - p0);
00741     //Eigen::Quaterniond q = q0.slerp(pose_command_filter_, q1);
00742     Eigen::Quaterniond q(tf_q.w(), tf_q.x(), tf_q.y(), tf_q.z());
00743     //x_desi_filtered_ = q * Eigen::Translation3d(p);
00744     x_desi_filtered_ = Eigen::Translation3d(p) * q;
00745   }
00746   CartVec x_err, x_err_ctrl_frame;
00747   //computePoseError(x, x_desi_, x_err);
00748   computePoseError(x, x_desi_filtered_, x_err);
00749 
00750   if(use_tip_frame_)
00751   { 
00752       St << 
00753           x(0,0),x(0,1),x(0,2),0,0,0,
00754           x(1,0),x(1,1),x(1,2),0,0,0,
00755           x(2,0),x(2,1),x(2,2),0,0,0,
00756           0,0,0,x(0,0),x(0,1),x(0,2),
00757           0,0,0,x(1,0),x(1,1),x(1,2),
00758           0,0,0,x(2,0),x(2,1),x(2,2);
00759       St.transposeInPlace();
00760   }
00761 
00762   // HERE WE CONVERT CALCULATIONS TO THE FRAME IN WHICH GAINS ARE SPECIFIED!
00763   x_err_ctrl_frame = St * x_err;
00764   CartVec xdot_desi = Kp.array() * x_err_ctrl_frame.array() * -1.0;  // aleeper
00765 
00766   // Caps the cartesian velocity
00767   if (vel_saturation_trans_ > 0.0)
00768   {
00769     if (fabs(xdot_desi.head<3>().norm()) > vel_saturation_trans_)
00770       xdot_desi.head<3>() *= (vel_saturation_trans_ / xdot_desi.head<3>().norm());
00771   }
00772   if (vel_saturation_rot_ > 0.0)
00773   {
00774     if (fabs(xdot_desi.tail<3>().norm()) > vel_saturation_rot_)
00775       xdot_desi.tail<3>() *= (vel_saturation_rot_ / xdot_desi.tail<3>().norm());
00776   }
00777 
00778   CartVec xdot_ctrl_frame = St * xdot;
00779   CartVec F_damp = Kd.array() * xdot_ctrl_frame.array();
00780   CartVec F_cmd = motion_selector.array() * xdot_desi.array() + 
00781                   force_selector.array() * (St * F_des_).array() - F_damp.array();
00782   // saturation force with F_max
00783   /*
00784      TODO What was I thinking? TODO
00785   double force_sat_scaling = 1.0, torque_sat_scaling = 1.0;
00786   for(int i=0;i<3;i++)
00787       if(F_max_[i] >= 0.0)
00788           force_sat_scaling = std::min(force_sat_scaling, fabs(F_max_[i] / F_cmd[i]));
00789   for(int i=3;i<6;i++)
00790       if(F_max_[i] >= 0.0)
00791           torque_sat_scaling = std::min(torque_sat_scaling, fabs(F_max_[i] / F_cmd[i]));
00792   F_cmd.head<3>() = force_sat_scaling * F_cmd.head<3>();
00793   F_cmd.tail<3>() = torque_sat_scaling * F_cmd.tail<3>();
00794   */
00795 
00796   // Cap force with F_max
00797   for(int i=0;i<6;i++) {
00798       if(F_max_[i] >= 0.0) {
00799           if(F_cmd[i] > 0)
00800               F_cmd[i] = std::min(F_max_[i], F_cmd[i]);
00801           else
00802               F_cmd[i] = -std::min(F_max_[i], -F_cmd[i]);
00803       }
00804   }
00805 
00806   CartVec F_motion = F_cmd;
00807 
00809   CartVec F_sensor_raw, F_sensor_zeroed, F_grav;
00810   {
00811     for(int i=0;i<6;i++)
00812         F_sensor_raw[i] = analog_in_->state_.state_[i];
00813     // ft_transform_ : ft_frame B tip_frame
00814     // x : base_frame B tip_frame
00815     Eigen::Vector4d z_grav(0, 0, -1, 0);
00816     z_grav = -1 * ft_transform_.matrix() * x.matrix().inverse() * z_grav;
00817     F_grav.head<3>() = gripper_mass_ * 9.81 * z_grav.head<3>();
00818     Eigen::Vector3d F_grav_vec(F_grav[0], F_grav[1], F_grav[2]);
00819     Eigen::Vector3d torque_vec = gripper_com_.cross(F_grav_vec);
00820     F_grav.tail<3>() = torque_vec;
00821     if(zero_wrench_) {
00822         F_sensor_zero_ = F_sensor_raw - F_grav;
00823         zero_wrench_ = false;
00824     }
00825     F_sensor_zeroed = (F_sensor_raw - F_grav - F_sensor_zero_);
00826 
00827     // put wrench in tip_frame
00828     Eigen::Vector3d F_sensor_zeroed_force(F_sensor_zeroed[0], F_sensor_zeroed[1], F_sensor_zeroed[2]);  
00829     Eigen::Vector3d F_sensor_zeroed_torque(F_sensor_zeroed[3], F_sensor_zeroed[4], F_sensor_zeroed[5]);  
00830     F_sensor_zeroed_force = ft_transform_.linear().transpose() * F_sensor_zeroed_force;
00831     F_sensor_zeroed_torque = ft_transform_.linear().transpose() * F_sensor_zeroed_torque;
00832     Eigen::Vector3d torque_offset = ft_transform_.translation().cross(F_sensor_zeroed_torque);
00833     F_sensor_zeroed.head<3>() = F_sensor_zeroed_force;
00834     F_sensor_zeroed.tail<3>() = F_sensor_zeroed_torque + torque_offset;
00835 
00836     if(!use_tip_frame_) {
00837         // put wrench in gains frame
00838         F_sensor_zeroed.head<3>() = x.linear() * F_sensor_zeroed.head<3>();
00839         F_sensor_zeroed.tail<3>() = x.linear() * F_sensor_zeroed.tail<3>();
00840         F_sensor_zeroed = St * F_sensor_zeroed;
00841     }
00842 
00843     // filter wrench signal
00844     double in_F, out_F;
00845     for(int i=0;i<6;i++) {
00846       in_F = F_sensor_zeroed[i];
00847       force_filter_[i]->update(in_F, out_F);
00848       F_sensor_zeroed[i] = out_F;
00849     }
00850     if(loop_count_ < 100)
00851       F_sensor_zeroed.setZero();
00852   }
00854 
00855   // Impedance control
00856 
00857   CartVec proportional_selector, integral_selector;
00858   proportional_selector.setZero();
00859   integral_selector.setZero();
00860   for(int i=0;i<6;i++)
00861       if(Kfi[i] != 0 || Kfi_max[i] != 0)
00862           integral_selector[i] = 1;
00863       else
00864           proportional_selector[i] = 1;
00865   CartVec F_control, F_control_p, F_control_i, F_err;
00866   F_err = F_cmd - F_sensor_zeroed;
00867   // Propotional with feed-forward:
00868   F_control_p = F_cmd.array() + Kfp.array() * F_err.array();
00869 
00870   // Propotional-Integral:
00871   F_integ_ = integral_selector.array() * (F_integ_.array() + Kfi.array() * F_err.array());
00872   for(int i=0;i<6;i++)
00873       if(F_integ_[i] > Kfi_max[i])
00874           F_integ_[i] = Kfi_max[i];
00875       else if(F_integ_[i] < -Kfi_max[i])
00876           F_integ_[i] = -Kfi_max[i];
00877   // Marc's anti-windup trick: set to zero when sign flips
00878   double velocity = std::sqrt(xdot(0) * xdot(0) + xdot(1) * xdot(1) + xdot(2) * xdot(2));
00879   for(int i=0;i<6;i++)
00880       if(((F_err[i] > 0) != (F_err_last_[i] > 0)) && velocity > 0.01)
00881           F_integ_[i] = 0;
00882   F_err_last_ = F_err;
00883   //F_control = F_cmd.array() + F_integ_.array() + Kfp.array() * (F_cmd - F_sensor_zeroed).array();
00884   F_control_i = F_integ_.array() + Kfp.array() * (F_cmd - F_sensor_zeroed).array();
00885 
00886   F_control = proportional_selector.array() * F_control_p.array() + 
00887               integral_selector.array() * F_control_i.array();
00888 
00889 
00890   // HERE WE CONVERT BACK TO THE ROOT FRAME SINCE THE JACOBIAN IS IN ROOT FRAME.
00891   //JointVec tau_pose = J.transpose() * St.transpose() * F_motion;
00892   JointVec tau_pose = J.transpose() * St.transpose() * F_control; // khawkins
00893 
00894   // ======== J psuedo-inverse and Nullspace computation
00895 
00896   // Computes pseudo-inverse of J
00897   Eigen::Matrix<double,6,6> I6; I6.setIdentity();
00898   Eigen::Matrix<double,6,6> JJt = J * J.transpose();
00899   Eigen::Matrix<double,6,6> JJt_inv;
00900   JJt_inv = JJt.inverse();
00901   Eigen::Matrix<double,6,6> JJt_damped = J * J.transpose() + jacobian_inverse_damping_ * I6;
00902   Eigen::Matrix<double,6,6> JJt_inv_damped;
00903   JJt_inv_damped = JJt_damped.inverse();
00904   Eigen::Matrix<double,Joints,6> J_pinv = J.transpose() * JJt_inv_damped;
00905 
00906   // Computes the nullspace of J
00907   Eigen::Matrix<double,Joints,Joints> I;
00908   I.setIdentity();
00909   Eigen::Matrix<double,Joints,Joints> N = I - J_pinv * J;
00910 
00911   // ======== Posture control
00912 
00913   // Computes the desired joint torques for achieving the posture
00914   JointVec tau_posture;
00915   tau_posture.setZero();
00916   if (use_posture_)
00917   {
00918     JointVec posture_err = q_posture_ - q;
00919     for (size_t j = 0; j < Joints; ++j)
00920     {
00921       if (chain_.getJoint(j)->joint_->type == urdf::Joint::CONTINUOUS)
00922         posture_err[j] = angles::normalize_angle(posture_err[j]);
00923     }
00924 
00925     for (size_t j = 0; j < Joints; ++j) {
00926       if (fabs(q_posture_[j] - 9999) < 1e-5)
00927         posture_err[j] = 0.0;
00928     }
00929 
00930     JointVec qdd_posture = k_posture_ * posture_err;
00931     tau_posture = joint_dd_ff_.array() * (N * qdd_posture).array();
00932   }
00933 
00934   JointVec tau = tau_pose + tau_posture;
00935 
00936   // ======== Torque Saturation
00937   double sat_scaling = 1.0;
00938   for (int i = 0; i < Joints; ++i) {
00939     if (saturation_[i] > 0.0)
00940       sat_scaling = std::min(sat_scaling, fabs(saturation_[i] / tau[i]));
00941   }
00942   JointVec tau_sat = sat_scaling * tau;
00943 
00944   chain_.addEfforts(tau_sat);
00945 
00946 
00947   // ======== Environment stiffness
00948 
00949   CartVec df = F_motion - last_wrench_;
00950   CartVec dx;
00951   computePoseError(last_pose_, x, dx);
00952 
00953   // Just in the Z direction for now
00954 
00955   double Df, Dx;
00956   if (fabs(dx[2]) >= res_position_)
00957     Df = df[2] * res_position_ / fabs(dx[2]);
00958   else
00959     Df = (1. - fabs(dx[2])/res_position_) * last_Df_ + df[2];
00960   if (fabs(df[2]) >= res_force_)
00961     Dx = dx[2] * res_force_ / fabs(df[2]);
00962   else
00963     Dx = (1. - fabs(df[2])/res_force_) * last_Dx_ + dx[2];
00964   last_Df_ = Df;
00965   last_Dx_ = Dx;
00966 
00967   double stiffness, compliance;
00968   if (fabs(dx[2]) >= res_position_)
00969     stiffness = fabs(df[2]) / fabs(dx[2]);
00970   else
00971     stiffness = (1 - fabs(dx[2])/res_position_) * last_stiffness_ + fabs(df[2]) / res_position_;
00972   if (fabs(df[2]) >= res_force_)
00973     compliance = fabs(dx[2]) / fabs(df[2]);
00974   else
00975     compliance = (1 - fabs(df[2])/res_force_) * last_compliance_ + fabs(dx[2]) / res_force_;
00976 
00977   last_pose_ = x;
00978   last_wrench_ = F_motion;
00979   last_stiffness_ = stiffness;
00980   last_compliance_ = compliance;
00981 
00982   // khawkins
00983   for(int i=0;i<6;i++)
00984       if(fabs(x_err_ctrl_frame[i]) > 0.001)
00985           K_effective_[i] = fabs(F_sensor_zeroed[i] / x_err_ctrl_frame[i]);
00986 
00987   if (loop_count_ % 10 == 0)
00988   {
00989     geometry_msgs::PoseStamped::Ptr pose_msg;
00990     geometry_msgs::Twist::Ptr twist_msg;
00991     geometry_msgs::WrenchStamped::Ptr wrench_msg;
00992     std_msgs::Float64MultiArray::Ptr q_msg;
00993 
00994     if (pose_msg = pub_x_.allocate()) {  // X
00995       pose_msg->header.stamp = time;
00996       tf::poseEigenToMsg(x, pose_msg->pose);
00997       pub_x_.publish(pose_msg);
00998     }
00999 
01000     if (pose_msg = pub_x_desi_.allocate()) {  // X desi
01001       pose_msg->header.stamp = time;
01002       tf::poseEigenToMsg(x_desi_, pose_msg->pose);
01003       pub_x_desi_.publish(pose_msg);
01004     }
01005 
01006     if (twist_msg = pub_x_err_.allocate()) {  // X err
01007       tf::twistEigenToMsg(x_err, *twist_msg);
01008       pub_x_err_.publish(twist_msg);
01009     }
01010 
01011     if (twist_msg = pub_xd_.allocate()) {  // Xdot
01012       tf::twistEigenToMsg(xdot_ctrl_frame, *twist_msg);
01013       pub_xd_.publish(twist_msg);
01014     }
01015 
01016     if (twist_msg = pub_xd_desi_.allocate()) {  // Xdot desi
01017       tf::twistEigenToMsg(xdot_desi, *twist_msg);
01018       pub_xd_desi_.publish(twist_msg);
01019     }
01020 
01021     if (twist_msg = pub_wrench_.allocate()) {  // F
01022       tf::twistEigenToMsg(F_motion, *twist_msg);
01023       pub_wrench_.publish(twist_msg);
01024     }
01025 
01026     if (wrench_msg = pub_sensor_ft_.allocate()) {  // F ft
01027       wrench_msg->header.stamp = time;
01028       wrench_msg->header.frame_id = tip_name_;
01029       tf::wrenchEigenToMsg(F_sensor_zeroed, wrench_msg->wrench);
01030       pub_sensor_ft_.publish(wrench_msg);
01031     }
01032 
01033     if (wrench_msg = pub_sensor_raw_ft_.allocate()) {  // F ft raw
01034       wrench_msg->header.stamp = time;
01035       wrench_msg->header.frame_id = force_torque_frame_;
01036       tf::wrenchEigenToMsg(F_sensor_raw, wrench_msg->wrench);
01037       pub_sensor_raw_ft_.publish(wrench_msg);
01038     }
01039 
01040     if (wrench_msg = pub_f_cmd_.allocate()) {  // F_cmd
01041       wrench_msg->header.stamp = time;
01042       wrench_msg->header.frame_id = tip_name_;
01043       tf::wrenchEigenToMsg(F_cmd, wrench_msg->wrench);
01044       pub_f_cmd_.publish(wrench_msg);
01045     }
01046 
01047     if (wrench_msg = pub_f_err_.allocate()) {  // F_err
01048       wrench_msg->header.stamp = time;
01049       wrench_msg->header.frame_id = tip_name_;
01050       tf::wrenchEigenToMsg(F_err, wrench_msg->wrench);
01051       pub_f_err_.publish(wrench_msg);
01052     }
01053 
01054     if (wrench_msg = pub_k_effective_.allocate()) {  // K_effective
01055       wrench_msg->header.stamp = time;
01056       wrench_msg->header.frame_id = tip_name_;
01057       tf::wrenchEigenToMsg(K_effective_, wrench_msg->wrench);
01058       pub_k_effective_.publish(wrench_msg);
01059     }
01060 
01061     if (q_msg = pub_tau_.allocate()) {  // tau
01062       for (size_t i = 0; i < Joints; ++i)
01063         q_msg->data[i] = tau[i];
01064       pub_tau_.publish(q_msg);
01065     }
01066 
01067     if (q_msg = pub_qdot_.allocate()) {  // qdot
01068       for (size_t i = 0; i < Joints; ++i)
01069         q_msg->data[i] = qdot[i];
01070       pub_qdot_.publish(q_msg);
01071     }
01072 
01073     StateMsg::Ptr state_msg;
01074     if (state_msg = pub_state_.allocate()) {
01075       state_msg->header.stamp = time;
01076       state_msg->x.header.stamp = time;
01077       tf::poseEigenToMsg(x, state_msg->x.pose);
01078       state_msg->x_desi.header.stamp = time;
01079       tf::poseEigenToMsg(x_desi_, state_msg->x_desi.pose);
01080       state_msg->x_desi_filtered.header.stamp = time;
01081       tf::poseEigenToMsg(x_desi_filtered_, state_msg->x_desi_filtered.pose);
01082       tf::twistEigenToMsg(x_err, state_msg->x_err);
01083       tf::twistEigenToMsg(xdot, state_msg->xd);
01084       tf::twistEigenToMsg(xdot_desi, state_msg->xd_desi);
01085       tf::wrenchEigenToMsg(F_motion, state_msg->F);
01086       tf::matrixEigenToMsg(J, state_msg->J);
01087       tf::matrixEigenToMsg(N, state_msg->N);
01088       for (size_t j = 0; j < Joints; ++j) {
01089         state_msg->tau_pose[j] = tau_pose[j];
01090         state_msg->tau_posture[j] = tau_posture[j];
01091         state_msg->tau[j] = tau[j];
01092       }
01093       state_msg->stiffness = stiffness;
01094       state_msg->compliance = compliance;
01095       state_msg->Df = Df / res_position_;
01096       state_msg->Dx = Dx / res_force_;
01097       state_msg->df = df[2];
01098       state_msg->dx = dx[2];
01099       pub_state_.publish(state_msg);
01100     }
01101   }
01102   
01103 }
01104 
01105 } //namespace
01106 
01107 PLUGINLIB_DECLARE_CLASS(hrl_pr2_force_ctrl, HybridForceController, hrl_pr2_force_ctrl::HybridForceController, pr2_controller_interface::Controller)
01108 


hrl_pr2_force_ctrl
Author(s): Kelsey Hawkins
autogenerated on Wed Nov 27 2013 11:42:28