moveit2
The MoveIt Motion Planning Framework for ROS 2.
robot_state.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, Sachin Chitta, Acorn Pooley, Mario Prats, Dave Coleman */
37 
38 #include <geometric_shapes/check_isometry.h>
39 #include <geometric_shapes/shape_operations.h>
43 #include <rclcpp/clock.hpp>
44 #include <rclcpp/logger.hpp>
45 #include <rclcpp/logging.hpp>
46 #include <rclcpp/time.hpp>
47 #include <tf2_eigen/tf2_eigen.hpp>
48 #include <cassert>
49 #include <functional>
52 #include <moveit/utils/logger.hpp>
53 
54 namespace moveit
55 {
56 namespace core
57 {
58 namespace
59 {
60 rclcpp::Logger getLogger()
61 {
62  return moveit::getLogger("robot_state");
63 }
64 } // namespace
65 
66 RobotState::RobotState(const RobotModelConstPtr& robot_model)
67  : robot_model_(robot_model)
68  , has_velocity_(false)
69  , has_acceleration_(false)
70  , has_effort_(false)
71  , dirty_link_transforms_(nullptr)
72  , dirty_collision_body_transforms_(nullptr)
73  , rng_(nullptr)
74 {
75  if (robot_model == nullptr)
76  {
77  throw std::invalid_argument("RobotState cannot be constructed with nullptr RobotModelConstPtr");
78  }
79 
80  dirty_link_transforms_ = robot_model_->getRootJoint();
81  init();
82 }
83 
84 RobotState::RobotState(const RobotState& other) : rng_(nullptr)
85 {
86  robot_model_ = other.robot_model_;
87  copyFrom(other);
88 }
89 
91 {
93 }
94 
95 void RobotState::init()
96 {
97  variable_joint_transforms_.resize(robot_model_->getJointModelCount(), Eigen::Isometry3d::Identity());
98  global_link_transforms_.resize(robot_model_->getLinkModelCount(), Eigen::Isometry3d::Identity());
99  global_collision_body_transforms_.resize(robot_model_->getLinkGeometryCount(), Eigen::Isometry3d::Identity());
100  dirty_joint_transforms_.resize(robot_model_->getJointModelCount(), 1);
101  position_.resize(robot_model_->getVariableCount());
102  velocity_.resize(robot_model_->getVariableCount());
103  effort_or_acceleration_.resize(robot_model_->getVariableCount());
104 }
105 
107 {
108  if (this != &other)
109  copyFrom(other);
110  return *this;
111 }
112 
113 void RobotState::copyFrom(const RobotState& other)
114 {
115  has_velocity_ = other.has_velocity_;
116  has_acceleration_ = other.has_acceleration_;
117  has_effort_ = other.has_effort_;
118 
119  dirty_collision_body_transforms_ = other.dirty_collision_body_transforms_;
120  dirty_link_transforms_ = other.dirty_link_transforms_;
121 
122  variable_joint_transforms_ = other.variable_joint_transforms_;
123  global_link_transforms_ = other.global_link_transforms_;
124  global_collision_body_transforms_ = other.global_collision_body_transforms_;
125  dirty_joint_transforms_ = other.dirty_joint_transforms_;
126  position_ = other.position_;
127  velocity_ = other.velocity_;
128  effort_or_acceleration_ = other.effort_or_acceleration_;
129 
130  // copy attached bodies
132  for (const auto& attached_body : other.attached_body_map_)
133  attachBody(std::make_unique<AttachedBody>(*attached_body.second));
134 }
135 
136 bool RobotState::checkJointTransforms(const JointModel* joint) const
137 {
138  if (dirtyJointTransform(joint))
139  {
140  RCLCPP_WARN(getLogger(), "Returning dirty joint transforms for joint '%s'", joint->getName().c_str());
141  return false;
142  }
143  return true;
144 }
145 
146 bool RobotState::checkLinkTransforms() const
147 {
148  if (dirtyLinkTransforms())
149  {
150  RCLCPP_WARN(getLogger(), "Returning dirty link transforms");
151  return false;
152  }
153  return true;
154 }
155 
156 bool RobotState::checkCollisionTransforms() const
157 {
159  {
160  RCLCPP_WARN(getLogger(), "Returning dirty collision body transforms");
161  return false;
162  }
163  return true;
164 }
165 
166 void RobotState::markVelocity()
167 {
168  if (!has_velocity_)
169  {
170  has_velocity_ = true;
171  std::fill(velocity_.begin(), velocity_.end(), 0.0);
172  }
173 }
174 
175 void RobotState::markAcceleration()
176 {
177  if (!has_acceleration_)
178  {
179  has_acceleration_ = true;
180  has_effort_ = false;
181  std::fill(effort_or_acceleration_.begin(), effort_or_acceleration_.end(), 0.0);
182  }
183 }
184 
185 void RobotState::markEffort()
186 {
187  if (!has_effort_)
188  {
189  has_acceleration_ = false;
190  has_effort_ = true;
191  std::fill(effort_or_acceleration_.begin(), effort_or_acceleration_.end(), 0.0);
192  }
193 }
194 
195 void RobotState::updateMimicJoint(const JointModel* joint)
196 {
197  if (joint->getVariableCount() == 0)
198  {
199  return;
200  }
201  double v = position_[joint->getFirstVariableIndex()];
202  for (const JointModel* jm : joint->getMimicRequests())
203  {
204  position_[jm->getFirstVariableIndex()] = jm->getMimicFactor() * v + jm->getMimicOffset();
205  markDirtyJointTransforms(jm);
206  }
207 }
208 
210 void RobotState::updateMimicJoints(const JointModelGroup* group)
211 {
212  for (const JointModel* jm : group->getMimicJointModels())
213  {
214  assert(jm->getVariableCount() != 0);
215  const int fvi = jm->getFirstVariableIndex();
216  position_[fvi] = jm->getMimicFactor() * position_[jm->getMimic()->getFirstVariableIndex()] + jm->getMimicOffset();
217  markDirtyJointTransforms(jm);
218  }
219  markDirtyJointTransforms(group);
220 }
221 
223 {
224  has_velocity_ = false;
225  markVelocity();
226 }
227 
229 {
230  has_acceleration_ = false;
231  markAcceleration();
232 }
233 
235 {
236  has_effort_ = false;
237  markEffort();
238 }
239 
241 {
242  has_velocity_ = false;
243 }
244 
246 {
247  has_acceleration_ = false;
248 }
249 
251 {
252  has_effort_ = false;
253 }
254 
256 {
257  dropVelocities();
259  dropEffort();
260 }
261 
263 {
264  random_numbers::RandomNumberGenerator& rng = getRandomNumberGenerator();
265  robot_model_->getVariableRandomPositions(rng, position_);
266  std::fill(dirty_joint_transforms_.begin(), dirty_joint_transforms_.end(), 1);
267  dirty_link_transforms_ = robot_model_->getRootJoint();
268  // mimic values are correctly set in RobotModel
269 }
270 
272 {
273  // we do not make calls to RobotModel for random number generation because mimic joints
274  // could trigger updates outside the state of the group itself
275  random_numbers::RandomNumberGenerator& rng = getRandomNumberGenerator();
276  setToRandomPositions(group, rng);
277 }
278 void RobotState::setToRandomPositions(const JointModelGroup* group, random_numbers::RandomNumberGenerator& rng)
279 {
280  const std::vector<const JointModel*>& joints = group->getActiveJointModels();
281  for (const JointModel* joint : joints)
282  joint->getVariableRandomPositions(rng, &position_[joint->getFirstVariableIndex()]);
283  updateMimicJoints(group);
284 }
285 
287  const std::vector<double>& distances)
288 {
289  // we do not make calls to RobotModel for random number generation because mimic joints
290  // could trigger updates outside the state of the group itself
291  random_numbers::RandomNumberGenerator& rng = getRandomNumberGenerator();
292  setToRandomPositionsNearBy(group, seed, distances, rng);
293 }
294 
296  const std::vector<double>& distances,
297  random_numbers::RandomNumberGenerator& rng)
298 {
299  const std::vector<const JointModel*>& joints = group->getActiveJointModels();
300  assert(distances.size() == joints.size());
301  for (std::size_t i = 0; i < joints.size(); ++i)
302  {
303  const int idx = joints[i]->getFirstVariableIndex();
304  joints[i]->getVariableRandomPositionsNearBy(rng, &position_.at(joints[i]->getFirstVariableIndex()),
305  &seed.position_.at(idx), distances[i]);
306  }
307  updateMimicJoints(group);
308 }
309 
311 {
312  // we do not make calls to RobotModel for random number generation because mimic joints
313  // could trigger updates outside the state of the group itself
314  random_numbers::RandomNumberGenerator& rng = getRandomNumberGenerator();
315  setToRandomPositionsNearBy(group, seed, distance, rng);
316 }
317 
319  random_numbers::RandomNumberGenerator& rng)
320 {
321  const std::vector<const JointModel*>& joints = group->getActiveJointModels();
322  for (const JointModel* joint : joints)
323  {
324  const int idx = joint->getFirstVariableIndex();
325  joint->getVariableRandomPositionsNearBy(rng, &position_.at(joint->getFirstVariableIndex()), &seed.position_.at(idx),
326  distance);
327  }
328  updateMimicJoints(group);
329 }
330 
331 bool RobotState::setToDefaultValues(const JointModelGroup* group, const std::string& name)
332 {
333  std::map<std::string, double> m;
334  bool r = group->getVariableDefaultPositions(name, m); // mimic values are updated
336  return r;
337 }
338 
340 {
341  robot_model_->getVariableDefaultPositions(position_); // mimic values are updated
342  // set velocity & acceleration to 0
343  std::fill(velocity_.begin(), velocity_.end(), 0);
344  std::fill(effort_or_acceleration_.begin(), effort_or_acceleration_.end(), 0);
345  std::fill(dirty_joint_transforms_.begin(), dirty_joint_transforms_.end(), 1);
346  dirty_link_transforms_ = robot_model_->getRootJoint();
347 }
348 
349 void RobotState::setVariablePositions(const double* position)
350 {
351  // assume everything is in order in terms of array lengths (for efficiency reasons)
352  memcpy(position_.data(), position, robot_model_->getVariableCount() * sizeof(double));
353 
354  // the full state includes mimic joint values, so no need to update mimic here
355 
356  // Since all joint values have potentially changed, we will need to recompute all transforms
357  std::fill(dirty_joint_transforms_.begin(), dirty_joint_transforms_.end(), 1);
358  dirty_link_transforms_ = robot_model_->getRootJoint();
359 }
360 
361 void RobotState::setVariablePositions(const std::map<std::string, double>& variable_map)
362 {
363  for (const std::pair<const std::string, double>& it : variable_map)
364  {
365  const int index = robot_model_->getVariableIndex(it.first);
366  position_[index] = it.second;
367  const JointModel* jm = robot_model_->getJointOfVariable(index);
368  markDirtyJointTransforms(jm);
369  updateMimicJoint(jm);
370  }
371 }
372 
373 void RobotState::getMissingKeys(const std::map<std::string, double>& variable_map,
374  std::vector<std::string>& missing_variables) const
375 {
376  missing_variables.clear();
377  const std::vector<std::string>& nm = robot_model_->getVariableNames();
378  for (const std::string& variable_name : nm)
379  {
380  if (variable_map.find(variable_name) == variable_map.end())
381  {
382  if (robot_model_->getJointOfVariable(variable_name)->getMimic() == nullptr)
383  missing_variables.push_back(variable_name);
384  }
385  }
386 }
387 
388 void RobotState::setVariablePositions(const std::map<std::string, double>& variable_map,
389  std::vector<std::string>& missing_variables)
390 {
391  setVariablePositions(variable_map);
392  getMissingKeys(variable_map, missing_variables);
393 }
394 
395 void RobotState::setVariablePositions(const std::vector<std::string>& variable_names,
396  const std::vector<double>& variable_position)
397 {
398  for (std::size_t i = 0; i < variable_names.size(); ++i)
399  {
400  const int index = robot_model_->getVariableIndex(variable_names[i]);
401  position_[index] = variable_position[i];
402  const JointModel* jm = robot_model_->getJointOfVariable(index);
403  markDirtyJointTransforms(jm);
404  updateMimicJoint(jm);
405  }
406 }
407 
408 void RobotState::setVariableVelocities(const std::map<std::string, double>& variable_map)
409 {
410  markVelocity();
411  for (const std::pair<const std::string, double>& it : variable_map)
412  velocity_[robot_model_->getVariableIndex(it.first)] = it.second;
413 }
414 
415 void RobotState::setVariableVelocities(const std::map<std::string, double>& variable_map,
416  std::vector<std::string>& missing_variables)
417 {
418  setVariableVelocities(variable_map);
419  getMissingKeys(variable_map, missing_variables);
420 }
421 
422 void RobotState::setVariableVelocities(const std::vector<std::string>& variable_names,
423  const std::vector<double>& variable_velocity)
424 {
425  markVelocity();
426  assert(variable_names.size() == variable_velocity.size());
427  for (std::size_t i = 0; i < variable_names.size(); ++i)
428  velocity_[robot_model_->getVariableIndex(variable_names[i])] = variable_velocity[i];
429 }
430 
431 void RobotState::setVariableAccelerations(const std::map<std::string, double>& variable_map)
432 {
433  markAcceleration();
434  for (const std::pair<const std::string, double>& it : variable_map)
435  effort_or_acceleration_[robot_model_->getVariableIndex(it.first)] = it.second;
436 }
437 
438 void RobotState::setVariableAccelerations(const std::map<std::string, double>& variable_map,
439  std::vector<std::string>& missing_variables)
440 {
441  setVariableAccelerations(variable_map);
442  getMissingKeys(variable_map, missing_variables);
443 }
444 
445 void RobotState::setVariableAccelerations(const std::vector<std::string>& variable_names,
446  const std::vector<double>& variable_acceleration)
447 {
448  markAcceleration();
449  assert(variable_names.size() == variable_acceleration.size());
450  for (std::size_t i = 0; i < variable_names.size(); ++i)
451  effort_or_acceleration_[robot_model_->getVariableIndex(variable_names[i])] = variable_acceleration[i];
452 }
453 
454 void RobotState::setVariableEffort(const std::map<std::string, double>& variable_map)
455 {
456  markEffort();
457  for (const std::pair<const std::string, double>& it : variable_map)
458  effort_or_acceleration_[robot_model_->getVariableIndex(it.first)] = it.second;
459 }
460 
461 void RobotState::setVariableEffort(const std::map<std::string, double>& variable_map,
462  std::vector<std::string>& missing_variables)
463 {
464  setVariableEffort(variable_map);
465  getMissingKeys(variable_map, missing_variables);
466 }
467 
468 void RobotState::setVariableEffort(const std::vector<std::string>& variable_names,
469  const std::vector<double>& variable_effort)
470 {
471  markEffort();
472  assert(variable_names.size() == variable_effort.size());
473  for (std::size_t i = 0; i < variable_names.size(); ++i)
474  effort_or_acceleration_[robot_model_->getVariableIndex(variable_names[i])] = variable_effort[i];
475 }
476 
478 {
479  if (has_velocity_)
480  {
481  for (size_t i = 0; i < robot_model_->getVariableCount(); ++i)
482  velocity_[i] *= -1;
483  }
484 }
485 
486 void RobotState::setJointPositions(const JointModel* joint, const double* position)
487 {
488  if (joint->getVariableCount() == 0)
489  {
490  return;
491  }
492  memcpy(&position_.at(joint->getFirstVariableIndex()), position, joint->getVariableCount() * sizeof(double));
493  markDirtyJointTransforms(joint);
494  updateMimicJoint(joint);
495 }
496 
497 void RobotState::setJointPositions(const JointModel* joint, const Eigen::Isometry3d& transform)
498 {
499  if (joint->getVariableCount() == 0)
500  {
501  return;
502  }
503  joint->computeVariablePositions(transform, &position_.at(joint->getFirstVariableIndex()));
504  markDirtyJointTransforms(joint);
505  updateMimicJoint(joint);
506 }
507 
508 void RobotState::setJointVelocities(const JointModel* joint, const double* velocity)
509 {
510  if (joint->getVariableCount() == 0)
511  {
512  return;
513  }
514  has_velocity_ = true;
515  memcpy(&velocity_.at(joint->getFirstVariableIndex()), velocity, joint->getVariableCount() * sizeof(double));
516 }
517 
518 const double* RobotState::getJointPositions(const JointModel* joint) const
519 {
520  if (joint->getVariableCount() == 0)
521  {
522  return nullptr;
523  }
524  return &position_.at(joint->getFirstVariableIndex());
525 }
526 
527 const double* RobotState::getJointVelocities(const JointModel* joint) const
528 {
529  if (joint->getVariableCount() == 0)
530  {
531  return nullptr;
532  }
533  return &velocity_.at(joint->getFirstVariableIndex());
534 }
535 
536 const double* RobotState::getJointAccelerations(const JointModel* joint) const
537 {
538  if (joint->getVariableCount() == 0)
539  {
540  return nullptr;
541  }
542  return &effort_or_acceleration_.at(joint->getFirstVariableIndex());
543 }
544 
545 const double* RobotState::getJointEffort(const JointModel* joint) const
546 {
547  if (joint->getVariableCount() == 0)
548  {
549  return nullptr;
550  }
551  return &effort_or_acceleration_.at(joint->getFirstVariableIndex());
552 }
553 
554 void RobotState::setJointEfforts(const JointModel* joint, const double* effort)
555 {
556  if (has_acceleration_)
557  {
558  RCLCPP_ERROR(getLogger(), "Unable to set joint efforts because array is being used for accelerations");
559  return;
560  }
561  if (joint->getVariableCount() == 0)
562  {
563  return;
564  }
565  has_effort_ = true;
566 
567  memcpy(&effort_or_acceleration_.at(joint->getFirstVariableIndex()), effort,
568  joint->getVariableCount() * sizeof(double));
569 }
570 
571 void RobotState::setJointGroupPositions(const JointModelGroup* group, const double* gstate)
572 {
573  const std::vector<int>& il = group->getVariableIndexList();
574  if (group->isContiguousWithinState())
575  {
576  memcpy(&position_.at(il[0]), gstate, group->getVariableCount() * sizeof(double));
577  }
578  else
579  {
580  for (std::size_t i = 0; i < il.size(); ++i)
581  position_[il[i]] = gstate[i];
582  }
583  updateMimicJoints(group);
584 }
585 
586 void RobotState::setJointGroupPositions(const JointModelGroup* group, const Eigen::VectorXd& values)
587 {
588  const std::vector<int>& il = group->getVariableIndexList();
589  for (std::size_t i = 0; i < il.size(); ++i)
590  position_[il[i]] = values(i);
591  updateMimicJoints(group);
592 }
593 
594 void RobotState::setJointGroupActivePositions(const JointModelGroup* group, const std::vector<double>& gstate)
595 {
596  assert(gstate.size() == group->getActiveVariableCount());
597  std::size_t i = 0;
598  for (const JointModel* jm : group->getActiveJointModels())
599  {
600  setJointPositions(jm, &gstate[i]);
601  i += jm->getVariableCount();
602  }
603  updateMimicJoints(group);
604 }
605 
606 void RobotState::setJointGroupActivePositions(const JointModelGroup* group, const Eigen::VectorXd& values)
607 {
608  assert(values.size() == group->getActiveVariableCount());
609  std::size_t i = 0;
610  for (const JointModel* jm : group->getActiveJointModels())
611  {
612  setJointPositions(jm, &values(i));
613  i += jm->getVariableCount();
614  }
615  updateMimicJoints(group);
616 }
617 
618 void RobotState::copyJointGroupPositions(const JointModelGroup* group, double* gstate) const
619 {
620  const std::vector<int>& il = group->getVariableIndexList();
621  if (group->isContiguousWithinState())
622  {
623  memcpy(gstate, &position_.at(il[0]), group->getVariableCount() * sizeof(double));
624  }
625  else
626  {
627  for (std::size_t i = 0; i < il.size(); ++i)
628  gstate[i] = position_[il[i]];
629  }
630 }
631 
632 void RobotState::copyJointGroupPositions(const JointModelGroup* group, Eigen::VectorXd& values) const
633 {
634  const std::vector<int>& il = group->getVariableIndexList();
635  values.resize(il.size());
636  for (std::size_t i = 0; i < il.size(); ++i)
637  values(i) = position_[il[i]];
638 }
639 
640 void RobotState::setJointGroupVelocities(const JointModelGroup* group, const double* gstate)
641 {
642  markVelocity();
643  const std::vector<int>& il = group->getVariableIndexList();
644  if (group->isContiguousWithinState())
645  {
646  memcpy(&velocity_.at(il[0]), gstate, group->getVariableCount() * sizeof(double));
647  }
648  else
649  {
650  for (std::size_t i = 0; i < il.size(); ++i)
651  velocity_[il[i]] = gstate[i];
652  }
653 }
654 
655 void RobotState::setJointGroupVelocities(const JointModelGroup* group, const Eigen::VectorXd& values)
656 {
657  markVelocity();
658  const std::vector<int>& il = group->getVariableIndexList();
659  for (std::size_t i = 0; i < il.size(); ++i)
660  velocity_[il[i]] = values(i);
661 }
662 
663 void RobotState::copyJointGroupVelocities(const JointModelGroup* group, double* gstate) const
664 {
665  const std::vector<int>& il = group->getVariableIndexList();
666  if (group->isContiguousWithinState())
667  {
668  memcpy(gstate, &velocity_.at(il[0]), group->getVariableCount() * sizeof(double));
669  }
670  else
671  {
672  for (std::size_t i = 0; i < il.size(); ++i)
673  gstate[i] = velocity_[il[i]];
674  }
675 }
676 
677 void RobotState::copyJointGroupVelocities(const JointModelGroup* group, Eigen::VectorXd& values) const
678 {
679  const std::vector<int>& il = group->getVariableIndexList();
680  values.resize(il.size());
681  for (std::size_t i = 0; i < il.size(); ++i)
682  values(i) = velocity_[il[i]];
683 }
684 
685 void RobotState::setJointGroupAccelerations(const JointModelGroup* group, const double* gstate)
686 {
687  markAcceleration();
688  const std::vector<int>& il = group->getVariableIndexList();
689  if (group->isContiguousWithinState())
690  {
691  memcpy(&effort_or_acceleration_.at(il[0]), gstate, group->getVariableCount() * sizeof(double));
692  }
693  else
694  {
695  for (std::size_t i = 0; i < il.size(); ++i)
696  effort_or_acceleration_[il[i]] = gstate[i];
697  }
698 }
699 
700 void RobotState::setJointGroupAccelerations(const JointModelGroup* group, const Eigen::VectorXd& values)
701 {
702  markAcceleration();
703  const std::vector<int>& il = group->getVariableIndexList();
704  for (std::size_t i = 0; i < il.size(); ++i)
705  effort_or_acceleration_[il[i]] = values(i);
706 }
707 
708 void RobotState::copyJointGroupAccelerations(const JointModelGroup* group, double* gstate) const
709 {
710  const std::vector<int>& il = group->getVariableIndexList();
711  if (group->isContiguousWithinState())
712  {
713  memcpy(gstate, &effort_or_acceleration_.at(il[0]), group->getVariableCount() * sizeof(double));
714  }
715  else
716  {
717  for (std::size_t i = 0; i < il.size(); ++i)
718  gstate[i] = effort_or_acceleration_[il[i]];
719  }
720 }
721 
722 void RobotState::copyJointGroupAccelerations(const JointModelGroup* group, Eigen::VectorXd& values) const
723 {
724  const std::vector<int>& il = group->getVariableIndexList();
725  values.resize(il.size());
726  for (std::size_t i = 0; i < il.size(); ++i)
727  values(i) = effort_or_acceleration_[il[i]];
728 }
729 
730 void RobotState::update(bool force)
731 {
732  // make sure we do everything from scratch if needed
733  if (force)
734  {
735  std::fill(dirty_joint_transforms_.begin(), dirty_joint_transforms_.end(), 1);
736  dirty_link_transforms_ = robot_model_->getRootJoint();
737  }
738 
739  // this actually triggers all needed updates
741 }
742 
744 {
745  if (dirty_link_transforms_ != nullptr)
747 
748  if (dirty_collision_body_transforms_ != nullptr)
749  {
750  const std::vector<const LinkModel*>& links = dirty_collision_body_transforms_->getDescendantLinkModels();
751  dirty_collision_body_transforms_ = nullptr;
752 
753  for (const LinkModel* link : links)
754  {
755  const EigenSTL::vector_Isometry3d& ot = link->getCollisionOriginTransforms();
756  const std::vector<int>& ot_id = link->areCollisionOriginTransformsIdentity();
757  const int index_co = link->getFirstCollisionBodyTransformIndex();
758  const int index_l = link->getLinkIndex();
759  for (std::size_t j = 0, end = ot.size(); j != end; ++j)
760  {
761  if (ot_id[j])
762  {
763  global_collision_body_transforms_[index_co + j] = global_link_transforms_[index_l];
764  }
765  else
766  {
767  global_collision_body_transforms_[index_co + j].affine().noalias() =
768  global_link_transforms_[index_l].affine() * ot[j].matrix();
769  }
770  }
771  }
772  }
773 }
774 
776 {
777  if (dirty_link_transforms_ != nullptr)
778  {
779  updateLinkTransformsInternal(dirty_link_transforms_);
780  if (dirty_collision_body_transforms_)
781  {
782  dirty_collision_body_transforms_ =
783  robot_model_->getCommonRoot(dirty_collision_body_transforms_, dirty_link_transforms_);
784  }
785  else
786  {
787  dirty_collision_body_transforms_ = dirty_link_transforms_;
788  }
789  dirty_link_transforms_ = nullptr;
790  }
791 }
792 
793 void RobotState::updateLinkTransformsInternal(const JointModel* start)
794 {
795  for (const LinkModel* link : start->getDescendantLinkModels())
796  {
797  int idx_link = link->getLinkIndex();
798  const LinkModel* parent = link->getParentLinkModel();
799  if (parent) // root JointModel will not have a parent
800  {
801  int idx_parent = parent->getLinkIndex();
802  if (link->parentJointIsFixed())
803  { // fixed joint
804  global_link_transforms_[idx_link].affine().noalias() =
805  global_link_transforms_[idx_parent].affine() * link->getJointOriginTransform().matrix();
806  }
807  else // non-fixed joint
808  {
809  if (link->jointOriginTransformIsIdentity())
810  { // Link has identity transform
811  global_link_transforms_[idx_link].affine().noalias() =
812  global_link_transforms_[idx_parent].affine() * getJointTransform(link->getParentJointModel()).matrix();
813  }
814  else
815  { // Link has non-identity transform
816  global_link_transforms_[idx_link].affine().noalias() =
817  global_link_transforms_[idx_parent].affine() * link->getJointOriginTransform().matrix() *
818  getJointTransform(link->getParentJointModel()).matrix();
819  }
820  }
821  }
822  else // is the origin / root / 'model frame'
823  {
824  const JointModel* root_joint = link->getParentJointModel();
825  if (root_joint->getVariableCount() == 0)
826  {
827  // The root joint doesn't have any variables: avoid calling getJointTransform() on it.
828  global_link_transforms_[idx_link] = Eigen::Isometry3d::Identity();
829  }
830  else if (link->jointOriginTransformIsIdentity())
831  {
832  global_link_transforms_[idx_link] = getJointTransform(root_joint);
833  }
834  else
835  {
836  global_link_transforms_[idx_link].affine().noalias() =
837  link->getJointOriginTransform().affine() * getJointTransform(root_joint).matrix();
838  }
839  }
840  }
841 
842  // update attached bodies tf; these are usually very few, so we update them all
843  for (const auto& attached_body : attached_body_map_)
844  {
845  attached_body.second->computeTransform(
846  global_link_transforms_[attached_body.second->getAttachedLink()->getLinkIndex()]);
847  }
848 }
849 
850 void RobotState::updateStateWithLinkAt(const LinkModel* link, const Eigen::Isometry3d& transform, bool backward)
851 {
852  updateLinkTransforms(); // no link transforms must be dirty, otherwise the transform we set will be overwritten
853 
854  // update the fact that collision body transforms are out of date
855  if (dirty_collision_body_transforms_)
856  {
857  dirty_collision_body_transforms_ =
858  robot_model_->getCommonRoot(dirty_collision_body_transforms_, link->getParentJointModel());
859  }
860  else
861  {
862  dirty_collision_body_transforms_ = link->getParentJointModel();
863  }
864 
865  global_link_transforms_[link->getLinkIndex()] = transform;
866 
867  // update link transforms for descendant links only (leaving the transform for the current link untouched)
868  const std::vector<const JointModel*>& cj = link->getChildJointModels();
869  for (const JointModel* joint : cj)
870  updateLinkTransformsInternal(joint);
871 
872  // if we also need to go backward
873  if (backward)
874  {
875  const LinkModel* parent_link = link;
876  const LinkModel* child_link;
877  while (parent_link->getParentJointModel()->getParentLinkModel())
878  {
879  child_link = parent_link;
880  parent_link = parent_link->getParentJointModel()->getParentLinkModel();
881 
882  // update the transform of the parent
883  global_link_transforms_[parent_link->getLinkIndex()] =
884  global_link_transforms_[child_link->getLinkIndex()] *
885  (child_link->getJointOriginTransform() *
886  variable_joint_transforms_[child_link->getParentJointModel()->getJointIndex()])
887  .inverse();
888 
889  // update link transforms for descendant links only (leaving the transform for the current link untouched)
890  // with the exception of the child link we are coming backwards from
891  const std::vector<const JointModel*>& cj = parent_link->getChildJointModels();
892  for (const JointModel* joint : cj)
893  {
894  if (joint != child_link->getParentJointModel())
895  updateLinkTransformsInternal(joint);
896  }
897  }
898  // all collision body transforms are invalid now
899  dirty_collision_body_transforms_ = parent_link->getParentJointModel();
900  }
901 
902  // update attached bodies tf; these are usually very few, so we update them all
903  for (const auto& attached_body : attached_body_map_)
904  {
905  attached_body.second->computeTransform(
906  global_link_transforms_[attached_body.second->getAttachedLink()->getLinkIndex()]);
907  }
908 }
909 
910 const LinkModel* RobotState::getRigidlyConnectedParentLinkModel(const std::string& frame) const
911 {
912  const LinkModel* link{ nullptr };
913 
914  size_t idx = 0;
915  if ((idx = frame.find('/')) != std::string::npos)
916  { // resolve sub frame
917  std::string object{ frame.substr(0, idx) };
918  if (!hasAttachedBody(object))
919  return nullptr;
920  auto body{ getAttachedBody(object) };
921  if (!body->hasSubframeTransform(frame))
922  return nullptr;
923  link = body->getAttachedLink();
924  }
925  else if (hasAttachedBody(frame))
926  {
927  link = getAttachedBody(frame)->getAttachedLink();
928  }
929  else if (getRobotModel()->hasLinkModel(frame))
930  link = getLinkModel(frame);
931 
932  return getRobotModel()->getRigidlyConnectedParentLinkModel(link);
933 }
934 
935 const Eigen::Isometry3d& RobotState::getJointTransform(const JointModel* joint)
936 {
937  const int idx = joint->getJointIndex();
938  if (joint->getVariableCount() == 0)
939  {
940  return variable_joint_transforms_[idx];
941  }
942 
943  unsigned char& dirty = dirty_joint_transforms_[idx];
944  if (dirty)
945  {
946  joint->computeTransform(&position_.at(joint->getFirstVariableIndex()), variable_joint_transforms_[idx]);
947  dirty = 0;
948  }
949  return variable_joint_transforms_[idx];
950 }
951 
952 bool RobotState::satisfiesBounds(double margin) const
953 {
954  const std::vector<const JointModel*>& jm = robot_model_->getActiveJointModels();
955  for (const JointModel* joint : jm)
956  {
957  if (!satisfiesBounds(joint, margin))
958  return false;
959  }
960  return true;
961 }
962 
963 bool RobotState::satisfiesBounds(const JointModelGroup* group, double margin) const
964 {
965  const std::vector<const JointModel*>& jm = group->getActiveJointModels();
966  for (const JointModel* joint : jm)
967  {
968  if (!satisfiesBounds(joint, margin))
969  return false;
970  }
971  return true;
972 }
973 
975 {
976  const std::vector<const JointModel*>& jm = robot_model_->getActiveJointModels();
977  for (const JointModel* joint : jm)
978  enforceBounds(joint);
979 }
980 
982 {
983  const std::vector<const JointModel*>& jm = joint_group->getActiveJointModels();
984  for (const JointModel* joint : jm)
985  enforceBounds(joint);
986 }
987 
989 {
990  if (joint->getVariableCount() == 0)
991  {
992  return;
993  }
994  if (joint->enforcePositionBounds(&position_.at(joint->getFirstVariableIndex())))
995  {
996  markDirtyJointTransforms(joint);
997  updateMimicJoint(joint);
998  }
999 }
1000 
1002 {
1003  for (const JointModel* jm : robot_model_->getActiveJointModels())
1004  harmonizePosition(jm);
1005 }
1006 
1008 {
1009  for (const JointModel* jm : joint_group->getActiveJointModels())
1010  harmonizePosition(jm);
1011 }
1012 
1014 {
1015  if (joint->getVariableCount() == 0)
1016  {
1017  return;
1018  }
1019  if (joint->harmonizePosition(&position_.at(joint->getFirstVariableIndex())))
1020  {
1021  // no need to mark transforms dirty, as the transform hasn't changed
1022  updateMimicJoint(joint);
1023  }
1024 }
1025 
1027 {
1028  if (joint->getVariableCount() == 0)
1029  {
1030  return;
1031  }
1032  joint->enforceVelocityBounds(&velocity_.at(joint->getFirstVariableIndex()));
1033 }
1034 
1035 std::pair<double, const JointModel*> RobotState::getMinDistanceToPositionBounds() const
1036 {
1037  return getMinDistanceToPositionBounds(robot_model_->getActiveJointModels());
1038 }
1039 
1040 std::pair<double, const JointModel*> RobotState::getMinDistanceToPositionBounds(const JointModelGroup* group) const
1041 {
1043 }
1044 
1045 std::pair<double, const JointModel*>
1046 RobotState::getMinDistanceToPositionBounds(const std::vector<const JointModel*>& joints) const
1047 {
1048  double distance = std::numeric_limits<double>::max();
1049  const JointModel* index = nullptr;
1050  for (const JointModel* joint : joints)
1051  {
1052  if (joint->getType() == JointModel::PLANAR || joint->getType() == JointModel::FLOATING)
1053  continue;
1054  if (joint->getType() == JointModel::REVOLUTE)
1055  {
1056  if (static_cast<const RevoluteJointModel*>(joint)->isContinuous())
1057  continue;
1058  }
1059 
1060  const double* joint_values = getJointPositions(joint);
1061  const JointModel::Bounds& bounds = joint->getVariableBounds();
1062  std::vector<double> lower_bounds(bounds.size()), upper_bounds(bounds.size());
1063  for (std::size_t j = 0; j < bounds.size(); ++j)
1064  {
1065  lower_bounds[j] = bounds[j].min_position_;
1066  upper_bounds[j] = bounds[j].max_position_;
1067  }
1068  double new_distance = joint->distance(joint_values, &lower_bounds[0]);
1069  if (new_distance < distance)
1070  {
1071  index = joint;
1072  distance = new_distance;
1073  }
1074  new_distance = joint->distance(joint_values, &upper_bounds[0]);
1075  if (new_distance < distance)
1076  {
1077  index = joint;
1078  distance = new_distance;
1079  }
1080  }
1081  return std::make_pair(distance, index);
1082 }
1083 
1084 bool RobotState::isValidVelocityMove(const RobotState& other, const JointModelGroup* group, double dt) const
1085 {
1086  const std::vector<const JointModel*>& jm = group->getActiveJointModels();
1087  for (const JointModel* joint_id : jm)
1088  {
1089  const int idx = joint_id->getFirstVariableIndex();
1090  const std::vector<VariableBounds>& bounds = joint_id->getVariableBounds();
1091 
1092  // Check velocity for each joint variable
1093  for (std::size_t var_id = 0; var_id < joint_id->getVariableCount(); ++var_id)
1094  {
1095  const double dtheta = std::abs(position_.at(idx + var_id) - *(other.getVariablePositions() + idx + var_id));
1096 
1097  if (dtheta > dt * bounds[var_id].max_velocity_)
1098  return false;
1099  }
1100  }
1101  return true;
1102 }
1103 
1104 double RobotState::distance(const RobotState& other, const JointModelGroup* joint_group) const
1105 {
1106  double d = 0.0;
1107  const std::vector<const JointModel*>& jm = joint_group->getActiveJointModels();
1108  for (const JointModel* joint : jm)
1109  {
1110  const int idx = joint->getFirstVariableIndex();
1111  d += joint->getDistanceFactor() * joint->distance(&position_.at(idx), &other.position_.at(idx));
1112  }
1113  return d;
1114 }
1115 
1116 double RobotState::distance(const RobotState& other, const JointModel* joint) const
1117 {
1118  if (joint->getVariableCount() == 0)
1119  {
1120  return 0.0;
1121  }
1122  const int idx = joint->getFirstVariableIndex();
1123  return joint->distance(&position_.at(idx), &other.position_.at(idx));
1124 }
1125 
1126 void RobotState::interpolate(const RobotState& to, double t, RobotState& state) const
1127 {
1128  checkInterpolationParamBounds(getLogger(), t);
1129  robot_model_->interpolate(getVariablePositions(), to.getVariablePositions(), t, state.getVariablePositions());
1130 
1131  std::fill(state.dirty_joint_transforms_.begin(), state.dirty_joint_transforms_.end(), 1);
1132  state.dirty_link_transforms_ = state.robot_model_->getRootJoint();
1133 }
1134 
1135 void RobotState::interpolate(const RobotState& to, double t, RobotState& state, const JointModelGroup* joint_group) const
1136 {
1137  checkInterpolationParamBounds(getLogger(), t);
1138  const std::vector<const JointModel*>& jm = joint_group->getActiveJointModels();
1139  for (const JointModel* joint : jm)
1140  {
1141  const int idx = joint->getFirstVariableIndex();
1142  joint->interpolate(&position_.at(idx), &to.position_.at(idx), t, &state.position_.at(idx));
1143  }
1144  state.updateMimicJoints(joint_group);
1145 }
1146 
1147 void RobotState::interpolate(const RobotState& to, double t, RobotState& state, const JointModel* joint) const
1148 {
1149  if (joint->getVariableCount() == 0)
1150  {
1151  return;
1152  }
1153 
1154  const int idx = joint->getFirstVariableIndex();
1155  joint->interpolate(&position_.at(idx), &to.position_.at(idx), t, &state.position_.at(idx));
1156  state.markDirtyJointTransforms(joint);
1157  state.updateMimicJoint(joint);
1158 }
1159 
1161 {
1162  attached_body_update_callback_ = callback;
1163 }
1164 
1165 bool RobotState::hasAttachedBody(const std::string& id) const
1166 {
1167  return attached_body_map_.find(id) != attached_body_map_.end();
1168 }
1169 
1170 const AttachedBody* RobotState::getAttachedBody(const std::string& id) const
1171 {
1172  const auto it = attached_body_map_.find(id);
1173  if (it == attached_body_map_.end())
1174  {
1175  RCLCPP_ERROR(getLogger(), "Attached body '%s' not found", id.c_str());
1176  return nullptr;
1177  }
1178  else
1179  return it->second.get();
1180 }
1181 
1182 void RobotState::attachBody(std::unique_ptr<AttachedBody> attached_body)
1183 {
1184  // If an attached body with the same id exists, remove it
1185  clearAttachedBody(attached_body->getName());
1186 
1187  attached_body->computeTransform(getGlobalLinkTransform(attached_body->getAttachedLink()));
1188  if (attached_body_update_callback_)
1189  attached_body_update_callback_(attached_body.get(), true);
1190  attached_body_map_[attached_body->getName()] = std::move(attached_body);
1191 }
1192 
1193 void RobotState::attachBody(const std::string& id, const Eigen::Isometry3d& pose,
1194  const std::vector<shapes::ShapeConstPtr>& shapes,
1195  const EigenSTL::vector_Isometry3d& shape_poses, const std::set<std::string>& touch_links,
1196  const std::string& link, const trajectory_msgs::msg::JointTrajectory& detach_posture,
1197  const FixedTransformsMap& subframe_poses)
1198 {
1199  attachBody(std::make_unique<AttachedBody>(robot_model_->getLinkModel(link), id, pose, shapes, shape_poses,
1200  touch_links, detach_posture, subframe_poses));
1201 }
1202 
1203 void RobotState::getAttachedBodies(std::vector<const AttachedBody*>& attached_bodies) const
1204 {
1205  attached_bodies.clear();
1206  attached_bodies.reserve(attached_body_map_.size());
1207  for (const auto& it : attached_body_map_)
1208  attached_bodies.push_back(it.second.get());
1209 }
1210 
1211 void RobotState::getAttachedBodies(std::vector<const AttachedBody*>& attached_bodies, const JointModelGroup* group) const
1212 {
1213  attached_bodies.clear();
1214  for (const auto& it : attached_body_map_)
1215  {
1216  if (group->hasLinkModel(it.second->getAttachedLinkName()))
1217  attached_bodies.push_back(it.second.get());
1218  }
1219 }
1220 
1221 void RobotState::getAttachedBodies(std::vector<const AttachedBody*>& attached_bodies, const LinkModel* link_model) const
1222 {
1223  attached_bodies.clear();
1224  for (const auto& it : attached_body_map_)
1225  {
1226  if (it.second->getAttachedLink() == link_model)
1227  attached_bodies.push_back(it.second.get());
1228  }
1229 }
1230 
1232 {
1233  for (const auto& it : attached_body_map_)
1234  {
1235  if (attached_body_update_callback_)
1236  attached_body_update_callback_(it.second.get(), false);
1237  }
1238  attached_body_map_.clear();
1239 }
1240 
1242 {
1243  for (auto it = attached_body_map_.cbegin(); it != attached_body_map_.cend(); ++it)
1244  {
1245  if (it->second->getAttachedLink() != link)
1246  {
1247  continue;
1248  }
1249  if (attached_body_update_callback_)
1250  attached_body_update_callback_(it->second.get(), false);
1251  const auto del = it++;
1252  attached_body_map_.erase(del);
1253  }
1254 }
1255 
1257 {
1258  for (auto it = attached_body_map_.cbegin(); it != attached_body_map_.cend(); ++it)
1259  {
1260  if (!group->hasLinkModel(it->second->getAttachedLinkName()))
1261  {
1262  continue;
1263  }
1264  if (attached_body_update_callback_)
1265  attached_body_update_callback_(it->second.get(), false);
1266  const auto del = it++;
1267  attached_body_map_.erase(del);
1268  }
1269 }
1270 
1271 bool RobotState::clearAttachedBody(const std::string& id)
1272 {
1273  const auto it = attached_body_map_.find(id);
1274  if (it != attached_body_map_.end())
1275  {
1276  if (attached_body_update_callback_)
1277  attached_body_update_callback_(it->second.get(), false);
1278  attached_body_map_.erase(it);
1279  return true;
1280  }
1281  else
1282  return false;
1283 }
1284 
1285 const Eigen::Isometry3d& RobotState::getFrameTransform(const std::string& frame_id, bool* frame_found)
1286 {
1288  return static_cast<const RobotState*>(this)->getFrameTransform(frame_id, frame_found);
1289 }
1290 
1291 const Eigen::Isometry3d& RobotState::getFrameTransform(const std::string& frame_id, bool* frame_found) const
1292 {
1293  const LinkModel* ignored_link;
1294  bool found;
1295  const auto& result = getFrameInfo(frame_id, ignored_link, found);
1296 
1297  if (frame_found)
1298  {
1299  *frame_found = found;
1300  }
1301  else if (!found)
1302  {
1303  RCLCPP_WARN(getLogger(), "getFrameTransform() did not find a frame with name %s.", frame_id.c_str());
1304  }
1305 
1306  return result;
1307 }
1308 
1309 const Eigen::Isometry3d& RobotState::getFrameInfo(const std::string& frame_id, const LinkModel*& robot_link,
1310  bool& frame_found) const
1311 {
1312  if (!frame_id.empty() && frame_id[0] == '/')
1313  return getFrameInfo(frame_id.substr(1), robot_link, frame_found);
1314 
1315  static const Eigen::Isometry3d IDENTITY_TRANSFORM = Eigen::Isometry3d::Identity();
1316  if (frame_id == robot_model_->getModelFrame())
1317  {
1318  robot_link = robot_model_->getRootLink();
1319  frame_found = true;
1320  return IDENTITY_TRANSFORM;
1321  }
1322  if ((robot_link = robot_model_->getLinkModel(frame_id, &frame_found)))
1323  {
1324  assert(checkLinkTransforms());
1325  return global_link_transforms_[robot_link->getLinkIndex()];
1326  }
1327  robot_link = nullptr;
1328 
1329  // Check names of the attached bodies
1330  const auto jt = attached_body_map_.find(frame_id);
1331  if (jt != attached_body_map_.end())
1332  {
1333  const Eigen::Isometry3d& transform = jt->second->getGlobalPose();
1334  robot_link = jt->second->getAttachedLink();
1335  frame_found = true;
1336  assert(checkLinkTransforms());
1337  return transform;
1338  }
1339 
1340  // Check if an AttachedBody has a subframe with name frame_id
1341  for (const auto& body : attached_body_map_)
1342  {
1343  const Eigen::Isometry3d& transform = body.second->getGlobalSubframeTransform(frame_id, &frame_found);
1344  if (frame_found)
1345  {
1346  robot_link = body.second->getAttachedLink();
1347  assert(checkLinkTransforms());
1348  return transform;
1349  }
1350  }
1351 
1352  robot_link = nullptr;
1353  frame_found = false;
1354  return IDENTITY_TRANSFORM;
1355 }
1356 
1357 bool RobotState::knowsFrameTransform(const std::string& frame_id) const
1358 {
1359  if (!frame_id.empty() && frame_id[0] == '/')
1360  return knowsFrameTransform(frame_id.substr(1));
1361  if (robot_model_->hasLinkModel(frame_id))
1362  return true;
1363 
1364  // Check if an AttachedBody with name frame_id exists
1365  const auto it = attached_body_map_.find(frame_id);
1366  if (it != attached_body_map_.end())
1367  return !it->second->getGlobalCollisionBodyTransforms().empty();
1368 
1369  // Check if an AttachedBody has a subframe with name frame_id
1370  for (const auto& body : attached_body_map_)
1371  {
1372  if (body.second->hasSubframeTransform(frame_id))
1373  return true;
1374  }
1375  return false;
1376 }
1377 
1378 void RobotState::getRobotMarkers(visualization_msgs::msg::MarkerArray& arr, const std::vector<std::string>& link_names,
1379  const std_msgs::msg::ColorRGBA& color, const std::string& ns,
1380  const rclcpp::Duration& dur, bool include_attached) const
1381 {
1382  std::size_t cur_num = arr.markers.size();
1383  getRobotMarkers(arr, link_names, include_attached);
1384  unsigned int id = cur_num;
1385  for (std::size_t i = cur_num; i < arr.markers.size(); ++i, ++id)
1386  {
1387  arr.markers[i].ns = ns;
1388  arr.markers[i].id = id;
1389  arr.markers[i].lifetime = dur;
1390  arr.markers[i].color = color;
1391  }
1392 }
1393 
1394 void RobotState::getRobotMarkers(visualization_msgs::msg::MarkerArray& arr, const std::vector<std::string>& link_names,
1395  bool include_attached) const
1396 {
1397  rclcpp::Clock clock;
1398  for (const std::string& link_name : link_names)
1399  {
1400  RCLCPP_DEBUG(getLogger(), "Trying to get marker for link '%s'", link_name.c_str());
1401  const LinkModel* link_model = robot_model_->getLinkModel(link_name);
1402  if (!link_model)
1403  continue;
1404  if (include_attached)
1405  {
1406  for (const auto& it : attached_body_map_)
1407  {
1408  if (it.second->getAttachedLink() == link_model)
1409  {
1410  for (std::size_t j = 0; j < it.second->getShapes().size(); ++j)
1411  {
1412  visualization_msgs::msg::Marker att_mark;
1413  att_mark.header.frame_id = robot_model_->getModelFrame();
1414  att_mark.header.stamp = clock.now();
1415  if (shapes::constructMarkerFromShape(it.second->getShapes()[j].get(), att_mark))
1416  {
1417  // if the object is invisible (0 volume) we skip it
1418  if (fabs(att_mark.scale.x * att_mark.scale.y * att_mark.scale.z) < std::numeric_limits<double>::epsilon())
1419  continue;
1420  att_mark.pose = tf2::toMsg(it.second->getGlobalCollisionBodyTransforms()[j]);
1421  arr.markers.push_back(att_mark);
1422  }
1423  }
1424  }
1425  }
1426  }
1427 
1428  if (link_model->getShapes().empty())
1429  continue;
1430 
1431  for (std::size_t j = 0; j < link_model->getShapes().size(); ++j)
1432  {
1433  visualization_msgs::msg::Marker mark;
1434  mark.header.frame_id = robot_model_->getModelFrame();
1435  mark.header.stamp = clock.now();
1436 
1437  // we prefer using the visual mesh, if a mesh is available and we have one body to render
1438  const std::string& mesh_resource = link_model->getVisualMeshFilename();
1439  if (mesh_resource.empty() || link_model->getShapes().size() > 1)
1440  {
1441  if (!shapes::constructMarkerFromShape(link_model->getShapes()[j].get(), mark))
1442  continue;
1443  // if the object is invisible (0 volume) we skip it
1444  if (fabs(mark.scale.x * mark.scale.y * mark.scale.z) < std::numeric_limits<double>::epsilon())
1445  continue;
1446  mark.pose =
1447  tf2::toMsg(global_collision_body_transforms_[link_model->getFirstCollisionBodyTransformIndex() + j]);
1448  }
1449  else
1450  {
1451  mark.type = mark.MESH_RESOURCE;
1452  mark.mesh_use_embedded_materials = false;
1453  mark.mesh_resource = mesh_resource;
1454  const Eigen::Vector3d& mesh_scale = link_model->getVisualMeshScale();
1455 
1456  mark.scale.x = mesh_scale[0];
1457  mark.scale.y = mesh_scale[1];
1458  mark.scale.z = mesh_scale[2];
1459  mark.pose = tf2::toMsg(global_link_transforms_[link_model->getLinkIndex()] * link_model->getVisualMeshOrigin());
1460  }
1461 
1462  arr.markers.push_back(mark);
1463  }
1464  }
1465 }
1466 
1467 Eigen::MatrixXd RobotState::getJacobian(const JointModelGroup* group,
1468  const Eigen::Vector3d& reference_point_position) const
1469 {
1470  Eigen::MatrixXd result;
1471  if (!getJacobian(group, group->getLinkModels().back(), reference_point_position, result, false))
1472  throw Exception("Unable to compute Jacobian");
1473  return result;
1474 }
1475 
1476 bool RobotState::getJacobian(const JointModelGroup* group, const LinkModel* link,
1477  const Eigen::Vector3d& reference_point_position, Eigen::MatrixXd& jacobian,
1478  bool use_quaternion_representation) const
1479 {
1480  assert(checkLinkTransforms());
1481 
1482  // Check that the group is a chain, contains 'link' and has joint models.
1483  if (!group->isChain())
1484  {
1485  RCLCPP_ERROR(getLogger(), "The group '%s' is not a chain. Cannot compute Jacobian.", group->getName().c_str());
1486  return false;
1487  }
1488 
1489  const std::set<const LinkModel*>& descendant_links = group->getUpdatedLinkModelsSet();
1490  if (descendant_links.find(link) == descendant_links.end())
1491  {
1492  RCLCPP_ERROR(getLogger(), "Link name '%s' does not exist in the chain '%s' or is not a child for this chain",
1493  link->getName().c_str(), group->getName().c_str());
1494  return false;
1495  }
1496 
1497  const std::vector<const JointModel*>& joint_models = group->getActiveJointModels();
1498  if (joint_models.empty())
1499  {
1500  RCLCPP_ERROR(getLogger(), "The group '%s' doesn't contain any joint models. Cannot compute Jacobian.",
1501  group->getName().c_str());
1502  return false;
1503  }
1504 
1505  // Get the link model of the group root link, and its inverted pose with respect to the RobotModel (URDF) root,
1506  // 'root_pose_world'.
1507  const JointModel* root_joint_model = group->getJointModels().front();
1508  const LinkModel* root_link_model = root_joint_model->getParentLinkModel();
1509  const Eigen::Isometry3d root_pose_world =
1510  root_link_model ? getGlobalLinkTransform(root_link_model).inverse() : Eigen::Isometry3d::Identity();
1511  const int rows = use_quaternion_representation ? 7 : 6;
1512  const int columns = group->getVariableCount();
1513  jacobian.resize(rows, columns);
1514 
1515  // Get the tip pose with respect to the group root link. Append the user-requested offset 'reference_point_position'.
1516  const Eigen::Isometry3d root_pose_tip = root_pose_world * getGlobalLinkTransform(link);
1517  const Eigen::Vector3d tip_point = root_pose_tip * reference_point_position;
1518 
1519  // Here we iterate over all the group active joints, and compute how much each of them contribute to the Cartesian
1520  // displacement at the tip. So we build the Jacobian incrementally joint by joint.
1521  std::size_t active_joints = group->getActiveJointModels().size();
1522  int i = 0;
1523  for (std::size_t joint = 0; joint < active_joints; ++joint)
1524  {
1525  // Get the child link for the current joint, and its pose with respect to the group root link.
1526  const JointModel* joint_model = joint_models[joint];
1527  const LinkModel* child_link_model = joint_model->getChildLinkModel();
1528  const Eigen::Isometry3d& root_pose_link = root_pose_world * getGlobalLinkTransform(child_link_model);
1529 
1530  // Compute the Jacobian for the specific joint model, given with respect to the group root link.
1531  if (joint_model->getType() == JointModel::REVOLUTE)
1532  {
1533  const Eigen::Vector3d axis_wrt_origin =
1534  root_pose_link.linear() * static_cast<const RevoluteJointModel*>(joint_model)->getAxis();
1535  jacobian.block<3, 1>(0, i) = axis_wrt_origin.cross(tip_point - root_pose_link.translation());
1536  jacobian.block<3, 1>(3, i) = axis_wrt_origin;
1537  }
1538  else if (joint_model->getType() == JointModel::PRISMATIC)
1539  {
1540  const Eigen::Vector3d axis_wrt_origin =
1541  root_pose_link.linear() * static_cast<const PrismaticJointModel*>(joint_model)->getAxis();
1542  jacobian.block<3, 1>(0, i) = axis_wrt_origin;
1543  jacobian.block<3, 1>(3, i) = Eigen::Vector3d::Zero();
1544  }
1545  else if (joint_model->getType() == JointModel::PLANAR)
1546  {
1547  jacobian.block<3, 1>(0, i) = root_pose_link.linear() * Eigen::Vector3d(1.0, 0.0, 0.0);
1548  jacobian.block<3, 1>(0, i + 1) = root_pose_link.linear() * Eigen::Vector3d(0.0, 1.0, 0.0);
1549  jacobian.block<3, 1>(0, i + 2) =
1550  (root_pose_link.linear() * Eigen::Vector3d(0.0, 0.0, 1.0)).cross(tip_point - root_pose_link.translation());
1551  jacobian.block<3, 1>(3, i + 2) = root_pose_link.linear() * Eigen::Vector3d(0.0, 0.0, 1.0);
1552  }
1553  else
1554  {
1555  RCLCPP_ERROR(getLogger(), "Unknown type of joint in Jacobian computation");
1556  return false;
1557  }
1558  i += joint_model->getVariableCount();
1559  }
1560 
1561  if (use_quaternion_representation)
1562  { // Quaternion representation
1563  // From "Advanced Dynamics and Motion Simulation" by Paul Mitiguy
1564  // d/dt ( [w] ) = 1/2 * [ -x -y -z ] * [ omega_1 ]
1565  // [x] [ w -z y ] [ omega_2 ]
1566  // [y] [ z w -x ] [ omega_3 ]
1567  // [z] [ -y x w ]
1568  Eigen::Quaterniond q(root_pose_tip.linear());
1569  double w = q.w(), x = q.x(), y = q.y(), z = q.z();
1570  Eigen::MatrixXd quaternion_update_matrix(4, 3);
1571  quaternion_update_matrix << -x, -y, -z, w, -z, y, z, w, -x, -y, x, w;
1572  jacobian.block(3, 0, 4, columns) = 0.5 * quaternion_update_matrix * jacobian.block(3, 0, 3, columns);
1573  }
1574  return true;
1575 }
1576 
1577 bool RobotState::setFromDiffIK(const JointModelGroup* jmg, const Eigen::VectorXd& twist, const std::string& tip,
1578  double dt, const GroupStateValidityCallbackFn& constraint)
1579 {
1580  Eigen::VectorXd qdot;
1581  computeVariableVelocity(jmg, qdot, twist, getLinkModel(tip));
1582  return integrateVariableVelocity(jmg, qdot, dt, constraint);
1583 }
1584 
1585 bool RobotState::setFromDiffIK(const JointModelGroup* jmg, const geometry_msgs::msg::Twist& twist,
1586  const std::string& tip, double dt, const GroupStateValidityCallbackFn& constraint)
1587 {
1588  Eigen::Matrix<double, 6, 1> t;
1589  tf2::fromMsg(twist, t);
1590  return setFromDiffIK(jmg, t, tip, dt, constraint);
1591 }
1592 
1593 void RobotState::computeVariableVelocity(const JointModelGroup* jmg, Eigen::VectorXd& qdot,
1594  const Eigen::VectorXd& twist, const LinkModel* tip) const
1595 {
1596  // Get the Jacobian of the group at the current configuration
1597  Eigen::MatrixXd j(6, jmg->getVariableCount());
1598  Eigen::Vector3d reference_point(0.0, 0.0, 0.0);
1599  getJacobian(jmg, tip, reference_point, j, false);
1600 
1601  // Rotate the jacobian to the end-effector frame
1602  Eigen::Isometry3d e_mb = getGlobalLinkTransform(tip).inverse();
1603  Eigen::MatrixXd e_wb = Eigen::ArrayXXd::Zero(6, 6);
1604  e_wb.block(0, 0, 3, 3) = e_mb.matrix().block(0, 0, 3, 3);
1605  e_wb.block(3, 3, 3, 3) = e_mb.matrix().block(0, 0, 3, 3);
1606  j = e_wb * j;
1607 
1608  // Do the Jacobian moore-penrose pseudo-inverse
1609  Eigen::JacobiSVD<Eigen::MatrixXd> svd_of_j(j, Eigen::ComputeThinU | Eigen::ComputeThinV);
1610  const Eigen::MatrixXd& u = svd_of_j.matrixU();
1611  const Eigen::MatrixXd& v = svd_of_j.matrixV();
1612  const Eigen::VectorXd& s = svd_of_j.singularValues();
1613 
1614  Eigen::VectorXd sinv = s;
1615  static const double PINVTOLER = std::numeric_limits<double>::epsilon();
1616  double maxsv = 0.0;
1617  for (std::size_t i = 0; i < static_cast<std::size_t>(s.rows()); ++i)
1618  {
1619  if (fabs(s(i)) > maxsv)
1620  maxsv = fabs(s(i));
1621  }
1622  for (std::size_t i = 0; i < static_cast<std::size_t>(s.rows()); ++i)
1623  {
1624  // Those singular values smaller than a percentage of the maximum singular value are removed
1625  if (fabs(s(i)) > maxsv * PINVTOLER)
1626  {
1627  sinv(i) = 1.0 / s(i);
1628  }
1629  else
1630  {
1631  sinv(i) = 0.0;
1632  }
1633  }
1634  Eigen::MatrixXd jinv = (v * sinv.asDiagonal() * u.transpose());
1635 
1636  // Compute joint velocity
1637  qdot = jinv * twist;
1638 }
1639 
1640 bool RobotState::integrateVariableVelocity(const JointModelGroup* jmg, const Eigen::VectorXd& qdot, double dt,
1641  const GroupStateValidityCallbackFn& constraint)
1642 {
1643  Eigen::VectorXd q(jmg->getVariableCount());
1644  copyJointGroupPositions(jmg, q);
1645  q = q + dt * qdot;
1646  setJointGroupPositions(jmg, q);
1647  enforceBounds(jmg);
1648 
1649  if (constraint)
1650  {
1651  std::vector<double> values;
1652  copyJointGroupPositions(jmg, values);
1653  return constraint(this, jmg, &values[0]);
1654  }
1655  else
1656  return true;
1657 }
1658 
1659 bool RobotState::setFromIK(const JointModelGroup* jmg, const geometry_msgs::msg::Pose& pose, double timeout,
1660  const GroupStateValidityCallbackFn& constraint,
1662  const kinematics::KinematicsBase::IKCostFn& cost_function)
1663 {
1664  const kinematics::KinematicsBaseConstPtr& solver = jmg->getSolverInstance();
1665  if (!solver)
1666  {
1667  RCLCPP_ERROR(getLogger(), "No kinematics solver instantiated for group '%s'", jmg->getName().c_str());
1668  return false;
1669  }
1670  return setFromIK(jmg, pose, solver->getTipFrame(), timeout, constraint, options, cost_function);
1671 }
1672 
1673 bool RobotState::setFromIK(const JointModelGroup* jmg, const geometry_msgs::msg::Pose& pose, const std::string& tip,
1674  double timeout, const GroupStateValidityCallbackFn& constraint,
1676  const kinematics::KinematicsBase::IKCostFn& cost_function)
1677 {
1678  Eigen::Isometry3d mat;
1679  tf2::fromMsg(pose, mat);
1680  static std::vector<double> consistency_limits;
1681  return setFromIK(jmg, mat, tip, consistency_limits, timeout, constraint, options, cost_function);
1682 }
1683 
1684 bool RobotState::setFromIK(const JointModelGroup* jmg, const Eigen::Isometry3d& pose, double timeout,
1685  const GroupStateValidityCallbackFn& constraint,
1687  const kinematics::KinematicsBase::IKCostFn& cost_function)
1688 {
1689  const kinematics::KinematicsBaseConstPtr& solver = jmg->getSolverInstance();
1690  if (!solver)
1691  {
1692  RCLCPP_ERROR(getLogger(), "No kinematics solver instantiated for group '%s'", jmg->getName().c_str());
1693  return false;
1694  }
1695  static std::vector<double> consistency_limits;
1696  return setFromIK(jmg, pose, solver->getTipFrame(), consistency_limits, timeout, constraint, options, cost_function);
1697 }
1698 
1699 bool RobotState::setFromIK(const JointModelGroup* jmg, const Eigen::Isometry3d& pose_in, const std::string& tip_in,
1700  double timeout, const GroupStateValidityCallbackFn& constraint,
1702  const kinematics::KinematicsBase::IKCostFn& cost_function)
1703 {
1704  static std::vector<double> consistency_limits;
1705  return setFromIK(jmg, pose_in, tip_in, consistency_limits, timeout, constraint, options, cost_function);
1706 }
1707 
1708 namespace
1709 {
1710 bool ikCallbackFnAdapter(RobotState* state, const JointModelGroup* group,
1711  const GroupStateValidityCallbackFn& constraint, const geometry_msgs::msg::Pose& /*unused*/,
1712  const std::vector<double>& ik_sol, moveit_msgs::msg::MoveItErrorCodes& error_code)
1713 {
1714  const std::vector<size_t>& bij = group->getKinematicsSolverJointBijection();
1715  std::vector<double> solution(bij.size());
1716  for (std::size_t i = 0; i < bij.size(); ++i)
1717  solution[bij[i]] = ik_sol[i];
1718  if (constraint(state, group, &solution[0]))
1719  {
1720  error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
1721  }
1722  else
1723  {
1724  error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1725  }
1726  return true;
1727 }
1728 } // namespace
1729 
1730 bool RobotState::setToIKSolverFrame(Eigen::Isometry3d& pose, const kinematics::KinematicsBaseConstPtr& solver)
1731 {
1732  return setToIKSolverFrame(pose, solver->getBaseFrame());
1733 }
1734 
1735 bool RobotState::setToIKSolverFrame(Eigen::Isometry3d& pose, const std::string& ik_frame)
1736 {
1737  // Bring the pose to the frame of the IK solver
1738  if (!Transforms::sameFrame(ik_frame, robot_model_->getModelFrame()))
1739  {
1740  const LinkModel* link_model =
1741  getLinkModel((!ik_frame.empty() && ik_frame[0] == '/') ? ik_frame.substr(1) : ik_frame);
1742  if (!link_model)
1743  {
1744  RCLCPP_ERROR(getLogger(), "The following IK frame does not exist: %s", ik_frame.c_str());
1745  return false;
1746  }
1747  pose = getGlobalLinkTransform(link_model).inverse() * pose;
1748  }
1749  return true;
1750 }
1751 
1752 bool RobotState::setFromIK(const JointModelGroup* jmg, const Eigen::Isometry3d& pose_in, const std::string& tip_in,
1753  const std::vector<double>& consistency_limits_in, double timeout,
1754  const GroupStateValidityCallbackFn& constraint,
1756  const kinematics::KinematicsBase::IKCostFn& cost_function)
1757 {
1758  // Convert from single pose and tip to vectors
1759  EigenSTL::vector_Isometry3d poses;
1760  poses.push_back(pose_in);
1761 
1762  std::vector<std::string> tips;
1763  tips.push_back(tip_in);
1764 
1765  std::vector<std::vector<double> > consistency_limits;
1766  consistency_limits.push_back(consistency_limits_in);
1767 
1768  return setFromIK(jmg, poses, tips, consistency_limits, timeout, constraint, options, cost_function);
1769 }
1770 
1771 bool RobotState::setFromIK(const JointModelGroup* jmg, const EigenSTL::vector_Isometry3d& poses_in,
1772  const std::vector<std::string>& tips_in, double timeout,
1773  const GroupStateValidityCallbackFn& constraint,
1775  const kinematics::KinematicsBase::IKCostFn& cost_function)
1776 {
1777  const std::vector<std::vector<double> > consistency_limits;
1778  return setFromIK(jmg, poses_in, tips_in, consistency_limits, timeout, constraint, options, cost_function);
1779 }
1780 
1781 bool RobotState::setFromIK(const JointModelGroup* jmg, const EigenSTL::vector_Isometry3d& poses_in,
1782  const std::vector<std::string>& tips_in,
1783  const std::vector<std::vector<double> >& consistency_limit_sets, double timeout,
1784  const GroupStateValidityCallbackFn& constraint,
1786  const kinematics::KinematicsBase::IKCostFn& cost_function)
1787 {
1788  // Error check
1789  if (poses_in.size() != tips_in.size())
1790  {
1791  RCLCPP_ERROR(getLogger(), "Number of poses must be the same as number of tips");
1792  return false;
1793  }
1794 
1795  // Load solver
1796  const kinematics::KinematicsBaseConstPtr& solver = jmg->getSolverInstance();
1797 
1798  // Check if this jmg has a solver
1799  bool valid_solver = true;
1800  if (!solver)
1801  {
1802  valid_solver = false;
1803  }
1804  // Check if this jmg's IK solver can handle multiple tips (non-chain solver)
1805  else if (poses_in.size() > 1)
1806  {
1807  std::string error_msg;
1808  if (!solver->supportsGroup(jmg, &error_msg))
1809  {
1810  const kinematics::KinematicsBase& solver_ref = *solver;
1811  RCLCPP_ERROR(getLogger(), "Kinematics solver %s does not support joint group %s. Error: %s",
1812  typeid(solver_ref).name(), jmg->getName().c_str(), error_msg.c_str());
1813  valid_solver = false;
1814  }
1815  }
1816 
1817  if (!valid_solver)
1818  {
1819  // Check if there are subgroups that can solve this for us (non-chains)
1820  if (poses_in.size() > 1)
1821  {
1822  // Forward to setFromIKSubgroups() to allow different subgroup IK solvers to work together
1823  return setFromIKSubgroups(jmg, poses_in, tips_in, consistency_limit_sets, timeout, constraint, options);
1824  }
1825  else
1826  {
1827  RCLCPP_ERROR(getLogger(), "No kinematics solver instantiated for group '%s'", jmg->getName().c_str());
1828  return false;
1829  }
1830  }
1831 
1832  // Check that no, or only one set of consistency limits has been passed in, and choose that one
1833  std::vector<double> consistency_limits;
1834  if (consistency_limit_sets.size() > 1)
1835  {
1836  RCLCPP_ERROR(getLogger(),
1837  "Invalid number (%zu) of sets of consistency limits for a setFromIK request "
1838  "that is being solved by a single IK solver",
1839  consistency_limit_sets.size());
1840  return false;
1841  }
1842  else if (consistency_limit_sets.size() == 1)
1843  consistency_limits = consistency_limit_sets[0];
1844 
1845  const std::vector<std::string>& solver_tip_frames = solver->getTipFrames();
1846 
1847  // Track which possible tips frames we have filled in so far
1848  std::vector<bool> tip_frames_used(solver_tip_frames.size(), false);
1849 
1850  // Create vector to hold the output frames in the same order as solver_tip_frames
1851  std::vector<geometry_msgs::msg::Pose> ik_queries(solver_tip_frames.size());
1852 
1853  // Bring each pose to the frame of the IK solver
1854  for (std::size_t i = 0; i < poses_in.size(); ++i)
1855  {
1856  // Make non-const
1857  Eigen::Isometry3d pose = poses_in[i];
1858  std::string pose_frame = tips_in[i];
1859 
1860  // Remove extra slash
1861  if (!pose_frame.empty() && pose_frame[0] == '/')
1862  pose_frame = pose_frame.substr(1);
1863 
1864  // bring the pose to the frame of the IK solver
1865  if (!setToIKSolverFrame(pose, solver))
1866  return false;
1867 
1868  // try all of the solver's possible tip frames to see if they uniquely align with any of our passed in pose tip
1869  // frames
1870  bool found_valid_frame = false;
1871  std::size_t solver_tip_id; // our current index
1872  for (solver_tip_id = 0; solver_tip_id < solver_tip_frames.size(); ++solver_tip_id)
1873  {
1874  // Check if this tip frame is already accounted for
1875  if (tip_frames_used[solver_tip_id])
1876  continue; // already has a pose
1877 
1878  // check if the tip frame can be transformed via fixed transforms to the frame known to the IK solver
1879  std::string solver_tip_frame = solver_tip_frames[solver_tip_id];
1880 
1881  // remove the frame '/' if there is one, so we can avoid calling Transforms::sameFrame() which may copy strings
1882  // more often that we need to
1883  if (!solver_tip_frame.empty() && solver_tip_frame[0] == '/')
1884  solver_tip_frame = solver_tip_frame.substr(1);
1885 
1886  if (pose_frame != solver_tip_frame)
1887  {
1888  if (hasAttachedBody(pose_frame))
1889  {
1890  const AttachedBody* body = getAttachedBody(pose_frame);
1891  pose_frame = body->getAttachedLinkName();
1892  pose = pose * body->getPose().inverse();
1893  }
1894  if (pose_frame != solver_tip_frame)
1895  {
1896  const LinkModel* link_model = getLinkModel(pose_frame);
1897  if (!link_model)
1898  {
1899  RCLCPP_ERROR(getLogger(), "The following Pose Frame does not exist: %s", pose_frame.c_str());
1900  return false;
1901  }
1902  const LinkTransformMap& fixed_links = link_model->getAssociatedFixedTransforms();
1903  for (const std::pair<const LinkModel* const, Eigen::Isometry3d>& fixed_link : fixed_links)
1904  {
1905  if (Transforms::sameFrame(fixed_link.first->getName(), solver_tip_frame))
1906  {
1907  pose_frame = solver_tip_frame;
1908  pose = pose * fixed_link.second;
1909  break;
1910  }
1911  }
1912  }
1913 
1914  } // end if pose_frame
1915 
1916  // Check if this pose frame works
1917  if (pose_frame == solver_tip_frame)
1918  {
1919  found_valid_frame = true;
1920  break;
1921  }
1922 
1923  } // end for solver_tip_frames
1924 
1925  // Make sure one of the tip frames worked
1926  if (!found_valid_frame)
1927  {
1928  RCLCPP_ERROR(getLogger(), "Cannot compute IK for query %zu pose reference frame '%s'", i, pose_frame.c_str());
1929  // Debug available tip frames
1930  std::stringstream ss;
1931  for (solver_tip_id = 0; solver_tip_id < solver_tip_frames.size(); ++solver_tip_id)
1932  ss << solver_tip_frames[solver_tip_id] << ", ";
1933  RCLCPP_ERROR(getLogger(), "Available tip frames: [%s]", ss.str().c_str());
1934  return false;
1935  }
1936 
1937  // Remove that tip from the list of available tip frames because each can only have one pose
1938  tip_frames_used[solver_tip_id] = true;
1939 
1940  // Convert Eigen pose to geometry_msgs pose
1941  geometry_msgs::msg::Pose ik_query;
1942  ik_query = tf2::toMsg(pose);
1943 
1944  // Save into vectors
1945  ik_queries[solver_tip_id] = ik_query;
1946  } // end for poses_in
1947 
1948  // Create poses for all remaining tips a solver expects, even if not passed into this function
1949  for (std::size_t solver_tip_id = 0; solver_tip_id < solver_tip_frames.size(); ++solver_tip_id)
1950  {
1951  // Check if this tip frame is already accounted for
1952  if (tip_frames_used[solver_tip_id])
1953  continue; // already has a pose
1954 
1955  // Process this tip
1956  std::string solver_tip_frame = solver_tip_frames[solver_tip_id];
1957 
1958  // remove the frame '/' if there is one, so we can avoid calling Transforms::sameFrame() which may copy strings more
1959  // often that we need to
1960  if (!solver_tip_frame.empty() && solver_tip_frame[0] == '/')
1961  solver_tip_frame = solver_tip_frame.substr(1);
1962 
1963  // Get the pose of a different EE tip link
1964  Eigen::Isometry3d current_pose = getGlobalLinkTransform(solver_tip_frame);
1965 
1966  // bring the pose to the frame of the IK solver
1967  if (!setToIKSolverFrame(current_pose, solver))
1968  return false;
1969 
1970  // Convert Eigen pose to geometry_msgs pose
1971  geometry_msgs::msg::Pose ik_query;
1972  ik_query = tf2::toMsg(current_pose);
1973 
1974  // Save into vectors - but this needs to be ordered in the same order as the IK solver expects its tip frames
1975  ik_queries[solver_tip_id] = ik_query;
1976 
1977  // Remove that tip from the list of available tip frames because each can only have one pose
1978  tip_frames_used[solver_tip_id] = true;
1979  }
1980 
1981  // if no timeout has been specified, use the default one
1982  if (timeout < std::numeric_limits<double>::epsilon())
1983  timeout = jmg->getDefaultIKTimeout();
1984 
1985  // set callback function
1987  if (constraint)
1988  {
1989  ik_callback_fn = ik_callback_fn = [this, jmg, constraint](const geometry_msgs::msg::Pose& pose,
1990  const std::vector<double>& joints,
1991  moveit_msgs::msg::MoveItErrorCodes& error_code) {
1992  ikCallbackFnAdapter(this, jmg, constraint, pose, joints, error_code);
1993  };
1994  }
1995 
1996  // Bijection
1997  const std::vector<size_t>& bij = jmg->getKinematicsSolverJointBijection();
1998 
1999  std::vector<double> initial_values;
2000  copyJointGroupPositions(jmg, initial_values);
2001  std::vector<double> seed(bij.size());
2002  for (std::size_t i = 0; i < bij.size(); ++i)
2003  seed[i] = initial_values[bij[i]];
2004 
2005  // compute the IK solution
2006  std::vector<double> ik_sol;
2007  moveit_msgs::msg::MoveItErrorCodes error;
2008 
2009  if (solver->searchPositionIK(ik_queries, seed, timeout, consistency_limits, ik_sol, ik_callback_fn, cost_function,
2010  error, options, this))
2011  {
2012  std::vector<double> solution(bij.size());
2013  for (std::size_t i = 0; i < bij.size(); ++i)
2014  solution[bij[i]] = ik_sol[i];
2015  setJointGroupPositions(jmg, solution);
2016  return true;
2017  }
2018  return false;
2019 }
2020 
2021 bool RobotState::setFromIKSubgroups(const JointModelGroup* jmg, const EigenSTL::vector_Isometry3d& poses_in,
2022  const std::vector<std::string>& tips_in,
2023  const std::vector<std::vector<double> >& consistency_limits, double timeout,
2024  const GroupStateValidityCallbackFn& constraint,
2025  const kinematics::KinematicsQueryOptions& /*options*/)
2026 {
2027  // Assume we have already ran setFromIK() and those checks
2028 
2029  // Get containing subgroups
2030  std::vector<const JointModelGroup*> sub_groups;
2031  jmg->getSubgroups(sub_groups);
2032 
2033  // Error check
2034  if (poses_in.size() != sub_groups.size())
2035  {
2036  RCLCPP_ERROR(getLogger(), "Number of poses (%zu) must be the same as number of sub-groups (%zu)", poses_in.size(),
2037  sub_groups.size());
2038  return false;
2039  }
2040 
2041  if (tips_in.size() != sub_groups.size())
2042  {
2043  RCLCPP_ERROR(getLogger(), "Number of tip names (%zu) must be same as number of sub-groups (%zu)", tips_in.size(),
2044  sub_groups.size());
2045  return false;
2046  }
2047 
2048  if (!consistency_limits.empty() && consistency_limits.size() != sub_groups.size())
2049  {
2050  RCLCPP_ERROR(getLogger(), "Number of consistency limit vectors must be the same as number of sub-groups");
2051  return false;
2052  }
2053 
2054  for (std::size_t i = 0; i < consistency_limits.size(); ++i)
2055  {
2056  if (consistency_limits[i].size() != sub_groups[i]->getVariableCount())
2057  {
2058  RCLCPP_ERROR(getLogger(), "Number of joints in consistency_limits is %zu but it should be should be %u", i,
2059  sub_groups[i]->getVariableCount());
2060  return false;
2061  }
2062  }
2063 
2064  // Populate list of kin solvers for the various subgroups
2065  std::vector<kinematics::KinematicsBaseConstPtr> solvers;
2066  for (std::size_t i = 0; i < poses_in.size(); ++i)
2067  {
2068  kinematics::KinematicsBaseConstPtr solver = sub_groups[i]->getSolverInstance();
2069  if (!solver)
2070  {
2071  RCLCPP_ERROR(getLogger(), "Could not find solver for group '%s'", sub_groups[i]->getName().c_str());
2072  return false;
2073  }
2074  solvers.push_back(solver);
2075  }
2076 
2077  // Make non-const versions
2078  EigenSTL::vector_Isometry3d transformed_poses = poses_in;
2079  std::vector<std::string> pose_frames = tips_in;
2080 
2081  // Each each pose's tip frame naming
2082  for (std::size_t i = 0; i < poses_in.size(); ++i)
2083  {
2084  ASSERT_ISOMETRY(transformed_poses[i]) // unsanitized input, could contain a non-isometry
2085  Eigen::Isometry3d& pose = transformed_poses[i];
2086  std::string& pose_frame = pose_frames[i];
2087 
2088  // bring the pose to the frame of the IK solver
2089  if (!setToIKSolverFrame(pose, solvers[i]))
2090  return false;
2091 
2092  // see if the tip frame can be transformed via fixed transforms to the frame known to the IK solver
2093  std::string solver_tip_frame = solvers[i]->getTipFrame();
2094 
2095  // remove the frame '/' if there is one, so we can avoid calling Transforms::sameFrame() which may copy strings more
2096  // often that we need to
2097  if (!solver_tip_frame.empty() && solver_tip_frame[0] == '/')
2098  solver_tip_frame = solver_tip_frame.substr(1);
2099 
2100  if (pose_frame != solver_tip_frame)
2101  {
2102  if (hasAttachedBody(pose_frame))
2103  {
2104  const AttachedBody* body = getAttachedBody(pose_frame);
2105  pose_frame = body->getAttachedLinkName();
2106  pose = pose * body->getPose().inverse(); // valid isometry
2107  }
2108  if (pose_frame != solver_tip_frame)
2109  {
2110  const LinkModel* link_model = getLinkModel(pose_frame);
2111  if (!link_model)
2112  return false;
2113  // getAssociatedFixedTransforms() returns valid isometries by contract
2114  const LinkTransformMap& fixed_links = link_model->getAssociatedFixedTransforms();
2115  for (const std::pair<const LinkModel* const, Eigen::Isometry3d>& fixed_link : fixed_links)
2116  {
2117  if (fixed_link.first->getName() == solver_tip_frame)
2118  {
2119  pose_frame = solver_tip_frame;
2120  pose = pose * fixed_link.second; // valid isometry
2121  break;
2122  }
2123  }
2124  }
2125  }
2126 
2127  if (pose_frame != solver_tip_frame)
2128  {
2129  RCLCPP_ERROR(getLogger(), "Cannot compute IK for query pose reference frame '%s', desired: '%s'",
2130  pose_frame.c_str(), solver_tip_frame.c_str());
2131  return false;
2132  }
2133  }
2134 
2135  // Convert Eigen poses to geometry_msg format
2136  std::vector<geometry_msgs::msg::Pose> ik_queries(poses_in.size());
2138  if (constraint)
2139  {
2140  ik_callback_fn = [this, jmg, constraint](const geometry_msgs::msg::Pose pose, const std::vector<double>& joints,
2141  moveit_msgs::msg::MoveItErrorCodes& error_code) {
2142  ikCallbackFnAdapter(this, jmg, constraint, pose, joints, error_code);
2143  };
2144  }
2145 
2146  for (std::size_t i = 0; i < transformed_poses.size(); ++i)
2147  {
2148  Eigen::Quaterniond quat(transformed_poses[i].linear());
2149  Eigen::Vector3d point(transformed_poses[i].translation());
2150  ik_queries[i].position.x = point.x();
2151  ik_queries[i].position.y = point.y();
2152  ik_queries[i].position.z = point.z();
2153  ik_queries[i].orientation.x = quat.x();
2154  ik_queries[i].orientation.y = quat.y();
2155  ik_queries[i].orientation.z = quat.z();
2156  ik_queries[i].orientation.w = quat.w();
2157  }
2158 
2159  // if no timeout has been specified, use the default one
2160  if (timeout < std::numeric_limits<double>::epsilon())
2161  timeout = jmg->getDefaultIKTimeout();
2162 
2163  auto start = std::chrono::system_clock::now();
2164  double elapsed = 0;
2165 
2166  bool first_seed = true;
2167  unsigned int attempts = 0;
2168  do
2169  {
2170  ++attempts;
2171  RCLCPP_DEBUG(getLogger(), "IK attempt: %d", attempts);
2172  bool found_solution = true;
2173  for (std::size_t sg = 0; sg < sub_groups.size(); ++sg)
2174  {
2175  const std::vector<size_t>& bij = sub_groups[sg]->getKinematicsSolverJointBijection();
2176  std::vector<double> seed(bij.size());
2177  // the first seed is the initial state
2178  if (first_seed)
2179  {
2180  std::vector<double> initial_values;
2181  copyJointGroupPositions(sub_groups[sg], initial_values);
2182  for (std::size_t i = 0; i < bij.size(); ++i)
2183  seed[i] = initial_values[bij[i]];
2184  }
2185  else
2186  {
2187  // sample a random seed
2188  random_numbers::RandomNumberGenerator& rng = getRandomNumberGenerator();
2189  std::vector<double> random_values;
2190  sub_groups[sg]->getVariableRandomPositions(rng, random_values);
2191  for (std::size_t i = 0; i < bij.size(); ++i)
2192  seed[i] = random_values[bij[i]];
2193  }
2194 
2195  // compute the IK solution
2196  std::vector<double> ik_sol;
2197  moveit_msgs::msg::MoveItErrorCodes error;
2198  const std::vector<double>& climits = consistency_limits.empty() ? std::vector<double>() : consistency_limits[sg];
2199  if (solvers[sg]->searchPositionIK(ik_queries[sg], seed, (timeout - elapsed) / sub_groups.size(), climits, ik_sol,
2200  error))
2201  {
2202  std::vector<double> solution(bij.size());
2203  for (std::size_t i = 0; i < bij.size(); ++i)
2204  solution[bij[i]] = ik_sol[i];
2205  setJointGroupPositions(sub_groups[sg], solution);
2206  }
2207  else
2208  {
2209  found_solution = false;
2210  break;
2211  }
2212  }
2213  if (found_solution)
2214  {
2215  std::vector<double> full_solution;
2216  copyJointGroupPositions(jmg, full_solution);
2217  if (constraint ? constraint(this, jmg, &full_solution[0]) : true)
2218  {
2219  RCLCPP_DEBUG(getLogger(), "Found IK solution");
2220  return true;
2221  }
2222  }
2223  elapsed = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - start).count();
2224  first_seed = false;
2225  } while (elapsed < timeout);
2226  return false;
2227 }
2228 
2229 void RobotState::computeAABB(std::vector<double>& aabb) const
2230 {
2231  assert(checkLinkTransforms());
2232 
2233  core::AABB bounding_box;
2234  std::vector<const LinkModel*> links = robot_model_->getLinkModelsWithCollisionGeometry();
2235  for (const LinkModel* link : links)
2236  {
2237  Eigen::Isometry3d transform = getGlobalLinkTransform(link); // intentional copy, we will translate
2238  const Eigen::Vector3d& extents = link->getShapeExtentsAtOrigin();
2239  transform.translate(link->getCenteredBoundingBoxOffset());
2240  bounding_box.extendWithTransformedBox(transform, extents);
2241  }
2242  for (const auto& it : attached_body_map_)
2243  {
2244  const EigenSTL::vector_Isometry3d& transforms = it.second->getGlobalCollisionBodyTransforms();
2245  const std::vector<shapes::ShapeConstPtr>& shapes = it.second->getShapes();
2246  for (std::size_t i = 0; i < transforms.size(); ++i)
2247  {
2248  Eigen::Vector3d extents = shapes::computeShapeExtents(shapes[i].get());
2249  bounding_box.extendWithTransformedBox(transforms[i], extents);
2250  }
2251  }
2252 
2253  aabb.clear();
2254  aabb.resize(6, 0.0);
2255  if (!bounding_box.isEmpty())
2256  {
2257  // The following is a shorthand for something like:
2258  // aabb[0, 2, 4] = bounding_box.min(); aabb[1, 3, 5] = bounding_box.max();
2259  Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<2> >(aabb.data(), 3) = bounding_box.min();
2260  Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<2> >(aabb.data() + 1, 3) = bounding_box.max();
2261  }
2262 }
2263 
2264 void RobotState::printStatePositions(std::ostream& out) const
2265 {
2266  const std::vector<std::string>& nm = robot_model_->getVariableNames();
2267  for (std::size_t i = 0; i < nm.size(); ++i)
2268  out << nm[i] << '=' << position_[i] << '\n';
2269 }
2270 
2271 void RobotState::printStatePositionsWithJointLimits(const JointModelGroup* jmg, std::ostream& out) const
2272 {
2273  // TODO(davetcoleman): support joints with multiple variables / multiple DOFs such as floating joints
2274  // TODO(davetcoleman): support unbounded joints
2275 
2276  const std::vector<const JointModel*>& joints = jmg->getActiveJointModels();
2277 
2278  // Loop through joints
2279  for (const JointModel* joint : joints)
2280  {
2281  // Ignore joints with more than one variable
2282  if (joint->getVariableCount() > 1)
2283  continue;
2284 
2285  double current_value = getVariablePosition(joint->getName());
2286 
2287  // check if joint is beyond limits
2288  bool out_of_bounds = !satisfiesBounds(joint);
2289 
2290  const VariableBounds& bound = joint->getVariableBounds()[0];
2291 
2292  if (out_of_bounds)
2293  out << MOVEIT_CONSOLE_COLOR_RED;
2294 
2295  out << " " << std::fixed << std::setprecision(5) << bound.min_position_ << '\t';
2296  double delta = bound.max_position_ - bound.min_position_;
2297  double step = delta / 20.0;
2298 
2299  bool marker_shown = false;
2300  for (double value = bound.min_position_; value < bound.max_position_; value += step)
2301  {
2302  // show marker of current value
2303  if (!marker_shown && current_value < value)
2304  {
2305  out << '|';
2306  marker_shown = true;
2307  }
2308  else
2309  out << '-';
2310  }
2311  if (!marker_shown)
2312  out << '|';
2313 
2314  // show max position
2315  out << " \t" << std::fixed << std::setprecision(5) << bound.max_position_ << " \t" << joint->getName()
2316  << " current: " << std::fixed << std::setprecision(5) << current_value << '\n';
2317 
2318  if (out_of_bounds)
2320  }
2321 }
2322 
2323 void RobotState::printDirtyInfo(std::ostream& out) const
2324 {
2325  out << " * Dirty Joint Transforms: \n";
2326  const std::vector<const JointModel*>& jm = robot_model_->getJointModels();
2327  for (const JointModel* joint : jm)
2328  {
2329  if (joint->getVariableCount() > 0 && dirtyJointTransform(joint))
2330  out << " " << joint->getName() << '\n';
2331  }
2332  out << " * Dirty Link Transforms: " << (dirty_link_transforms_ ? dirty_link_transforms_->getName() : "NULL") << '\n';
2333  out << " * Dirty Collision Body Transforms: "
2334  << (dirty_collision_body_transforms_ ? dirty_collision_body_transforms_->getName() : "NULL\n");
2335 }
2336 
2337 void RobotState::printStateInfo(std::ostream& out) const
2338 {
2339  out << "Robot State @" << this << '\n';
2340 
2341  std::size_t n = robot_model_->getVariableCount();
2342  if (!position_.empty())
2343  {
2344  out << " * Position: ";
2345  for (std::size_t i = 0; i < n; ++i)
2346  out << position_[i] << ' ';
2347  out << '\n';
2348  }
2349  else
2350  out << " * Position: NULL\n";
2351 
2352  if (!velocity_.empty())
2353  {
2354  out << " * Velocity: ";
2355  for (std::size_t i = 0; i < n; ++i)
2356  out << velocity_[i] << ' ';
2357  out << '\n';
2358  }
2359  else
2360  out << " * Velocity: NULL\n";
2361 
2362  if (has_acceleration_)
2363  {
2364  out << " * Acceleration: ";
2365  for (std::size_t i = 0; i < n; ++i)
2366  out << effort_or_acceleration_[i] << ' ';
2367  out << '\n';
2368  }
2369  else
2370  out << " * Acceleration: NULL\n";
2371 
2372  out << " * Dirty Link Transforms: " << (dirty_link_transforms_ ? dirty_link_transforms_->getName() : "NULL\n");
2373  out << " * Dirty Collision Body Transforms: "
2374  << (dirty_collision_body_transforms_ ? dirty_collision_body_transforms_->getName() : "NULL\n");
2375 
2376  printTransforms(out);
2377 }
2378 
2379 void RobotState::printTransform(const Eigen::Isometry3d& transform, std::ostream& out) const
2380 {
2381  if (checkIsometry(transform, CHECK_ISOMETRY_PRECISION, false))
2382  {
2383  Eigen::Quaterniond q(transform.linear());
2384  out << "T.xyz = [" << transform.translation().x() << ", " << transform.translation().y() << ", "
2385  << transform.translation().z() << "], Q.xyzw = [" << q.x() << ", " << q.y() << ", " << q.z() << ", " << q.w()
2386  << ']';
2387  }
2388  else
2389  {
2390  out << "[NON-ISOMETRY] "
2391  << transform.matrix().format(
2392  Eigen::IOFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", "; ", "", "", "[", "]"));
2393  }
2394  out << '\n';
2395 }
2396 
2397 void RobotState::printTransforms(std::ostream& out) const
2398 {
2399  if (variable_joint_transforms_.empty())
2400  {
2401  out << "No transforms computed\n";
2402  return;
2403  }
2404 
2405  out << "Joint transforms:\n";
2406  const std::vector<const JointModel*>& jm = robot_model_->getJointModels();
2407  for (const JointModel* joint : jm)
2408  {
2409  out << " " << joint->getName();
2410  const int idx = joint->getJointIndex();
2411  if (dirty_joint_transforms_[idx])
2412  out << " [dirty]";
2413  out << ": ";
2414  printTransform(variable_joint_transforms_[idx], out);
2415  }
2416 
2417  out << "Link poses:\n";
2418  const std::vector<const LinkModel*>& link_model = robot_model_->getLinkModels();
2419  for (const LinkModel* link : link_model)
2420  {
2421  out << " " << link->getName() << ": ";
2422  printTransform(global_link_transforms_[link->getLinkIndex()], out);
2423  }
2424 }
2425 
2427 {
2428  std::stringstream ss;
2429  ss << "ROBOT: " << robot_model_->getName() << '\n';
2430  getStateTreeJointString(ss, robot_model_->getRootJoint(), " ", true);
2431  return ss.str();
2432 }
2433 
2434 namespace
2435 {
2436 void getPoseString(std::ostream& ss, const Eigen::Isometry3d& pose, const std::string& pfx)
2437 {
2438  ss.precision(3);
2439  for (int y = 0; y < 4; ++y)
2440  {
2441  ss << pfx;
2442  for (int x = 0; x < 4; ++x)
2443  {
2444  ss << std::setw(8) << pose(y, x) << ' ';
2445  }
2446  ss << '\n';
2447  }
2448 }
2449 } // namespace
2450 
2451 void RobotState::getStateTreeJointString(std::ostream& ss, const JointModel* jm, const std::string& pfx0,
2452  bool last) const
2453 {
2454  std::string pfx = pfx0 + "+--";
2455 
2456  ss << pfx << "Joint: " << jm->getName() << '\n';
2457 
2458  pfx = pfx0 + (last ? " " : "| ");
2459 
2460  for (std::size_t i = 0; i < jm->getVariableCount(); ++i)
2461  {
2462  ss.precision(3);
2463  ss << pfx << jm->getVariableNames()[i] << std::setw(12) << position_[jm->getFirstVariableIndex() + i] << '\n';
2464  }
2465 
2466  const LinkModel* link_model = jm->getChildLinkModel();
2467 
2468  ss << pfx << "Link: " << link_model->getName() << '\n';
2469  getPoseString(ss, link_model->getJointOriginTransform(), pfx + "joint_origin:");
2470  if (!variable_joint_transforms_.empty())
2471  {
2472  getPoseString(ss, variable_joint_transforms_[jm->getJointIndex()], pfx + "joint_variable:");
2473  getPoseString(ss, global_link_transforms_[link_model->getLinkIndex()], pfx + "link_global:");
2474  }
2475 
2476  for (std::vector<const JointModel*>::const_iterator it = link_model->getChildJointModels().begin();
2477  it != link_model->getChildJointModels().end(); ++it)
2478  getStateTreeJointString(ss, *it, pfx, it + 1 == link_model->getChildJointModels().end());
2479 }
2480 
2481 std::ostream& operator<<(std::ostream& out, const RobotState& s)
2482 {
2483  s.printStateInfo(out);
2484  return out;
2485 }
2486 
2487 } // end of namespace core
2488 } // end of namespace moveit
Provides an interface for kinematics solvers.
std::function< double(const geometry_msgs::msg::Pose &, const moveit::core::RobotState &, const moveit::core::JointModelGroup *, const std::vector< double > &)> IKCostFn
Signature for a cost function used to evaluate IK solutions.
std::function< void(const geometry_msgs::msg::Pose &, const std::vector< double > &, moveit_msgs::msg::MoveItErrorCodes &)> IKCallbackFn
Signature for a callback to validate an IK solution. Typically used for collision checking.
This may be thrown if unrecoverable errors occur.
Definition: exceptions.h:53
Represents an axis-aligned bounding box.
Definition: aabb.h:47
void extendWithTransformedBox(const Eigen::Isometry3d &transform, const Eigen::Vector3d &box)
Extend with a box transformed by the given transform.
Definition: aabb.cpp:40
Object defining bodies that can be attached to robot links.
Definition: attached_body.h:58
const std::string & getAttachedLinkName() const
Get the name of the link this body is attached to.
Definition: attached_body.h:92
const LinkModel * getAttachedLink() const
Get the model of the link this body is attached to.
Definition: attached_body.h:98
const Eigen::Isometry3d & getPose() const
Get the pose of the attached body relative to the parent link.
Definition: attached_body.h:80
double getDefaultIKTimeout() const
Get the default IK timeout.
bool isChain() const
Check if this group is a linear chain.
const std::vector< const JointModel * > & getActiveJointModels() const
Get the active joints in this group (that have controllable DOF). This does not include mimic joints.
const std::string & getName() const
Get the name of the joint group.
const std::set< const LinkModel * > & getUpdatedLinkModelsSet() const
Return the same data as getUpdatedLinkModels() but as a set.
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
const kinematics::KinematicsBaseConstPtr getSolverInstance() const
bool hasLinkModel(const std::string &link) const
Check if a link is part of this group.
void getSubgroups(std::vector< const JointModelGroup * > &sub_groups) const
Get the groups that are subsets of this one (in terms of joints set)
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 getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< int > & getVariableIndexList() const
Get the index locations in the complete robot state for all the variables in this group.
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.
unsigned int getActiveVariableCount() const
Get the number of variables that describe the active joints in this joint group. This excludes variab...
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition: joint_model.h:117
const LinkModel * getParentLinkModel() const
Get the link that this joint connects to. The robot is assumed to start with a joint,...
Definition: joint_model.h:162
virtual void computeVariablePositions(const Eigen::Isometry3d &transform, double *joint_values) const =0
Given the transform generated by joint, compute the corresponding joint values. Make sure the passed ...
size_t getJointIndex() const
Get the index of this joint within the robot model.
Definition: joint_model.h:222
const LinkModel * getChildLinkModel() const
Get the link that this joint connects to. There will always be such a link.
Definition: joint_model.h:168
std::vector< VariableBounds > Bounds
The datatype for the joint bounds.
Definition: joint_model.h:131
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
Definition: joint_model.h:216
virtual bool harmonizePosition(double *values, const Bounds &other_bounds) const
Definition: joint_model.cpp:93
virtual void interpolate(const double *from, const double *to, const double t, double *state) const =0
Computes the state that lies at time t in [0, 1] on the segment that connects from state to to state....
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
virtual double distance(const double *value1, const double *value2) const =0
Compute the distance between two joint states of the same model (represented by the variable values)
bool enforceVelocityBounds(double *values) const
Force the specified velocities to be within bounds. Return true if changes were made.
Definition: joint_model.h:320
virtual void computeTransform(const double *joint_values, Eigen::Isometry3d &transf) const =0
Given the joint values for a joint, compute the corresponding transform. The computed transform is gu...
bool enforcePositionBounds(double *values) const
Force the specified values to be inside bounds and normalized. Quaternions are normalized,...
Definition: joint_model.h:292
JointType getType() const
Get the type of joint.
Definition: joint_model.h:151
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:72
int getFirstCollisionBodyTransformIndex() const
Definition: link_model.h:97
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
const Eigen::Isometry3d & getVisualMeshOrigin() const
Get the transform for the visual mesh origin.
Definition: link_model.h:224
const std::vector< shapes::ShapeConstPtr > & getShapes() const
Get shape associated to the collision geometry for this link.
Definition: link_model.h:176
const Eigen::Vector3d & getVisualMeshScale() const
Get the scale of the mesh resource for this link.
Definition: link_model.h:218
const JointModel * getParentJointModel() const
Get the joint model whose child this link is. There will always be a parent joint.
Definition: link_model.h:108
const std::string & getName() const
The name of this link.
Definition: link_model.h:86
const Eigen::Isometry3d & getJointOriginTransform() const
When transforms are computed for this link, they are usually applied to the link's origin....
Definition: link_model.h:143
const LinkModel * getParentLinkModel() const
Get the link model whose child this link is (through some joint). There may not always be a parent li...
Definition: link_model.h:117
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...
Definition: link_model.h:128
size_t getLinkIndex() const
The index of this joint when traversing the kinematic tree in depth first fashion.
Definition: link_model.h:92
const std::string & getVisualMeshFilename() const
Get the filename of the mesh resource used for visual display of this link.
Definition: link_model.h:212
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
void zeroVelocities()
Set all velocities to 0.0.
RobotState & operator=(const RobotState &other)
Copy operator.
void setJointEfforts(const JointModel *joint, const double *effort)
void setAttachedBodyUpdateCallback(const AttachedBodyCallback &callback)
void setJointVelocities(const JointModel *joint, const double *velocity)
void printTransforms(std::ostream &out=std::cout) const
void printTransform(const Eigen::Isometry3d &transform, std::ostream &out=std::cout) const
const double * getJointEffort(const std::string &joint_name) const
Definition: robot_state.h:567
const LinkModel * getLinkModel(const std::string &link) const
Get the model of a particular link.
Definition: robot_state.h:122
void attachBody(std::unique_ptr< AttachedBody > attached_body)
Add an attached body to this state.
const Eigen::Isometry3d & getGlobalLinkTransform(const std::string &link_name)
Get the link transform w.r.t. the root link (model frame) of the RobotModel. This is typically the ro...
Definition: robot_state.h:1246
void updateStateWithLinkAt(const std::string &link_name, const Eigen::Isometry3d &transform, bool backward=false)
Update the state after setting a particular link to the input global transform pose.
Definition: robot_state.h:1221
bool getJacobian(const JointModelGroup *group, const LinkModel *link, const Eigen::Vector3d &reference_point_position, Eigen::MatrixXd &jacobian, bool use_quaternion_representation=false) const
Compute the Jacobian with reference to a particular point on a given link, for a specified group.
const double * getJointPositions(const std::string &joint_name) const
Definition: robot_state.h:543
std::pair< double, const JointModel * > getMinDistanceToPositionBounds() const
Get the minimm distance from this state to the bounds. The minimum distance and the joint for which t...
void copyJointGroupVelocities(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the velocity values of the variables that make up the group into another loca...
Definition: robot_state.h:769
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
const Eigen::Isometry3d & getJointTransform(const std::string &joint_name)
Definition: robot_state.h:1308
void setJointGroupAccelerations(const std::string &joint_group_name, const double *gstate)
Given accelerations for the variables that make up a group, in the order found in the group (includin...
Definition: robot_state.h:826
void setJointGroupVelocities(const std::string &joint_group_name, const double *gstate)
Given velocities for the variables that make up a group, in the order found in the group (including v...
Definition: robot_state.h:726
void computeVariableVelocity(const JointModelGroup *jmg, Eigen::VectorXd &qdot, const Eigen::VectorXd &twist, const LinkModel *tip) const
Given a twist for a particular link (tip), compute the corresponding velocity for every variable and ...
void computeAABB(std::vector< double > &aabb) const
Compute an axis-aligned bounding box that contains the current state. The format for aabb is (minx,...
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
Definition: robot_state.h:583
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
Definition: robot_state.h:669
bool clearAttachedBody(const std::string &id)
Remove the attached body named id. Return false if the object was not found (and thus not removed)....
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
Definition: robot_state.h:104
void harmonizePositions()
Call harmonizePosition() for all joints / all joints in group / given joint.
void setVariableVelocities(const double *velocity)
Given an array with velocity values for all variables, set those values as the velocities in this sta...
Definition: robot_state.h:253
bool dirtyCollisionBodyTransforms() const
Definition: robot_state.h:1336
void zeroAccelerations()
Set all accelerations to 0.0.
bool isValidVelocityMove(const RobotState &other, const JointModelGroup *group, double dt) const
Check that the time to move between two waypoints is sufficient given velocity limits and time step.
bool setFromDiffIK(const JointModelGroup *group, const Eigen::VectorXd &twist, const std::string &tip, double dt, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn())
Set the joint values from a Cartesian velocity applied during a time dt.
double * getVariablePositions()
Get a raw pointer to the positions of the variables stored in this state. Use carefully....
Definition: robot_state.h:147
void printStatePositionsWithJointLimits(const moveit::core::JointModelGroup *jmg, std::ostream &out=std::cout) const
Output to console the current state of the robot's joint limits.
const double * getJointVelocities(const std::string &joint_name) const
Definition: robot_state.h:551
void dropDynamics()
Reduce RobotState to kinematic information (remove velocity, acceleration and effort,...
bool dirtyJointTransform(const JointModel *joint) const
Definition: robot_state.h:1326
void setToRandomPositionsNearBy(const JointModelGroup *group, const RobotState &seed, double distance)
Set all joints in group to random values near the value in seed. distance is the maximum amount each ...
bool dirty() const
Returns true if anything in this state is dirty.
Definition: robot_state.h:1342
void updateLinkTransforms()
Update the reference frame transforms for links. This call is needed before using the transforms of l...
void interpolate(const RobotState &to, double t, RobotState &state) const
double distance(const RobotState &other) const
Return the sum of joint distances to "other" state. An L1 norm. Only considers active joints.
Definition: robot_state.h:1354
std::string getStateTreeString() const
const Eigen::Isometry3d & getFrameTransform(const std::string &frame_id, bool *frame_found=nullptr)
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
void setToRandomPositions()
Set all joints to random values. Values will be within default bounds.
bool satisfiesBounds(double margin=0.0) const
void setVariableEffort(const double *effort)
Given an array with effort values for all variables, set those values as the effort in this state.
Definition: robot_state.h:445
void setJointGroupActivePositions(const JointModelGroup *group, const std::vector< double > &gstate)
Given positions for the variables of active joints that make up a group, in the order found in the gr...
bool dirtyLinkTransforms() const
Definition: robot_state.h:1331
void printStateInfo(std::ostream &out=std::cout) const
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Definition: robot_state.h:207
void update(bool force=false)
Update all transforms.
void dropAccelerations()
Remove accelerations from this state (this differs from setting them to zero)
void getRobotMarkers(visualization_msgs::msg::MarkerArray &arr, const std::vector< std::string > &link_names, const std_msgs::msg::ColorRGBA &color, const std::string &ns, const rclcpp::Duration &dur, bool include_attached=false) const
Get a MarkerArray that fully describes the robot markers for a given robot.
const AttachedBody * getAttachedBody(const std::string &name) const
Get the attached body named name. Return nullptr if not found.
bool setFromIKSubgroups(const JointModelGroup *group, const EigenSTL::vector_Isometry3d &poses, const std::vector< std::string > &tips, const std::vector< std::vector< double >> &consistency_limits, double timeout=0.0, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions())
setFromIK for multiple poses and tips (end effectors) when no solver exists for the jmg that can solv...
bool setToIKSolverFrame(Eigen::Isometry3d &pose, const kinematics::KinematicsBaseConstPtr &solver)
Transform pose from the robot model's base frame to the reference frame of the IK solver.
void setToDefaultValues()
Set all joints to their default positions. The default position is 0, or if that is not within bounds...
void printStatePositions(std::ostream &out=std::cout) const
std::size_t getVariableCount() const
Get the number of variables that make up this state.
Definition: robot_state.h:110
void printDirtyInfo(std::ostream &out=std::cout) const
void setVariableAccelerations(const double *acceleration)
Given an array with acceleration values for all variables, set those values as the accelerations in t...
Definition: robot_state.h:348
void copyJointGroupAccelerations(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the acceleration values of the variables that make up the group into another ...
Definition: robot_state.h:869
RobotState(const RobotModelConstPtr &robot_model)
A state can be constructed from a specified robot model. No values are initialized....
Definition: robot_state.cpp:66
void dropEffort()
Remove effort values from this state (this differs from setting them to zero)
bool knowsFrameTransform(const std::string &frame_id) const
Check if a transformation matrix from the model frame (root of model) to frame frame_id is known.
bool integrateVariableVelocity(const JointModelGroup *jmg, const Eigen::VectorXd &qdot, double dt, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn())
Given the velocities for the variables in this group (qdot) and an amount of time (dt),...
const double * getJointAccelerations(const std::string &joint_name) const
Definition: robot_state.h:559
void enforcePositionBounds(const JointModel *joint)
bool hasAttachedBody(const std::string &id) const
Check if an attached body named id exists in this state.
void enforceVelocityBounds(const JointModel *joint)
random_numbers::RandomNumberGenerator & getRandomNumberGenerator()
Return the instance of a random number generator.
Definition: robot_state.h:1562
void invertVelocity()
Invert velocity if present.
const Eigen::Isometry3d & getFrameInfo(const std::string &frame_id, const LinkModel *&robot_link, bool &frame_found) const
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
void harmonizePosition(const JointModel *joint)
void clearAttachedBodies()
Clear all attached bodies. This calls delete on the AttachedBody instances, if needed.
void dropVelocities()
Remove velocities from this state (this differs from setting them to zero)
void zeroEffort()
Set all effort values to 0.0.
const moveit::core::LinkModel * getRigidlyConnectedParentLinkModel(const std::string &frame) const
Get the latest link upwards the kinematic tree which is only connected via fixed joints.
void updateCollisionBodyTransforms()
Update the transforms for the collision bodies. This call is needed before calling collision checking...
bool setFromIK(const JointModelGroup *group, const geometry_msgs::msg::Pose &pose, double timeout=0.0, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions(), const kinematics::KinematicsBase::IKCostFn &cost_function=kinematics::KinematicsBase::IKCostFn())
If the group this state corresponds to is a chain and a solver is available, then the joint values ca...
void setJointPositions(const std::string &joint_name, const double *position)
Definition: robot_state.h:515
static bool sameFrame(const std::string &frame1, const std::string &frame2)
Check if two frames end up being the same once the missing / are added as prefix (if they are missing...
Definition: transforms.cpp:70
#define MOVEIT_CONSOLE_COLOR_RESET
#define MOVEIT_CONSOLE_COLOR_RED
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
std::function< bool(RobotState *robot_state, const JointModelGroup *joint_group, const double *joint_group_variable_values)> GroupStateValidityCallbackFn
Signature for functions that can verify that if the group joint_group in robot_state is set to joint_...
Definition: robot_state.h:70
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::ostream & operator<<(std::ostream &out, const VariableBounds &b)
Operator overload for printing variable bounds to a stream.
std::map< std::string, Eigen::Isometry3d, std::less< std::string >, Eigen::aligned_allocator< std::pair< const std::string, Eigen::Isometry3d > > > FixedTransformsMap
Map frame names to the transformation matrix that can transform objects from the frame name to the pl...
Definition: transforms.h:53
std::function< void(AttachedBody *body, bool attached)> AttachedBodyCallback
Definition: attached_body.h:51
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
Definition: world.h:49
A set of options for the kinematics solver.