moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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
47constexpr double EPSILON = 1e-2;
48constexpr double M_TAU = 2 * M_PI;
49
50class LoadPlanningModelsPr2 : public testing::Test
51{
52protected:
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
65protected:
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);
189 std::map<std::string, double> jv;
190 jv["base_joint/x"] = 0.433;
191 jv["base_joint/theta"] = -0.5;
193 moveit_msgs::msg::RobotState robot_state;
195
196 moveit::core::RobotState ks2(robot_model2);
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
219TEST_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);
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
268TEST_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);
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
354int 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 & getPose() const
Get the pose of the attached body relative to the parent link.
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 & getGlobalPose() const
Get the pose of the attached body, relative to the world.
const std::vector< std::string > & getSubgroupNames() const
Get the names of the groups that are subsets of this one (in terms of joints set)
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
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...
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
bool isSubgroup(const std::string &group) const
Check if the joints of group group are a subset of the joints in this group.
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
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 JointModel * getRootJoint() const
Get the root joint. There will be one root joint unless the model is empty. This is either extracted ...
const JointModelGroup * getJointModelGroup(const std::string &name) const
Get a joint group from this model (by name)
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
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....
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.
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.
Definition world.h:49
constexpr double M_TAU
int main(int argc, char **argv)
TEST_F(LoadPlanningModelsPr2, InitOK)
constexpr double EPSILON