moveit2
The MoveIt Motion Planning Framework for ROS 2.
joint_model_group.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Ioan A. Sucan
5  * Copyright (c) 2013, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Willow Garage nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 /* Author: Ioan Sucan, Dave Coleman */
37 
42 #include <rclcpp/logger.hpp>
43 #include <rclcpp/logging.hpp>
44 #include <algorithm>
45 #include <moveit/utils/logger.hpp>
46 
48 
49 namespace moveit
50 {
51 namespace core
52 {
53 namespace
54 {
55 rclcpp::Logger getLogger()
56 {
57  return moveit::getLogger("joint_model_group");
58 }
59 
60 // check if a parent or ancestor of joint is included in this group
61 bool includesParent(const JointModel* joint, const JointModelGroup* group)
62 {
63  bool found = false;
64  // if we find that an ancestor is also in the group, then the joint is not a root
65  while (joint->getParentLinkModel() != nullptr)
66  {
67  joint = joint->getParentLinkModel()->getParentJointModel();
68  if (group->hasJointModel(joint->getName()) && joint->getVariableCount() > 0 && joint->getMimic() == nullptr)
69  {
70  found = true;
71  break;
72  }
73  else if (joint->getMimic() != nullptr)
74  {
75  const JointModel* mjoint = joint->getMimic();
76  if (group->hasJointModel(mjoint->getName()) && mjoint->getVariableCount() > 0 && mjoint->getMimic() == nullptr)
77  {
78  found = true;
79  }
80  else if (includesParent(mjoint, group))
81  {
82  found = true;
83  }
84  if (found)
85  break;
86  }
87  }
88  return found;
89 }
90 
91 // check if joint a is right below b, in the kinematic chain, with no active DOF missing
92 bool jointPrecedes(const JointModel* a, const JointModel* b)
93 {
94  if (!a->getParentLinkModel())
95  return false;
96  const JointModel* p = a->getParentLinkModel()->getParentJointModel();
97  while (p)
98  {
99  if (p == b)
100  return true;
101  if (p->getType() == JointModel::FIXED)
102  {
103  p = p->getParentLinkModel() ? p->getParentLinkModel()->getParentJointModel() : nullptr;
104  }
105  else
106  {
107  break;
108  }
109  }
110 
111  return false;
112 }
113 } // namespace
114 
115 JointModelGroup::JointModelGroup(const std::string& group_name, const srdf::Model::Group& config,
116  const std::vector<const JointModel*>& unsorted_group_joints,
117  const RobotModel* parent_model)
118  : parent_model_(parent_model)
119  , name_(group_name)
120  , common_root_(nullptr)
121  , variable_count_(0)
122  , active_variable_count_(0)
123  , is_contiguous_index_list_(true)
124  , is_chain_(false)
125  , is_single_dof_(true)
126  , config_(config)
127 {
128  // sort joints in Depth-First order
129  joint_model_vector_ = unsorted_group_joints;
130  std::sort(joint_model_vector_.begin(), joint_model_vector_.end(), OrderJointsByIndex());
132 
133  // figure out active joints, mimic joints, fixed joints
134  // construct index maps, list of variables
135  for (const JointModel* joint_model : joint_model_vector_)
136  {
137  joint_model_name_vector_.push_back(joint_model->getName());
138  joint_model_map_[joint_model->getName()] = joint_model;
139  unsigned int vc = joint_model->getVariableCount();
140  if (vc > 0)
141  {
142  if (vc > 1)
143  is_single_dof_ = false;
144  const std::vector<std::string>& name_order = joint_model->getVariableNames();
145 
146  if (joint_model->getMimic() == nullptr)
147  {
148  active_joint_model_vector_.push_back(joint_model);
149  active_joint_model_name_vector_.push_back(joint_model->getName());
151  active_joint_models_bounds_.push_back(&joint_model->getVariableBounds());
153  }
154  else
155  mimic_joints_.push_back(joint_model);
156  for (const std::string& name : name_order)
157  {
158  variable_names_.push_back(name);
159  variable_names_set_.insert(name);
160  }
161 
162  int first_index = joint_model->getFirstVariableIndex();
163  for (std::size_t j = 0; j < name_order.size(); ++j)
164  {
165  variable_index_list_.push_back(first_index + j);
166  joint_variables_index_map_[name_order[j]] = variable_count_ + j;
167  }
168  joint_variables_index_map_[joint_model->getName()] = variable_count_;
169 
170  if (joint_model->getType() == JointModel::REVOLUTE &&
171  static_cast<const RevoluteJointModel*>(joint_model)->isContinuous())
172  continuous_joint_model_vector_.push_back(joint_model);
173 
174  variable_count_ += vc;
175  }
176  else
177  fixed_joints_.push_back(joint_model);
178  }
179 
180  // now we need to find all the set of joints within this group
181  // that root distinct subtrees
182  for (const JointModel* active_joint_model : active_joint_model_vector_)
183  {
184  // if we find that an ancestor is also in the group, then the joint is not a root
185  if (!includesParent(active_joint_model, this))
186  joint_roots_.push_back(active_joint_model);
187  }
188 
189  // when updating this group within a state, it is useful to know
190  // if the full state of a group is contiguous within the full state of the robot
191  if (variable_index_list_.empty())
192  {
194  }
195  else
196  {
197  for (std::size_t i = 1; i < variable_index_list_.size(); ++i)
198  {
199  if (variable_index_list_[i] != variable_index_list_[i - 1] + 1)
200  {
202  break;
203  }
204  }
205  }
206 
207  // when updating/sampling a group state only, only mimic joints that have their parent within the group get updated.
208  for (const JointModel* mimic_joint : mimic_joints_)
209  {
210  // if the joint we mimic is also in this group, we will need to do updates when sampling
211  if (hasJointModel(mimic_joint->getMimic()->getName()))
212  {
213  int src = joint_variables_index_map_[mimic_joint->getMimic()->getName()];
214  int dest = joint_variables_index_map_[mimic_joint->getName()];
215  GroupMimicUpdate mu(src, dest, mimic_joint->getMimicFactor(), mimic_joint->getMimicOffset());
216  group_mimic_update_.push_back(mu);
217  }
218  }
219 
220  // now we need to make another pass for group links (we include the fixed joints here)
221  std::set<const LinkModel*> group_links_set;
222  for (const JointModel* joint_model : joint_model_vector_)
223  group_links_set.insert(joint_model->getChildLinkModel());
224  for (const LinkModel* group_link : group_links_set)
225  link_model_vector_.push_back(group_link);
226  std::sort(link_model_vector_.begin(), link_model_vector_.end(), OrderLinksByIndex());
227 
228  for (const LinkModel* link_model : link_model_vector_)
229  {
230  link_model_map_[link_model->getName()] = link_model;
231  link_model_name_vector_.push_back(link_model->getName());
232  // if this is the first link of the group with a valid parent and includes geometry (for example `base_link`) it should included
233  if (link_model_with_geometry_vector_.empty() && link_model->getParentLinkModel() &&
234  !link_model->getParentLinkModel()->getShapes().empty())
235  {
236  link_model_with_geometry_vector_.push_back(link_model->getParentLinkModel());
237  link_model_with_geometry_name_vector_.push_back(link_model->getParentLinkModel()->getName());
238  }
239  // all child links with collision geometry should also be included
240  if (!link_model->getShapes().empty())
241  {
242  link_model_with_geometry_vector_.push_back(link_model);
243  link_model_with_geometry_name_vector_.push_back(link_model->getName());
244  }
245  }
246 
247  // compute the common root of this group
248  if (!joint_roots_.empty())
249  {
251  for (std::size_t i = 1; i < joint_roots_.size(); ++i)
253  }
254 
255  // compute updated links
256  for (const JointModel* joint_root : joint_roots_)
257  {
258  const std::vector<const LinkModel*>& links = joint_root->getDescendantLinkModels();
259  updated_link_model_set_.insert(links.begin(), links.end());
260  }
261  for (const LinkModel* updated_link_model : updated_link_model_set_)
262  {
263  updated_link_model_name_set_.insert(updated_link_model->getName());
264  updated_link_model_vector_.push_back(updated_link_model);
265  if (!updated_link_model->getShapes().empty())
266  {
267  updated_link_model_with_geometry_vector_.push_back(updated_link_model);
268  updated_link_model_with_geometry_set_.insert(updated_link_model);
269  updated_link_model_with_geometry_name_set_.insert(updated_link_model->getName());
270  }
271  }
272  std::sort(updated_link_model_vector_.begin(), updated_link_model_vector_.end(), OrderLinksByIndex());
274  OrderLinksByIndex());
275  for (const LinkModel* updated_link_model : updated_link_model_vector_)
276  updated_link_model_name_vector_.push_back(updated_link_model->getName());
277  for (const LinkModel* updated_link_model_with_geometry : updated_link_model_with_geometry_vector_)
278  updated_link_model_with_geometry_name_vector_.push_back(updated_link_model_with_geometry->getName());
279 
280  // check if this group should actually be a chain
281  if (joint_roots_.size() == 1 && !active_joint_model_vector_.empty())
282  {
283  bool chain = true;
284  // due to our sorting, the joints are sorted in a DF fashion, so looking at them in reverse,
285  // we should always get to the parent.
286  for (std::size_t k = joint_model_vector_.size() - 1; k > 0; --k)
287  {
288  if (!jointPrecedes(joint_model_vector_[k], joint_model_vector_[k - 1]))
289  {
290  chain = false;
291  break;
292  }
293  }
294  if (chain)
295  is_chain_ = true;
296  }
297 }
298 
300 
301 void JointModelGroup::setSubgroupNames(const std::vector<std::string>& subgroups)
302 {
303  subgroup_names_ = subgroups;
304  subgroup_names_set_.clear();
305  for (const std::string& subgroup_name : subgroup_names_)
306  subgroup_names_set_.insert(subgroup_name);
307 }
308 
309 void JointModelGroup::getSubgroups(std::vector<const JointModelGroup*>& sub_groups) const
310 {
311  sub_groups.resize(subgroup_names_.size());
312  for (std::size_t i = 0; i < subgroup_names_.size(); ++i)
313  sub_groups[i] = parent_model_->getJointModelGroup(subgroup_names_[i]);
314 }
315 
316 bool JointModelGroup::hasJointModel(const std::string& joint) const
317 {
318  return joint_model_map_.find(joint) != joint_model_map_.end();
319 }
320 
321 bool JointModelGroup::hasLinkModel(const std::string& link) const
322 {
323  return link_model_map_.find(link) != link_model_map_.end();
324 }
325 
326 const LinkModel* JointModelGroup::getLinkModel(const std::string& name) const
327 {
328  LinkModelMapConst::const_iterator it = link_model_map_.find(name);
329  if (it == link_model_map_.end())
330  {
331  RCLCPP_ERROR(getLogger(), "Link '%s' not found in group '%s'", name.c_str(), name_.c_str());
332  return nullptr;
333  }
334  return it->second;
335 }
336 
337 const JointModel* JointModelGroup::getJointModel(const std::string& name) const
338 {
339  JointModelMapConst::const_iterator it = joint_model_map_.find(name);
340  if (it == joint_model_map_.end())
341  {
342  RCLCPP_ERROR(getLogger(), "Joint '%s' not found in group '%s'", name.c_str(), name_.c_str());
343  return nullptr;
344  }
345  return it->second;
346 }
347 
348 void JointModelGroup::getVariableRandomPositions(random_numbers::RandomNumberGenerator& rng, double* values,
349  const JointBoundsVector& active_joint_bounds) const
350 {
351  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
352  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
353  {
354  active_joint_model_vector_[i]->getVariableRandomPositions(rng, values + active_joint_model_start_index_[i],
355  *active_joint_bounds[i]);
356  }
357 
358  updateMimicJoints(values);
359 }
360 
361 void JointModelGroup::getVariableRandomPositionsNearBy(random_numbers::RandomNumberGenerator& rng, double* values,
362  const JointBoundsVector& active_joint_bounds, const double* near,
363  double distance) const
364 {
365  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
366  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
367  {
368  active_joint_model_vector_[i]->getVariableRandomPositionsNearBy(rng, values + active_joint_model_start_index_[i],
369  *active_joint_bounds[i],
371  distance);
372  }
373  updateMimicJoints(values);
374 }
375 
376 void JointModelGroup::getVariableRandomPositionsNearBy(random_numbers::RandomNumberGenerator& rng, double* values,
377  const JointBoundsVector& active_joint_bounds, const double* near,
378  const std::map<JointModel::JointType, double>& distance_map) const
379 {
380  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
381  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
382  {
383  double distance = 0.0;
384  std::map<JointModel::JointType, double>::const_iterator iter =
385  distance_map.find(active_joint_model_vector_[i]->getType());
386  if (iter != distance_map.end())
387  {
388  distance = iter->second;
389  }
390  else
391  {
392  RCLCPP_WARN(getLogger(), "Did not pass in distance for '%s'", active_joint_model_vector_[i]->getName().c_str());
393  }
394  active_joint_model_vector_[i]->getVariableRandomPositionsNearBy(rng, values + active_joint_model_start_index_[i],
395  *active_joint_bounds[i],
397  distance);
398  }
399  updateMimicJoints(values);
400 }
401 
402 void JointModelGroup::getVariableRandomPositionsNearBy(random_numbers::RandomNumberGenerator& rng, double* values,
403  const JointBoundsVector& active_joint_bounds, const double* near,
404  const std::vector<double>& distances) const
405 {
406  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
407  if (distances.size() != active_joint_model_vector_.size())
408  {
409  throw Exception("When sampling random values nearby for group '" + name_ +
410  "', distances vector should be of size " + std::to_string(active_joint_model_vector_.size()) +
411  ", but it is of size " + std::to_string(distances.size()));
412  }
413  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
414  {
415  active_joint_model_vector_[i]->getVariableRandomPositionsNearBy(rng, values + active_joint_model_start_index_[i],
416  *active_joint_bounds[i],
418  distances[i]);
419  }
420  updateMimicJoints(values);
421 }
422 
423 bool JointModelGroup::satisfiesPositionBounds(const double* state, const JointBoundsVector& active_joint_bounds,
424  double margin) const
425 {
426  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
427  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
428  {
430  *active_joint_bounds[i], margin))
431  return false;
432  }
433  return true;
434 }
435 
436 bool JointModelGroup::enforcePositionBounds(double* state, const JointBoundsVector& active_joint_bounds) const
437 {
438  assert(active_joint_bounds.size() == active_joint_model_vector_.size());
439  bool change = false;
440  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
441  {
443  *active_joint_bounds[i]))
444  change = true;
445  }
446  if (change)
447  updateMimicJoints(state);
448  return change;
449 }
450 
451 double JointModelGroup::getMaximumExtent(const JointBoundsVector& active_joint_bounds) const
452 {
453  double max_distance = 0.0;
454  for (std::size_t j = 0; j < active_joint_model_vector_.size(); ++j)
455  {
456  max_distance += active_joint_model_vector_[j]->getMaximumExtent(*active_joint_bounds[j]) *
457  active_joint_model_vector_[j]->getDistanceFactor();
458  }
459  return max_distance;
460 }
461 
462 double JointModelGroup::distance(const double* state1, const double* state2) const
463 {
464  double d = 0.0;
465  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
466  {
467  d += active_joint_model_vector_[i]->getDistanceFactor() *
469  state2 + active_joint_model_start_index_[i]);
470  }
471  return d;
472 }
473 
474 void JointModelGroup::interpolate(const double* from, const double* to, double t, double* state) const
475 {
476  // we interpolate values only for active joint models (non-mimic)
477  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
478  {
482  }
483 
484  // now we update mimic as needed
485  updateMimicJoints(state);
486 }
487 
488 void JointModelGroup::updateMimicJoints(double* values) const
489 {
490  // update mimic (only local joints as we are dealing with a local group state)
491  for (const GroupMimicUpdate& mimic_update : group_mimic_update_)
492  values[mimic_update.dest] = values[mimic_update.src] * mimic_update.factor + mimic_update.offset;
493 }
494 
495 void JointModelGroup::addDefaultState(const std::string& name, const std::map<std::string, double>& default_state)
496 {
497  default_states_[name] = default_state;
498  default_states_names_.push_back(name);
499 }
500 
501 bool JointModelGroup::getVariableDefaultPositions(const std::string& name, std::map<std::string, double>& values) const
502 {
503  std::map<std::string, std::map<std::string, double> >::const_iterator it = default_states_.find(name);
504  if (it == default_states_.end())
505  return false;
506  values = it->second;
507  return true;
508 }
509 
511 {
512  for (std::size_t i = 0; i < active_joint_model_vector_.size(); ++i)
514  updateMimicJoints(values);
515 }
516 
517 void JointModelGroup::getVariableDefaultPositions(std::map<std::string, double>& values) const
518 {
519  std::vector<double> tmp(variable_count_);
521  for (std::size_t i = 0; i < variable_names_.size(); ++i)
522  values[variable_names_[i]] = tmp[i];
523 }
524 
526 {
528 }
529 
530 void JointModelGroup::setEndEffectorParent(const std::string& group, const std::string& link)
531 {
532  end_effector_parent_.first = group;
533  end_effector_parent_.second = link;
534 }
535 
536 void JointModelGroup::attachEndEffector(const std::string& eef_name)
537 {
538  attached_end_effector_names_.push_back(eef_name);
539 }
540 
541 bool JointModelGroup::getEndEffectorTips(std::vector<std::string>& tips) const
542 {
543  // Get a vector of tip links
544  std::vector<const LinkModel*> tip_links;
545  if (!getEndEffectorTips(tip_links))
546  return false;
547 
548  // Convert to string names
549  tips.clear();
550  for (const LinkModel* link_model : tip_links)
551  tips.push_back(link_model->getName());
552  return true;
553 }
554 
555 bool JointModelGroup::getEndEffectorTips(std::vector<const LinkModel*>& tips) const
556 {
557  tips.clear();
558  for (const std::string& name : getAttachedEndEffectorNames())
559  {
561  if (!eef)
562  {
563  RCLCPP_ERROR(getLogger(), "Unable to find joint model group for eef");
564  return false;
565  }
566  const std::string& eef_parent = eef->getEndEffectorParentGroup().second;
567 
568  const LinkModel* eef_link = parent_model_->getLinkModel(eef_parent);
569  if (!eef_link)
570  {
571  RCLCPP_ERROR(getLogger(), "Unable to find end effector link for eef");
572  return false;
573  }
574  // insert eef_link into tips, maintaining a *sorted* vector, thus enabling use of std::lower_bound
575  const auto insert_it = std::lower_bound(tips.cbegin(), tips.cend(), eef_link);
576  if (insert_it == tips.end() || eef_link != *insert_it) // only insert if not a duplicate
577  tips.insert(insert_it, eef_link);
578  }
579  return true;
580 }
581 
583 {
584  std::vector<const LinkModel*> tips;
585  getEndEffectorTips(tips);
586  if (tips.size() == 1)
587  {
588  return tips.front();
589  }
590  else if (tips.size() > 1)
591  {
592  RCLCPP_ERROR(getLogger(), "More than one end effector tip found for joint model group, so cannot return only one");
593  }
594  else
595  {
596  RCLCPP_ERROR(getLogger(), "No end effector tips found in joint model group");
597  }
598  return nullptr;
599 }
600 
601 int JointModelGroup::getVariableGroupIndex(const std::string& variable) const
602 {
603  VariableIndexMap::const_iterator it = joint_variables_index_map_.find(variable);
604  if (it == joint_variables_index_map_.end())
605  {
606  RCLCPP_ERROR(getLogger(), "Variable '%s' is not part of group '%s'", variable.c_str(), name_.c_str());
607  return -1;
608  }
609  return it->second;
610 }
611 
613 {
614  group_kinematics_.first.default_ik_timeout_ = ik_timeout;
615  if (group_kinematics_.first.solver_instance_)
616  group_kinematics_.first.solver_instance_->setDefaultTimeout(ik_timeout);
617  for (std::pair<const JointModelGroup* const, KinematicsSolver>& it : group_kinematics_.second)
618  it.second.default_ik_timeout_ = ik_timeout;
619 }
620 
621 bool JointModelGroup::computeJointVariableIndices(const std::vector<std::string>& joint_names,
622  std::vector<size_t>& joint_bijection) const
623 {
624  joint_bijection.clear();
625  for (const std::string& joint_name : joint_names)
626  {
627  VariableIndexMap::const_iterator it = joint_variables_index_map_.find(joint_name);
628  if (it == joint_variables_index_map_.end())
629  {
630  // skip reported fixed joints
631  if (hasJointModel(joint_name) && getJointModel(joint_name)->getType() == JointModel::FIXED)
632  continue;
633  RCLCPP_ERROR(getLogger(),
634  "Looking for variables for joint '%s', "
635  "but group '%s' does not contain such a joint.",
636  joint_name.c_str(), getName().c_str());
637  return false;
638  }
639  const JointModel* jm = getJointModel(joint_name);
640  for (size_t k = 0; k < jm->getVariableCount(); ++k)
641  joint_bijection.push_back(it->second + k);
642  }
643  return true;
644 }
645 
646 void JointModelGroup::setSolverAllocators(const std::pair<SolverAllocatorFn, SolverAllocatorMapFn>& solvers)
647 {
648  if (solvers.first)
649  {
650  group_kinematics_.first.allocator_ = solvers.first;
651  group_kinematics_.first.solver_instance_ = solvers.first(this);
652  if (group_kinematics_.first.solver_instance_)
653  {
654  group_kinematics_.first.solver_instance_->setDefaultTimeout(group_kinematics_.first.default_ik_timeout_);
655  if (!computeJointVariableIndices(group_kinematics_.first.solver_instance_->getJointNames(),
656  group_kinematics_.first.bijection_))
657  group_kinematics_.first.reset();
658  }
659  }
660  else
661  {
662  // we now compute a joint bijection only if we have a solver map
663  for (const std::pair<const JointModelGroup* const, SolverAllocatorFn>& it : solvers.second)
664  {
665  if (it.first->getSolverInstance())
666  {
667  KinematicsSolver& ks = group_kinematics_.second[it.first];
668  ks.allocator_ = it.second;
669  ks.solver_instance_ = const_cast<JointModelGroup*>(it.first)->getSolverInstance();
670  ks.default_ik_timeout_ = group_kinematics_.first.default_ik_timeout_;
671  if (!computeJointVariableIndices(ks.solver_instance_->getJointNames(), ks.bijection_))
672  {
673  group_kinematics_.second.clear();
674  break;
675  }
676  }
677  }
678  }
679 }
680 
681 bool JointModelGroup::canSetStateFromIK(const std::string& tip) const
682 {
683  const kinematics::KinematicsBaseConstPtr& solver = getSolverInstance();
684  if (!solver || tip.empty())
685  return false;
686 
687  const std::vector<std::string>& tip_frames = solver->getTipFrames();
688 
689  if (tip_frames.empty())
690  {
691  RCLCPP_WARN(getLogger(), "Group %s has no tip frame(s)", name_.c_str());
692  return false;
693  }
694 
695  // loop through all tip frames supported by the JMG
696  for (const std::string& tip_frame : tip_frames)
697  {
698  // remove frame reference, if specified
699  const std::string& tip_local = tip[0] == '/' ? tip.substr(1) : tip;
700  const std::string& tip_frame_local = tip_frame[0] == '/' ? tip_frame.substr(1) : tip_frame;
701  RCLCPP_DEBUG(getLogger(), "comparing input tip: %s to this groups tip: %s ", tip_local.c_str(),
702  tip_frame_local.c_str());
703 
704  // Check if the IK solver's tip is the same as the frame of inquiry
705  if (tip_local != tip_frame_local)
706  {
707  // If not the same, check if this planning group includes the frame of inquiry
708  if (hasLinkModel(tip_frame_local))
709  {
710  const LinkModel* lm = getLinkModel(tip_frame_local);
711  const LinkTransformMap& fixed_links = lm->getAssociatedFixedTransforms();
712  // Check if our frame of inquiry is located anywhere further down the chain (towards the tip of the arm)
713  for (const std::pair<const LinkModel* const, Eigen::Isometry3d>& fixed_link : fixed_links)
714  {
715  if (fixed_link.first->getName() == tip_local)
716  return true;
717  }
718  }
719  }
720  else
721  return true;
722  }
723 
724  // Did not find any valid tip frame links to use
725  return false;
726 }
727 
728 void JointModelGroup::printGroupInfo(std::ostream& out) const
729 {
730  out << "Group '" << name_ << "' using " << variable_count_ << " variables\n";
731  out << " * Joints:\n";
732  for (const JointModel* joint_model : joint_model_vector_)
733  out << " '" << joint_model->getName() << "' (" << joint_model->getTypeName() << ")\n";
734  out << " * Variables:\n";
735  for (const std::string& variable_name : variable_names_)
736  {
737  int local_idx = joint_variables_index_map_.find(variable_name)->second;
738  const JointModel* jm = parent_model_->getJointOfVariable(variable_name);
739  out << " '" << variable_name << "', index "
740  << (jm->getFirstVariableIndex() + jm->getLocalVariableIndex(variable_name)) << " in full state, index "
741  << local_idx << " in group state";
742  if (jm->getMimic())
743  out << ", mimic '" << jm->getMimic()->getName() << '\'';
744  out << '\n';
745  out << " " << parent_model_->getVariableBounds(variable_name) << '\n';
746  }
747  out << " * Variables Index List:\n ";
748  for (int variable_index : variable_index_list_)
749  out << variable_index << ' ';
751  {
752  out << "(contiguous)";
753  }
754  else
755  {
756  out << "(non-contiguous)";
757  }
758  out << '\n';
759  if (group_kinematics_.first)
760  {
761  out << " * Kinematics solver bijection:\n";
762  out << " ";
763  for (unsigned int index : group_kinematics_.first.bijection_)
764  out << index << ' ';
765  out << '\n';
766  }
767  if (!group_kinematics_.second.empty())
768  {
769  out << " * Compound kinematics solver:\n";
770  for (const std::pair<const JointModelGroup* const, KinematicsSolver>& it : group_kinematics_.second)
771  {
772  out << " " << it.first->getName() << ':';
773  for (unsigned int index : it.second.bijection_)
774  out << ' ' << index;
775  out << '\n';
776  }
777  }
778 
779  if (!group_mimic_update_.empty())
780  {
781  out << " * Local Mimic Updates:\n";
782  for (const GroupMimicUpdate& mimic_update : group_mimic_update_)
783  {
784  out << " [" << mimic_update.dest << "] = " << mimic_update.factor << " * [" << mimic_update.src << "] + "
785  << mimic_update.offset << '\n';
786  }
787  }
788  out << '\n';
789 }
790 
791 bool JointModelGroup::isValidVelocityMove(const std::vector<double>& from_joint_pose,
792  const std::vector<double>& to_joint_pose, double dt) const
793 {
794  // Check for equal sized arrays
795  if (from_joint_pose.size() != to_joint_pose.size())
796  {
797  RCLCPP_ERROR(getLogger(), "To and from joint poses are of different sizes.");
798  return false;
799  }
800 
801  return isValidVelocityMove(&from_joint_pose[0], &to_joint_pose[0], from_joint_pose.size(), dt);
802 }
803 
804 bool JointModelGroup::isValidVelocityMove(const double* from_joint_pose, const double* to_joint_pose,
805  std::size_t array_size, double dt) const
806 {
807  const std::vector<const JointModel::Bounds*>& bounds = getActiveJointModelsBounds();
808  const std::vector<size_t>& bij = getKinematicsSolverJointBijection();
809 
810  for (std::size_t i = 0; i < array_size; ++i)
811  {
812  double dtheta = std::abs(from_joint_pose[i] - to_joint_pose[i]);
813  const std::vector<moveit::core::VariableBounds>* var_bounds = bounds[bij[i]];
814 
815  if (var_bounds->size() != 1)
816  {
817  // TODO(davetcoleman) Support multiple variables
818  RCLCPP_ERROR(getLogger(), "Attempting to check velocity bounds for waypoint move with joints that have multiple "
819  "variables");
820  return false;
821  }
822  const double max_velocity = (*var_bounds)[0].max_velocity_;
823 
824  double max_dtheta = dt * max_velocity;
825  if (dtheta > max_dtheta)
826  {
827  RCLCPP_DEBUG(getLogger(), "Not valid velocity move because of joint %lu", i);
828  return false;
829  }
830  }
831 
832  return true;
833 }
834 } // end of namespace core
835 } // end of namespace moveit
This may be thrown if unrecoverable errors occur.
Definition: exceptions.h:53
std::set< const LinkModel * > updated_link_model_with_geometry_set_
The list of downstream link models in the order they should be updated (may include links that are no...
std::vector< int > variable_index_list_
The list of index values this group includes, with respect to a full robot state; this includes mimic...
std::string name_
Name of group.
std::vector< const JointModel * > joint_model_vector_
Joint instances in the order they appear in the group state.
bool is_contiguous_index_list_
True if the state of this group is contiguous within the full robot state; this also means that the i...
std::vector< const JointModel * > continuous_joint_model_vector_
The set of continuous joints this group contains.
bool getEndEffectorTips(std::vector< const LinkModel * > &tips) const
Get the unique set of end effector tips included in a particular joint model group as defined by the ...
std::vector< const JointModel * > active_joint_model_vector_
Active joint instances in the order they appear in the group state.
std::vector< const JointModel * > joint_roots_
The list of active joint models that are roots in this group.
void setDefaultIKTimeout(double ik_timeout)
Set the default IK timeout.
std::vector< const LinkModel * > link_model_vector_
The links that are on the direct lineage between joints and joint_roots_, as well as the children of ...
std::vector< const LinkModel * > updated_link_model_with_geometry_vector_
The list of downstream link models in the order they should be updated (may include links that are no...
const std::string & getName() const
Get the name of the joint group.
std::map< std::string, std::map< std::string, double > > default_states_
The set of default states specified for this group in the SRDF.
void getVariableRandomPositions(random_numbers::RandomNumberGenerator &rng, double *values) const
Compute random values for the state of the joint group.
std::vector< std::string > updated_link_model_name_vector_
The list of downstream link names in the order they should be updated (may include links that are not...
double distance(const double *state1, const double *state2) const
void getVariableRandomPositionsNearBy(random_numbers::RandomNumberGenerator &rng, double *values, const double *near, const double distance) const
Compute random values for the state of the joint group.
void attachEndEffector(const std::string &eef_name)
Notify this group that there is an end-effector attached to it.
void setSolverAllocators(const SolverAllocatorFn &solver, const SolverAllocatorMapFn &solver_map=SolverAllocatorMapFn())
std::vector< std::string > variable_names_
The names of the DOF that make up this group (this is just a sequence of joint variable names; not ne...
bool computeJointVariableIndices(const std::vector< std::string > &joint_names, std::vector< size_t > &joint_bijection) const
Computes the indices of joint variables given a vector of joint names to look up.
std::vector< std::string > default_states_names_
The names of the default states specified for this group in the SRDF.
const JointModel * common_root_
The joint that is a common root for all joints in this group (not necessarily part of this group)
void setEndEffectorName(const std::string &name)
Set the name of the end-effector, and remember this group is indeed an end-effector.
LinkModelMapConst link_model_map_
A map from link names to their instances.
std::vector< std::string > attached_end_effector_names_
If an end-effector is attached to this group, the name of that end-effector is stored in this variabl...
JointBoundsVector active_joint_models_bounds_
The bounds for all the active joint models.
JointModelGroup(const std::string &name, const srdf::Model::Group &config, const std::vector< const JointModel * > &joint_vector, const RobotModel *parent_model)
const std::pair< std::string, std::string > & getEndEffectorParentGroup() const
Get the name of the group this end-effector attaches to (first) and the name of the link in that grou...
JointModelMapConst joint_model_map_
A map from joint names to their instances. This includes all joints in the group.
const JointModel * getJointModel(const std::string &joint) const
Get a joint by its name. Throw an exception if the joint is not part of this group.
std::vector< const LinkModel * > updated_link_model_vector_
The list of downstream link models in the order they should be updated (may include links that are no...
std::set< std::string > variable_names_set_
The names of the DOF that make up this group (this is just a sequence of joint variable names; not ne...
bool enforcePositionBounds(double *state) const
const std::vector< std::string > & getAttachedEndEffectorNames() const
Get the names of the end effectors attached to this group.
const kinematics::KinematicsBaseConstPtr getSolverInstance() const
bool hasJointModel(const std::string &joint) const
Check if a joint is part of this group.
std::vector< int > active_joint_model_start_index_
For each active joint model in this group, hold the index at which the corresponding joint state star...
std::set< std::string > updated_link_model_with_geometry_name_set_
The list of downstream link names in the order they should be updated (may include links that are not...
const LinkModel * getLinkModel(const std::string &link) const
Get a link by its name. Throw an exception if the link is not part of this group.
void interpolate(const double *from, const double *to, double t, double *state) const
const moveit::core::LinkModel * getOnlyOneEndEffectorTip() const
Get one end effector tip, throwing an error if there ends up being more in the joint model group This...
std::vector< std::string > subgroup_names_
The set of labelled subgroups that are included in this group.
std::set< const LinkModel * > updated_link_model_set_
The list of downstream link models in the order they should be updated (may include links that are no...
bool isValidVelocityMove(const std::vector< double > &from_joint_pose, const std::vector< double > &to_joint_pose, double dt) const
Check that the time to move between two waypoints is sufficient given velocity limits.
unsigned int active_variable_count_
The number of variables necessary to describe the active joints in this group of joints.
bool hasLinkModel(const std::string &link) const
Check if a link is part of this group.
void updateMimicJoints(double *values) const
Update the variable values for the state of a group with respect to the mimic joints....
std::vector< GroupMimicUpdate > group_mimic_update_
bool satisfiesPositionBounds(const double *state, double margin=0.0) const
unsigned int variable_count_
The number of variables necessary to describe this group of joints.
const JointBoundsVector & getActiveJointModelsBounds() const
Get the bounds for all the active joints.
void addDefaultState(const std::string &name, const std::map< std::string, double > &default_state)
std::pair< KinematicsSolver, KinematicsSolverMap > group_kinematics_
void getSubgroups(std::vector< const JointModelGroup * > &sub_groups) const
Get the groups that are subsets of this one (in terms of joints set)
bool canSetStateFromIK(const std::string &tip) const
const std::vector< size_t > & getKinematicsSolverJointBijection() const
Return the mapping between the order of the joints in this group and the order of the joints in the k...
std::vector< const LinkModel * > link_model_with_geometry_vector_
std::set< std::string > updated_link_model_name_set_
The list of downstream link names in the order they should be updated (may include links that are not...
std::vector< const JointModel * > mimic_joints_
Joints that mimic other joints.
std::vector< std::string > link_model_name_vector_
The names of the links in this group.
VariableIndexMap joint_variables_index_map_
The group includes all the joint variables that make up the joints the group consists of....
bool getVariableDefaultPositions(const std::string &name, std::map< std::string, double > &values) const
Get the values that correspond to a named state as read from the URDF. Return false on failure.
std::vector< std::string > updated_link_model_with_geometry_name_vector_
The list of downstream link names in the order they should be updated (may include links that are not...
int getVariableGroupIndex(const std::string &variable) const
Get the index of a variable within the group. Return -1 on error.
std::pair< std::string, std::string > end_effector_parent_
First: name of the group that is parent to this end-effector group; Second: the link this in the pare...
std::vector< std::string > active_joint_model_name_vector_
Names of active joints in the order they appear in the group state.
const RobotModel * parent_model_
Owner model.
std::vector< std::string > joint_model_name_vector_
Names of joints in the order they appear in the group state.
void setSubgroupNames(const std::vector< std::string > &subgroups)
Set the names of the subgroups for this group.
void setEndEffectorParent(const std::string &group, const std::string &link)
If this group is an end-effector, specify the parent group (e.g., the arm holding the eef) and the li...
std::set< std::string > subgroup_names_set_
The set of labelled subgroups that are included in this group.
std::vector< std::string > link_model_with_geometry_name_vector_
The names of the links in this group that also have geometry.
std::vector< const JointModel * > fixed_joints_
The joints that have no DOF (fixed)
void printGroupInfo(std::ostream &out=std::cout) const
Print information about the constructed model.
std::string end_effector_name_
The name of the end effector, if this group is an end-effector.
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition: joint_model.h:117
size_t getLocalVariableIndex(const std::string &variable) const
Get the index of the variable within this joint.
Definition: joint_model.cpp:85
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
Definition: joint_model.h:216
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
Definition: joint_model.h:210
const std::string & getName() const
Get the name of the joint.
Definition: joint_model.h:145
const std::vector< const LinkModel * > & getDescendantLinkModels() const
Get all the link models that descend from this joint, in the kinematic tree.
Definition: joint_model.h:422
const JointModel * getMimic() const
Get the joint this one is mimicking.
Definition: joint_model.h:390
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:72
const LinkTransformMap & getAssociatedFixedTransforms() const
Get the set of links that are attached to this one via fixed transforms. The returned transforms are ...
Definition: link_model.h:199
bool isContinuous() const
Check if this joint wraps around.
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
Definition: robot_model.h:76
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a specific variable. Throw an exception of variable is not found.
Definition: robot_model.h:433
const JointModelGroup * getEndEffector(const std::string &name) const
Get the joint group that corresponds to a given end-effector name.
const JointModelGroup * getJointModelGroup(const std::string &name) const
Get a joint group from this model (by name)
const JointModel * getJointOfVariable(int variable_index) const
Definition: robot_model.h:213
const LinkModel * getLinkModel(const std::string &link, bool *has_link=nullptr) const
Get a link by its name. Output error and return nullptr when the link is missing.
const JointModel * getCommonRoot(const JointModel *a, const JointModel *b) const
Get the deepest joint in the kinematic tree that is a common parent of both joints passed as argument...
Definition: robot_model.h:451
std::map< const LinkModel *, Eigen::Isometry3d, std::less< const LinkModel * >, Eigen::aligned_allocator< std::pair< const LinkModel *const, Eigen::Isometry3d > > > LinkTransformMap
Map from link model instances to Eigen transforms.
Definition: link_model.h:68
std::vector< const JointModel::Bounds * > JointBoundsVector
Main namespace for MoveIt.
Definition: exceptions.h:43
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition: logger.cpp:79
double distance(const urdf::Pose &transform)
Definition: pr2_arm_ik.h:55
name
Definition: setup.py:7
FilterFn chain(const std::vector< FilterFn > &filter_functions)
std::vector< size_t > bijection_
The mapping between the order of the joints in the group and the order of the joints in the kinematic...
SolverAllocatorFn allocator_
Function type that allocates a kinematics solver for a particular group.