cartesian_twist.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2014, Fetch Robotics Inc.
5  * Copyright (c) 2013, Unbounded Robotics Inc.
6  * Copyright (c) 2008, Willow Garage, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Unbounded Robotics nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *********************************************************************/
36 
37 /*
38  * Derived a bit from pr2_controllers/cartesian_pose_controller.cpp
39  * Author: Michael Ferguson, Wim Meeussen, Hanjun Song
40  */
41 
44 
45 #include <urdf/model.h>
47 
48 #include <tf_conversions/tf_kdl.h>
49 
51 
52 namespace robot_controllers
53 {
54 CartesianTwistController::CartesianTwistController() :
55  initialized_(false),
56  is_active_(false)
57 {
58 }
59 
61 {
62  // We absolutely need access to the controller manager
63  if (!manager)
64  {
65  initialized_ = false;
66  return -1;
67  }
68 
69  Controller::init(nh, manager);
70  manager_ = manager;
71 
72  // Initialize KDL structures
73  std::string tip_link, root_link;
74  nh.param<std::string>("root_name", root_link, "torso_lift_link");
75  nh.param<std::string>("tip_name", tip_link, "wrist_roll_link");
76 
77  // Load URDF
78  urdf::Model model;
79  if (!model.initParam("robot_description"))
80  {
81  ROS_ERROR("Failed to parse URDF");
82  return -1;
83  }
84 
85  // Load the tree
86  KDL::Tree kdl_tree;
87  if (!kdl_parser::treeFromUrdfModel(model, kdl_tree))
88  {
89  ROS_ERROR("Could not construct tree from URDF");
90  return -1;
91  }
92 
93  // Populate the Chain
94  if (!kdl_tree.getChain(root_link, tip_link, kdl_chain_))
95  {
96  ROS_ERROR("Could not construct chain from URDF");
97  return -1;
98  }
99 
102  unsigned num_joints = kdl_chain_.getNrOfJoints();
103  tgt_jnt_pos_.resize(num_joints);
104  tgt_jnt_vel_.resize(num_joints);
105  last_tgt_jnt_vel_.resize(num_joints);
106 
107  // Init Joint Handles
108  joints_.clear();
109  for (size_t i = 0; i < kdl_chain_.getNrOfSegments(); ++i)
112 
113  if (joints_.size() != num_joints)
114  {
115  ROS_ERROR("Inconsistant joint count %d, %d", num_joints, int(joints_.size()));
116  return -1;
117  }
118 
119  for (unsigned ii = 0; ii < num_joints; ++ii)
120  {
121  last_tgt_jnt_vel_(ii) = 0.0;
122  }
123 
124  // Subscribe to command
125  command_sub_ = nh.subscribe<geometry_msgs::TwistStamped>("command", 1,
126  boost::bind(&CartesianTwistController::command, this, _1));
128 
129  initialized_ = true;
130  return 0;
131 }
132 
134 {
135  if (!initialized_)
136  {
137  ROS_ERROR_NAMED("CartesianTwistController",
138  "Unable to start, not initialized.");
139  is_active_ = false;
140  return false;
141  }
142 
143  for (unsigned ii = 0; ii < joints_.size(); ++ii)
144  {
145  last_tgt_jnt_vel_(ii) = joints_[ii]->getVelocity();
146  tgt_jnt_pos_(ii) = joints_[ii]->getPosition();
147  }
148  is_active_ = true;
149  return true;
150 }
151 
153 {
154  is_active_ = false;
155  return true;
156 }
157 
159 {
160  // Simply stop
161  return (manager_->requestStop(getName()) == 0);
162 }
163 
165 {
166  // Need to initialize KDL structs
167  if (!initialized_)
168  return; // Should never really hit this
169 
170  KDL::Frame cart_pose;
171  // Copy desired twist and update time to local var to reduce lock contention
172  KDL::Twist twist;
173  ros::Time last_command_time;
174  {
175  boost::mutex::scoped_lock lock(mutex_);
176  // FK is used to transform the twist command seen from end-effector frame to the one seen from body frame.
177  if (fksolver_->JntToCart(tgt_jnt_pos_, cart_pose) < 0)
178  {
179  twist.Zero();
180  ROS_ERROR_THROTTLE(1.0, "FKsolver solver failed");
181  }
182  else
183  {
184  if (twist_command_frame_ == "end_effector_frame")
185  {
186  twist = cart_pose.M*twist_command_;
187  }
188  else
189  {
190  twist = twist_command_;
191  }
192  }
193  last_command_time = last_command_time_;
194  }
195 
196  unsigned num_joints = joints_.size();
197 
198  if ((now - last_command_time) > ros::Duration(0.5))
199  {
201  }
202 
203  // change the twist here
204  if (solver_->CartToJnt(tgt_jnt_pos_, twist, tgt_jnt_vel_) < 0)
205  {
206  for (unsigned ii = 0; ii < num_joints; ++ii)
207  {
208  tgt_jnt_vel_(ii) = 0.0;
209  }
210  }
211 
212  // Limit joint velocities by scaling all target velocities equally so resulting movement is in same direction
213  double max_vel = 0.0;
214  for (unsigned ii = 0; ii < num_joints; ++ii)
215  {
216  max_vel = std::max(std::abs(tgt_jnt_vel_(ii)), max_vel);
217  }
218 
219  double joint_velocity_limit = 0.5;
220  double scale = 1.0;
221  if (max_vel > joint_velocity_limit)
222  {
223  double scale = joint_velocity_limit / max_vel;
224  for (unsigned ii = 0; ii < num_joints; ++ii)
225  {
226  tgt_jnt_vel_(ii) *= scale;
227  }
228  ROS_DEBUG_THROTTLE(1.0, "Joint velocity limit reached.");
229  }
230 
231  // Make sure solver didn't generate any NaNs.
232  for (unsigned ii = 0; ii < num_joints; ++ii)
233  {
234  if (!std::isfinite(tgt_jnt_vel_(ii)))
235  {
236  ROS_ERROR_THROTTLE(1.0, "Target joint velocity (%d) is not finite : %f", ii, tgt_jnt_vel_(ii));
237  tgt_jnt_vel_(ii) = 1.0;
238  }
239  }
240 
241  // Limit accelerations while trying to keep same resulting direction
242  // somewhere between previous and current value
243  scale = 1.0;
244  double accel_limit = 1.0;
245  double vel_delta_limit = accel_limit * dt.toSec();
246  for (unsigned ii = 0; ii < num_joints; ++ii)
247  {
248  double vel_delta = std::abs(tgt_jnt_vel_(ii) - last_tgt_jnt_vel_(ii));
249  if (vel_delta > vel_delta_limit)
250  {
251  scale = std::min(scale, vel_delta_limit/vel_delta);
252  }
253  }
254 
255  if (scale <= 0.0)
256  {
257  ROS_ERROR_THROTTLE(1.0, "CartesianTwistController: acceleration limit produces non-positive scale %f", scale);
258  scale = 0.0;
259  }
260 
261  // Linear interpolate betwen previous velocity and new target velocity using scale.
262  // scale = 1.0 final velocity = new target velocity
263  // scale = 0.0 final velocity = previous velocity
264  for (unsigned ii = 0; ii < num_joints; ++ii)
265  {
266  tgt_jnt_vel_(ii) = (tgt_jnt_vel_(ii) - last_tgt_jnt_vel_(ii))*scale + last_tgt_jnt_vel_(ii);
267  }
268 
269  // Calculate new target position of joint. Put target position a few timesteps into the future
270  double dt_sec = dt.toSec();
271  for (unsigned ii = 0; ii < num_joints; ++ii)
272  {
273  tgt_jnt_pos_(ii) += tgt_jnt_vel_(ii) * dt_sec;
274  }
275 
276  // Limit target position of joint
277  for (unsigned ii = 0; ii < num_joints; ++ii)
278  {
279  if (!joints_[ii]->isContinuous())
280  {
281  if (tgt_jnt_pos_(ii) > joints_[ii]->getPositionMax())
282  {
283  tgt_jnt_pos_(ii) = joints_[ii]->getPositionMax();
284  }
285  else if (tgt_jnt_pos_(ii) < joints_[ii]->getPositionMin())
286  {
287  tgt_jnt_pos_(ii) = joints_[ii]->getPositionMin();
288  }
289  }
290  }
291 
292 
293  for (size_t ii = 0; ii < joints_.size(); ++ii)
294  {
295  joints_[ii]->setPosition(tgt_jnt_pos_(ii), tgt_jnt_vel_(ii), 0.0);
297  }
298 }
299 
300 void CartesianTwistController::command(const geometry_msgs::TwistStamped::ConstPtr& goal)
301 {
302  // Need to initialize KDL structs
303  if (!initialized_)
304  {
305  ROS_ERROR("CartesianTwistController: Cannot accept goal, controller is not initialized.");
306  return;
307  }
308 
309  if (goal->header.frame_id.empty())
310  {
312  return;
313  }
314 
315  KDL::Twist twist;
316  twist(0) = goal->twist.linear.x;
317  twist(1) = goal->twist.linear.y;
318  twist(2) = goal->twist.linear.z;
319  twist(3) = goal->twist.angular.x;
320  twist(4) = goal->twist.angular.y;
321  twist(5) = goal->twist.angular.z;
322 
323  for (int ii=0; ii<6; ++ii)
324  {
325  if (!std::isfinite(twist(ii)))
326  {
327  ROS_ERROR_THROTTLE(1.0, "Twist command value (%d) is not finite : %f", ii, twist(ii));
328  twist(ii) = 0.0;
329  }
330  }
331 
332  ros::Time now(ros::Time::now());
333 
334  {
335  boost::mutex::scoped_lock lock(mutex_);
336  twist_command_frame_ = goal->header.frame_id;
337  twist_command_ = twist;
338  last_command_time_ = now;
339  }
340  // Try to start up
341  if (!is_active_ && manager_->requestStart(getName()) != 0)
342  {
343  ROS_ERROR("CartesianTwistController: Cannot start, blocked by another controller.");
344  return;
345  }
346 }
347 
349 {
350  std::vector<std::string> names;
351  if (initialized_)
352  {
353  for (size_t i = 0; i < kdl_chain_.getNrOfSegments(); ++i)
355  names.push_back(kdl_chain_.getSegment(i).getJoint().getName());
356  }
357  return names;
358 }
359 
361 {
362  return getCommandedNames();
363 }
364 
365 } // namespace robot_controllers
boost::shared_ptr< KDL::ChainIkSolverVel_wdls > solver_
static Twist Zero()
const Segment & getSegment(unsigned int nr) const
KDL_PARSER_PUBLIC bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
virtual int init(ros::NodeHandle &nh, ControllerManager *manager)
Initialize the controller and any required data structures.
#define ROS_DEBUG_THROTTLE(rate,...)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
unsigned int getNrOfSegments() const
void command(const geometry_msgs::TwistStamped::ConstPtr &goal)
Controller command.
virtual int requestStart(const std::string &name)
boost::shared_ptr< KDL::ChainFkSolverPos_recursive > fksolver_
Rotation M
#define ROS_ERROR_THROTTLE(rate,...)
virtual int requestStop(const std::string &name)
const std::string & getName() const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
const Joint & getJoint() const
virtual void update(const ros::Time &now, const ros::Duration &dt)
This is the update loop for the controller.
unsigned int getNrOfJoints() const
virtual std::vector< std::string > getClaimedNames()
Get the names of joints/controllers which this controller exclusively claims.
void resize(unsigned int newSize)
virtual bool stop(bool force)
Attempt to stop the controller. This should be called only by the ControllerManager instance...
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
virtual int init(ros::NodeHandle &nh, ControllerManager *manager)
virtual bool reset()
Cleanly reset the controller to it&#39;s initial state. Some controllers may choose to stop themselves...
#define ROS_ERROR_NAMED(name,...)
virtual std::vector< std::string > getCommandedNames()
Get the names of joints/controllers which this controller commands.
static Time now()
virtual bool start()
Attempt to start the controller. This should be called only by the ControllerManager instance...
JointHandlePtr getJointHandle(const std::string &name)
std::vector< JointHandlePtr > joints_
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
#define ROS_ERROR(...)
const JointType & getType() const


robot_controllers
Author(s): Michael Ferguson
autogenerated on Sun Sep 27 2020 03:22:39