control_policies.hpp
Go to the documentation of this file.
1 // -- BEGIN LICENSE BLOCK ----------------------------------------------
2 // Copyright 2020 FZI Forschungszentrum Informatik
3 // Created on behalf of Universal Robots A/S
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // -- END LICENSE BLOCK ------------------------------------------------
17 
18 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
26 
28 
29 #include <memory>
30 #include <geometry_msgs/PoseStamped.h>
31 #include <geometry_msgs/TwistStamped.h>
32 
33 // KDL
34 #include <kdl/tree.hpp>
36 #include <kdl/jntarray.hpp>
41 #include "kdl/chainiksolvervel_wdls.hpp"
42 #include "kdl/frames.hpp"
43 #include "kdl/framevel.hpp"
44 #include "kdl/jntarrayvel.hpp"
45 
46 // URDF
47 #include <urdf/model.h>
48 
50 {
51 template <class HWInterface, class HandleType>
53  ros::NodeHandle& controller_nh)
54 {
55  std::string robot_description;
56  std::vector<std::string> joint_names;
57  urdf::Model robot_model;
58  KDL::Tree robot_tree;
59 
60  const std::string ns = controller_nh.getNamespace();
61 
62  // Preconditions
63  auto* hw_interface = hw->get<HWInterface>();
64  if (!hw_interface)
65  {
66  ROS_ERROR_STREAM(ns << ": No PositionJointInterface found.");
67  return false;
68  }
69 
70  // Joint control interfaces
71  if (!controller_nh.getParam("joints", joint_names))
72  {
73  ROS_ERROR_STREAM(ns << ": Failed to load joints from parameter server");
74  return false;
75  }
76  for (size_t i = 0; i < joint_names.size(); ++i)
77  {
78  joint_handles_.push_back(hw_interface->getHandle(joint_names[i]));
79  }
80 
81  // Manipulator specific configuration
82  if (!root_nh.getParam("robot_description", robot_description))
83  {
84  ROS_ERROR_STREAM(ns << ": Failed to load robot_description from parameter server");
85  return false;
86  }
87  if (!controller_nh.getParam("base", robot_base_))
88  {
89  ROS_ERROR_STREAM(ns << ": Failed to load base from parameter server");
90  return false;
91  }
92  if (!controller_nh.getParam("tip", robot_tip_))
93  {
94  ROS_ERROR_STREAM(ns << ": Failed to load tip from parameter server");
95  return false;
96  }
97 
98  // Construction of kinematics
99  if (!robot_model.initString(robot_description))
100  {
101  ROS_ERROR_STREAM(ns << ": Failed to parse urdf model from robot_description");
102  return false;
103  }
104  if (!kdl_parser::treeFromUrdfModel(robot_model, robot_tree))
105  {
106  ROS_ERROR_STREAM(ns << ": Failed to parse KDL tree from urdf model");
107  return false;
108  }
109  if (!robot_tree.getChain(robot_base_, robot_tip_, robot_chain_))
110  {
111  ROS_ERROR_STREAM(ns << ": Failed to parse robot chain from urdf model.");
112  return false;
113  }
114 
115  fk_solver_ = std::make_unique<KDL::ChainFkSolverVel_recursive>(robot_chain_);
116 
117  return true;
118 }
119 
120 template <class HWInterface, class HandleType>
122 {
123  const size_t size = joint_handles_.size();
124 
125  KDL::JntArrayVel current(size);
126  KDL::FrameVel pose;
127 
128  // Compute forward kinematics
129  for (size_t i = 0; i < size; ++i)
130  {
131  current.q(i) = joint_handles_[i].getPosition();
132  current.qdot(i) = joint_handles_[i].getVelocity();
133  }
134  fk_solver_->JntToCart(current, pose);
135 
136  // Pose
137  CartesianState state;
138  state.p.x() = pose.value().p.x();
139  state.p.y() = pose.value().p.y();
140  state.p.z() = pose.value().p.z();
141  pose.value().M.GetQuaternion(state.q.x(), state.q.y(), state.q.z(), state.q.w());
142 
143  // Velocity
144  state.v.x() = pose.deriv().vel.x();
145  ;
146  state.v.y() = pose.deriv().vel.y();
147  ;
148  state.v.z() = pose.deriv().vel.z();
149  ;
150  state.w.x() = pose.deriv().rot.x();
151  ;
152  state.w.y() = pose.deriv().rot.y();
153  ;
154  state.w.z() = pose.deriv().rot.z();
155  ;
156 
157  return state;
158 };
159 
160 //--------------------------------------------------------------------------------
161 // Cartesian pose
162 //--------------------------------------------------------------------------------
163 
165  ros::NodeHandle& root_nh,
166  ros::NodeHandle& controller_nh)
167 {
168  const std::string ns = controller_nh.getNamespace();
169 
170  // Preconditions
171  auto* cmd_interface = hw->get<ros_controllers_cartesian::PoseCommandInterface>();
172  if (!cmd_interface)
173  {
174  ROS_ERROR_STREAM(ns << ": No PoseCommandInterface found.");
175  return false;
176  }
177  if (!controller_nh.getParam("base", base_))
178  {
179  ROS_ERROR_STREAM(ns << ": Failed to load base from parameter server");
180  return false;
181  }
182  if (!controller_nh.getParam("tip", tip_))
183  {
184  ROS_ERROR_STREAM(ns << ": Failed to load tip from parameter server");
185  return false;
186  }
187 
188  handle_ = cmd_interface->getHandle(tip_);
189 
190  return true;
191 }
192 
194 {
195  geometry_msgs::Pose target;
196 
197  target.position.x = cmd.p.x();
198  target.position.y = cmd.p.y();
199  target.position.z = cmd.p.z();
200  target.orientation.x = cmd.q.x();
201  target.orientation.y = cmd.q.y();
202  target.orientation.z = cmd.q.z();
203  target.orientation.w = cmd.q.w();
204 
205  handle_.setCommand(target);
206 }
207 
209 {
210  geometry_msgs::Pose pose = handle_.getPose();
211  geometry_msgs::Twist twist = handle_.getTwist();
212  geometry_msgs::Accel accel = handle_.getAccel();
213 
214  CartesianState state;
215  state.p.x() = pose.position.x;
216  state.p.y() = pose.position.y;
217  state.p.z() = pose.position.z;
218  state.q.x() = pose.orientation.x;
219  state.q.y() = pose.orientation.y;
220  state.q.z() = pose.orientation.z;
221  state.q.w() = pose.orientation.w;
222 
223  state.v.x() = twist.linear.x;
224  state.v.y() = twist.linear.y;
225  state.v.z() = twist.linear.z;
226  state.w.x() = twist.angular.x;
227  state.w.y() = twist.angular.y;
228  state.w.z() = twist.angular.z;
229 
230  state.v_dot.x() = accel.linear.x;
231  state.v_dot.y() = accel.linear.y;
232  state.v_dot.z() = accel.linear.z;
233  state.w_dot.x() = accel.angular.x;
234  state.w_dot.y() = accel.angular.y;
235  state.w_dot.z() = accel.angular.z;
236 
237  return state;
238 }
239 
240 //--------------------------------------------------------------------------------
241 // Joint position
242 //--------------------------------------------------------------------------------
243 
245  ros::NodeHandle& root_nh,
246  ros::NodeHandle& controller_nh)
247 {
248  if (!Base::init(hw, root_nh, controller_nh))
249  {
250  return false;
251  };
252 
253  // Load user specified inverse kinematics solver
254  std::string solver_type = controller_nh.param("ik_solver", std::string("example_solver"));
255 
256  solver_loader_ = std::make_unique<pluginlib::ClassLoader<IKSolver>>("cartesian_trajectory_controller", "ros_"
257  "controllers_"
258  "cartesian::"
259  "IKSolver");
260  try
261  {
262  ik_solver_.reset(solver_loader_->createUnmanagedInstance(solver_type));
263  }
265  {
266  ROS_ERROR_STREAM(ex.what());
267  return false;
268  }
269 
270  if (!ik_solver_->init(robot_chain_, root_nh, controller_nh))
271  {
272  return false;
273  }
274 
275  return true;
276 }
277 
279 {
280  const size_t size = joint_handles_.size();
281 
282  KDL::JntArray current(size);
283  KDL::JntArray target(size);
284  KDL::Frame goal;
285 
286  goal.p[0] = cmd.p.x();
287  goal.p[1] = cmd.p.y();
288  goal.p[2] = cmd.p.z();
289  goal.M = KDL::Rotation::Quaternion(cmd.q.x(), cmd.q.y(), cmd.q.z(), cmd.q.w());
290 
291  // Start where we are
292  for (size_t i = 0; i < size; ++i)
293  {
294  current(i) = joint_handles_[i].getPosition();
295  }
296 
297  // Compute inverse kinematics
298  ik_solver_->cartToJnt(current, goal, target);
299 
300  // Command each joint
301  for (size_t i = 0; i < size; ++i)
302  {
303  joint_handles_[i].setCommand(target(i));
304  }
305 }
306 
307 //--------------------------------------------------------------------------------
308 // Joint velocity
309 //--------------------------------------------------------------------------------
310 
312  ros::NodeHandle& root_nh,
313  ros::NodeHandle& controller_nh)
314 {
315  if (!Base::init(hw, root_nh, controller_nh))
316  {
317  return false;
318  };
319 
320  ik_solver_ = std::make_unique<KDL::ChainIkSolverVel_wdls>(robot_chain_);
321  return true;
322 }
323 
325 {
326  const size_t size = joint_handles_.size();
327 
328  KDL::JntArray current(size);
329  KDL::JntArray target(size);
330  KDL::Twist goal;
331 
332  goal.vel[0] = cmd.v.x();
333  goal.vel[1] = cmd.v.y();
334  goal.vel[2] = cmd.v.z();
335  goal.rot[0] = cmd.w.x();
336  goal.rot[1] = cmd.w.y();
337  goal.rot[2] = cmd.w.z();
338 
339  // Start where we are
340  for (size_t i = 0; i < size; ++i)
341  {
342  current(i) = joint_handles_[i].getPosition();
343  }
344 
345  // Compute joint velocities
346  ik_solver_->CartToJnt(current, goal, target);
347 
348  // Command each joint
349  for (size_t i = 0; i < size; ++i)
350  {
351  joint_handles_[i].setCommand(target(i));
352  }
353 }
354 
355 //--------------------------------------------------------------------------------
356 // Trajectory publishing
357 //--------------------------------------------------------------------------------
358 
360  ros::NodeHandle& root_nh,
361  ros::NodeHandle& controller_nh)
362 {
363  if (!Base::init(hw, root_nh, controller_nh))
364  {
365  return false;
366  };
367 
368  // Publishers
369  pose_publisher_ = controller_nh.advertise<geometry_msgs::PoseStamped>("reference_pose", 10);
370  twist_publisher_ = controller_nh.advertise<geometry_msgs::TwistStamped>("reference_twist", 10);
371 
372  return true;
373 }
374 
376 {
377  // Pose
378  geometry_msgs::PoseStamped p;
379  p.header.frame_id = this->robot_base_;
380  p.header.stamp = ros::Time::now();
381  p.pose.position.x = cmd.p.x();
382  p.pose.position.y = cmd.p.y();
383  p.pose.position.z = cmd.p.z();
384  p.pose.orientation.x = cmd.q.x();
385  p.pose.orientation.y = cmd.q.y();
386  p.pose.orientation.z = cmd.q.z();
387  p.pose.orientation.w = cmd.q.w();
388 
389  pose_publisher_.publish(p);
390 
391  // Twist
392  geometry_msgs::TwistStamped t;
393  t.header.frame_id = this->robot_base_;
394  t.header.stamp = ros::Time::now();
395  t.twist.linear.x = cmd.v.x();
396  t.twist.linear.y = cmd.v.y();
397  t.twist.linear.z = cmd.v.z();
398  t.twist.angular.x = cmd.w.x();
399  t.twist.angular.y = cmd.w.y();
400  t.twist.angular.z = cmd.w.z();
401 
402  twist_publisher_.publish(t);
403 }
404 } // namespace ros_controllers_cartesian
double y() const
double x() const
URDF_EXPORT bool initString(const std::string &xmlstring)
KDL_PARSER_PUBLIC bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
Vector vel
Frame value() const
static Rotation Quaternion(double x, double y, double z, double w)
Rotation M
bool param(const std::string &param_name, T &param_val, const T &default_val) const
Vector rot
bool getParam(const std::string &key, std::string &s) const
virtual bool init(hardware_interface::RobotHW *hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh) override
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const std::string & getNamespace() const
void GetQuaternion(double &x, double &y, double &z, double &w) const
Twist deriv() const
double z() const
static Time now()
#define ROS_ERROR_STREAM(args)


cartesian_trajectory_controller
Author(s):
autogenerated on Thu Feb 23 2023 03:10:48