kinematic_tree.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2018-2020, University of Edinburgh, University of Oxford
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without specific
15 // prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 #include <algorithm>
31 #include <iostream>
32 #include <queue>
33 #include <set>
34 
39 #include <octomap_msgs/Octomap.h>
41 #include <tf_conversions/tf_kdl.h>
42 #include <kdl/frames_io.hpp>
44 
46 #include <exotica_core/server.h>
47 #include <exotica_core/tools.h>
48 
49 namespace exotica
50 {
52 
54 {
55  flags = _flags;
56  frame.resize(_size);
57  Phi.resize(_size);
58  if (flags & KIN_FK_VEL) Phi_dot.resize(_size);
59  KDL::Jacobian Jzero(_n);
60  Jzero.data.setZero();
61  Hessian Hzero = Hessian::Constant(6, Eigen::MatrixXd::Zero(_n, _n));
62  if (_flags & KIN_J) jacobian = ArrayJacobian::Constant(_size, Jzero);
63  if (_flags & KIN_H) hessian = ArrayHessian::Constant(_size, Hzero);
64  x.setZero(_n);
65 }
66 
68 
70 
71 KinematicFrameRequest::KinematicFrameRequest(std::string _frame_A_link_name, KDL::Frame _frame_A_offset, std::string _frame_B_link_name, KDL::Frame _frame_B_offset) : frame_A_link_name(_frame_A_link_name), frame_A_offset(_frame_A_offset), frame_B_link_name(_frame_B_link_name), frame_B_offset(_frame_B_offset)
72 {
73 }
74 
76 
77 KinematicSolution::KinematicSolution(int _start, int _length) : start(_start), length(_length)
78 {
79 }
80 
81 void KinematicSolution::Create(std::shared_ptr<KinematicResponse> solution)
82 {
83  if (start < 0 || length < 0) ThrowPretty("Kinematic solution was not initialized!");
84  new (&Phi) Eigen::Map<ArrayFrame>(solution->Phi.data() + start, length);
85  new (&X) Eigen::Map<Eigen::VectorXd>(solution->x.data(), solution->x.rows());
86  if (solution->flags & KIN_FK_VEL) new (&Phi_dot) Eigen::Map<ArrayTwist>(solution->Phi_dot.data() + start, length);
87  if (solution->flags & KIN_J) new (&jacobian) Eigen::Map<ArrayJacobian>(solution->jacobian.data() + start, length);
88  if (solution->flags & KIN_H) new (&hessian) Eigen::Map<ArrayHessian>(solution->hessian.data() + start, length);
89 }
90 
92 {
93  return num_controlled_joints_;
94 }
95 
97 {
98  return num_joints_;
99 }
100 
101 void KinematicTree::Instantiate(const std::string& joint_group, robot_model::RobotModelPtr model, const std::string& name)
102 {
103  if (!model) ThrowPretty("No robot model provided!");
104  model_joints_names_ = model->getVariableNames();
105  name_ = name;
106 
107  // Check if no joint group name is given - if so, default to all joints.
108  const robot_model::JointModelGroup* group = model->getJointModelGroup(joint_group);
109  if (!group)
110  {
111  auto names = model->getJointModelGroupNames();
112 
113  // If a particular joint group is desired, but we may have a user error and will throw an exception.
114  if (!joint_group.empty())
115  {
116  std::stringstream ss;
117  ss << "Joint group '" << joint_group << "' not defined in the robot model. " << names.size() << " joint groups available";
118  if (names.size() > static_cast<std::size_t>(0))
119  {
120  ss << ": ";
121  for (const auto& joint_group_name : names)
122  ss << joint_group_name << ", ";
123  }
124  ThrowPretty(ss.str());
125  }
126  else
127  {
128  // The joint group was left empty: We default to all _active_ joints (no fixed, no mimic).
129  // Alternatives: getJointModelNames, getVariableNames
130  for (auto joint_model : model->getActiveJointModels())
131  controlled_joints_names_.push_back(joint_model->getName());
132  }
133  }
134  else
135  {
136  // Use the joints from the desired joint group.
137  controlled_joints_names_ = group->getVariableNames();
138  }
139 
140  model_ = model;
141  KDL::Tree robot_kinematics;
142  if (kdl_parser::treeFromUrdfModel(*model_->getURDF(), robot_kinematics))
143  {
144  BuildTree(robot_kinematics);
145  }
146  else
147  {
148  ThrowPretty("Can't load URDF model!");
149  }
150 
151  if (Server::IsRos())
152  {
153  shapes_pub_ = Server::Advertise<visualization_msgs::MarkerArray>(name_ + (name_ == "" ? "" : "/") + "CollisionShapes", 1, true);
154  octomap_pub_ = Server::Advertise<octomap_msgs::Octomap>(name_ + (name_ == "" ? "" : "/") + "OctoMap", 1, true);
155  debug_scene_changed_ = true;
156  // Clear scene
157  visualization_msgs::MarkerArray msg;
158  msg.markers.resize(1);
159  msg.markers[0].action = 3; // DELETE_ALL
160  shapes_pub_.publish(msg);
161  }
162 }
163 
164 void KinematicTree::BuildTree(const KDL::Tree& robot_kinematics)
165 {
166  model_tree_.clear();
167  tree_.clear();
168  tree_map_.clear();
169  model_joints_map_.clear();
170  model_link_names_.clear();
171  controlled_link_names_.clear();
172 
173  // Handle the root joint
174  const robot_model::JointModel* root_joint = model_->getRootJoint();
175  root_joint_name_ = root_joint->getName();
176  std::string world_frame_name;
177  for (const srdf::Model::VirtualJoint& s : model_->getSRDF()->getVirtualJoints())
178  {
179  if (s.name_ == root_joint->getName())
180  {
181  world_frame_name = s.parent_frame_;
182  }
183  }
184  // if (world_frame_name == "") ThrowPretty("Can't initialize root joint!");
185  if (world_frame_name.empty())
186  {
187  world_frame_name = "world_frame";
188  WARNING_NAMED("KinematicTree", "No virtual joint defined. Defaulting world frame to " << world_frame_name)
189  }
190 
191  // Extract Root Inertial
192  double root_mass = 0.0;
193  KDL::Vector root_cog = KDL::Vector::Zero();
194  auto& urdf_root_inertial = model_->getURDF()->getRoot()->inertial;
195  if (urdf_root_inertial)
196  {
197  root_mass = urdf_root_inertial->mass;
198  root_cog = KDL::Vector(urdf_root_inertial->origin.position.x,
199  urdf_root_inertial->origin.position.y,
200  urdf_root_inertial->origin.position.z);
201  if (debug)
202  HIGHLIGHT_NAMED("Root Inertial", "Mass: " << root_mass
203  << " kg - CoG: " << root_cog);
204  }
205  // TODO: Note, this does not set the rotational inertia component, i.e. the
206  // inertial matrix would be wrong
207  KDL::RigidBodyInertia root_inertial(root_mass, root_cog);
208 
209  // Add general world_frame joint
210  model_tree_.push_back(std::make_shared<KinematicElement>(-1, nullptr, KDL::Segment(world_frame_name, KDL::Joint(root_joint->getName(), KDL::Joint::None))));
211  if (root_joint->getType() == robot_model::JointModel::FIXED)
212  {
213  model_base_type_ = BaseType::FIXED;
214  }
215  else if (root_joint->getType() == robot_model::JointModel::FLOATING)
216  {
217  model_base_type_ = BaseType::FLOATING;
218  model_tree_.resize(7);
220  const std::vector<std::string> floating_base_suffix = {
221  "/trans_x", "/trans_y", "/trans_z",
222  "/rot_z", "/rot_y", "/rot_x"};
223  for (size_t i = 0; i < 6; ++i)
224  {
225  model_tree_[i + 1] = std::make_shared<KinematicElement>(i, model_tree_[i], KDL::Segment(world_frame_name + floating_base_suffix[i], KDL::Joint(root_joint_name_ + floating_base_suffix[i], types[i])));
226  model_tree_[i]->children.push_back(model_tree_[i + 1]);
227  }
228 
229  // The floating base rotation is defined as xyzw quaternion in the robot
230  // model, but we are following a RPY-fixed axis (YPR rotating axis)
231  // virtual joint convention in exotica - thus delete the rot_w from the
232  // list of joint names
233  auto RotW = std::find(controlled_joints_names_.begin(), controlled_joints_names_.end(), root_joint->getVariableNames()[6]);
234  if (RotW != controlled_joints_names_.end()) controlled_joints_names_.erase(RotW);
235  RotW = std::find(model_joints_names_.begin(), model_joints_names_.end(), root_joint->getVariableNames()[6]);
236  if (RotW != model_joints_names_.end()) model_joints_names_.erase(RotW);
237 
238  // NB: We do not want to swap the XYZ labels for the rotation joints
239  // to not change the order in which joint and model state are stored.
240  }
241  else if (root_joint->getType() == robot_model::JointModel::PLANAR)
242  {
243  model_base_type_ = BaseType::PLANAR;
244  model_tree_.resize(4);
247  for (int i = 0; i < 3; ++i)
248  {
249  model_tree_[i + 1] = std::make_shared<KinematicElement>(
250  i, model_tree_[i],
251  KDL::Segment(
252  root_joint->getVariableNames()[i],
253  KDL::Joint(root_joint->getVariableNames()[i], types[i])));
254  model_tree_[i]->children.push_back(model_tree_[i + 1]);
255  }
256  }
257  else
258  {
259  ThrowPretty("Unsupported root joint type: " << root_joint->getTypeName());
260  }
261 
262  AddElementFromSegmentMapIterator(robot_kinematics.getRootSegment(), *(model_tree_.end() - 1));
263 
264  // Set root inertial
265  if (root_joint->getType() == robot_model::JointModel::FIXED)
266  {
267  model_tree_[2]->segment.setInertia(root_inertial);
268  }
269  else if (root_joint->getType() == robot_model::JointModel::FLOATING)
270  {
271  model_tree_[7]->segment.setInertia(root_inertial);
272  }
273  else if (root_joint->getType() == robot_model::JointModel::PLANAR)
274  {
275  model_tree_[4]->segment.setInertia(root_inertial);
276  }
277 
278  for (auto element : model_tree_) tree_.push_back(element);
279 
280  UpdateModel();
281  tree_state_.setZero();
282 
283  if (debug)
284  {
285  for (int i = 0; i < tree_.size() - 1; ++i)
287  "Tree", "Joint: " << tree_[i].lock()->segment.getJoint().getName() << " - Link: " << tree_[i].lock()->segment.getName()
288  << ", mass: " << tree_[i].lock()->segment.getInertia().getMass()
289  << ", CoM: " << tree_[i].lock()->segment.getInertia().getCOG());
290  }
291 
292  num_joints_ = model_joints_names_.size();
293  num_controlled_joints_ = controlled_joints_names_.size();
294  state_size_ = num_controlled_joints_; // TODO: We should probably deprecate state_size_
295  if (num_controlled_joints_ < 1) ThrowPretty("No update joints specified!");
296  controlled_joints_.resize(num_controlled_joints_);
297  for (std::shared_ptr<KinematicElement> Joint : model_tree_)
298  {
299  Joint->is_robot_link = true;
300  Joint->control_id = IsControlled(Joint);
301  Joint->is_controlled = Joint->control_id >= 0;
302  model_joints_map_[Joint->segment.getJoint().getName()] = Joint;
303  model_link_names_.push_back(Joint->segment.getName());
304  if (Joint->is_controlled)
305  {
306  controlled_joints_[Joint->control_id] = Joint;
307  controlled_joints_map_[Joint->segment.getJoint().getName()] = Joint;
308  controlled_link_names_.push_back(Joint->segment.getName());
309 
310  // The model_base_type_ defined above refers to the base type of the
311  // overall robot model - not of the set of controlled joints. E.g. a
312  // floating-base robot can have a scene defined where the
313  // floating-base virtual joint is _not_ part of the planning
314  // group/scene. Thus we need to establish the BaseType of the joint
315  // group, the controlled_base_type_ - if a controlled joint corresponds
316  // to a floating base joint, the controlled_base_type_ is the same as the
317  // model_base_type_.
318  if (Joint->segment.getJoint().getName().find(
319  root_joint->getName()) != std::string::npos)
320  controlled_base_type_ = model_base_type_;
321  }
322  }
323  model_tree_[0]->is_robot_link = false;
324 
325  joint_limits_ = Eigen::MatrixXd::Zero(num_controlled_joints_, 2);
326  velocity_limits_ = Eigen::VectorXd::Zero(num_controlled_joints_);
327  acceleration_limits_ = Eigen::VectorXd::Zero(num_controlled_joints_);
328  ResetJointLimits();
329 
330  if (debug) HIGHLIGHT_NAMED("KinematicTree::BuildTree", "Number of controlled joints: " << num_controlled_joints_ << " - Number of model joints: " << num_joints_);
331 
332  // Create random distributions for state sampling
333  generator_ = std::mt19937(rd_());
334 
335  // Add visual shapes
336  const urdf::ModelInterfaceSharedPtr& urdf = model_->getURDF();
337  std::vector<urdf::LinkSharedPtr> urdf_links;
338  urdf->getLinks(urdf_links);
339  for (urdf::LinkSharedPtr urdf_link : urdf_links)
340  {
341  if (urdf_link->visual_array.size() > 0)
342  {
343  std::shared_ptr<KinematicElement> element = tree_map_[urdf_link->name].lock();
344  int i = 0;
345  element->visual.reserve(urdf_link->visual_array.size());
346  for (urdf::VisualSharedPtr urdf_visual : urdf_link->visual_array)
347  {
348  VisualElement visual;
349  visual.name = urdf_link->name + "_visual_" + std::to_string(i);
350  visual.frame = KDL::Frame(KDL::Rotation::Quaternion(urdf_visual->origin.rotation.x, urdf_visual->origin.rotation.y, urdf_visual->origin.rotation.z, urdf_visual->origin.rotation.w), KDL::Vector(urdf_visual->origin.position.x, urdf_visual->origin.position.y, urdf_visual->origin.position.z));
351  if (urdf_visual->material)
352  {
353  urdf::MaterialSharedPtr material = urdf_visual->material->name == "" ? urdf_visual->material : urdf->getMaterial(urdf_visual->material->name);
354  visual.color(0) = material->color.r;
355  visual.color(1) = material->color.g;
356  visual.color(2) = material->color.b;
357  visual.color(3) = material->color.a;
358  }
359  else
360  {
361  if (debug)
362  HIGHLIGHT("No material for " << visual.name);
363  }
364 
365  switch (urdf_visual->geometry->type)
366  {
367  case urdf::Geometry::BOX:
368  {
369  std::shared_ptr<urdf::Box> box = std::static_pointer_cast<urdf::Box>(ToStdPtr(urdf_visual->geometry));
370  visual.shape = std::shared_ptr<shapes::Box>(new shapes::Box(box->dim.x, box->dim.y, box->dim.z));
371  }
372  break;
373  case urdf::Geometry::SPHERE:
374  {
375  std::shared_ptr<urdf::Sphere> sphere = std::static_pointer_cast<urdf::Sphere>(ToStdPtr(urdf_visual->geometry));
376  visual.shape = std::shared_ptr<shapes::Sphere>(new shapes::Sphere(sphere->radius));
377  }
378  break;
379  case urdf::Geometry::CYLINDER:
380  {
381  std::shared_ptr<urdf::Cylinder> cylinder = std::static_pointer_cast<urdf::Cylinder>(ToStdPtr(urdf_visual->geometry));
382  visual.shape = std::shared_ptr<shapes::Cylinder>(new shapes::Cylinder(cylinder->radius, cylinder->length));
383  }
384  break;
385  case urdf::Geometry::MESH:
386  {
387  std::shared_ptr<urdf::Mesh> mesh = std::static_pointer_cast<urdf::Mesh>(ToStdPtr(urdf_visual->geometry));
388  visual.shape_resource_path = mesh->filename;
389  visual.scale = Eigen::Vector3d(mesh->scale.x, mesh->scale.y, mesh->scale.z);
390  visual.shape = std::shared_ptr<shapes::Mesh>(shapes::createMeshFromResource(mesh->filename));
391  }
392  break;
393  default:
394  ThrowPretty("Unknown geometry type: " << urdf_visual->geometry->type);
395  }
396  element->visual.push_back(visual);
397  ++i;
398  }
399  }
400  }
401 }
402 
404 {
405  root_ = tree_[0].lock();
406  tree_state_.conservativeResize(tree_.size());
407  for (std::weak_ptr<KinematicElement> joint : tree_)
408  {
409  tree_map_[joint.lock()->segment.getName()] = joint.lock();
410  }
411  debug_tree_.resize(tree_.size() - 1);
412  UpdateTree();
413  debug_scene_changed_ = true;
414 }
415 
417 {
418  collision_tree_map_.clear();
419  tree_map_.clear();
420  environment_tree_.clear();
421  tree_.resize(model_tree_.size());
422  UpdateModel();
423  debug_scene_changed_ = true;
424 
425  // Remove all CollisionShapes
426  if (Server::IsRos())
427  {
428  visualization_msgs::Marker mrk;
429  mrk.action = 3; // visualization_msgs::Marker::DELETEALL; // NB: enum only defined in ROS-jacobian and newer, functionality still there
430  marker_array_msg_.markers.push_back(mrk);
431  }
432 }
433 
434 void KinematicTree::ChangeParent(const std::string& name, const std::string& parent_name, const KDL::Frame& pose, bool relative)
435 {
436  if (tree_map_.find(name) == tree_map_.end()) ThrowPretty("Attempting to attach unknown frame '" << name << "'!");
437  std::shared_ptr<KinematicElement> child = tree_map_.find(name)->second.lock();
438  if (child->id < model_tree_.size()) ThrowPretty("Can't re-attach robot link '" << name << "'!");
439  if (child->shape) ThrowPretty("Can't re-attach collision shape without reattaching the object! ('" << name << "')");
440  std::shared_ptr<KinematicElement> parent;
441  if (parent_name == "")
442  {
443  if (tree_map_.find(root_->segment.getName()) == tree_map_.end()) ThrowPretty("Attempting to attach to unknown frame '" << root_->segment.getName() << "'!");
444  parent = tree_map_.find(root_->segment.getName())->second.lock();
445  }
446  else
447  {
448  if (tree_map_.find(parent_name) == tree_map_.end()) ThrowPretty("Attempting to attach to unknown frame '" << parent_name << "'!");
449  parent = tree_map_.find(parent_name)->second.lock();
450  }
451  if (parent->shape) ThrowPretty("Can't attach object to a collision shape object! ('" << parent_name << "')");
452  if (relative)
453  {
454  child->segment = KDL::Segment(child->segment.getName(), child->segment.getJoint(), pose, child->segment.getInertia());
455  }
456  else
457  {
458  child->segment = KDL::Segment(child->segment.getName(), child->segment.getJoint(), parent->frame.Inverse() * child->frame * pose, child->segment.getInertia());
459  }
460 
461  // Iterate over Parent's children to find child and then remove it
462  for (auto it = child->parent.lock()->children.begin(); it != child->parent.lock()->children.end();)
463  {
464  std::shared_ptr<KinematicElement> childOfParent = it->lock();
465  if (childOfParent == child)
466  {
467  child->parent.lock()->children.erase(it);
468  }
469  else
470  {
471  ++it;
472  }
473  }
474 
475  child->parent = parent;
476  child->parent_name = parent->segment.getName();
477  parent->children.push_back(child);
478  child->UpdateClosestRobotLink();
479  debug_scene_changed_ = true;
480 }
481 
482 std::shared_ptr<KinematicElement> KinematicTree::AddEnvironmentElement(const std::string& name, const Eigen::Isometry3d& transform, const std::string& parent, shapes::ShapeConstPtr shape, const KDL::RigidBodyInertia& inertia, const Eigen::Vector4d& color, const std::vector<VisualElement>& visual, bool is_controlled)
483 {
484  std::shared_ptr<KinematicElement> element = AddElement(name, transform, parent, shape, inertia, color, visual, is_controlled);
485  environment_tree_.push_back(element);
486  return element;
487 }
488 
489 std::shared_ptr<KinematicElement> KinematicTree::AddElement(const std::string& name, const Eigen::Isometry3d& transform, const std::string& parent, const std::string& shape_resource_path, Eigen::Vector3d scale, const KDL::RigidBodyInertia& inertia, const Eigen::Vector4d& color, const std::vector<VisualElement>& visual, bool is_controlled)
490 {
491  std::string shape_path(shape_resource_path);
492  if (shape_path.empty())
493  {
494  ThrowPretty("Shape path cannot be empty!");
495  }
496  // Exotica package path resolution
497  else if (shape_path.substr(0, 1) == "{")
498  {
499  shape_path = "file://" + ParsePath(shape_path);
500  }
501  // ROS resource path resolution
502  else if (shape_path.substr(0, 10) == "package://" || shape_path.substr(0, 8) == "file:///")
503  {
504  }
505  else
506  {
507  ThrowPretty("Path cannot be resolved.");
508  }
509 
511  std::shared_ptr<KinematicElement> element = AddElement(name, transform, parent, shape, inertia, color, visual, is_controlled);
512  element->shape_resource_path = shape_path;
513  element->scale = scale;
514  return element;
515 }
516 
517 std::shared_ptr<KinematicElement> KinematicTree::AddElement(const std::string& name, const Eigen::Isometry3d& transform, const std::string& parent, shapes::ShapeConstPtr shape, const KDL::RigidBodyInertia& inertia, const Eigen::Vector4d& color, const std::vector<VisualElement>& visual, bool is_controlled)
518 {
519  std::shared_ptr<KinematicElement> parent_element;
520  if (parent == "")
521  {
522  parent_element = root_;
523  }
524  else
525  {
526  bool found = false;
527  for (const auto& element : tree_)
528  {
529  if (element.lock()->segment.getName() == parent)
530  {
531  parent_element = element.lock();
532  found = true;
533  break;
534  }
535  }
536  if (!found) ThrowPretty("Can't find parent link named '" << parent << "'!");
537  }
538  KDL::Frame transform_kdl;
539  tf::transformEigenToKDL(transform, transform_kdl);
540  std::shared_ptr<KinematicElement> new_element = std::make_shared<KinematicElement>(tree_.size(), parent_element, KDL::Segment(name, KDL::Joint(KDL::Joint::None), transform_kdl, inertia));
541  if (shape)
542  {
543  new_element->shape = shape;
544  collision_tree_map_[new_element->segment.getName()] = new_element;
545 
546  // Set color if set. If all zeros, default to preset (grey).
547  if (color != Eigen::Vector4d::Zero()) new_element->color = color;
548  }
549  new_element->parent_name = parent;
550  new_element->is_controlled = is_controlled;
551  tree_.push_back(new_element);
552  parent_element->children.push_back(new_element);
553  new_element->UpdateClosestRobotLink();
554  tree_map_[name] = new_element;
555  new_element->visual = visual;
556  debug_scene_changed_ = true;
557  return new_element;
558 }
559 
560 void KinematicTree::AddElementFromSegmentMapIterator(KDL::SegmentMap::const_iterator segment, std::shared_ptr<KinematicElement> parent)
561 {
562  std::shared_ptr<KinematicElement> new_element = std::make_shared<KinematicElement>(model_tree_.size(), parent, segment->second.segment);
563  model_tree_.push_back(new_element);
564  if (parent) parent->children.push_back(new_element);
565  for (KDL::SegmentMap::const_iterator child : segment->second.children)
566  {
567  AddElementFromSegmentMapIterator(child, new_element);
568  }
569 }
570 
571 int KinematicTree::IsControlled(std::shared_ptr<KinematicElement> joint)
572 {
573  for (int i = 0; i < controlled_joints_names_.size(); ++i)
574  {
575  if (controlled_joints_names_[i] == joint->segment.getJoint().getName()) return i;
576  }
577  return -1;
578 }
579 
580 int KinematicTree::IsControlledLink(const std::string& link_name)
581 {
582  try
583  {
584  auto element = tree_map_[link_name].lock();
585 
586  if (element && element->is_controlled)
587  {
588  return element->control_id;
589  }
590 
591  while (element)
592  {
593  element = element->parent.lock();
594 
595  if (element && element->is_controlled)
596  {
597  return element->control_id;
598  }
599  }
600  }
601  catch (const std::out_of_range& e)
602  {
603  return -1;
604  }
605  return -1;
606 }
607 
608 std::shared_ptr<KinematicResponse> KinematicTree::RequestFrames(const KinematicsRequest& request)
609 {
610  flags_ = request.flags;
611  if (flags_ & KIN_H) flags_ = flags_ | KIN_J;
612  solution_.reset(new KinematicResponse(flags_, request.frames.size(), num_controlled_joints_));
613 
614  state_size_ = num_controlled_joints_;
615 
616  for (int i = 0; i < request.frames.size(); ++i)
617  {
618  if (request.frames[i].frame_A_link_name == "")
619  solution_->frame[i].frame_A = root_;
620  else
621  try
622  {
623  solution_->frame[i].frame_A = tree_map_.at(request.frames[i].frame_A_link_name);
624  }
625  catch (const std::out_of_range& e)
626  {
627  ThrowPretty("No frame_A link exists named '" << request.frames[i].frame_A_link_name << "'");
628  }
629  if (request.frames[i].frame_B_link_name == "")
630  solution_->frame[i].frame_B = root_;
631  else
632  try
633  {
634  solution_->frame[i].frame_B = tree_map_.at(request.frames[i].frame_B_link_name);
635  }
636  catch (const std::out_of_range& e)
637  {
638  ThrowPretty("No frame_B link exists named '" << request.frames[i].frame_B_link_name << "'");
639  }
640 
641  solution_->frame[i].frame_A_offset = request.frames[i].frame_A_offset;
642  solution_->frame[i].frame_B_offset = request.frames[i].frame_B_offset;
643  }
644 
645  if (debug)
646  {
647  for (KinematicFrame& frame : solution_->frame)
648  {
649  HIGHLIGHT(frame.frame_B.lock()->segment.getName() << " " << (frame.frame_B_offset == KDL::Frame::Identity() ? "" : ToString(frame.frame_B_offset)) << " -> " << frame.frame_A.lock()->segment.getName() << " " << (frame.frame_A_offset == KDL::Frame::Identity() ? "" : ToString(frame.frame_A_offset)));
650  }
651  }
652 
653  debug_frames_.resize(solution_->frame.size() * 2);
654 
655  return solution_;
656 }
657 
659 {
660  if (x.size() != state_size_) ThrowPretty("Wrong state vector size! Got " << x.size() << " expected " << state_size_);
661 
662  for (int i = 0; i < num_controlled_joints_; ++i)
663  tree_state_(controlled_joints_[i].lock()->id) = x(i);
664 
665  // Store the updated state in the KinematicResponse (solution_)
666  solution_->x = x;
667 
668  UpdateTree();
669  UpdateFK();
670  if (flags_ & KIN_J) UpdateJ();
671  if (flags_ & KIN_J && flags_ & KIN_H) UpdateH();
672  if (debug) PublishFrames();
673 }
674 
676 {
677  std::queue<std::shared_ptr<KinematicElement>> elements;
678  elements.push(root_);
679  root_->RemoveExpiredChildren();
680  while (elements.size() > 0)
681  {
682  auto element = elements.front();
683  elements.pop();
684  // Elements with id > -1 have parent links.
685  // ID=-1 is the global world reference frame.
686  if (element->id > -1)
687  {
688  if (element->segment.getJoint().getType() != KDL::Joint::JointType::None)
689  {
690  element->frame = element->parent.lock()->frame * element->GetPose(tree_state_(element->id));
691  }
692  else
693  {
694  element->frame = element->parent.lock()->frame * element->GetPose();
695  }
696  }
697  // Root of tree.
698  else
699  {
700  // NB: We could simply set KDL::Frame() here, however, to support
701  // trajectories for the base joint, we return GetPose();
702  element->frame = element->GetPose();
703  }
704  element->RemoveExpiredChildren();
705  for (std::weak_ptr<KinematicElement> child : element->children)
706  {
707  elements.push(child.lock());
708  }
709  }
710 }
711 
712 void KinematicTree::PublishFrames(const std::string& tf_prefix)
713 {
714  if (Server::IsRos())
715  {
716  const ros::Time timestamp = ros::Time::now();
717 
718  // Step 1: Publish frames for every element in the tree.
719  {
720  int i = 0;
721  for (std::weak_ptr<KinematicElement> element : tree_)
722  {
723  tf::Transform T;
724  tf::transformKDLToTF(element.lock()->frame, T);
725  if (i > 0) debug_tree_[i - 1] = tf::StampedTransform(T, timestamp, tf::resolve(tf_prefix, GetRootFrameName()), tf::resolve(tf_prefix, element.lock()->segment.getName()));
726  ++i;
727  }
728  Server::SendTransform(debug_tree_);
729  i = 0;
730  for (KinematicFrame& frame : solution_->frame)
731  {
732  tf::Transform T;
733  tf::transformKDLToTF(frame.temp_B, T);
734  debug_frames_[i * 2] = tf::StampedTransform(T, timestamp, tf::resolve(tf_prefix, GetRootFrameName()), tf::resolve(tf_prefix, "Frame" + std::to_string(i) + "B" + frame.frame_B.lock()->segment.getName()));
735  tf::transformKDLToTF(frame.temp_AB, T);
736  debug_frames_[i * 2 + 1] = tf::StampedTransform(T, timestamp, tf::resolve(tf_prefix, "Frame" + std::to_string(i) + "B" + frame.frame_B.lock()->segment.getName()), tf::resolve(tf_prefix, "Frame" + std::to_string(i) + "A" + frame.frame_A.lock()->segment.getName()));
737  ++i;
738  }
739  Server::SendTransform(debug_frames_);
740  }
741 
742  // Step 2: Publish visualisation markers for non-robot-model elements in the tree.
743  if (debug_scene_changed_)
744  {
745  debug_scene_changed_ = false;
746  marker_array_msg_.markers.clear();
747  for (int i = 0; i < tree_.size(); ++i)
748  {
749  // Mesh from path
750  if (tree_[i].lock()->shape_resource_path != "")
751  {
752  visualization_msgs::Marker mrk;
753  mrk.action = visualization_msgs::Marker::ADD;
754  mrk.frame_locked = true;
755  mrk.id = i;
756  mrk.ns = "CollisionObjects";
757  mrk.color = GetColor(tree_[i].lock()->color);
758  mrk.header.frame_id = tf_prefix + "/" + tree_[i].lock()->segment.getName();
759  mrk.pose.orientation.w = 1.0;
760  mrk.type = visualization_msgs::Marker::MESH_RESOURCE;
761  mrk.mesh_resource = tree_[i].lock()->shape_resource_path;
762  mrk.mesh_use_embedded_materials = true;
763  mrk.scale.x = tree_[i].lock()->scale(0);
764  mrk.scale.y = tree_[i].lock()->scale(1);
765  mrk.scale.z = tree_[i].lock()->scale(2);
766  marker_array_msg_.markers.push_back(mrk);
767  }
768  // Non-robot collision objects
769  else if (tree_[i].lock()->shape && (!tree_[i].lock()->closest_robot_link.lock() || !tree_[i].lock()->closest_robot_link.lock()->is_robot_link))
770  {
771  if (tree_[i].lock()->shape->type != shapes::ShapeType::OCTREE)
772  {
773  visualization_msgs::Marker mrk;
774  shapes::constructMarkerFromShape(tree_[i].lock()->shape.get(), mrk);
775  mrk.action = visualization_msgs::Marker::ADD;
776  mrk.frame_locked = true;
777  mrk.id = i;
778  mrk.ns = "CollisionObjects";
779  mrk.color = GetColor(tree_[i].lock()->color);
780  mrk.header.frame_id = tf_prefix + "/" + tree_[i].lock()->segment.getName();
781  mrk.pose.orientation.w = 1.0;
782  marker_array_msg_.markers.push_back(mrk);
783  }
784  // Octree
785  else
786  {
787  // OcTree needs separate handling as it's not supported in constructMarkerFromShape
788  // NB: This only supports a single OctoMap in the KinematicTree as we only have one publisher!
789  octomap::OcTree my_octomap = *std::static_pointer_cast<const shapes::OcTree>(tree_[i].lock()->shape)->octree.get();
790  octomap_msgs::Octomap octomap_msg;
791  octomap_msgs::binaryMapToMsg(my_octomap, octomap_msg);
792  octomap_msg.header.frame_id = tf_prefix + "/" + tree_[i].lock()->segment.getName();
793  octomap_pub_.publish(octomap_msg);
794  }
795  }
796  }
797  shapes_pub_.publish(marker_array_msg_);
798  }
799  }
800 }
801 
803 {
804  frame.temp_A = frame.frame_A.lock()->frame * frame.frame_A_offset;
805  frame.temp_B = frame.frame_B.lock()->frame * frame.frame_B_offset;
806  frame.temp_AB = frame.temp_B.Inverse() * frame.temp_A;
807  return frame.temp_AB;
808 }
809 
810 KDL::Frame KinematicTree::FK(std::shared_ptr<KinematicElement> element_A, const KDL::Frame& offset_a, std::shared_ptr<KinematicElement> element_B, const KDL::Frame& offset_b) const
811 {
812  if (!element_A) ThrowPretty("The pointer to KinematicElement A is dead.");
813  KinematicFrame frame;
814  frame.frame_A = element_A;
815  frame.frame_B = (element_B == nullptr) ? root_ : element_B;
816  frame.frame_A_offset = offset_a;
817  frame.frame_B_offset = offset_b;
818  return FK(frame);
819 }
820 
821 KDL::Frame KinematicTree::FK(const std::string& element_A, const KDL::Frame& offset_a, const std::string& element_B, const KDL::Frame& offset_b) const
822 {
823  std::string name_a = element_A == "" ? root_->segment.getName() : element_A;
824  std::string name_b = element_B == "" ? root_->segment.getName() : element_B;
825  auto A = tree_map_.find(name_a);
826  if (A == tree_map_.end()) ThrowPretty("Can't find link '" << name_a << "'!");
827  auto B = tree_map_.find(name_b);
828  if (B == tree_map_.end()) ThrowPretty("Can't find link '" << name_b << "'!");
829  return FK(A->second.lock(), offset_a, B->second.lock(), offset_b);
830 }
831 
833 {
834  int i = 0;
835  for (KinematicFrame& frame : solution_->frame)
836  {
837  solution_->Phi(i) = FK(frame);
838  ++i;
839  }
840 }
841 
842 Eigen::MatrixXd KinematicTree::Jacobian(std::shared_ptr<KinematicElement> element_A, const KDL::Frame& offset_a, std::shared_ptr<KinematicElement> element_B, const KDL::Frame& offset_b) const
843 {
844  if (!element_A) ThrowPretty("The pointer to KinematicElement A is dead.");
845  KinematicFrame frame;
846  frame.frame_A = element_A;
847  frame.frame_B = (element_B == nullptr) ? root_ : element_B;
848  frame.frame_A_offset = offset_a;
849  frame.frame_B_offset = offset_b;
850  KDL::Jacobian ret(num_controlled_joints_);
851  ComputeJ(frame, ret);
852  return ret.data;
853 }
854 
855 Eigen::MatrixXd KinematicTree::Jacobian(const std::string& element_A, const KDL::Frame& offset_a, const std::string& element_B, const KDL::Frame& offset_b) const
856 {
857  std::string name_a = element_A == "" ? root_->segment.getName() : element_A;
858  std::string name_b = element_B == "" ? root_->segment.getName() : element_B;
859  auto A = tree_map_.find(name_a);
860  if (A == tree_map_.end()) ThrowPretty("Can't find link '" << name_a << "'!");
861  auto B = tree_map_.find(name_b);
862  if (B == tree_map_.end()) ThrowPretty("Can't find link '" << name_b << "'!");
863  return Jacobian(A->second.lock(), offset_a, B->second.lock(), offset_b);
864 }
865 
866 exotica::Hessian KinematicTree::Hessian(std::shared_ptr<KinematicElement> element_A, const KDL::Frame& offset_a, std::shared_ptr<KinematicElement> element_B, const KDL::Frame& offset_b) const
867 {
868  if (!element_A) ThrowPretty("The pointer to KinematicElement A is dead.");
869  KinematicFrame frame;
870  frame.frame_A = element_A;
871  frame.frame_B = (element_B == nullptr) ? root_ : element_B;
872  frame.frame_A_offset = offset_a;
873  frame.frame_B_offset = offset_b;
874  KDL::Jacobian J(num_controlled_joints_);
875  ComputeJ(frame, J);
876  exotica::Hessian hessian = exotica::Hessian::Constant(6, Eigen::MatrixXd::Zero(num_controlled_joints_, num_controlled_joints_));
877  ComputeH(frame, J, hessian);
878  return hessian;
879 }
880 
881 exotica::Hessian KinematicTree::Hessian(const std::string& element_A, const KDL::Frame& offset_a, const std::string& element_B, const KDL::Frame& offset_b) const
882 {
883  std::string name_a = element_A == "" ? root_->segment.getName() : element_A;
884  std::string name_b = element_B == "" ? root_->segment.getName() : element_B;
885  auto A = tree_map_.find(name_a);
886  if (A == tree_map_.end()) ThrowPretty("Can't find link '" << name_a << "'!");
887  auto B = tree_map_.find(name_b);
888  if (B == tree_map_.end()) ThrowPretty("Can't find link '" << name_b << "'!");
889  return this->Hessian(A->second.lock(), offset_a, B->second.lock(), offset_b);
890 }
891 
893 {
894  jacobian.data.setZero();
895  (void)FK(frame); // Create temporary offset frames
896  std::shared_ptr<KinematicElement> it = frame.frame_A.lock();
897  while (it != nullptr)
898  {
899  if (it->is_controlled)
900  {
901  KDL::Frame segment_reference;
902  if (it->parent.lock() != nullptr) segment_reference = it->parent.lock()->frame;
903  jacobian.setColumn(it->control_id, frame.temp_B.M.Inverse() * (segment_reference.M * it->segment.twist(tree_state_(it->id), 1.0)).RefPoint(frame.temp_A.p - it->frame.p));
904  }
905  it = it->parent.lock();
906  }
907  it = frame.frame_B.lock();
908  while (it != nullptr)
909  {
910  if (it->is_controlled)
911  {
912  KDL::Frame segment_reference;
913  if (it->parent.lock() != nullptr) segment_reference = it->parent.lock()->frame;
914  jacobian.setColumn(it->control_id, jacobian.getColumn(it->control_id) - (frame.temp_B.M.Inverse() * (segment_reference.M * it->segment.twist(tree_state_(it->id), 1.0)).RefPoint(frame.temp_A.p - it->frame.p)));
915  }
916  it = it->parent.lock();
917  }
918 }
919 
921 {
922  hessian.conservativeResize(6);
923  for (int i = 0; i < 6; ++i)
924  {
925  hessian(i).resize(jacobian.columns(), jacobian.columns());
926  hessian(i).setZero();
927  }
928 
929  KDL::Twist axis;
930 
931  for (int i = 0; i < jacobian.columns(); ++i)
932  {
933  axis.rot = jacobian.getColumn(i).rot;
934  for (int j = i; j < jacobian.columns(); ++j)
935  {
936  KDL::Twist Hij = axis * jacobian.getColumn(j);
937  hessian(0)(i, j) = Hij[0];
938  hessian(1)(i, j) = Hij[1];
939  hessian(2)(i, j) = Hij[2];
940  hessian(0)(j, i) = Hij[0];
941  hessian(1)(j, i) = Hij[1];
942  hessian(2)(j, i) = Hij[2];
943  if (i != j)
944  {
945  hessian(3)(j, i) = Hij[3];
946  hessian(4)(j, i) = Hij[4];
947  hessian(5)(j, i) = Hij[5];
948  }
949  }
950  }
951 }
952 
954 {
955  int i = 0;
956  for (KinematicFrame& frame : solution_->frame)
957  {
958  ComputeJ(frame, solution_->jacobian(i));
959  ++i;
960  }
961 }
962 
964 {
965  int i = 0;
966  for (KinematicFrame& frame : solution_->frame)
967  {
968  ComputeH(frame, solution_->jacobian(i), solution_->hessian(i));
969  ++i;
970  }
971 }
972 
974 {
975  return model_base_type_;
976 }
977 
979 {
980  return controlled_base_type_;
981 }
982 
983 std::map<std::string, std::vector<double>> KinematicTree::GetUsedJointLimits() const
984 {
985  std::map<std::string, std::vector<double>> limits;
986  for (auto it : controlled_joints_)
987  {
988  limits[it.lock()->segment.getJoint().getName()] = it.lock()->joint_limits;
989  }
990  return limits;
991 }
992 
993 robot_model::RobotModelPtr KinematicTree::GetRobotModel() const
994 {
995  return model_;
996 }
997 
999 {
1000  Eigen::VectorXd q_rand(num_controlled_joints_);
1001  for (unsigned int i = 0; i < num_controlled_joints_; ++i)
1002  {
1003  q_rand(i) = random_state_distributions_[i](generator_);
1004  }
1005  return q_rand;
1006 }
1007 
1009 {
1010  if (lower_in.rows() == num_controlled_joints_)
1011  {
1012  for (unsigned int i = 0; i < num_controlled_joints_; ++i)
1013  {
1014  controlled_joints_[i].lock()->joint_limits[LIMIT_POSITION_LOWER] = lower_in(i);
1015  }
1016  }
1017  else
1018  {
1019  ThrowPretty("Got " << lower_in.rows() << " but " << num_controlled_joints_ << " expected.");
1020  }
1021 
1022  UpdateJointLimits();
1023 }
1024 
1026 {
1027  if (upper_in.rows() == num_controlled_joints_)
1028  {
1029  for (unsigned int i = 0; i < num_controlled_joints_; ++i)
1030  {
1031  controlled_joints_[i].lock()->joint_limits[LIMIT_POSITION_UPPER] = upper_in(i);
1032  }
1033  }
1034  else
1035  {
1036  ThrowPretty("Got " << upper_in.rows() << " but " << num_controlled_joints_ << " expected.");
1037  }
1038 
1039  UpdateJointLimits();
1040 }
1041 
1043 {
1044  if (velocity_in.rows() == num_controlled_joints_)
1045  {
1046  for (unsigned int i = 0; i < num_controlled_joints_; ++i)
1047  {
1048  controlled_joints_[i].lock()->velocity_limit = velocity_in(i);
1049  }
1050  }
1051  else
1052  {
1053  ThrowPretty("Got " << velocity_in.rows() << " but " << num_controlled_joints_ << " expected.");
1054  }
1055 
1056  UpdateJointLimits();
1057 }
1058 
1060 {
1061  if (acceleration_in.rows() == num_controlled_joints_)
1062  {
1063  for (unsigned int i = 0; i < num_controlled_joints_; ++i)
1064  {
1065  controlled_joints_[i].lock()->acceleration_limit = acceleration_in(i);
1066  }
1067 
1068  has_acceleration_limit_ = true;
1069  }
1070  else
1071  {
1072  ThrowPretty("Got " << acceleration_in.rows() << " but " << num_controlled_joints_ << " expected.");
1073  }
1074 
1075  UpdateJointLimits();
1076 }
1077 
1079  const std::vector<double>& lower, const std::vector<double>& upper)
1080 {
1081  if (controlled_base_type_ != BaseType::FLOATING)
1082  {
1083  ThrowPretty("This is not a floating joint!");
1084  }
1085  if (lower.size() != 6 || upper.size() != 6)
1086  {
1087  ThrowPretty("Wrong limit data size!");
1088  }
1089  for (int i = 0; i < 6; ++i)
1090  {
1091  controlled_joints_[i].lock()->joint_limits = {lower[i], upper[i]};
1092  }
1093 
1094  UpdateJointLimits();
1095 }
1096 
1098  const std::vector<double>& lower, const std::vector<double>& upper, const std::vector<double>& velocity, const std::vector<double>& acceleration)
1099 {
1100  if (controlled_base_type_ != BaseType::FLOATING)
1101  {
1102  ThrowPretty("This is not a floating joint!");
1103  }
1104  if (lower.size() != 6 || upper.size() != 6)
1105  {
1106  ThrowPretty("Wrong joint limit data size!");
1107  }
1108  if (velocity.size() != 6 && velocity.size() != 0)
1109  {
1110  ThrowPretty("Wrong velocity limit size!");
1111  }
1112  if (acceleration.size() != 6 && acceleration.size() != 0)
1113  {
1114  ThrowPretty("Wrong acceleration limit size!");
1115  }
1116  for (int i = 0; i < 6; ++i)
1117  {
1118  controlled_joints_[i].lock()->joint_limits = {lower[i], upper[i]};
1119  controlled_joints_[i].lock()->velocity_limit = {velocity.size() != 0 ? velocity[i] : inf};
1120  controlled_joints_[i].lock()->acceleration_limit = {acceleration.size() != 0 ? acceleration[i] : inf};
1121  }
1122 
1123  UpdateJointLimits();
1124 }
1125 
1127  const std::vector<double>& lower, const std::vector<double>& upper)
1128 {
1129  if (controlled_base_type_ != BaseType::PLANAR)
1130  {
1131  ThrowPretty("This is not a planar joint!");
1132  }
1133  if (lower.size() != 3 || upper.size() != 3)
1134  {
1135  ThrowPretty("Wrong limit data size!");
1136  }
1137  for (int i = 0; i < 3; ++i)
1138  {
1139  controlled_joints_[i].lock()->joint_limits = {lower[i], upper[i]};
1140  }
1141 
1142  UpdateJointLimits();
1143 }
1144 
1146  const std::vector<double>& lower, const std::vector<double>& upper, const std::vector<double>& velocity, const std::vector<double>& acceleration)
1147 {
1148  if (controlled_base_type_ != BaseType::PLANAR)
1149  {
1150  ThrowPretty("This is not a planar joint!");
1151  }
1152  if (lower.size() != 3 || upper.size() != 3)
1153  {
1154  ThrowPretty("Wrong joint limit data size!");
1155  }
1156  if (velocity.size() != 3 && velocity.size() != 0)
1157  {
1158  ThrowPretty("Wrong velocity limit size!");
1159  }
1160  if (acceleration.size() != 3 && acceleration.size() != 0)
1161  {
1162  ThrowPretty("Wrong acceleration limit size!");
1163  }
1164  for (int i = 0; i < 3; ++i)
1165  {
1166  controlled_joints_[i].lock()->joint_limits = {lower[i], upper[i]};
1167  controlled_joints_[i].lock()->velocity_limit = {velocity.size() != 0 ? velocity[i] : inf};
1168  controlled_joints_[i].lock()->acceleration_limit = {acceleration.size() != 0 ? acceleration[i] : inf};
1169  }
1170 
1171  UpdateJointLimits();
1172 }
1173 
1175 {
1176  std::vector<std::string> vars = model_->getVariableNames();
1177  for (int i = 0; i < vars.size(); ++i)
1178  {
1179  if (controlled_joints_map_.find(vars[i]) != controlled_joints_map_.end())
1180  {
1181  auto& ControlledJoint = controlled_joints_map_.at(vars[i]);
1182  int index = ControlledJoint.lock()->control_id;
1183 
1184  // moveit_core::RobotModel does not have effort limits
1185  // TODO: use urdf::Model instead
1186 
1187  // Check for bounds, else set limits to inf
1188  if (model_->getVariableBounds(vars[i]).position_bounded_)
1189  {
1190  controlled_joints_[index].lock()->joint_limits = {model_->getVariableBounds(vars[i]).min_position_, model_->getVariableBounds(vars[i]).max_position_};
1191  }
1192  else
1193  {
1194  controlled_joints_[index].lock()->joint_limits = {-inf, inf};
1195  }
1196  if (model_->getVariableBounds(vars[i]).velocity_bounded_)
1197  {
1198  controlled_joints_[index].lock()->velocity_limit = {model_->getVariableBounds(vars[i]).max_velocity_};
1199  }
1200  else
1201  {
1202  controlled_joints_[index].lock()->velocity_limit = {inf};
1203  }
1204  if (model_->getVariableBounds(vars[i]).acceleration_bounded_)
1205  {
1206  controlled_joints_[index].lock()->acceleration_limit = {model_->getVariableBounds(vars[i]).max_acceleration_};
1207  }
1208  else
1209  {
1210  controlled_joints_[index].lock()->acceleration_limit = {inf};
1211  }
1212  }
1213  }
1214 
1217  if (controlled_base_type_ == BaseType::FLOATING)
1218  {
1219  controlled_joints_[0].lock()->joint_limits = {-inf, inf};
1220  controlled_joints_[1].lock()->joint_limits = {-inf, inf};
1221  controlled_joints_[2].lock()->joint_limits = {-inf, inf};
1222  controlled_joints_[3].lock()->joint_limits = {-pi, pi};
1223  controlled_joints_[4].lock()->joint_limits = {-pi, pi};
1224  controlled_joints_[5].lock()->joint_limits = {-pi, pi};
1225  }
1226  else if (controlled_base_type_ == BaseType::PLANAR)
1227  {
1228  controlled_joints_[0].lock()->joint_limits = {-inf, inf};
1229  controlled_joints_[1].lock()->joint_limits = {-inf, inf};
1230  controlled_joints_[2].lock()->joint_limits = {-pi, pi};
1231  }
1232 
1233  UpdateJointLimits();
1234 }
1235 
1237 {
1238  joint_limits_.setZero();
1239  for (int i = 0; i < num_controlled_joints_; ++i)
1240  {
1241  joint_limits_(i, LIMIT_POSITION_LOWER) = controlled_joints_[i].lock()->joint_limits[LIMIT_POSITION_LOWER];
1242  joint_limits_(i, LIMIT_POSITION_UPPER) = controlled_joints_[i].lock()->joint_limits[LIMIT_POSITION_UPPER];
1243  velocity_limits_(i) = controlled_joints_[i].lock()->velocity_limit;
1244  acceleration_limits_(i) = controlled_joints_[i].lock()->acceleration_limit;
1245  }
1246 
1247  // Update random state distributions for generating random controlled states
1248  random_state_distributions_.clear();
1249  for (int i = 0; i < num_controlled_joints_; ++i)
1250  {
1251  random_state_distributions_.push_back(std::uniform_real_distribution<double>(joint_limits_(i, LIMIT_POSITION_LOWER), joint_limits_(i, LIMIT_POSITION_UPPER)));
1252  // TODO: Implement random velocities and accelerations
1253  }
1254 }
1255 
1256 const std::string& KinematicTree::GetRootFrameName() const
1257 {
1258  return root_->segment.getName();
1259 }
1260 
1261 const std::string& KinematicTree::GetRootJointName() const
1262 {
1263  return root_joint_name_;
1264 }
1265 
1266 Eigen::VectorXd KinematicTree::GetModelState() const
1267 {
1268  Eigen::VectorXd ret(model_joints_names_.size());
1269 
1270  for (int i = 0; i < model_joints_names_.size(); ++i)
1271  {
1272  ret(i) = tree_state_(model_joints_map_.at(model_joints_names_[i]).lock()->id);
1273  }
1274  return ret;
1275 }
1276 
1277 std::map<std::string, double> KinematicTree::GetModelStateMap() const
1278 {
1279  std::map<std::string, double> ret;
1280  for (const std::string& joint_name : model_joints_names_)
1281  {
1282  ret[joint_name] = tree_state_(model_joints_map_.at(joint_name).lock()->id);
1283  }
1284  return ret;
1285 }
1286 
1287 std::vector<std::string> KinematicTree::GetKinematicChain(const std::string& begin, const std::string& end) const
1288 {
1289  // check existence of requested links
1290  for (const std::string& l : {begin, end})
1291  {
1292  if (!tree_map_.count(l))
1293  {
1294  ThrowPretty("Link '" + l + "' does not exist.");
1295  }
1296  }
1297 
1298  // get chain in reverse order, end...begin
1299  std::vector<std::string> chain;
1300  for (std::weak_ptr<KinematicElement> l = tree_map_.at(end);
1301  l.lock()->segment.getName() != begin;
1302  l = l.lock()->parent, chain.push_back(l.lock()->segment.getJoint().getName()))
1303  {
1304  if (l.lock()->parent.lock() == nullptr)
1305  {
1306  ThrowPretty("There is no connection between '" + begin + "' and '" + end + "'!");
1307  }
1308  }
1309 
1310  // return vector in order, begin...end
1311  std::reverse(chain.begin(), chain.end());
1312  return chain;
1313 }
1314 
1315 std::vector<std::string> KinematicTree::GetKinematicChainLinks(const std::string& begin, const std::string& end) const
1316 {
1317  // check existence of requested links
1318  for (const std::string& l : {begin, end})
1319  {
1320  if (!tree_map_.count(l))
1321  {
1322  ThrowPretty("Link '" + l + "' does not exist.");
1323  }
1324  }
1325 
1326  // get chain in reverse order, end...begin
1327  std::vector<std::string> chain;
1328  for (std::shared_ptr<const KinematicElement> l = tree_map_.at(end).lock(); l->segment.getName() != begin; l = l->parent.lock())
1329  {
1330  chain.push_back(l->segment.getName());
1331  if (l->parent.lock() == nullptr)
1332  {
1333  ThrowPretty("There is no connection between '" + begin + "' and '" + end + "'!");
1334  }
1335  }
1336 
1337  // return vector in order, begin...end
1338  std::reverse(chain.begin(), chain.end());
1339  return chain;
1340 }
1341 
1343 {
1344  // Work-around in case someone passed a vector of size num_controlled_joints_
1345  if (x.rows() == num_controlled_joints_)
1346  {
1347  Update(x);
1348  return;
1349  }
1350 
1351  if (x.rows() != model_joints_names_.size()) ThrowPretty("Model state vector has wrong size, expected " << model_joints_names_.size() << " got " << x.rows());
1352  for (int i = 0; i < model_joints_names_.size(); ++i)
1353  {
1354  tree_state_(model_joints_map_.at(model_joints_names_[i]).lock()->id) = x(i);
1355  }
1356  UpdateTree();
1357  UpdateFK();
1358  if (flags_ & KIN_J) UpdateJ();
1359  if (debug) PublishFrames();
1360 }
1361 
1362 void KinematicTree::SetModelState(const std::map<std::string, double>& x)
1363 {
1364  for (auto& joint : x)
1365  {
1366  try
1367  {
1368  tree_state_(model_joints_map_.at(joint.first).lock()->id) = joint.second;
1369  }
1370  catch (const std::out_of_range& e)
1371  {
1372  WARNING("Robot model does not contain joint '" << joint.first << "' - ignoring.");
1373  }
1374  }
1375  UpdateTree();
1376  UpdateFK();
1377  if (flags_ & KIN_J) UpdateJ();
1378  if (debug) PublishFrames();
1379 }
1380 
1381 Eigen::VectorXd KinematicTree::GetControlledState() const
1382 {
1383  Eigen::VectorXd x(num_controlled_joints_);
1384  for (int i = 0; i < controlled_joints_.size(); ++i)
1385  {
1386  x(i) = tree_state_(controlled_joints_[i].lock()->id);
1387  }
1388  return x;
1389 }
1390 
1391 bool KinematicTree::HasModelLink(const std::string& link) const
1392 {
1393  return std::find(std::begin(model_link_names_), std::end(model_link_names_), link) != std::end(model_link_names_);
1394 }
1395 
1397 {
1398  Eigen::VectorXd x(num_controlled_joints_);
1399  for (int i = 0; i < controlled_joints_.size(); ++i)
1400  {
1401  x(i) = controlled_joints_[i].lock()->segment.getInertia().getMass();
1402  }
1403  return x;
1404 }
1405 
1406 std::map<std::string, shapes::ShapeType> KinematicTree::GetCollisionObjectTypes() const
1407 {
1408  std::map<std::string, shapes::ShapeType> ret;
1409  for (const auto& element : collision_tree_map_)
1410  {
1411  ret[element.second.lock()->segment.getName()] = element.second.lock()->shape->type;
1412  }
1413  return ret;
1414 }
1415 
1416 bool KinematicTree::DoesLinkWithNameExist(std::string name) const
1417 {
1418  // Check whether it exists in TreeMap, which should encompass both EnvironmentTree and model_tree_
1419  return tree_map_.find(name) != tree_map_.end();
1420 }
1421 
1422 std::shared_ptr<KinematicElement> KinematicTree::FindKinematicElementByName(const std::string& frame_name)
1423 {
1424  auto it = tree_map_.find(frame_name);
1425  if (it == tree_map_.end()) ThrowPretty("KinematicElement does not exist:" << frame_name);
1426 
1427  return it->second.lock();
1428 }
1429 } // namespace exotica
#define HIGHLIGHT(x)
Definition: printable.h:61
Eigen::Map< ArrayJacobian > jacobian
std::map< std::string, double > GetModelStateMap() const
void Create(std::shared_ptr< KinematicResponse > solution)
void ComputeH(KinematicFrame &frame, const KDL::Jacobian &jacobian, exotica::Hessian &hessian) const
bool DoesLinkWithNameExist(std::string name) const
Checks whether a link with this name exists in any of the trees.
std::vector< KinematicFrameRequest > frames
void Update(Eigen::VectorXdRefConst x)
KDL_PARSER_PUBLIC bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
Eigen::VectorXd GetRandomControlledState()
Random state generation.
std::map< std::string, shapes::ShapeType > GetCollisionObjectTypes() const
int IsControlled(std::shared_ptr< KinematicElement > joint)
Rotation Inverse() const
std::weak_ptr< KinematicElement > frame_B
BaseType GetModelBaseType() const
std::shared_ptr< KinematicElement > FindKinematicElementByName(const std::string &frame_name)
#define WARNING_NAMED(name, x)
Definition: printable.h:63
Eigen::MatrixXd Jacobian(std::shared_ptr< KinematicElement > element_A, const KDL::Frame &offset_a, std::shared_ptr< KinematicElement > element_B, const KDL::Frame &offset_b) const
void AddElementFromSegmentMapIterator(KDL::SegmentMap::const_iterator segment, std::shared_ptr< KinematicElement > parent)
XmlRpcServer s
void transformKDLToTF(const KDL::Frame &k, tf::Transform &t)
static Rotation Quaternion(double x, double y, double z, double w)
Eigen::Map< Eigen::VectorXd > X
#define ThrowPretty(m)
Definition: exception.h:36
Eigen::Map< ArrayHessian > hessian
exotica::Hessian Hessian(std::shared_ptr< KinematicElement > element_A, const KDL::Frame &offset_a, std::shared_ptr< KinematicElement > element_B, const KDL::Frame &offset_b) const
std::vector< std::string > GetKinematicChainLinks(const std::string &begin, const std::string &end) const
GetKinematicChainLinks get the links between begin and end of kinematic chain.
Eigen::VectorXd GetControlledLinkMass() const
KinematicRequestFlags flags
std_msgs::ColorRGBA GetColor(double r, double g, double b, double a=1.0)
Definition: tools.h:69
std::shared_ptr< Shape > ShapePtr
static bool binaryMapToMsg(const OctomapT &octomap, Octomap &msg)
KinematicRequestFlags
std::weak_ptr< KinematicElement > frame_A
void transformEigenToKDL(const Eigen::Affine3d &e, KDL::Frame &k)
const std::string & GetRootJointName() const
unsigned int columns() const
shapes::ShapePtr shape
Rotation M
Eigen::VectorXd GetModelState() const
std::shared_ptr< KinematicElement > AddEnvironmentElement(const std::string &name, const Eigen::Isometry3d &transform, const std::string &parent="", shapes::ShapeConstPtr shape=shapes::ShapeConstPtr(nullptr), const KDL::RigidBodyInertia &inertia=KDL::RigidBodyInertia::Zero(), const Eigen::Vector4d &color=Eigen::Vector4d(0.5, 0.5, 0.5, 1.0), const std::vector< VisualElement > &visual={}, bool is_controlled=false)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Eigen::Matrix< double, 6, Eigen::Dynamic > data
std::string resolve(const std::string &prefix, const std::string &frame_name)
void SetJointLimitsLower(Eigen::VectorXdRefConst lower_in)
static void SendTransform(const tf::StampedTransform &transform)
Definition: server.h:145
const std::string & getName() const
void SetJointLimitsUpper(Eigen::VectorXdRefConst upper_in)
unsigned int index
void Instantiate(const std::string &joint_group, robot_model::RobotModelPtr model, const std::string &name)
int GetNumModelJoints() const
std::string ToString(const KDL::Frame &s)
Definition: printable.cpp:40
Eigen::VectorXd GetControlledState() const
constexpr double inf
KinematicRequestFlags flags
std::shared_ptr< T > ToStdPtr(const boost::shared_ptr< T > &p)
Definition: tools.h:148
Vector rot
Eigen::Array< Eigen::MatrixXd, Eigen::Dynamic, 1 > Hessian
Definition: conversions.h:154
void BuildTree(const KDL::Tree &RobotKinematics)
constexpr double pi
KDL::Frame FK(KinematicFrame &frame) const
const std::string & GetRootFrameName() const
int IsControlledLink(const std::string &link_name)
bool HasModelLink(const std::string &link) const
std::vector< std::string > GetKinematicChain(const std::string &begin, const std::string &end) const
GetKinematicChain get list of joints in a kinematic chain.
void setColumn(unsigned int i, const Twist &t)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW std::string name
Eigen::Map< ArrayFrame > Phi
Frame Inverse() const
bool constructMarkerFromShape(const Shape *shape, visualization_msgs::Marker &mk, bool use_mesh_triangle_list=false)
void ComputeJ(KinematicFrame &frame, KDL::Jacobian &jacobian) const
Twist getColumn(unsigned int i) const
void SetJointAccelerationLimits(Eigen::VectorXdRefConst acceleration_in)
const Eigen::Ref< const Eigen::VectorXd > & VectorXdRefConst
Convenience wrapper for storing references to sub-matrices/vectors.
Definition: conversions.h:52
int GetNumControlledJoints() const
void ChangeParent(const std::string &name, const std::string &parent, const KDL::Frame &pose, bool relative)
Eigen::Map< ArrayTwist > Phi_dot
SegmentMap::const_iterator getRootSegment() const
void SetPlanarBaseLimitsPosXYEulerZ(const std::vector< double > &lower, const std::vector< double > &upper)
std::vector< KinematicFrame > frame
std::string ParsePath(const std::string &path)
Definition: tools.cpp:145
Mesh * createMeshFromResource(const std::string &resource)
#define HIGHLIGHT_NAMED(name, x)
Definition: printable.h:62
void SetJointVelocityLimits(Eigen::VectorXdRefConst velocity_in)
static Frame Identity()
static Time now()
The KinematicResponse is the container to keep kinematic update data. The corresponding KinematicSolu...
void SetFloatingBaseLimitsPosXYZEulerZYX(const std::vector< double > &lower, const std::vector< double > &upper)
robot_model::RobotModelPtr GetRobotModel() const
void PublishFrames(const std::string &tf_prefix="exotica")
static bool IsRos()
Definition: server.h:96
BaseType GetControlledBaseType() const
std::shared_ptr< KinematicElement > AddElement(const std::string &name, const Eigen::Isometry3d &transform, const std::string &parent="", shapes::ShapeConstPtr shape=shapes::ShapeConstPtr(nullptr), const KDL::RigidBodyInertia &inertia=KDL::RigidBodyInertia::Zero(), const Eigen::Vector4d &color=Eigen::Vector4d(0.5, 0.5, 0.5, 1.0), const std::vector< VisualElement > &visual={}, bool is_controlled=false)
std::shared_ptr< KinematicResponse > RequestFrames(const KinematicsRequest &request)
double x
#define WARNING(x)
With endline.
Definition: printable.h:56
static Vector Zero()
void SetModelState(Eigen::VectorXdRefConst x)
std::map< std::string, std::vector< double > > GetUsedJointLimits() const
std::shared_ptr< const Shape > ShapeConstPtr


exotica_core
Author(s): Yiming Yang, Michael Camilleri
autogenerated on Sat Apr 10 2021 02:34:49