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