moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
test_world.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2012, 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 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: Acorn Pooley */
36
37#include <gtest/gtest.h>
39#include <geometric_shapes/shapes.h>
40#include <functional>
41
42using namespace collision_detection;
43
44TEST(World, AddRemoveShape)
45{
46 World world;
47
48 // Create some shapes
49 shapes::ShapePtr ball = std::make_shared<shapes::Sphere>(1.0);
50 shapes::ShapePtr box = std::make_shared<shapes::Box>(1, 2, 3);
51 shapes::ShapePtr cyl = std::make_shared<shapes::Cylinder>(4, 5);
52
53 EXPECT_EQ(1, ball.use_count());
54
55 EXPECT_FALSE(world.hasObject("ball"));
56
57 // Add ball object
58 world.addToObject("ball", ball, Eigen::Isometry3d::Identity());
59
60 EXPECT_EQ(2, ball.use_count());
61 EXPECT_TRUE(world.hasObject("ball"));
62
63 bool move_ok = world.moveShapeInObject("ball", ball, Eigen::Isometry3d(Eigen::Translation3d(0, 0, 9)));
64 EXPECT_TRUE(move_ok);
65
66 EXPECT_EQ(2, ball.use_count());
67 EXPECT_TRUE(world.hasObject("ball"));
68
69 bool rm_nonexistant = world.removeShapeFromObject("xyz", ball);
70 EXPECT_FALSE(rm_nonexistant);
71
72 bool rm_wrong_shape = world.removeShapeFromObject("ball", box);
73 EXPECT_FALSE(rm_wrong_shape);
74
75 EXPECT_EQ(2, ball.use_count());
76 EXPECT_EQ(1, box.use_count());
77
78 // remove ball object
79 bool rm_ball = world.removeShapeFromObject("ball", ball);
80 EXPECT_TRUE(rm_ball);
81
82 EXPECT_EQ(1, ball.use_count());
83 EXPECT_FALSE(world.hasObject("ball"));
84
85 // add ball again
86 world.addToObject("ball", ball, Eigen::Isometry3d::Identity());
87
88 EXPECT_EQ(2, ball.use_count());
89 EXPECT_TRUE(world.hasObject("ball"));
90
91 EXPECT_FALSE(world.hasObject("mix1"));
92
93 {
94 std::vector<shapes::ShapeConstPtr> shapes;
95 EigenSTL::vector_Isometry3d poses;
96
97 shapes.push_back(box);
98 shapes.push_back(cyl);
99 shapes.push_back(ball);
100
101 poses.push_back(Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1)));
102 poses.push_back(Eigen::Isometry3d(Eigen::Translation3d(0, 0, 2)));
103 poses.push_back(Eigen::Isometry3d(Eigen::Translation3d(0, 0, 3)));
104
105 EXPECT_FALSE(world.hasObject("mix1"));
106
107 // add mix1 object
108 world.addToObject("mix1", shapes, poses);
109 }
110
111 EXPECT_TRUE(world.hasObject("mix1"));
112
113 EXPECT_EQ(2, box.use_count());
114 EXPECT_EQ(2, cyl.use_count());
115 EXPECT_EQ(3, ball.use_count());
116
117 // add ball2
118 world.addToObject("ball2", ball, Eigen::Isometry3d(Eigen::Translation3d(0, 0, 4)));
119
120 EXPECT_EQ(2, box.use_count());
121 EXPECT_EQ(2, cyl.use_count());
122 EXPECT_EQ(4, ball.use_count());
123
124 bool rm_cyl = world.removeShapeFromObject("mix1", cyl);
125 EXPECT_TRUE(rm_cyl);
126
127 EXPECT_EQ(2, box.use_count());
128 EXPECT_EQ(1, cyl.use_count());
129 EXPECT_EQ(4, ball.use_count());
130
131 rm_cyl = world.removeShapeFromObject("mix1", cyl);
132 EXPECT_FALSE(rm_cyl);
133
134 EXPECT_EQ(2, box.use_count());
135 EXPECT_EQ(1, cyl.use_count());
136 EXPECT_EQ(4, ball.use_count());
137
138 EXPECT_TRUE(world.hasObject("mix1"));
139
140 EXPECT_EQ(3u, world.size());
141
142 {
143 World::ObjectConstPtr obj = world.getObject("mix1");
144 EXPECT_EQ(2, obj.use_count());
145
146 ASSERT_EQ(2u, obj->shapes_.size());
147 ASSERT_EQ(2u, obj->shape_poses_.size());
148
149 // check translation.z of pose
150 EXPECT_EQ(1.0, obj->shape_poses_[0](2, 3));
151 EXPECT_EQ(3.0, obj->shape_poses_[1](2, 3));
152
153 move_ok = world.moveShapeInObject("mix1", ball, Eigen::Isometry3d(Eigen::Translation3d(0, 0, 5)));
154 EXPECT_TRUE(move_ok);
155
156 World::ObjectConstPtr obj2 = world.getObject("mix1");
157 EXPECT_EQ(2, obj2.use_count());
158 EXPECT_EQ(1, obj.use_count());
159
160 EXPECT_EQ(1.0, obj2->shape_poses_[0](2, 3));
161 EXPECT_EQ(5.0, obj2->shape_poses_[1](2, 3));
162
163 EXPECT_EQ(1.0, obj->shape_poses_[0](2, 3));
164 EXPECT_EQ(3.0, obj->shape_poses_[1](2, 3));
165
166 // moving object causes copy, thus extra references to shapes in obj
167 EXPECT_EQ(3, box.use_count());
168 EXPECT_EQ(1, cyl.use_count());
169 EXPECT_EQ(5, ball.use_count());
170
171 world.removeObject("mix1");
172
173 EXPECT_EQ(2u, world.size());
174
175 // no change since obj2 still holds a ref
176 EXPECT_EQ(3, box.use_count());
177 EXPECT_EQ(1, cyl.use_count());
178 EXPECT_EQ(5, ball.use_count());
179
180 EXPECT_FALSE(world.hasObject("mix1"));
181 EXPECT_TRUE(world.hasObject("ball2"));
182
183 // ask for nonexistent object
184 World::ObjectConstPtr obj3 = world.getObject("abc");
185 EXPECT_FALSE(obj3);
186 }
187
188 EXPECT_EQ(1, box.use_count());
189 EXPECT_EQ(1, cyl.use_count());
190 EXPECT_EQ(3, ball.use_count());
191
192 EXPECT_EQ(2u, world.size());
193
194 world.clearObjects();
195
196 EXPECT_EQ(1, box.use_count());
197 EXPECT_EQ(1, cyl.use_count());
198 EXPECT_EQ(1, ball.use_count());
199
200 EXPECT_FALSE(world.hasObject("mix1"));
201 EXPECT_FALSE(world.hasObject("ball"));
202 EXPECT_FALSE(world.hasObject("ball2"));
203
204 EXPECT_EQ(0u, world.size());
205}
206
207/* structure to hold copy of callback args */
209{
212 int cnt_;
213 TestAction() : obj_(""), cnt_(0)
214 {
215 reset();
216 }
217 void reset()
218 {
219 obj_.id_ = "";
220 obj_.shapes_.clear();
221 obj_.shape_poses_.clear();
222 action_ = 0x7f;
223 }
224};
225
226/* notification callback */
227static void trackChangesNotify(TestAction& ta, const World::ObjectConstPtr& obj, World::Action action)
228{
229 ta.obj_ = *obj;
230 ta.action_ = action;
231 ta.cnt_++;
232}
233
234TEST(World, TrackChanges)
235{
236 World world;
237
238 TestAction ta;
239 World::ObserverHandle observer_ta;
240 observer_ta = world.addObserver([&ta](const World::ObjectConstPtr& object, World::Action action) {
241 return trackChangesNotify(ta, object, action);
242 });
243
244 // Create some shapes
245 shapes::ShapePtr ball = std::make_shared<shapes::Sphere>(1.0);
246 shapes::ShapePtr box = std::make_shared<shapes::Box>(1, 2, 3);
247 shapes::ShapePtr cyl = std::make_shared<shapes::Cylinder>(4, 5);
248
249 world.addToObject("obj1", ball, Eigen::Isometry3d::Identity());
250
251 EXPECT_EQ(1, ta.cnt_);
252 EXPECT_EQ("obj1", ta.obj_.id_);
253 EXPECT_EQ(World::CREATE | World::ADD_SHAPE, ta.action_);
254 ta.reset();
255
256 bool move_ok = world.moveShapeInObject("obj1", ball, Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1)));
257 EXPECT_TRUE(move_ok);
258
259 EXPECT_EQ(2, ta.cnt_);
260 EXPECT_EQ("obj1", ta.obj_.id_);
261 EXPECT_EQ(World::MOVE_SHAPE, ta.action_);
262 ta.reset();
263
264 world.addToObject("obj1", box, Eigen::Isometry3d::Identity());
265
266 EXPECT_EQ(3, ta.cnt_);
267 EXPECT_EQ("obj1", ta.obj_.id_);
268 EXPECT_EQ(World::ADD_SHAPE, ta.action_);
269 ta.reset();
270
271 TestAction ta2;
272 World::ObserverHandle observer_ta2;
273 observer_ta2 = world.addObserver([&ta2](const World::ObjectConstPtr& object, World::Action action) {
274 return trackChangesNotify(ta2, object, action);
275 });
276
277 world.addToObject("obj2", cyl, Eigen::Isometry3d::Identity());
278
279 EXPECT_EQ(4, ta.cnt_);
280 EXPECT_EQ("obj2", ta.obj_.id_);
281 EXPECT_EQ(World::CREATE | World::ADD_SHAPE, ta.action_);
282 ta.reset();
283 EXPECT_EQ(1, ta2.cnt_);
284 EXPECT_EQ("obj2", ta2.obj_.id_);
285 EXPECT_EQ(World::CREATE | World::ADD_SHAPE, ta2.action_);
286 ta2.reset();
287
288 world.addToObject("obj3", box, Eigen::Isometry3d::Identity());
289
290 EXPECT_EQ(5, ta.cnt_);
291 EXPECT_EQ("obj3", ta.obj_.id_);
292 EXPECT_EQ(World::CREATE | World::ADD_SHAPE, ta.action_);
293 ta.reset();
294 EXPECT_EQ(2, ta2.cnt_);
295 EXPECT_EQ("obj3", ta2.obj_.id_);
296 EXPECT_EQ(World::CREATE | World::ADD_SHAPE, ta2.action_);
297 ta2.reset();
298
299 // remove nonexistent obj
300 bool rm_bad = world.removeShapeFromObject("xyz", ball);
301 EXPECT_FALSE(rm_bad);
302 EXPECT_EQ(5, ta.cnt_);
303 EXPECT_EQ(2, ta2.cnt_);
304
305 // remove wrong shape
306 rm_bad = world.removeShapeFromObject("obj2", ball);
307 EXPECT_FALSE(rm_bad);
308 EXPECT_EQ(5, ta.cnt_);
309 EXPECT_EQ(2, ta2.cnt_);
310
311 TestAction ta3;
312 World::ObserverHandle observer_ta3;
313 observer_ta3 = world.addObserver([&ta3](const World::ObjectConstPtr& object, World::Action action) {
314 return trackChangesNotify(ta3, object, action);
315 });
316
317 bool rm_good = world.removeShapeFromObject("obj2", cyl);
318 EXPECT_TRUE(rm_good);
319
320 EXPECT_EQ(6, ta.cnt_);
321 EXPECT_EQ("obj2", ta.obj_.id_);
322 EXPECT_EQ(World::DESTROY, ta.action_);
323 ta.reset();
324 EXPECT_EQ(3, ta2.cnt_);
325 EXPECT_EQ("obj2", ta2.obj_.id_);
326 EXPECT_EQ(World::DESTROY, ta2.action_);
327 ta2.reset();
328 EXPECT_EQ(1, ta3.cnt_);
329 EXPECT_EQ("obj2", ta3.obj_.id_);
330 EXPECT_EQ(World::DESTROY, ta3.action_);
331 ta3.reset();
332
333 world.removeObserver(observer_ta2);
334
335 rm_good = world.removeShapeFromObject("obj1", ball);
336 EXPECT_TRUE(rm_good);
337
338 EXPECT_EQ(7, ta.cnt_);
339 EXPECT_EQ("obj1", ta.obj_.id_);
340 EXPECT_EQ(World::REMOVE_SHAPE, ta.action_);
341 ta.reset();
342 EXPECT_EQ(3, ta2.cnt_);
343
344 EXPECT_EQ(2, ta3.cnt_);
345 EXPECT_EQ("obj1", ta3.obj_.id_);
346 EXPECT_EQ(World::REMOVE_SHAPE, ta3.action_);
347 ta3.reset();
348
349 // remove all 2 objects (should make 2 DESTROY callbacks per ta)
350 world.clearObjects();
351
352 EXPECT_EQ(9, ta.cnt_);
353 EXPECT_EQ(World::DESTROY, ta.action_);
354 ta.reset();
355 EXPECT_EQ(3, ta2.cnt_);
356
357 EXPECT_EQ(4, ta3.cnt_);
358 EXPECT_EQ(World::DESTROY, ta3.action_);
359 ta3.reset();
360
361 world.removeObserver(observer_ta);
362 world.removeObserver(observer_ta3);
363
364 EXPECT_EQ(9, ta.cnt_);
365 EXPECT_EQ(3, ta2.cnt_);
366 EXPECT_EQ(4, ta3.cnt_);
367
368 world.addToObject("obj4", box, Eigen::Isometry3d::Identity());
369
370 EXPECT_EQ(9, ta.cnt_);
371 EXPECT_EQ(3, ta2.cnt_);
372 EXPECT_EQ(4, ta3.cnt_);
373}
374
375TEST(World, ObjectPoseAndSubframes)
376{
377 World world;
378
379 TestAction ta;
380 World::ObserverHandle observer_ta;
381 observer_ta = world.addObserver([&ta](const World::ObjectConstPtr& object, World::Action action) {
382 return trackChangesNotify(ta, object, action);
383 });
384
385 // Create shapes
386 shapes::ShapePtr ball = std::make_shared<shapes::Sphere>(1.0);
387 shapes::ShapePtr box = std::make_shared<shapes::Box>(1, 1, 1);
388 shapes::ShapePtr cyl = std::make_shared<shapes::Cylinder>(0.5, 3); // radius, length
389
390 // Confirm that setting object pose creates an object
391 world.setObjectPose("mix1", Eigen::Isometry3d::Identity());
392
393 EXPECT_EQ(1, ta.cnt_);
394 EXPECT_EQ("mix1", ta.obj_.id_);
395 EXPECT_EQ(World::CREATE, ta.action_);
396
397 // Move multi-shape objects, use object pose, use subframes
398 world.addToObject("mix1", box, Eigen::Isometry3d::Identity());
399 world.addToObject("mix1", cyl, Eigen::Isometry3d(Eigen::Translation3d(0, 0, 2)));
400
402 subframes["frame1"] = Eigen::Isometry3d(Eigen::Translation3d(0, 0, 2));
403 subframes["frame2"] = Eigen::Isometry3d(Eigen::Translation3d(0, 1, 0));
404 world.setSubframesOfObject("mix1", subframes);
405
406 // Check subframes and shape poses
407 bool found_ok, found_bad;
408 Eigen::Isometry3d pose = world.getTransform("mix1/frame1", found_ok);
409 EXPECT_TRUE(found_ok);
410 EXPECT_EQ(2.0, pose(2, 3)); // check translation.z
411
412 pose = world.getTransform("mix1/frame2", found_ok);
413 EXPECT_TRUE(found_ok);
414 EXPECT_EQ(1.0, pose(1, 3)); // check translation.y
415 EXPECT_EQ(0.0, pose(2, 3)); // z
416
417 pose = world.getTransform("mix1/frame3", found_bad);
418 EXPECT_FALSE(found_bad);
419
420 // Set new object pose, check that all shapes and subframes moved
421 world.setObjectPose("mix1", Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1)));
422
423 pose = world.getTransform("mix1/frame1", found_ok);
424 EXPECT_TRUE(found_ok);
425 EXPECT_EQ(3.0, pose(2, 3)); // z
426
427 pose = world.getTransform("mix1/frame2", found_ok);
428 EXPECT_TRUE(found_ok);
429 EXPECT_EQ(1.0, pose(1, 3)); // y
430 EXPECT_EQ(1.0, pose(2, 3)); // z
431
432 pose = world.getGlobalShapeTransform("mix1", 0);
433 EXPECT_TRUE(found_ok);
434 EXPECT_EQ(1.0, pose(2, 3)); // z
435
436 World::ObjectConstPtr obj = world.getObject("mix1");
437 EXPECT_EQ(0.0, obj->shape_poses_[0](2, 3)); // Internal shape poses do *not* change
438 EXPECT_EQ(2.0, obj->shape_poses_[1](2, 3));
439
440 // Shift object, check that object pose changed
441 world.moveObject("mix1", Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1)));
442
443 pose = world.getTransform("mix1", found_ok);
444 EXPECT_TRUE(found_ok);
445 EXPECT_EQ(2.0, pose(2, 3)); // z
446
447 pose = world.getTransform("mix1/frame1", found_ok);
448 EXPECT_TRUE(found_ok);
449 EXPECT_EQ(4.0, pose(2, 3)); // z
450
451 EXPECT_EQ(0.0, obj->shape_poses_[0](2, 3)); // Internal shape poses should still be constant
452 EXPECT_EQ(2.0, obj->shape_poses_[1](2, 3));
453
454 // Move object absolute, check object pose
455 world.setObjectPose("mix1", Eigen::Isometry3d(Eigen::Translation3d(0, 0, 1)));
456 pose = world.getTransform("mix1", found_ok);
457 EXPECT_TRUE(found_ok);
458 EXPECT_EQ(1.0, pose(2, 3)); // z
459}
460
461int main(int argc, char** argv)
462{
463 testing::InitGoogleTest(&argc, argv);
464 return RUN_ALL_TESTS();
465}
Represents an action that occurred on an object in the world. Several bits may be set indicating seve...
Definition world.h:268
Maintain a representation of the environment.
Definition world.h:59
const Eigen::Isometry3d & getTransform(const std::string &name) const
Get the transform to an object or subframe with given name. If name does not exist,...
Definition world.cpp:166
void removeObserver(const ObserverHandle observer_handle)
remove a notifier callback
Definition world.cpp:410
std::size_t size() const
Definition world.h:138
bool hasObject(const std::string &object_id) const
Check if a particular object exists in the collision world.
Definition world.cpp:137
bool removeObject(const std::string &object_id)
Remove a particular object. If there are no external pointers to the corresponding instance of Object...
Definition world.cpp:347
bool moveShapeInObject(const std::string &object_id, const shapes::ShapeConstPtr &shape, const Eigen::Isometry3d &shape_pose)
Update the pose of a shape in an object. Shape equality is verified by comparing pointers....
Definition world.cpp:238
bool removeShapeFromObject(const std::string &object_id, const shapes::ShapeConstPtr &shape)
Remove shape from object. Shape equality is verified by comparing pointers. Ownership of the object i...
Definition world.cpp:316
const Eigen::Isometry3d & getGlobalShapeTransform(const std::string &object_id, int shape_index) const
Get the global transform to a shape of an object with multiple shapes. shape_index is the index of th...
Definition world.cpp:208
void addToObject(const std::string &object_id, const Eigen::Isometry3d &pose, const std::vector< shapes::ShapeConstPtr > &shapes, const EigenSTL::vector_Isometry3d &shape_poses)
Add a pose and shapes to an object in the map. This function makes repeated calls to addToObjectInter...
Definition world.cpp:77
bool moveObject(const std::string &object_id, const Eigen::Isometry3d &transform)
Move the object pose (thus moving all shapes and subframes in the object) according to the given tran...
Definition world.cpp:282
ObserverHandle addObserver(const ObserverCallbackFn &callback)
register a callback function for notification of changes. callback will be called right after any cha...
Definition world.cpp:403
bool setObjectPose(const std::string &object_id, const Eigen::Isometry3d &pose)
Set the pose of an object. The pose is specified in the world frame.
Definition world.cpp:294
bool setSubframesOfObject(const std::string &object_id, const moveit::core::FixedTransformsMap &subframe_poses)
Set subframes on an object. The frames are relative to the object pose.
Definition world.cpp:365
void clearObjects()
Clear all objects. If there are no other pointers to corresponding instances of Objects,...
Definition world.cpp:359
ObjectConstPtr getObject(const std::string &object_id) const
Get a particular object.
Definition world.cpp:118
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
Definition world.h:49
World::Action action_
World::Object obj_
A representation of an object.
Definition world.h:79
EIGEN_MAKE_ALIGNED_OPERATOR_NEW std::string id_
The id for this object.
Definition world.h:87
EigenSTL::vector_Isometry3d shape_poses_
The poses of the corresponding entries in shapes_, relative to the object pose.
Definition world.h:101
std::vector< shapes::ShapeConstPtr > shapes_
All the shapes making up this object.
Definition world.h:96
TEST(World, AddRemoveShape)
int main(int argc, char **argv)