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