moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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>
46
48
49namespace moveit
50{
51namespace core
52{
53namespace
54{
55rclcpp::Logger getLogger()
56{
57 return moveit::getLogger("moveit.core.joint_model_group");
58}
59
60// check if a parent or ancestor of joint is included in this group
61bool 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
92bool 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
115JointModelGroup::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
301void 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
309void 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)
314}
315
316bool JointModelGroup::hasJointModel(const std::string& joint) const
317{
318 return joint_model_map_.find(joint) != joint_model_map_.end();
319}
320
321bool JointModelGroup::hasLinkModel(const std::string& link) const
322{
323 return link_model_map_.find(link) != link_model_map_.end();
324}
325
326const 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
337const 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
348void 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
361void 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
376void 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
402void 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
423bool 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
436bool 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
451double 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
462double 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() *
470 }
471 return d;
472}
473
474void 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
488void 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
495void 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
501bool 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
517void 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
525void JointModelGroup::setEndEffectorName(const std::string& name)
526{
527 end_effector_name_ = name;
528}
529
530void 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
536void JointModelGroup::attachEndEffector(const std::string& eef_name)
537{
538 attached_end_effector_names_.push_back(eef_name);
539}
540
541bool 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
555bool JointModelGroup::getEndEffectorTips(std::vector<const LinkModel*>& tips) const
556{
557 tips.clear();
558 for (const std::string& name : getAttachedEndEffectorNames())
559 {
560 const JointModelGroup* eef = parent_model_->getEndEffector(name);
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
601int 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
621bool 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
646void 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
681bool 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
728void 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
791bool 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
804bool 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
835std::pair<Eigen::VectorXd, Eigen::VectorXd> JointModelGroup::getLowerAndUpperLimits() const
836{
837 // Get the group joints lower/upper position limits.
838 Eigen::VectorXd lower_limits(active_variable_count_);
839 Eigen::VectorXd upper_limits(active_variable_count_);
840 int variable_index = 0;
842 {
843 for (const moveit::core::VariableBounds& variable_bounds : *joint_bounds)
844 {
845 lower_limits[variable_index] =
846 variable_bounds.position_bounded_ ? variable_bounds.min_position_ : -std::numeric_limits<double>::infinity();
847 upper_limits[variable_index] =
848 variable_bounds.position_bounded_ ? variable_bounds.max_position_ : std::numeric_limits<double>::infinity();
849 variable_index++;
850 }
851 }
852 return { lower_limits, upper_limits };
853}
854
855std::pair<Eigen::VectorXd, Eigen::VectorXd> JointModelGroup::getMaxVelocitiesAndAccelerationBounds() const
856{
857 Eigen::VectorXd max_joint_velocities = Eigen::VectorXd::Constant(active_variable_count_, 0.0);
858 Eigen::VectorXd max_joint_accelerations = Eigen::VectorXd::Constant(active_variable_count_, 0.0);
859 // Check if variable count matches number of joint model bounds
861 {
862 // TODO(sjahr) Support multiple variables
863 RCLCPP_ERROR(getLogger(), "Number of active joint models does not match number of active joint model bounds. "
864 "Returning bound vectors with zeros");
865 return { max_joint_velocities, max_joint_accelerations };
866 }
867 // Check if the joint group contains multi-dof joints
868 for (const auto& bound : active_joint_models_bounds_)
869 {
870 if (bound->size() != 1)
871 {
872 RCLCPP_ERROR(getLogger(), "Multi-dof joints are currently not supported by "
873 "getMaxVelocitiesAndAccelerationBounds(). Returning bound vectors with zeros.");
874 return { max_joint_velocities, max_joint_accelerations };
875 }
876 }
877 // Populate max_joint_velocity and acceleration vectors
878 for (std::size_t i = 0; i < active_joint_models_bounds_.size(); ++i)
879 {
880 max_joint_velocities[i] = std::min(-active_joint_models_bounds_[i]->at(0).min_velocity_,
881 active_joint_models_bounds_[i]->at(0).max_velocity_);
882 max_joint_accelerations[i] = std::min(-active_joint_models_bounds_[i]->at(0).min_acceleration_,
883 active_joint_models_bounds_[i]->at(0).max_acceleration_);
884 }
885 return { max_joint_velocities, max_joint_accelerations };
886}
887} // end of namespace core
888} // end of namespace moveit
This may be thrown if unrecoverable errors occur.
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.
const JointBoundsVector & getActiveJointModelsBounds() const
Get the bounds for all the active joints.
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...
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.
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...
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.
const std::string & getName() const
Get the name of the joint group.
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)
JointModelMapConst joint_model_map_
A map from joint names to their instances. This includes all joints in the group.
std::pair< Eigen::VectorXd, Eigen::VectorXd > getLowerAndUpperLimits() const
Get the lower and upper position limits of all active variables in the group.
std::pair< Eigen::VectorXd, Eigen::VectorXd > getMaxVelocitiesAndAccelerationBounds() const
Gets the pair of maximum joint velocities/accelerations for a given group. Asserts that the group con...
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 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 std::vector< std::string > & getAttachedEndEffectorNames() const
Get the names of the end effectors attached to this group.
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.
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...
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.
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
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....
size_t getLocalVariableIndex(const std::string &variable) const
Get the index of the variable within this joint.
std::vector< VariableBounds > Bounds
The datatype for the joint bounds.
const std::vector< const LinkModel * > & getDescendantLinkModels() const
Get all the link models that descend from this joint, in the kinematic tree.
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
const std::string & getName() const
Get the name of the joint.
const JointModel * getMimic() const
Get the joint this one is mimicking.
JointType getType() const
Get the type of joint.
A link from the robot. Contains the constant transform applied to the link and its geometry.
const LinkTransformMap & getAssociatedFixedTransforms() const
Get the set of links that are attached to this one via fixed transforms. The returned transforms are ...
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
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...
const JointModel * getJointOfVariable(int variable_index) const
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 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 VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a specific variable. Throw an exception of variable is not found.
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.
std::vector< const JointModel::Bounds * > JointBoundsVector
Main namespace for MoveIt.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79
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.