jt_cartesian_controller.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
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: Stuart Glaser
36 
38 
39 #include <Eigen/LU>
40 
41 #include <ros/ros.h>
42 
43 #include <angles/angles.h>
44 
47 
48 
49 namespace controller {
50 
51 JTCartesianController::JTCartesianController()
52  : robot_state_(NULL), use_posture_(false)
53 {}
54 
56 {
60 }
61 
62 
64 {
65  node_ = n;
66 
67  // get name of root and tip from the parameter server
68  std::string tip_name;
69  if (!node_.getParam("root_name", root_name_)){
70  ROS_ERROR("JTCartesianController: No root name found on parameter server (namespace: %s)",
71  node_.getNamespace().c_str());
72  return false;
73  }
74  if (!node_.getParam("tip_name", tip_name)){
75  ROS_ERROR("JTCartesianController: No tip name found on parameter server (namespace: %s)",
76  node_.getNamespace().c_str());
77  return false;
78  }
79 
80  // test if we got robot pointer
81  assert(robot_state);
82  robot_state_ = robot_state;
83 
84  // Chain of joints
85  if (!chain_.init(robot_state_, root_name_, tip_name))
86  return false;
87  if (!chain_.allCalibrated())
88  {
89  ROS_ERROR("Not all joints in the chain are calibrated (namespace: %s)", node_.getNamespace().c_str());
90  return false;
91  }
92  if (chain_.size() != Joints)
93  {
94  ROS_ERROR("The JTCartesianController works with %d joints, but the chain from %s to %s has %d joints.",
95  Joints, root_name_.c_str(), tip_name.c_str(), chain_.size());
96  return false;
97  }
98 
99  // Kinematics
100  KDL::Chain kdl_chain;
101  chain_.toKDL(kdl_chain);
102  kin_.reset(new Kin<Joints>(kdl_chain));
103 
104  // Cartesian gains
105  double kp_trans, kd_trans, kp_rot, kd_rot;
106  if (!node_.getParam("cart_gains/trans/p", kp_trans) ||
107  !node_.getParam("cart_gains/trans/d", kd_trans))
108  {
109  ROS_ERROR("P and D translational gains not specified (namespace: %s)", node_.getNamespace().c_str());
110  return false;
111  }
112  if (!node_.getParam("cart_gains/rot/p", kp_rot) ||
113  !node_.getParam("cart_gains/rot/d", kd_rot))
114  {
115  ROS_ERROR("P and D rotational gains not specified (namespace: %s)", node_.getNamespace().c_str());
116  return false;
117  }
118  Kp << kp_trans, kp_trans, kp_trans, kp_rot, kp_rot, kp_rot;
119  Kd << kd_trans, kd_trans, kd_trans, kd_rot, kd_rot, kd_rot;
120 
121  node_.param("pose_command_filter", pose_command_filter_, 1.0);
122 
123  // Velocity saturation
124  node_.param("vel_saturation_trans", vel_saturation_trans_, 0.0);
125  node_.param("vel_saturation_rot", vel_saturation_rot_, 0.0);
126 
127  node_.param("jacobian_inverse_damping", jacobian_inverse_damping_, 0.0);
128  node_.param("joint_vel_filter", joint_vel_filter_, 1.0);
129 
130  // Joint gains
131  for (int i = 0; i < Joints; ++i)
132  node_.param("joint_feedforward/" + chain_.getJoint(i)->joint_->name, joint_dd_ff_[i], 0.0);
133  for (int i = 0; i < Joints; ++i)
134  node_.param("saturation/" + chain_.getJoint(i)->joint_->name, saturation_[i], 0.0);
135 
136  // Posture gains
137  node_.param("k_posture", k_posture_, 1.0);
138 
139  node_.param("resolution/force", res_force_, 0.01);
140  node_.param("resolution/position", res_position_, 0.001);
141  node_.param("resolution/torque", res_torque_, 0.01);
142  node_.param("resolution/orientation", res_orientation_, 0.001);
143 
144 
146  sub_posture_ = node_.subscribe("command_posture", 5, &JTCartesianController::commandPosture, this);
147  sub_pose_ = node_.subscribe("command_pose", 1, &JTCartesianController::commandPose, this);
148 
149  StateMsg state_template;
150  state_template.header.frame_id = root_name_;
151  state_template.x.header.frame_id = root_name_;
152  state_template.x_desi.header.frame_id = root_name_;
153  state_template.x_desi_filtered.header.frame_id = root_name_;
154  state_template.tau_pose.resize(Joints);
155  state_template.tau_posture.resize(Joints);
156  state_template.tau.resize(Joints);
157  state_template.J.layout.dim.resize(2);
158  state_template.J.data.resize(6*Joints);
159  state_template.N.layout.dim.resize(2);
160  state_template.N.data.resize(Joints*Joints);
161  pub_state_.init(node_, "state", 10);
162  pub_state_.lock();
163  pub_state_.msg_ = state_template;
164  pub_state_.unlock();
165 
166  pub_x_desi_.init(node_, "state/x_desi", 10);
167  pub_x_desi_.lock();
168  pub_x_desi_.msg_.header.frame_id = root_name_;
170 
171  return true;
172 }
173 
175 {
176  //Kp << 800.0, 800.0, 800.0, 80.0, 80.0, 80.0;
177  //Kd << 12.0, 12.0, 12.0, 0.0, 0.0, 0.0;
178 
179  JointVec q;
180  chain_.getPositions(q);
181  kin_->fk(q, x_desi_);
184  q_posture_ = q;
185  qdot_filtered_.setZero();
186  last_wrench_.setZero();
187 
188  loop_count_ = 0;
189 }
190 
191 
192 static void computePoseError(const Eigen::Affine3d &xact, const Eigen::Affine3d &xdes, Eigen::Matrix<double,6,1> &err)
193 {
194  err.head<3>() = xact.translation() - xdes.translation();
195  err.tail<3>() = 0.5 * (xdes.linear().col(0).cross(xact.linear().col(0)) +
196  xdes.linear().col(1).cross(xact.linear().col(1)) +
197  xdes.linear().col(2).cross(xact.linear().col(2)));
198 }
199 
201 {
202  // get time
203  ros::Time time = robot_state_->getTime();
204  ros::Duration dt = time - last_time_;
205  last_time_ = time;
206  ++loop_count_;
207 
208  // ======== Measures current arm state
209 
210  JointVec q;
211  chain_.getPositions(q);
212 
213  Eigen::Affine3d x;
214  kin_->fk(q, x);
215 
216  Jacobian J;
217  kin_->jac(q, J);
218 
219 
220  JointVec qdot_raw;
221  chain_.getVelocities(qdot_raw);
222  for (int i = 0; i < Joints; ++i)
223  qdot_filtered_[i] += joint_vel_filter_ * (qdot_raw[i] - qdot_filtered_[i]);
224  JointVec qdot = qdot_filtered_;
225  CartVec xdot = J * qdot;
226 
227  // ======== Controls to the current pose setpoint
228 
229  {
230  Eigen::Vector3d p0(x_desi_filtered_.translation());
231  Eigen::Vector3d p1(x_desi_.translation());
232  Eigen::Quaterniond q0(x_desi_filtered_.linear());
233  Eigen::Quaterniond q1(x_desi_.linear());
234  q0.normalize();
235  q1.normalize();
236 
237  tf::Quaternion tf_q0(q0.x(), q0.y(), q0.z(), q0.w());
238  tf::Quaternion tf_q1(q1.x(), q1.y(), q1.z(), q1.w());
239  tf::Quaternion tf_q = tf_q0.slerp(tf_q1, pose_command_filter_);
240 
241  Eigen::Vector3d p = p0 + pose_command_filter_ * (p1 - p0);
242  //Eigen::Quaterniond q = q0.slerp(pose_command_filter_, q1);
243  Eigen::Quaterniond q(tf_q.w(), tf_q.x(), tf_q.y(), tf_q.z());
244  //x_desi_filtered_ = q * Eigen::Translation3d(p);
245  x_desi_filtered_ = Eigen::Translation3d(p) * q;
246  }
247  CartVec x_err;
248  //computePoseError(x, x_desi_, x_err);
250 
251  CartVec xdot_desi = (Kp.array() / Kd.array()) * x_err.array() * -1.0;
252 
253  // Caps the cartesian velocity
254  if (vel_saturation_trans_ > 0.0)
255  {
256  if (fabs(xdot_desi.head<3>().norm()) > vel_saturation_trans_)
257  xdot_desi.head<3>() *= (vel_saturation_trans_ / xdot_desi.head<3>().norm());
258  }
259  if (vel_saturation_rot_ > 0.0)
260  {
261  if (fabs(xdot_desi.tail<3>().norm()) > vel_saturation_rot_)
262  xdot_desi.tail<3>() *= (vel_saturation_rot_ / xdot_desi.tail<3>().norm());
263  }
264 
265  CartVec F = Kd.array() * (xdot_desi - xdot).array();
266 
267  JointVec tau_pose = J.transpose() * F;
268 
269  // ======== J psuedo-inverse and Nullspace computation
270 
271  // Computes pseudo-inverse of J
272  Eigen::Matrix<double,6,6> I6; I6.setIdentity();
273  //Eigen::Matrix<double,6,6> JJt = J * J.transpose();
274  //Eigen::Matrix<double,6,6> JJt_inv = JJt.inverse();
275  Eigen::Matrix<double,6,6> JJt_damped = J * J.transpose() + jacobian_inverse_damping_ * I6;
276  Eigen::Matrix<double,6,6> JJt_inv_damped = JJt_damped.inverse();
277  Eigen::Matrix<double,Joints,6> J_pinv = J.transpose() * JJt_inv_damped;
278 
279  // Computes the nullspace of J
280  Eigen::Matrix<double,Joints,Joints> I;
281  I.setIdentity();
282  Eigen::Matrix<double,Joints,Joints> N = I - J_pinv * J;
283 
284  // ======== Posture control
285 
286  // Computes the desired joint torques for achieving the posture
287  JointVec tau_posture;
288  tau_posture.setZero();
289  if (use_posture_)
290  {
291  JointVec posture_err = q_posture_ - q;
292  for (size_t j = 0; j < Joints; ++j)
293  {
294  if (chain_.getJoint(j)->joint_->type == urdf::Joint::CONTINUOUS)
295  posture_err[j] = angles::normalize_angle(posture_err[j]);
296  }
297 
298  for (size_t j = 0; j < Joints; ++j) {
299  if (fabs(q_posture_[j] - 9999) < 1e-5)
300  posture_err[j] = 0.0;
301  }
302 
303  JointVec qdd_posture = k_posture_ * posture_err;
304  tau_posture = joint_dd_ff_.array() * (N * qdd_posture).array();
305  }
306 
307  JointVec tau = tau_pose + tau_posture;
308 
309  // ======== Torque Saturation
310  double sat_scaling = 1.0;
311  for (int i = 0; i < Joints; ++i) {
312  if (saturation_[i] > 0.0)
313  sat_scaling = std::min(sat_scaling, fabs(saturation_[i] / tau[i]));
314  }
315  JointVec tau_sat = sat_scaling * tau;
316 
317  chain_.addEfforts(tau_sat);
318 
319  if (loop_count_ % 10 == 0)
320  {
321  if (pub_x_desi_.trylock()) {
322  pub_x_desi_.msg_.header.stamp = time;
325  }
326 
327  if (pub_state_.trylock()) {
328  pub_state_.msg_.header.stamp = time;
329  pub_state_.msg_.x.header.stamp = time;
331  pub_state_.msg_.x_desi.header.stamp = time;
333  pub_state_.msg_.x_desi_filtered.header.stamp = time;
334  tf::poseEigenToMsg(x_desi_filtered_, pub_state_.msg_.x_desi_filtered.pose);
335  tf::twistEigenToMsg(x_err, pub_state_.msg_.x_err);
337  tf::twistEigenToMsg(xdot_desi, pub_state_.msg_.xd_desi);
341  for (size_t j = 0; j < Joints; ++j) {
342  pub_state_.msg_.tau_pose[j] = tau_pose[j];
343  pub_state_.msg_.tau_posture[j] = tau_posture[j];
344  pub_state_.msg_.tau[j] = tau[j];
345  }
347  }
348  }
349 }
350 
351 } //namespace
PLUGINLIB_EXPORT_CLASS(my_controller_ns::MyControllerClass, pr2_controller_interface::Controller)
Header header
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void twistEigenToMsg(const Eigen::Matrix< double, 6, 1 > &e, geometry_msgs::Twist &m)
void getPositions(std::vector< double > &)
realtime_tools::RealtimePublisher< geometry_msgs::PoseStamped > pub_x_desi_
void commandPosture(const std_msgs::Float64MultiArray::ConstPtr &msg)
static void computePoseError(const Eigen::Affine3d &xact, const Eigen::Affine3d &xdes, Eigen::Matrix< double, 6, 1 > &err)
realtime_tools::RealtimePublisher< StateMsg > pub_state_
Eigen::Matrix< double, 6, 1 > Kp
boost::shared_ptr< const urdf::Joint > joint_
Eigen::Matrix< double, 6, 1 > Kd
void getVelocities(std::vector< double > &)
Quaternion slerp(const Quaternion &q, const tfScalar &t) const
void setGains(const std_msgs::Float64MultiArray::ConstPtr &msg)
bool init(pr2_mechanism_model::RobotState *robot, ros::NodeHandle &n)
Eigen::Matrix< double, 6, 1 > CartVec
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void matrixEigenToMsg(const Eigen::MatrixBase< Derived > &e, std_msgs::Float64MultiArray &m)
const std::string & getNamespace() const
TFSIMD_FORCE_INLINE const tfScalar & x() const
def normalize_angle(angle)
JointState * getJoint(unsigned int actuated_joint_i)
Eigen::Matrix< double, Joints, 1 > JointVec
void init(const ros::NodeHandle &node, const std::string &topic, int queue_size, bool latched=false)
void wrenchEigenToMsg(const Eigen::Matrix< double, 6, 1 > &e, geometry_msgs::Wrench &m)
bool getParam(const std::string &key, std::string &s) const
Eigen::Matrix< double, 6, Joints > Jacobian
bool init(RobotState *robot_state, const std::string &root, const std::string &tip)
robot_mechanism_controllers::JTCartesianControllerState StateMsg
pr2_mechanism_model::RobotState * robot_state_
boost::scoped_ptr< Kin< Joints > > kin_
#define ROS_ERROR(...)
ros::Time stamp
void toKDL(KDL::Chain &chain)
void addEfforts(KDL::JntArray &)
void commandPose(const geometry_msgs::PoseStamped::ConstPtr &command)


robot_mechanism_controllers
Author(s): John Hsu, Melonee Wise, Stuart Glaser
autogenerated on Wed Jun 5 2019 19:34:03