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 {
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()
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.
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.
const Segment & getSegment(unsigned int nr) const
#define ROS_ERROR(...)
virtual int requestStart(const std::string &name)
boost::shared_ptr< KDL::ChainFkSolverPos_recursive > fksolver_
Rotation M
const Joint & getJoint() const
virtual int requestStop(const std::string &name)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
unsigned int getNrOfJoints() const
#define ROS_ERROR_THROTTLE(period,...)
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
virtual void update(const ros::Time &now, const ros::Duration &dt)
This is the update loop for the controller.
virtual std::vector< std::string > getClaimedNames()
Get the names of joints/controllers which this controller exclusively claims.
const JointType & getType() const
void resize(unsigned int newSize)
virtual bool stop(bool force)
Attempt to stop the controller. This should be called only by the ControllerManager instance...
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()
const std::string & getName() const
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_DEBUG_THROTTLE(period,...)


robot_controllers
Author(s): Michael Ferguson
autogenerated on Mon Feb 28 2022 23:26:08