moveit2
The MoveIt Motion Planning Framework for ROS 2.
test_kinematic_complex.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
40 #include <urdf_parser/urdf_parser.h>
41 #include <fstream>
42 #include <gtest/gtest.h>
43 #include <geometric_shapes/shapes.h>
44 
46 
47 constexpr double EPSILON = 1e-2;
48 constexpr double M_TAU = 2 * M_PI;
49 
50 class LoadPlanningModelsPr2 : public testing::Test
51 {
52 protected:
53  void SetUp() override
54  {
55  const std::string robot_name = "pr2";
58  robot_model_ = std::make_shared<moveit::core::RobotModel>(urdf_model_, srdf_model_);
59  };
60 
61  void TearDown() override
62  {
63  }
64 
65 protected:
66  urdf::ModelInterfaceSharedPtr urdf_model_;
67  srdf::ModelSharedPtr srdf_model_;
68  moveit::core::RobotModelPtr robot_model_;
69 };
70 
72 {
73  ASSERT_EQ(urdf_model_->getName(), "pr2");
74  ASSERT_EQ(srdf_model_->getName(), "pr2");
75 }
76 
78 {
79  auto srdf_model = std::make_shared<srdf::Model>();
80 
81  // with no world multidof we should get a fixed joint
82  moveit::core::RobotModel robot_model0(urdf_model_, srdf_model);
83  EXPECT_TRUE(robot_model0.getRootJoint()->getVariableCount() == 0);
84 
85  static const std::string SMODEL1 = "<?xml version=\"1.0\" ?>"
86  "<robot name=\"pr2\">"
87  "<virtual_joint name=\"base_joint\" child_link=\"base_footprint\" "
88  "parent_frame=\"base_footprint\" type=\"planar\"/>"
89  "</robot>";
90  srdf_model->initString(*urdf_model_, SMODEL1);
91 
92  moveit::core::RobotModel robot_model1(urdf_model_, srdf_model);
93  ASSERT_TRUE(robot_model1.getRootJoint() != nullptr);
94  EXPECT_EQ(robot_model1.getModelFrame(), "base_footprint");
95 
96  static const std::string SMODEL2 = "<?xml version=\"1.0\" ?>"
97  "<robot name=\"pr2\">"
98  "<virtual_joint name=\"world_joint\" child_link=\"base_footprint\" "
99  "parent_frame=\"odom_combined\" type=\"floating\"/>"
100  "</robot>";
101  srdf_model->initString(*urdf_model_, SMODEL2);
102 
103  moveit::core::RobotModel robot_model2(urdf_model_, srdf_model);
104  ASSERT_TRUE(robot_model2.getRootJoint() != nullptr);
105  EXPECT_EQ(robot_model2.getModelFrame(), "odom_combined");
106 }
107 
109 {
110  static const std::string SMODEL1 = "<?xml version=\"1.0\" ?>"
111  "<robot name=\"pr2\">"
112  "<virtual_joint name=\"base_joint\" child_link=\"base_footprint\" "
113  "parent_frame=\"base_footprint\" type=\"planar\"/>"
114  "<group name=\"left_arm_base_tip\">"
115  "<chain base_link=\"monkey_base\" tip_link=\"monkey_tip\"/>"
116  "</group>"
117  "<group name=\"left_arm_joints\">"
118  "<joint name=\"l_monkey_pan_joint\"/>"
119  "<joint name=\"l_monkey_fles_joint\"/>"
120  "</group>"
121  "</robot>";
122 
123  auto srdf_model = std::make_shared<srdf::Model>();
124  srdf_model->initString(*urdf_model_, SMODEL1);
125  moveit::core::RobotModel robot_model1(urdf_model_, srdf_model);
126 
127  const moveit::core::JointModelGroup* left_arm_base_tip_group = robot_model1.getJointModelGroup("left_arm_base_tip");
128  ASSERT_TRUE(left_arm_base_tip_group == nullptr);
129 
130  const moveit::core::JointModelGroup* left_arm_joints_group = robot_model1.getJointModelGroup("left_arm_joints");
131  ASSERT_TRUE(left_arm_joints_group == nullptr);
132 
133  static const std::string SMODEL2 = "<?xml version=\"1.0\" ?>"
134  "<robot name=\"pr2\">"
135  "<virtual_joint name=\"base_joint\" child_link=\"base_footprint\" "
136  "parent_frame=\"base_footprint\" type=\"planar\"/>"
137  "<group name=\"left_arm_base_tip\">"
138  "<chain base_link=\"torso_lift_link\" tip_link=\"l_wrist_roll_link\"/>"
139  "</group>"
140  "<group name=\"left_arm_joints\">"
141  "<joint name=\"l_shoulder_pan_joint\"/>"
142  "<joint name=\"l_shoulder_lift_joint\"/>"
143  "<joint name=\"l_upper_arm_roll_joint\"/>"
144  "<joint name=\"l_elbow_flex_joint\"/>"
145  "<joint name=\"l_forearm_roll_joint\"/>"
146  "<joint name=\"l_wrist_flex_joint\"/>"
147  "<joint name=\"l_wrist_roll_joint\"/>"
148  "</group>"
149  "</robot>";
150  srdf_model->initString(*urdf_model_, SMODEL2);
151 
152  auto robot_model2 = std::make_shared<moveit::core::RobotModel>(urdf_model_, srdf_model);
153 
154  left_arm_base_tip_group = robot_model2->getJointModelGroup("left_arm_base_tip");
155  ASSERT_TRUE(left_arm_base_tip_group != nullptr);
156 
157  left_arm_joints_group = robot_model2->getJointModelGroup("left_arm_joints");
158  ASSERT_TRUE(left_arm_joints_group != nullptr);
159 
160  EXPECT_EQ(left_arm_base_tip_group->getJointModels().size(), 9u);
161  EXPECT_EQ(left_arm_joints_group->getJointModels().size(), 7u);
162 
163  EXPECT_EQ(left_arm_joints_group->getVariableNames().size(), left_arm_joints_group->getVariableCount());
164  EXPECT_EQ(left_arm_joints_group->getVariableCount(), 7u);
165 
166  EXPECT_EQ(robot_model2->getVariableNames().size(), robot_model2->getVariableCount());
167 
168  bool found_shoulder_pan_link = false;
169  bool found_wrist_roll_link = false;
170  for (const moveit::core::LinkModel* link_model : left_arm_base_tip_group->getLinkModels())
171  {
172  if (link_model->getName() == "l_shoulder_pan_link")
173  {
174  EXPECT_TRUE(!found_shoulder_pan_link);
175  found_shoulder_pan_link = true;
176  }
177  if (link_model->getName() == "l_wrist_roll_link")
178  {
179  EXPECT_TRUE(!found_wrist_roll_link);
180  found_wrist_roll_link = true;
181  }
182  EXPECT_TRUE(link_model->getName() != "torso_lift_link");
183  }
184  EXPECT_TRUE(found_shoulder_pan_link);
185  EXPECT_TRUE(found_wrist_roll_link);
186 
187  moveit::core::RobotState ks(robot_model2);
188  ks.setToDefaultValues();
189  std::map<std::string, double> jv;
190  jv["base_joint/x"] = 0.433;
191  jv["base_joint/theta"] = -0.5;
192  ks.setVariablePositions(jv);
193  moveit_msgs::msg::RobotState robot_state;
195 
196  moveit::core::RobotState ks2(robot_model2);
197  moveit::core::robotStateMsgToRobotState(robot_state, ks2);
198 
199  const double* v1 = ks.getVariablePositions();
200  const double* v2 = ks2.getVariablePositions();
201  for (std::size_t i = 0; i < ks.getVariableCount(); ++i)
202  EXPECT_NEAR(v1[i], v2[i], 1e-5);
203 }
204 
206 {
207  moveit::core::RobotModel robot_model(urdf_model_, srdf_model_);
208  const moveit::core::JointModelGroup* jmg = robot_model.getJointModelGroup("arms");
209  ASSERT_TRUE(jmg);
210  EXPECT_EQ(jmg->getSubgroupNames().size(), 2u);
211  EXPECT_TRUE(jmg->isSubgroup("right_arm"));
212 
213  const moveit::core::JointModelGroup* jmg2 = robot_model.getJointModelGroup("whole_body");
214  EXPECT_EQ(jmg2->getSubgroupNames().size(), 5u);
215  EXPECT_TRUE(jmg2->isSubgroup("arms"));
216  EXPECT_TRUE(jmg2->isSubgroup("right_arm"));
217 }
218 
219 TEST_F(LoadPlanningModelsPr2, AssociatedFixedLinks)
220 {
221  auto model = std::make_shared<moveit::core::RobotModel>(urdf_model_, srdf_model_);
222  EXPECT_TRUE(model->getLinkModel("r_gripper_palm_link")->getAssociatedFixedTransforms().size() > 1);
223 }
224 
226 {
227  auto robot_model = std::make_shared<moveit::core::RobotModel>(urdf_model_, srdf_model_);
228 
229  moveit::core::RobotState ks(robot_model);
230  ks.setToDefaultValues();
231 
232  moveit::core::RobotState ks2(robot_model);
233  ks2.setToDefaultValues();
234 
235  const auto identity = Eigen::Isometry3d::Identity();
236  std::vector<shapes::ShapeConstPtr> shapes;
237  EigenSTL::vector_Isometry3d poses;
238  shapes::Shape* shape = new shapes::Box(.1, .1, .1);
239  shapes.push_back(shapes::ShapeConstPtr(shape));
240  poses.push_back(identity);
241  std::set<std::string> touch_links;
242 
243  trajectory_msgs::msg::JointTrajectory empty_state;
244 
245  ks.attachBody(std::make_unique<moveit::core::AttachedBody>(robot_model->getLinkModel("r_gripper_palm_link"), "box",
246  identity, shapes, poses, touch_links, empty_state));
247 
248  std::vector<const moveit::core::AttachedBody*> attached_bodies_1;
249  ks.getAttachedBodies(attached_bodies_1);
250  ASSERT_EQ(attached_bodies_1.size(), 1u);
251 
252  std::vector<const moveit::core::AttachedBody*> attached_bodies_2;
253  ks2 = ks;
254  ks2.getAttachedBodies(attached_bodies_2);
255  ASSERT_EQ(attached_bodies_2.size(), 1u);
256 
257  ks.clearAttachedBody("box");
258  attached_bodies_1.clear();
259  ks.getAttachedBodies(attached_bodies_1);
260  ASSERT_EQ(attached_bodies_1.size(), 0u);
261 
262  ks2 = ks;
263  attached_bodies_2.clear();
264  ks2.getAttachedBodies(attached_bodies_2);
265  ASSERT_EQ(attached_bodies_2.size(), 0u);
266 }
267 
268 TEST_F(LoadPlanningModelsPr2, ObjectPoseAndSubframes)
269 {
270  auto robot_model = std::make_shared<moveit::core::RobotModel>(urdf_model_, srdf_model_);
271 
272  moveit::core::RobotState ks(robot_model);
273  ks.setToDefaultValues();
274 
275  std::vector<shapes::ShapeConstPtr> shapes;
276  EigenSTL::vector_Isometry3d poses;
277  shapes::Shape* shape = new shapes::Box(.1, .1, .1);
278  shapes.push_back(shapes::ShapeConstPtr(shape));
279  poses.push_back(Eigen::Isometry3d::Identity());
280  std::set<std::string> touch_links;
281  Eigen::Isometry3d pose_a = Eigen::Isometry3d::Identity();
282  Eigen::Isometry3d pose_b = Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1));
284  subframes["frame1"] = Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1));
285 
286  trajectory_msgs::msg::JointTrajectory empty_state;
287  ks.attachBody(std::make_unique<moveit::core::AttachedBody>(robot_model->getLinkModel("r_gripper_palm_link"), "boxA",
288  pose_a, shapes, poses, touch_links, empty_state,
289  subframes));
290  ks.attachBody(std::make_unique<moveit::core::AttachedBody>(robot_model->getLinkModel("r_gripper_palm_link"), "boxB",
291  pose_b, shapes, poses, touch_links, empty_state,
292  subframes));
293 
294  // Check position of shape in each body
295  Eigen::Isometry3d p;
296  p = ks.getAttachedBody("boxA")->getShapePosesInLinkFrame()[0];
297  EXPECT_EQ(0.0, p(2, 3)); // check translation.z
298  p = ks.getAttachedBody("boxB")->getShapePosesInLinkFrame()[0];
299  EXPECT_EQ(1.0, p(2, 3)); // z
300 
301  // Expect the pose and the subframe to have the same effect
302  Eigen::Isometry3d p2;
303 
304  p = ks.getFrameTransform("boxA/frame1");
305  p2 = ks.getFrameTransform("boxB");
306  EXPECT_TRUE(p.isApprox(p2, EPSILON));
307 
308  // Ensure that conversion to and from message in conversions.cpp works
309  moveit_msgs::msg::RobotState msg;
310  robotStateToRobotStateMsg(ks, msg, true);
311 
312  // Add another object C that is defined in a frame that is not the link.
313  // The object will be transformed into the link's frame, which
314  // uses an otherwise inactive section of _msgToAttachedBody.
315  Eigen::Isometry3d pose_c = Eigen::Isometry3d(Eigen::Translation3d(0.1, 0.2, 0.3)) *
316  Eigen::AngleAxisd(0.1 * M_TAU, Eigen::Vector3d::UnitX()) *
317  Eigen::AngleAxisd(0.2 * M_TAU, Eigen::Vector3d::UnitY()) *
318  Eigen::AngleAxisd(0.4 * M_TAU, Eigen::Vector3d::UnitZ());
319  Eigen::Quaterniond q(pose_c.linear());
320  moveit_msgs::msg::AttachedCollisionObject new_aco = msg.attached_collision_objects[0];
321  new_aco.object.id = "boxC";
322  new_aco.object.header.frame_id = "r_shoulder_pan_link";
323  new_aco.object.pose.position.x = pose_c.translation()[0];
324  new_aco.object.pose.position.y = pose_c.translation()[1];
325  new_aco.object.pose.position.z = pose_c.translation()[2];
326  new_aco.object.pose.orientation.x = q.vec()[0];
327  new_aco.object.pose.orientation.y = q.vec()[1];
328  new_aco.object.pose.orientation.z = q.vec()[2];
329  new_aco.object.pose.orientation.w = q.w();
330  msg.attached_collision_objects.push_back(new_aco);
331 
332  // Confirm that object B is unchanged after the conversion
333  moveit::core::RobotState ks3(robot_model);
334  robotStateMsgToRobotState(msg, ks3, true);
335  Eigen::Isometry3d p_original, p_reconverted;
336  p_original = ks.getAttachedBody("boxB")->getPose();
337  p_reconverted = ks3.getAttachedBody("boxB")->getPose();
338  EXPECT_TRUE(p_original.isApprox(p_reconverted, EPSILON));
339 
340  // Confirm that the position of object C is what we expect
341  Eigen::Isometry3d p_link, p_header_frame;
342  p_link = ks3.getFrameTransform("r_gripper_palm_link");
343  p_header_frame = ks3.getFrameTransform("r_shoulder_pan_link");
344 
345  p = p_header_frame * pose_c; // Object pose in world
346  p2 = ks3.getAttachedBody("boxC")->getGlobalPose();
347  EXPECT_TRUE(p.isApprox(p2, EPSILON));
348 
349  p = p_link.inverse() * p_header_frame * pose_c; // Object pose in link frame
350  p2 = ks3.getAttachedBody("boxC")->getPose();
351  EXPECT_TRUE(p.isApprox(p2, EPSILON));
352 }
353 
354 int main(int argc, char** argv)
355 {
356  testing::InitGoogleTest(&argc, argv);
357  return RUN_ALL_TESTS();
358 }
moveit::core::RobotModelPtr robot_model_
urdf::ModelInterfaceSharedPtr urdf_model_
srdf::ModelSharedPtr srdf_model_
const Eigen::Isometry3d & getGlobalPose() const
Get the pose of the attached body, relative to the world.
Definition: attached_body.h:86
const EigenSTL::vector_Isometry3d & getShapePosesInLinkFrame() const
Get the fixed transforms (the transforms to the shapes of this body, relative to the link)....
const Eigen::Isometry3d & getPose() const
Get the pose of the attached body relative to the parent link.
Definition: attached_body.h:80
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up the joints included in this group. The number of returned...
const std::vector< std::string > & getSubgroupNames() const
Get the names of the groups that are subsets of this one (in terms of joints set)
bool isSubgroup(const std::string &group) const
Check if the joints of group group are a subset of the joints in this group.
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
Definition: joint_model.h:210
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:72
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
Definition: robot_model.h:76
const std::string & getModelFrame() const
Get the frame in which the transforms for this model are computed (when using a RobotState)....
Definition: robot_model.h:94
const JointModel * getRootJoint() const
Get the root joint. There will be one root joint unless the model is empty. This is either extracted ...
Definition: robot_model.cpp:72
const JointModelGroup * getJointModelGroup(const std::string &name) const
Get a joint group from this model (by name)
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
void attachBody(std::unique_ptr< AttachedBody > attached_body)
Add an attached body to this state.
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
bool clearAttachedBody(const std::string &id)
Remove the attached body named id. Return false if the object was not found (and thus not removed)....
double * getVariablePositions()
Get a raw pointer to the positions of the variables stored in this state. Use carefully....
Definition: robot_state.h:147
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...
const AttachedBody * getAttachedBody(const std::string &name) const
Get the attached body named name. Return nullptr if not found.
void setToDefaultValues()
Set all joints to their default positions. The default position is 0, or if that is not within bounds...
std::size_t getVariableCount() const
Get the number of variables that make up this state.
Definition: robot_state.h:110
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
srdf::ModelSharedPtr loadSRDFModel(const std::string &robot_name)
Loads an SRDF Model from moveit_resources.
urdf::ModelInterfaceSharedPtr loadModelInterface(const std::string &robot_name)
Loads a URDF Model Interface from moveit_resources.
std::map< std::string, Eigen::Isometry3d, std::less< std::string >, Eigen::aligned_allocator< std::pair< const std::string, Eigen::Isometry3d > > > FixedTransformsMap
Map frame names to the transformation matrix that can transform objects from the frame name to the pl...
Definition: transforms.h:53
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::msg::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
Convert a robot state msg (with accompanying extra transforms) to a MoveIt robot state.
p
Definition: pick.py:62
Definition: world.h:49
constexpr double M_TAU
int main(int argc, char **argv)
TEST_F(LoadPlanningModelsPr2, InitOK)
constexpr double EPSILON