39 #include <geometric_shapes/shape_operations.h>
40 #include <rclcpp/logger.hpp>
52 static const rclcpp::Logger LOGGER = rclcpp::get_logger(
"moveit_robot_model.robot_model");
59 buildModel(*urdf_model, *srdf_model);
82 void RobotModel::buildModel(
const urdf::ModelInterface& urdf_model,
const srdf::Model& srdf_model)
89 RCLCPP_INFO(LOGGER,
"Loading robot model '%s'...",
model_name_.c_str());
91 if (urdf_model.getRoot())
93 const urdf::Link* root_link_ptr = urdf_model.getRoot().get();
96 RCLCPP_DEBUG(LOGGER,
"... building kinematic chain");
97 root_joint_ = buildRecursive(
nullptr, root_link_ptr, srdf_model);
100 RCLCPP_DEBUG(LOGGER,
"... building mimic joints");
101 buildMimic(urdf_model);
103 RCLCPP_DEBUG(LOGGER,
"... computing joint indexing");
108 RCLCPP_WARN(LOGGER,
"No geometry is associated to any robot links");
113 RCLCPP_DEBUG(LOGGER,
"... constructing joint groups");
114 buildGroups(srdf_model);
116 RCLCPP_DEBUG(LOGGER,
"... constructing joint group states");
117 buildGroupStates(srdf_model);
124 RCLCPP_WARN(LOGGER,
"No root link found");
130 typedef std::map<const JointModel*, std::pair<std::set<const LinkModel*, OrderLinksByIndex>,
131 std::set<const JointModel*, OrderJointsByIndex>>>
134 void computeDescendantsHelper(
const JointModel* joint, std::vector<const JointModel*>& parents,
135 std::set<const JointModel*>& seen, DescMap& descendants)
139 if (seen.find(joint) != seen.end())
143 for (
const JointModel* parent : parents)
144 descendants[parent].second.insert(joint);
146 const LinkModel* lm = joint->getChildLinkModel();
150 for (
const JointModel* parent : parents)
151 descendants[parent].first.insert(lm);
152 descendants[joint].first.insert(lm);
154 parents.push_back(joint);
155 const std::vector<const JointModel*>& ch = lm->getChildJointModels();
156 for (
const JointModel* child_joint_model : ch)
157 computeDescendantsHelper(child_joint_model, parents, seen, descendants);
158 const std::vector<const JointModel*>& mim = joint->getMimicRequests();
159 for (
const JointModel* mimic_joint_model : mim)
160 computeDescendantsHelper(mimic_joint_model, parents, seen, descendants);
164 void computeCommonRootsHelper(
const JointModel* joint, std::vector<int>& common_roots,
int size)
168 const LinkModel* lm = joint->getChildLinkModel();
172 const std::vector<const JointModel*>& ch = lm->getChildJointModels();
173 for (std::size_t i = 0; i < ch.size(); ++i)
175 const std::vector<const JointModel*>&
a = ch[i]->getDescendantJointModels();
176 for (std::size_t j = i + 1; j < ch.size(); ++j)
178 const std::vector<const JointModel*>& b = ch[j]->getDescendantJointModels();
179 for (
const JointModel* m : b)
180 common_roots[ch[i]->getJointIndex() * size + m->getJointIndex()] =
181 common_roots[ch[i]->getJointIndex() + m->getJointIndex() * size] = joint->getJointIndex();
182 for (
const JointModel* k :
a)
184 common_roots[k->getJointIndex() * size + ch[j]->getJointIndex()] =
185 common_roots[k->getJointIndex() + ch[j]->getJointIndex() * size] = joint->getJointIndex();
186 for (
const JointModel* m : b)
187 common_roots[k->getJointIndex() * size + m->getJointIndex()] =
188 common_roots[k->getJointIndex() + m->getJointIndex() * size] = joint->getJointIndex();
191 computeCommonRootsHelper(ch[i], common_roots, size);
196 void RobotModel::computeCommonRoots()
218 const std::vector<const JointModel*>&
d = joint_model->getDescendantJointModels();
219 for (
const JointModel* descendant_joint_model :
d)
221 joint_model->getJointIndex()] =
227 void RobotModel::computeDescendants()
230 std::vector<const JointModel*> parents;
231 std::set<const JointModel*> seen;
234 computeDescendantsHelper(
root_joint_, parents, seen, descendants);
235 for (std::pair<
const JointModel*
const, std::pair<std::set<const LinkModel*, OrderLinksByIndex>,
236 std::set<const JointModel*, OrderJointsByIndex>>>& descendant :
239 JointModel* jm =
const_cast<JointModel*
>(descendant.first);
240 for (
const JointModel* jt : descendant.second.second)
241 jm->addDescendantJointModel(jt);
242 for (
const LinkModel* jt : descendant.second.first)
243 jm->addDescendantLinkModel(jt);
247 void RobotModel::buildJointInfo()
257 const std::vector<std::string>& name_order = joint->getVariableNames();
260 if (!name_order.empty())
262 for (std::size_t j = 0; j < name_order.size(); ++j)
268 if (joint->getMimic() ==
nullptr)
277 if (joint->getType() ==
JointModel::REVOLUTE &&
static_cast<const RevoluteJointModel*
>(joint)->isContinuous())
283 std::size_t vc = joint->getVariableCount();
295 if (link_considered[link->getLinkIndex()])
300 for (
auto& tf_base : associated_transforms)
302 link_considered[tf_base.first->getLinkIndex()] =
true;
303 for (
auto& tf_target : associated_transforms)
305 if (&tf_base != &tf_target)
306 const_cast<LinkModel*
>(tf_base.first)
307 ->addAssociatedFixedTransform(tf_target.first, tf_base.second.inverse() * tf_target.second);
312 computeDescendants();
313 computeCommonRoots();
316 void RobotModel::buildGroupStates(
const srdf::Model& srdf_model)
319 const std::vector<srdf::Model::GroupState>& ds = srdf_model.getGroupStates();
320 for (
const srdf::Model::GroupState& group_state : ds)
325 std::vector<const JointModel*> remaining_joints = jmg->getActiveJointModels();
326 std::map<std::string, double> state;
327 for (std::map<std::string, std::vector<double>>::const_iterator jt = group_state.joint_values_.begin();
328 jt != group_state.joint_values_.end(); ++jt)
330 if (jmg->hasJointModel(jt->first))
332 const JointModel* jm = jmg->getJointModel(jt->first);
333 const std::vector<std::string>& vn = jm->getVariableNames();
335 auto it_found = std::find(remaining_joints.begin(), remaining_joints.end(), jm);
336 if (it_found != remaining_joints.end())
337 remaining_joints.erase(it_found);
338 if (vn.size() == jt->second.size())
339 for (std::size_t j = 0; j < vn.size(); ++j)
340 state[vn[j]] = jt->second[j];
343 "The model for joint '%s' requires %d variable values, "
344 "but only %d variable values were supplied in default state '%s' for group '%s'",
345 jt->first.c_str(),
static_cast<int>(vn.size()),
static_cast<int>(jt->second.size()),
346 group_state.name_.c_str(), jmg->getName().c_str());
350 "Group state '%s' specifies value for joint '%s', "
351 "but that joint is not part of group '%s'",
352 group_state.name_.c_str(), jt->first.c_str(), jmg->getName().c_str());
354 if (!remaining_joints.empty())
356 std::stringstream missing;
357 missing << (*remaining_joints.begin())->
getName();
358 for (
auto j = ++remaining_joints.begin(); j != remaining_joints.end(); ++j)
360 missing <<
", " << (*j)->getName();
362 RCLCPP_WARN_STREAM(LOGGER,
"Group state '" << group_state.name_
363 <<
"' doesn't specify all group joints in group '"
364 << group_state.group_ <<
"'. " << missing.str() <<
" "
365 << (remaining_joints.size() > 1 ?
"are" :
"is") <<
" missing.");
368 jmg->addDefaultState(group_state.name_, state);
371 RCLCPP_ERROR(LOGGER,
"Group state '%s' specified for group '%s', but that group does not exist",
372 group_state.name_.c_str(), group_state.group_.c_str());
376 void RobotModel::buildMimic(
const urdf::ModelInterface& urdf_model)
381 const urdf::Joint* jm = urdf_model.getJoint(joint_model->getName()).get();
385 JointModelMap::const_iterator jit =
joint_model_map_.find(jm->mimic->joint_name);
388 if (joint_model->getVariableCount() == jit->second->getVariableCount())
389 joint_model->setMimic(jit->second, jm->mimic->multiplier, jm->mimic->offset);
391 RCLCPP_ERROR(LOGGER,
"Join '%s' cannot mimic joint '%s' because they have different number of DOF",
392 joint_model->getName().c_str(), jm->mimic->joint_name.c_str());
395 RCLCPP_ERROR(LOGGER,
"Joint '%s' cannot mimic unknown joint '%s'", joint_model->getName().c_str(),
396 jm->mimic->joint_name.c_str());
406 if (joint_model->getMimic())
408 if (joint_model->getMimic()->getMimic())
410 joint_model->setMimic(joint_model->getMimic()->getMimic(),
411 joint_model->getMimicFactor() * joint_model->getMimic()->getMimicFactor(),
412 joint_model->getMimicOffset() +
413 joint_model->getMimicFactor() * joint_model->getMimic()->getMimicOffset());
416 if (joint_model == joint_model->getMimic())
418 RCLCPP_ERROR(LOGGER,
"Cycle found in joint that mimic each other. Ignoring all mimic joints.");
420 joint_model_recal->setMimic(
nullptr, 0.0, 0.0);
428 if (joint_model->getMimic())
430 const_cast<JointModel*
>(joint_model->getMimic())->addMimicRequest(joint_model);
448 RCLCPP_ERROR(LOGGER,
"End-effector '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
462 RCLCPP_ERROR(LOGGER,
"End-effector '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
478 RCLCPP_ERROR(LOGGER,
"Group '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
489 RCLCPP_ERROR(LOGGER,
"Group '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
495 void RobotModel::buildGroups(
const srdf::Model& srdf_model)
497 const std::vector<srdf::Model::Group>& group_configs = srdf_model.getGroups();
500 std::vector<bool> processed(group_configs.size(),
false);
508 for (std::size_t i = 0; i < group_configs.size(); ++i)
512 bool all_subgroups_added =
true;
513 for (
const std::string& subgroup : group_configs[i].subgroups_)
516 all_subgroups_added =
false;
519 if (all_subgroups_added)
523 if (!addJointModelGroup(group_configs[i]))
525 RCLCPP_WARN(LOGGER,
"Failed to add group '%s'", group_configs[i].name_.c_str());
531 for (std::size_t i = 0; i < processed.size(); ++i)
534 RCLCPP_WARN(LOGGER,
"Could not process group '%s' due to unmet subgroup dependencies",
535 group_configs[i].name_.c_str());
547 buildGroupsInfoSubgroups();
548 buildGroupsInfoEndEffectors(srdf_model);
551 void RobotModel::buildGroupsInfoSubgroups()
556 JointModelGroup* jmg = it->second;
557 std::vector<std::string> subgroup_names;
558 std::set<const JointModel*> joints(jmg->getJointModels().begin(), jmg->getJointModels().end());
561 if (jt->first != it->first)
564 JointModelGroup* sub_jmg = jt->second;
565 const std::vector<const JointModel*>& sub_joints = sub_jmg->getJointModels();
566 for (
const JointModel* sub_joint : sub_joints)
567 if (joints.find(sub_joint) == joints.end())
573 subgroup_names.push_back(sub_jmg->getName());
575 if (!subgroup_names.empty())
576 jmg->setSubgroupNames(subgroup_names);
580 void RobotModel::buildGroupsInfoEndEffectors(
const srdf::Model& srdf_model)
583 const std::vector<srdf::Model::EndEffector>& eefs = srdf_model.getEndEffectors();
587 for (
const srdf::Model::EndEffector& eef : eefs)
588 if (eef.component_group_ == it->first)
591 it->second->setEndEffectorName(eef.name_);
597 std::vector<JointModelGroup*> possible_parent_groups;
600 if (jt->first != it->first)
602 if (jt->second->hasLinkModel(eef.parent_link_))
604 jt->second->attachEndEffector(eef.name_);
605 possible_parent_groups.push_back(jt->second);
609 JointModelGroup* eef_parent_group =
nullptr;
611 if (!eef.parent_group_.empty())
616 if (jt->second->hasLinkModel(eef.parent_link_))
618 if (jt->second != it->second)
619 eef_parent_group = jt->second;
621 RCLCPP_ERROR(LOGGER,
"Group '%s' for end-effector '%s' cannot be its own parent",
622 eef.parent_group_.c_str(), eef.name_.c_str());
626 "Group '%s' was specified as parent group for end-effector '%s' "
627 "but it does not include the parent link '%s'",
628 eef.parent_group_.c_str(), eef.name_.c_str(), eef.parent_link_.c_str());
631 RCLCPP_ERROR(LOGGER,
"Group name '%s' not found (specified as parent group for end-effector '%s')",
632 eef.parent_group_.c_str(), eef.name_.c_str());
636 if (eef_parent_group ==
nullptr)
637 if (!possible_parent_groups.empty())
641 std::size_t best = 0;
642 for (std::size_t g = 1; g < possible_parent_groups.size(); ++g)
646 eef_parent_group = possible_parent_groups[best];
649 if (eef_parent_group)
651 it->second->setEndEffectorParent(eef_parent_group->getName(), eef.parent_link_);
655 RCLCPP_WARN(LOGGER,
"Could not identify parent group for end-effector '%s'", eef.name_.c_str());
656 it->second->setEndEffectorParent(
"", eef.parent_link_);
663 bool RobotModel::addJointModelGroup(
const srdf::Model::Group& gc)
667 RCLCPP_WARN(LOGGER,
"A group named '%s' already exists. Not adding.", gc.name_.c_str());
671 std::set<const JointModel*> jset;
674 for (
const std::pair<std::string, std::string>& chain : gc.chains_)
678 if (base_link && tip_link)
681 const LinkModel* lm = tip_link;
682 std::vector<const JointModel*> cj;
687 cj.push_back(lm->getParentJointModel());
688 lm = lm->getParentJointModel()->getParentLinkModel();
696 std::size_t index = 0;
697 std::vector<const JointModel*> cj2;
700 for (std::size_t j = 0; j < cj.size(); ++j)
701 if (cj[j] == lm->getParentJointModel())
708 cj2.push_back(lm->getParentJointModel());
709 lm = lm->getParentJointModel()->getParentLinkModel();
713 jset.insert(cj.begin(), cj.begin() + index);
714 jset.insert(cj2.begin(), cj2.end());
719 jset.insert(cj.begin(), cj.end());
724 for (
const std::string& joint : gc.joints_)
732 for (
const std::string& link : gc.links_)
736 jset.insert(l->getParentJointModel());
740 for (
const std::string& subgroup : gc.subgroups_)
746 const std::vector<const JointModel*>& js = sg->getJointModels();
747 for (
const JointModel* j : js)
751 const std::vector<const JointModel*>& fs = sg->getFixedJointModels();
752 for (
const JointModel*
f : fs)
756 const std::vector<const JointModel*>& ms = sg->getMimicJointModels();
757 for (
const JointModel* m : ms)
764 RCLCPP_WARN(LOGGER,
"Group '%s' must have at least one valid joint", gc.name_.c_str());
768 std::vector<const JointModel*> joints;
769 joints.reserve(jset.size());
770 for (
const JointModel* it : jset)
771 joints.push_back(it);
773 JointModelGroup* jmg =
new JointModelGroup(gc.name_, gc, joints,
this);
779 JointModel* RobotModel::buildRecursive(LinkModel* parent,
const urdf::Link* urdf_link,
const srdf::Model& srdf_model)
782 JointModel* joint = constructJointModel(urdf_link, srdf_model);
784 if (joint ==
nullptr)
792 joint->setParentLinkModel(parent);
795 LinkModel* link = constructLinkModel(urdf_link);
796 joint->setChildLinkModel(link);
797 link->setParentLinkModel(parent);
804 if (!link->getShapes().empty())
811 link->setParentJointModel(joint);
814 for (
const urdf::LinkSharedPtr& child_link : urdf_link->child_links)
816 JointModel* jm = buildRecursive(link, child_link.get(), srdf_model);
818 link->addChildJointModel(jm);
826 static inline VariableBounds jointBoundsFromURDF(
const urdf::Joint* urdf_joint)
829 if (urdf_joint->safety)
831 b.position_bounded_ =
true;
832 b.min_position_ = urdf_joint->safety->soft_lower_limit;
833 b.max_position_ = urdf_joint->safety->soft_upper_limit;
834 if (urdf_joint->limits)
836 if (urdf_joint->limits->lower > b.min_position_)
837 b.min_position_ = urdf_joint->limits->lower;
838 if (urdf_joint->limits->upper < b.max_position_)
839 b.max_position_ = urdf_joint->limits->upper;
844 if (urdf_joint->limits)
846 b.position_bounded_ =
true;
847 b.min_position_ = urdf_joint->limits->lower;
848 b.max_position_ = urdf_joint->limits->upper;
851 if (urdf_joint->limits)
853 b.max_velocity_ = fabs(urdf_joint->limits->velocity);
854 b.min_velocity_ = -b.max_velocity_;
855 b.velocity_bounded_ = b.max_velocity_ > std::numeric_limits<double>::epsilon();
861 JointModel* RobotModel::constructJointModel(
const urdf::Link* child_link,
const srdf::Model& srdf_model)
863 JointModel* new_joint_model =
nullptr;
864 auto parent_joint = child_link->parent_joint ? child_link->parent_joint.get() :
nullptr;
873 switch (parent_joint->type)
875 case urdf::Joint::REVOLUTE:
877 RevoluteJointModel* j =
new RevoluteJointModel(parent_joint->name, joint_index, first_variable_index);
878 j->setVariableBounds(j->getName(), jointBoundsFromURDF(parent_joint));
879 j->setContinuous(
false);
880 j->setAxis(
Eigen::Vector3d(parent_joint->axis.x, parent_joint->axis.y, parent_joint->axis.z));
884 case urdf::Joint::CONTINUOUS:
886 RevoluteJointModel* j =
new RevoluteJointModel(parent_joint->name, joint_index, first_variable_index);
887 j->setVariableBounds(j->getName(), jointBoundsFromURDF(parent_joint));
888 j->setContinuous(
true);
889 j->setAxis(
Eigen::Vector3d(parent_joint->axis.x, parent_joint->axis.y, parent_joint->axis.z));
893 case urdf::Joint::PRISMATIC:
895 PrismaticJointModel* j =
new PrismaticJointModel(parent_joint->name, joint_index, first_variable_index);
896 j->setVariableBounds(j->getName(), jointBoundsFromURDF(parent_joint));
897 j->setAxis(
Eigen::Vector3d(parent_joint->axis.x, parent_joint->axis.y, parent_joint->axis.z));
901 case urdf::Joint::FLOATING:
902 new_joint_model =
new FloatingJointModel(parent_joint->name, joint_index, first_variable_index);
904 case urdf::Joint::PLANAR:
905 new_joint_model =
new PlanarJointModel(parent_joint->name, joint_index, first_variable_index);
908 new_joint_model =
new FixedJointModel(parent_joint->name, joint_index, first_variable_index);
911 RCLCPP_ERROR(LOGGER,
"Unknown joint type: %d",
static_cast<int>(parent_joint->type));
917 const std::vector<srdf::Model::VirtualJoint>& virtual_joints = srdf_model.getVirtualJoints();
918 for (
const srdf::Model::VirtualJoint& virtual_joint : virtual_joints)
920 if (virtual_joint.child_link_ != child_link->name)
922 if (child_link->name ==
"world" && virtual_joint.type_ ==
"fixed" && child_link->collision_array.empty() &&
923 !child_link->collision && child_link->visual_array.empty() && !child_link->visual)
926 new_joint_model =
new FixedJointModel(virtual_joint.name_, joint_index, first_variable_index);
929 "Skipping virtual joint '%s' because its child frame '%s' "
930 "does not match the URDF frame '%s'",
931 virtual_joint.name_.c_str(), virtual_joint.child_link_.c_str(), child_link->name.c_str());
933 else if (virtual_joint.parent_frame_.empty())
935 RCLCPP_WARN(LOGGER,
"Skipping virtual joint '%s' because its parent frame is empty",
936 virtual_joint.name_.c_str());
940 if (virtual_joint.type_ ==
"fixed")
941 new_joint_model =
new FixedJointModel(virtual_joint.name_, joint_index, first_variable_index);
942 else if (virtual_joint.type_ ==
"planar")
943 new_joint_model =
new PlanarJointModel(virtual_joint.name_, joint_index, first_variable_index);
944 else if (virtual_joint.type_ ==
"floating")
945 new_joint_model =
new FloatingJointModel(virtual_joint.name_, joint_index, first_variable_index);
949 if (virtual_joint.type_ !=
"fixed")
957 if (!new_joint_model)
959 RCLCPP_INFO(LOGGER,
"No root/virtual joint specified in SRDF. Assuming fixed joint");
960 new_joint_model =
new FixedJointModel(
"ASSUMED_FIXED_ROOT_JOINT", joint_index, first_variable_index);
966 new_joint_model->setDistanceFactor(new_joint_model->getStateSpaceDimension());
967 const std::vector<srdf::Model::PassiveJoint>& pjoints = srdf_model.getPassiveJoints();
968 for (
const srdf::Model::PassiveJoint& pjoint : pjoints)
970 if (new_joint_model->getName() == pjoint.name_)
972 new_joint_model->setPassive(
true);
977 for (
const srdf::Model::JointProperty& property : srdf_model.getJointProperties(new_joint_model->getName()))
979 if (property.property_name_ ==
"angular_distance_weight")
981 double angular_distance_weight;
984 std::string::size_type sz;
985 angular_distance_weight = std::stod(property.value_, &sz);
986 if (sz != property.value_.size())
988 RCLCPP_WARN_STREAM(LOGGER,
"Extra characters after property " << property.property_name_ <<
" for joint "
989 << property.joint_name_ <<
" as double: '"
990 << property.value_.substr(sz) <<
"'");
993 catch (
const std::invalid_argument& e)
995 RCLCPP_ERROR_STREAM(LOGGER,
"Unable to parse property " << property.property_name_ <<
" for joint "
996 << property.joint_name_ <<
" as double: '"
997 << property.value_ <<
"'");
1001 if (new_joint_model->getType() == JointModel::JointType::PLANAR)
1003 ((PlanarJointModel*)new_joint_model)->setAngularDistanceWeight(angular_distance_weight);
1005 else if (new_joint_model->getType() == JointModel::JointType::FLOATING)
1007 ((FloatingJointModel*)new_joint_model)->setAngularDistanceWeight(angular_distance_weight);
1011 RCLCPP_ERROR_STREAM(LOGGER,
"Cannot apply property " << property.property_name_
1012 <<
" to joint type: " << new_joint_model->getTypeName());
1015 else if (property.property_name_ ==
"motion_model")
1017 if (new_joint_model->getType() != JointModel::JointType::PLANAR)
1019 RCLCPP_ERROR(LOGGER,
"Cannot apply property %s to joint type: %s", property.property_name_.c_str(),
1020 new_joint_model->getTypeName().c_str());
1025 if (property.value_ ==
"holonomic")
1027 motion_model = PlanarJointModel::MotionModel::HOLONOMIC;
1029 else if (property.value_ ==
"diff_drive")
1031 motion_model = PlanarJointModel::MotionModel::DIFF_DRIVE;
1035 RCLCPP_ERROR_STREAM(LOGGER,
"Unknown value for property " << property.property_name_ <<
" ("
1036 << property.joint_name_ <<
"): '" << property.value_
1038 RCLCPP_ERROR(LOGGER,
"Valid values are 'holonomic' and 'diff_drive'");
1042 ((PlanarJointModel*)new_joint_model)->setMotionModel(motion_model);
1044 else if (property.property_name_ ==
"min_translational_distance")
1046 if (new_joint_model->getType() != JointModel::JointType::PLANAR)
1048 RCLCPP_ERROR(LOGGER,
"Cannot apply property %s to joint type: %s", property.property_name_.c_str(),
1049 new_joint_model->getTypeName().c_str());
1052 double min_translational_distance;
1055 std::string::size_type sz;
1056 min_translational_distance = std::stod(property.value_, &sz);
1057 if (sz != property.value_.size())
1059 RCLCPP_WARN_STREAM(LOGGER,
"Extra characters after property " << property.property_name_ <<
" for joint "
1060 << property.joint_name_ <<
" as double: '"
1061 << property.value_.substr(sz) <<
"'");
1064 catch (
const std::invalid_argument& e)
1066 RCLCPP_ERROR_STREAM(LOGGER,
"Unable to parse property " << property.property_name_ <<
" for joint "
1067 << property.joint_name_ <<
" as double: '"
1068 << property.value_ <<
"'");
1072 ((PlanarJointModel*)new_joint_model)->setMinTranslationalDistance(min_translational_distance);
1076 RCLCPP_ERROR(LOGGER,
"Unknown joint property: %s", property.property_name_.c_str());
1081 return new_joint_model;
1086 static inline Eigen::Isometry3d urdfPose2Isometry3d(
const urdf::Pose& pose)
1088 Eigen::Quaterniond q(pose.rotation.w, pose.rotation.x, pose.rotation.y, pose.rotation.z);
1089 Eigen::Isometry3d af(Eigen::Translation3d(pose.position.x, pose.position.y, pose.position.z) * q);
1094 LinkModel* RobotModel::constructLinkModel(
const urdf::Link* urdf_link)
1097 LinkModel* new_link_model =
new LinkModel(urdf_link->name, link_index);
1099 const std::vector<urdf::CollisionSharedPtr>& col_array =
1100 urdf_link->collision_array.empty() ? std::vector<urdf::CollisionSharedPtr>(1, urdf_link->collision) :
1101 urdf_link->collision_array;
1103 std::vector<shapes::ShapeConstPtr>
shapes;
1104 EigenSTL::vector_Isometry3d poses;
1106 for (
const urdf::CollisionSharedPtr& col : col_array)
1108 if (col && col->geometry)
1110 shapes::ShapeConstPtr s = constructShape(col->geometry.get());
1114 poses.push_back(urdfPose2Isometry3d(col->origin));
1120 bool warn_about_missing_collision =
false;
1123 const auto& vis_array = urdf_link->visual_array.empty() ? std::vector<urdf::VisualSharedPtr>{ urdf_link->visual } :
1124 urdf_link->visual_array;
1125 for (
const urdf::VisualSharedPtr& vis : vis_array)
1127 if (vis && vis->geometry)
1128 warn_about_missing_collision =
true;
1131 if (warn_about_missing_collision)
1133 RCLCPP_WARN_STREAM(LOGGER,
1134 "Link " << urdf_link->name
1135 <<
" has visual geometry but no collision geometry. "
1136 "Collision geometry will be left empty. "
1137 "Fix your URDF file by explicitly specifying collision geometry.");
1140 new_link_model->setGeometry(
shapes, poses);
1143 if (urdf_link->visual && urdf_link->visual->geometry)
1145 if (urdf_link->visual->geometry->type == urdf::Geometry::MESH)
1147 const urdf::Mesh* mesh =
static_cast<const urdf::Mesh*
>(urdf_link->visual->geometry.get());
1148 if (!mesh->filename.empty())
1149 new_link_model->setVisualMesh(mesh->filename, urdfPose2Isometry3d(urdf_link->visual->origin),
1153 else if (urdf_link->collision && urdf_link->collision->geometry)
1155 if (urdf_link->collision->geometry->type == urdf::Geometry::MESH)
1157 const urdf::Mesh* mesh =
static_cast<const urdf::Mesh*
>(urdf_link->collision->geometry.get());
1158 if (!mesh->filename.empty())
1159 new_link_model->setVisualMesh(mesh->filename, urdfPose2Isometry3d(urdf_link->collision->origin),
1164 if (urdf_link->parent_joint)
1165 new_link_model->setJointOriginTransform(
1166 urdfPose2Isometry3d(urdf_link->parent_joint->parent_to_joint_origin_transform));
1168 return new_link_model;
1171 shapes::ShapePtr RobotModel::constructShape(
const urdf::Geometry* geom)
1173 shapes::Shape* new_shape =
nullptr;
1176 case urdf::Geometry::SPHERE:
1177 new_shape =
new shapes::Sphere(
static_cast<const urdf::Sphere*
>(geom)->radius);
1179 case urdf::Geometry::BOX:
1181 urdf::Vector3 dim =
static_cast<const urdf::Box*
>(geom)->dim;
1182 new_shape =
new shapes::Box(dim.x, dim.y, dim.z);
1185 case urdf::Geometry::CYLINDER:
1186 new_shape =
new shapes::Cylinder(
static_cast<const urdf::Cylinder*
>(geom)->radius,
1187 static_cast<const urdf::Cylinder*
>(geom)->length);
1189 case urdf::Geometry::MESH:
1191 const urdf::Mesh* mesh =
static_cast<const urdf::Mesh*
>(geom);
1192 if (!mesh->filename.empty())
1195 shapes::Mesh* m = shapes::createMeshFromResource(mesh->filename, scale);
1201 RCLCPP_ERROR(LOGGER,
"Unknown geometry type: %d",
static_cast<int>(geom->type));
1205 return shapes::ShapePtr(new_shape);
1223 RCLCPP_ERROR(LOGGER,
"Joint '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
1231 RCLCPP_ERROR(LOGGER,
"Joint index '%li' out of bounds of joints in model '%s'", index,
model_name_.c_str());
1243 RCLCPP_ERROR(LOGGER,
"Joint '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
1256 RCLCPP_ERROR(LOGGER,
"Link index '%li' out of bounds of links in model '%s'", index,
model_name_.c_str());
1274 RCLCPP_ERROR(LOGGER,
"Link '%s' not found in model '%s'",
name.c_str(),
model_name_.c_str());
1298 int src = mimic_joint->getMimic()->getFirstVariableIndex();
1299 int dest = mimic_joint->getFirstVariableIndex();
1300 values[
dest] = values[src] * mimic_joint->getMimicFactor() + mimic_joint->getMimicOffset();
1312 std::map<std::string, double>& values)
const
1338 std::vector<std::string>& missing_variables)
const
1340 missing_variables.clear();
1341 std::set<std::string> keys(variables.begin(), variables.end());
1343 if (keys.find(variable_name) == keys.end())
1345 missing_variables.push_back(variable_name);
1358 double max_distance = 0.0;
1362 return max_distance;
1366 double margin)
const
1371 *active_joint_bounds[i], margin))
1379 bool change =
false;
1382 *active_joint_bounds[i]))
1401 moveit::core::checkInterpolationParamBounds(LOGGER, t);
1416 std::map<std::string, SolverAllocatorFn>::const_iterator jt = allocators.find(jmg->getName());
1417 if (jt != allocators.end())
1419 std::pair<SolverAllocatorFn, SolverAllocatorMapFn> solver_allocator_pair;
1420 solver_allocator_pair.first = jt->second;
1421 jmg->setSolverAllocators(solver_allocator_pair);
1429 std::pair<SolverAllocatorFn, SolverAllocatorMapFn> solver_allocator_pair;
1430 std::map<std::string, SolverAllocatorFn>::const_iterator jt = allocators.find(jmg->getName());
1431 if (jt == allocators.end())
1434 std::set<const JointModel*> joints;
1435 joints.insert(jmg->getJointModels().begin(), jmg->getJointModels().end());
1437 std::vector<const JointModelGroup*> subs;
1440 for (
const std::pair<const std::string, SolverAllocatorFn>& allocator : allocators)
1448 std::set<const JointModel*> sub_joints;
1451 if (std::includes(joints.begin(), joints.end(), sub_joints.begin(), sub_joints.end()))
1453 std::set<const JointModel*> joint_model_set;
1454 std::set_difference(joints.begin(), joints.end(), sub_joints.begin(), sub_joints.end(),
1455 std::inserter(joint_model_set, joint_model_set.end()));
1461 subs.push_back(sub);
1462 joints.swap(joint_model_set);
1469 std::stringstream ss;
1472 ss << sub->getName() <<
" ";
1473 solver_allocator_pair.second[sub] = allocators.find(sub->getName())->second;
1475 RCLCPP_DEBUG(LOGGER,
"Added sub-group IK allocators for group '%s': [ %s]", jmg->getName().c_str(),
1478 jmg->setSolverAllocators(solver_allocator_pair);
1487 std::ios_base::fmtflags old_flags = out.flags();
1488 out.setf(std::ios::fixed, std::ios::floatfield);
1489 std::streamsize old_prec = out.precision();
1491 out <<
"Joints: \n";
1494 out <<
" '" << joint_model->getName() <<
"' (" << joint_model->getTypeName() <<
")\n";
1495 out <<
" * Joint Index: " << joint_model->getJointIndex() <<
'\n';
1496 const std::vector<std::string>& vn = joint_model->getVariableNames();
1497 out <<
" * " << vn.size() << (vn.size() > 1 ?
" variables:" : (vn.empty() ?
" variables" :
" variable:\n"));
1498 int idx = joint_model->getFirstVariableIndex();
1499 for (
const std::string& it : vn)
1501 out <<
" * '" << it <<
"', index " << idx++ <<
" in full state";
1502 if (joint_model->getMimic())
1503 out <<
", mimic '" << joint_model->getMimic()->getName() <<
"'";
1504 if (joint_model->isPassive())
1507 out <<
" " << joint_model->getVariableBounds(it) <<
'\n';
1511 out.precision(old_prec);
1512 out.flags(old_flags);
1516 out <<
" '" << link_model->getName() <<
"' with " << link_model->getShapes().size() <<
" geoms\n";
1517 if (link_model->parentJointIsFixed())
1519 <<
"parent joint is fixed" <<
'\n';
1520 if (link_model->jointOriginTransformIsIdentity())
1522 <<
"joint origin transform is identity\n";
1525 out <<
"Available groups: \n";
1527 joint_model_group->printGroupInfo(out);
This may be thrown if unrecoverable errors occur.
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
const LinkModel * getParentLinkModel() const
Get the link that this joint connects to. The robot is assumed to start with a joint,...
const LinkModel * getChildLinkModel() const
Get the link that this joint connects to. There will always be such a link.
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 JointModel * getParentJointModel() const
Get the joint model whose child this link is. There will always be a parent joint.
const Eigen::Isometry3d & getJointOriginTransform() const
When transforms are computed for this link, they are usually applied to the link's origin....
const LinkModel * getParentLinkModel() const
Get the link model whose child this link is (through some joint). There may not always be a parent li...
const std::vector< const JointModel * > & getChildJointModels() const
A link may have 0 or more child joints. From those joints there will certainly be other descendant li...
MotionModel
different types of planar joints we support
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
std::size_t link_geometry_count_
Total number of geometric shapes in this model.
std::size_t getVariableCount() const
Get the number of variables that describe this model.
std::string model_frame_
The reference (base) frame for this model. The frame is either extracted from the SRDF as a virtual j...
std::vector< const JointModel * > single_dof_joints_
std::vector< const JointModel * > joint_model_vector_const_
The vector of joints in the model, in the order they appear in the state vector.
std::vector< std::string > link_model_names_with_collision_geometry_vector_
The vector of link names that corresponds to link_models_with_collision_geometry_vector_.
std::vector< std::string > joint_model_group_names_
A vector of all group names, in alphabetical order.
std::vector< const LinkModel * > link_models_with_collision_geometry_vector_
Only links that have collision geometry specified.
void updateMimicJoints(double *values) const
Update the variable values for the state of a group with respect to the mimic joints.
bool hasJointModelGroup(const std::string &group) const
Check if the JointModelGroup group exists.
srdf::ModelConstSharedPtr srdf_
void computeFixedTransforms(const LinkModel *link, const Eigen::Isometry3d &transform, LinkTransformMap &associated_transforms)
Get the transforms between link and all its rigidly attached descendants.
const std::vector< const JointModel * > & getJointModels() const
Get the array of joints, in the order they appear in the robot state.
std::vector< const LinkModel * > link_model_vector_const_
The vector of links that are updated when computeTransforms() is called, in the order they are update...
std::vector< std::string > link_model_names_vector_
The vector of link names that corresponds to link_model_vector_.
std::vector< int > common_joint_roots_
For every two joints, the index of the common root for the joints is stored.
std::vector< JointModelGroup * > joint_model_groups_
The array of joint model groups, in alphabetical order.
bool hasEndEffector(const std::string &eef) const
Check if an end effector exists.
void interpolate(const double *from, const double *to, double t, double *state) const
std::vector< JointModel * > joint_model_vector_
The vector of joints in the model, in the order they appear in the state vector.
std::vector< const JointModel * > mimic_joints_
The set of mimic joints this model contains.
const LinkModel * getRootLink() const
Get the physical root link of the robot.
const JointModel * getRootJoint() const
Get the root joint. There will be one root joint unless the model is empty. This is either extracted ...
bool hasJointModel(const std::string &name) const
Check if a joint exists. Return true if it does.
size_t getVariableIndex(const std::string &variable) const
Get the index of a variable in the robot state.
~RobotModel()
Destructor. Clear all memory.
void getVariableRandomPositions(random_numbers::RandomNumberGenerator &rng, double *values) const
Compute the random values for a RobotState.
JointBoundsVector active_joint_models_bounds_
The bounds for all the active joint models.
std::vector< const JointModel * > active_joint_model_vector_const_
The vector of joints in the model, in the order they appear in the state vector.
std::vector< const JointModel * > joints_of_variable_
The joints that correspond to each variable index.
LinkModelMap link_model_map_
A map from link names to their instances.
void getVariableDefaultPositions(double *values) const
Compute the default values for a RobotState.
std::vector< std::string > active_joint_model_names_vector_
The vector of joint names that corresponds to active_joint_model_vector_.
std::vector< std::string > variable_names_
The names of the DOF that make up this state (this is just a sequence of joint variable names; not ne...
std::vector< int > active_joint_model_start_index_
urdf::ModelInterfaceSharedPtr urdf_
std::vector< const JointModelGroup * > joint_model_groups_const_
The array of joint model groups, in alphabetical order.
std::vector< LinkModel * > link_model_vector_
The vector of links that are updated when computeTransforms() is called, in the order they are update...
VariableIndexMap joint_variables_index_map_
The state includes all the joint variables that make up the joints the state consists of....
const JointModelGroup * getEndEffector(const std::string &name) const
Get the joint group that corresponds to a given end-effector name.
JointModelGroupMap joint_model_group_map_
A map from group names to joint groups.
std::vector< const JointModelGroup * > end_effectors_
The array of end-effectors, in alphabetical order.
void getMissingVariableNames(const std::vector< std::string > &variables, std::vector< std::string > &missing_variables) const
RobotModel(const urdf::ModelInterfaceSharedPtr &urdf_model, const srdf::ModelConstSharedPtr &srdf_model)
Construct a kinematic model from a parsed description and a list of planning groups.
std::vector< const JointModel * > multi_dof_joints_
const JointModelGroup * getJointModelGroup(const std::string &name) const
Get a joint group from this model (by name)
std::vector< const JointModel * > continuous_joint_model_vector_
The set of continuous joints this model contains.
JointModelGroupMap end_effectors_map_
The known end effectors.
static const moveit::core::LinkModel * getRigidlyConnectedParentLinkModel(const LinkModel *link)
Get the latest link upwards the kinematic tree, which is only connected via fixed joints.
void printModelInfo(std::ostream &out) const
Print information about the constructed model.
std::vector< std::string > joint_model_names_vector_
The vector of joint names that corresponds to joint_model_vector_.
double distance(const double *state1, const double *state2) const
Return the sum of joint distances between two states. An L1 norm. Only considers active joints.
const JointModel * getJointOfVariable(int variable_index) const
bool hasLinkModel(const std::string &name) const
Check if a link exists. Return true if it does.
JointModelMap joint_model_map_
A map from joint names to their instances.
std::size_t variable_count_
Get the number of variables necessary to describe this model.
double getMaximumExtent() const
std::string model_name_
The name of the robot.
const LinkModel * root_link_
The first physical link for the robot.
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.
bool satisfiesPositionBounds(const double *state, double margin=0.0) const
std::vector< JointModel * > active_joint_model_vector_
The vector of joints in the model, in the order they appear in the state vector.
void setKinematicsAllocators(const std::map< std::string, SolverAllocatorFn > &allocators)
A map of known kinematics solvers (associated to their group name)
const JointModel * getJointModel(const std::string &joint) const
Get a joint by its name. Output error and return nullptr when the joint is missing.
const JointModel * root_joint_
The root joint.
const std::string & getName() const
Get the model name.
bool enforcePositionBounds(double *state) const
Vec3fX< details::Vec3Data< double > > Vector3d
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.