Skip to content

Commit c149c30

Browse files
felixvdv4hn
andauthored
Update subframe tutorial with object pose (#520)
* Update subframe tutorial with object pose Co-authored-by: v4hn <[email protected]>
1 parent 6475e8e commit c149c30

File tree

2 files changed

+50
-138
lines changed

2 files changed

+50
-138
lines changed

doc/subframes/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
add_executable(subframes_tutorial src/subframes_tutorial.cpp)
22
target_link_libraries(subframes_tutorial ${catkin_LIBRARIES} ${Boost_LIBRARIES})
33
install(TARGETS subframes_tutorial DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
4+
5+
install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})

doc/subframes/src/subframes_tutorial.cpp

Lines changed: 48 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
// ROS
3838
#include <ros/ros.h>
39+
#include <ros/console.h>
3940

4041
// MoveIt
4142
#include <moveit/planning_scene_interface/planning_scene_interface.h>
@@ -54,8 +55,8 @@ const double tau = 2 * M_PI;
5455
// Creating the planning request
5556
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5657
// In this tutorial, we use a small helper function to create our planning requests and move the robot.
57-
bool moveToCartPose(const geometry_msgs::PoseStamped& pose, moveit::planning_interface::MoveGroupInterface& group,
58-
const std::string& end_effector_link)
58+
bool moveToCartesianPose(const geometry_msgs::PoseStamped& pose, moveit::planning_interface::MoveGroupInterface& group,
59+
const std::string& end_effector_link)
5960
{
6061
// To use subframes of objects that are attached to the robot in planning, you need to set the end effector of your
6162
// move_group to the subframe of the object. The format has to be ``object_name/subframe_name``, as shown
@@ -101,84 +102,64 @@ void spawnCollisionObjects(moveit::planning_interface::PlanningSceneInterface& p
101102
moveit_msgs::CollisionObject box;
102103
box.id = "box";
103104
box.header.frame_id = "panda_hand";
105+
box.pose.position.z = z_offset_box;
106+
box.pose.orientation.w = 1.0; // Neutral orientation
107+
104108
box.primitives.resize(1);
105-
box.primitive_poses.resize(1);
106109
box.primitives[0].type = box.primitives[0].BOX;
107110
box.primitives[0].dimensions.resize(3);
108111
box.primitives[0].dimensions[0] = 0.05;
109112
box.primitives[0].dimensions[1] = 0.1;
110113
box.primitives[0].dimensions[2] = 0.02;
111-
box.primitive_poses[0].position.z = z_offset_box;
112114

113115
// Then, we define the subframes of the CollisionObject. The subframes are defined in the ``frame_id`` coordinate
114116
// system, just like the shapes that make up the object. Each subframe consists of a name and a pose.
115117
// In this tutorial, we set the orientation of the subframes so that the z-axis of the subframe
116118
// points away from the object.
117119
// This is not strictly necessary, but it is helpful to follow a convention, and it avoids confusion when
118120
// setting the orientation of the target pose later on.
119-
box.subframe_names.resize(5);
120-
box.subframe_poses.resize(5);
121+
box.subframe_names.resize(3);
122+
box.subframe_poses.resize(3);
121123

122124
box.subframe_names[0] = "bottom";
123125
box.subframe_poses[0].position.y = -.05;
124-
box.subframe_poses[0].position.z = 0.0 + z_offset_box;
125126

126127
tf2::Quaternion orientation;
127-
orientation.setRPY(tau / 4, 0, 0); // A quarter turn about the x-axis
128+
orientation.setRPY(tau / 4.0, 0, 0); // A quarter turn about the x-axis
128129
box.subframe_poses[0].orientation = tf2::toMsg(orientation);
129130
// END_SUB_TUTORIAL
130131

131132
box.subframe_names[1] = "top";
132133
box.subframe_poses[1].position.y = .05;
133-
box.subframe_poses[1].position.z = 0.0 + z_offset_box;
134-
orientation.setRPY(-tau / 4, 0, 0);
134+
orientation.setRPY(-tau / 4.0, 0, 0);
135135
box.subframe_poses[1].orientation = tf2::toMsg(orientation);
136136

137-
box.subframe_names[2] = "corner_1";
138-
box.subframe_poses[2].position.x = -.025;
137+
box.subframe_names[2] = "corner";
138+
box.subframe_poses[2].position.x = .025;
139139
box.subframe_poses[2].position.y = -.05;
140-
box.subframe_poses[2].position.z = -.01 + z_offset_box;
141-
orientation.setRPY(tau / 4, 0, 0);
140+
box.subframe_poses[2].position.z = -.01;
141+
orientation.setRPY(tau / 8.0, 5.0 / 8.0 * tau, 0.0);
142142
box.subframe_poses[2].orientation = tf2::toMsg(orientation);
143143

144-
box.subframe_names[3] = "corner_2";
145-
box.subframe_poses[3].position.x = .025;
146-
box.subframe_poses[3].position.y = -.05;
147-
box.subframe_poses[3].position.z = -.01 + z_offset_box;
148-
orientation.setRPY(tau / 4, 0, 0);
149-
box.subframe_poses[3].orientation = tf2::toMsg(orientation);
150-
151-
box.subframe_names[4] = "side";
152-
box.subframe_poses[4].position.x = .0;
153-
box.subframe_poses[4].position.y = .0;
154-
box.subframe_poses[4].position.z = -.01 + z_offset_box;
155-
orientation.setRPY(0, tau / 2, 0);
156-
box.subframe_poses[4].orientation = tf2::toMsg(orientation);
157-
158144
// Next, define the cylinder
159145
moveit_msgs::CollisionObject cylinder;
160146
cylinder.id = "cylinder";
161147
cylinder.header.frame_id = "panda_hand";
148+
cylinder.pose.position.z = z_offset_cylinder;
149+
orientation.setRPY(0, tau / 4.0, 0);
150+
cylinder.pose.orientation = tf2::toMsg(orientation);
151+
162152
cylinder.primitives.resize(1);
163-
cylinder.primitive_poses.resize(1);
164153
cylinder.primitives[0].type = box.primitives[0].CYLINDER;
165154
cylinder.primitives[0].dimensions.resize(2);
166155
cylinder.primitives[0].dimensions[0] = 0.06; // height (along x)
167156
cylinder.primitives[0].dimensions[1] = 0.005; // radius
168-
cylinder.primitive_poses[0].position.x = 0.0;
169-
cylinder.primitive_poses[0].position.y = 0.0;
170-
cylinder.primitive_poses[0].position.z = 0.0 + z_offset_cylinder;
171-
orientation.setRPY(0, tau / 4, 0);
172-
cylinder.primitive_poses[0].orientation = tf2::toMsg(orientation);
173157

174158
cylinder.subframe_poses.resize(1);
175159
cylinder.subframe_names.resize(1);
176160
cylinder.subframe_names[0] = "tip";
177-
cylinder.subframe_poses[0].position.x = 0.03;
178-
cylinder.subframe_poses[0].position.y = 0.0;
179-
cylinder.subframe_poses[0].position.z = 0.0 + z_offset_cylinder;
180-
orientation.setRPY(0, tau / 4, 0);
181-
cylinder.subframe_poses[0].orientation = tf2::toMsg(orientation);
161+
cylinder.subframe_poses[0].position.z = 0.03;
162+
cylinder.subframe_poses[0].orientation.w = 1.0; // Neutral orientation
182163

183164
// BEGIN_SUB_TUTORIAL object2
184165
// Lastly, the objects are published to the PlanningScene. In this tutorial, we publish a box and a cylinder.
@@ -188,47 +169,6 @@ void spawnCollisionObjects(moveit::planning_interface::PlanningSceneInterface& p
188169
}
189170
// END_SUB_TUTORIAL
190171

191-
void createArrowMarker(visualization_msgs::Marker& marker, const geometry_msgs::Pose& pose, const Eigen::Vector3d& dir,
192-
int id, double scale = 0.1)
193-
{
194-
marker.action = visualization_msgs::Marker::ADD;
195-
marker.type = visualization_msgs::Marker::CYLINDER;
196-
marker.id = id;
197-
marker.scale.x = 0.1 * scale;
198-
marker.scale.y = 0.1 * scale;
199-
marker.scale.z = scale;
200-
201-
Eigen::Isometry3d pose_eigen;
202-
tf2::fromMsg(pose, pose_eigen);
203-
marker.pose = tf2::toMsg(pose_eigen * Eigen::Translation3d(dir * (0.5 * scale)) *
204-
Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d::UnitZ(), dir));
205-
206-
marker.color.r = 0.0;
207-
marker.color.g = 0.0;
208-
marker.color.b = 0.0;
209-
marker.color.a = 1.0;
210-
}
211-
212-
void createFrameMarkers(visualization_msgs::MarkerArray& markers, const geometry_msgs::PoseStamped& target,
213-
const std::string& ns, bool locked = false)
214-
{
215-
int id = markers.markers.size();
216-
visualization_msgs::Marker m;
217-
m.header.frame_id = target.header.frame_id;
218-
m.ns = ns;
219-
m.frame_locked = locked;
220-
221-
createArrowMarker(m, target.pose, Eigen::Vector3d::UnitX(), ++id);
222-
m.color.r = 1.0;
223-
markers.markers.push_back(m);
224-
createArrowMarker(m, target.pose, Eigen::Vector3d::UnitY(), ++id);
225-
m.color.g = 1.0;
226-
markers.markers.push_back(m);
227-
createArrowMarker(m, target.pose, Eigen::Vector3d::UnitZ(), ++id);
228-
m.color.b = 1.0;
229-
markers.markers.push_back(m);
230-
}
231-
232172
int main(int argc, char** argv)
233173
{
234174
ros::init(argc, argv, "panda_arm_subframes");
@@ -259,27 +199,7 @@ int main(int argc, char** argv)
259199
planning_scene_monitor->requestPlanningSceneState();
260200
planning_scene_monitor::LockedPlanningSceneRO planning_scene(planning_scene_monitor);
261201

262-
// Visualize frames as rviz markers
263-
ros::Publisher marker_publisher = nh.advertise<visualization_msgs::MarkerArray>("visualization_marker_array", 10);
264-
auto showFrames = [&](geometry_msgs::PoseStamped target, const std::string& eef) {
265-
visualization_msgs::MarkerArray markers;
266-
// convert target pose into planning frame
267-
Eigen::Isometry3d tf;
268-
tf2::fromMsg(target.pose, tf);
269-
target.pose = tf2::toMsg(planning_scene->getFrameTransform(target.header.frame_id) * tf);
270-
target.header.frame_id = planning_scene->getPlanningFrame();
271-
createFrameMarkers(markers, target, "target");
272-
273-
// convert eef in pose relative to panda_hand
274-
target.header.frame_id = "panda_hand";
275-
target.pose = tf2::toMsg(planning_scene->getFrameTransform(target.header.frame_id).inverse() *
276-
planning_scene->getFrameTransform(eef));
277-
createFrameMarkers(markers, target, "eef", true);
278-
279-
marker_publisher.publish(markers);
280-
};
281-
282-
// Define a pose in the robot base.
202+
// Define a pose near the robot base.
283203
tf2::Quaternion target_orientation;
284204
geometry_msgs::PoseStamped fixed_pose, target_pose;
285205
fixed_pose.header.frame_id = "panda_link0";
@@ -295,11 +215,13 @@ int main(int argc, char** argv)
295215
ROS_INFO("==========================\n"
296216
"Press a key and hit Enter to execute an action. \n0 to exit"
297217
"\n1 to move cylinder tip to box bottom \n2 to move cylinder tip to box top"
298-
"\n3 to move cylinder tip to box corner 1 \n4 to move cylinder tip to box corner 2"
299-
"\n5 to move cylinder tip to side of box"
300-
"\n6 to return the robot to the start pose"
301-
"\n7 to move the robot's wrist to a cartesian pose"
218+
"\n3 to move cylinder tip to box corner"
219+
"\n"
220+
"\n5 to return the robot to the start pose"
221+
"\n"
222+
"\n7 to move the robot's wrist to a cartesian pose near the robot base"
302223
"\n8 to move cylinder/tip to the same cartesian pose"
224+
"\n9 to move panda_link8 near box/bottom"
303225
"\n----------"
304226
"\n10 to remove box and cylinder from the scene"
305227
"\n11 to spawn box and cylinder"
@@ -319,12 +241,11 @@ int main(int argc, char** argv)
319241
// The target pose is given relative to a box subframe:
320242
target_pose.header.frame_id = "box/bottom";
321243
// The orientation is determined by RPY angles to align the cylinder and box subframes:
322-
target_orientation.setRPY(0, tau / 2, tau / 4);
244+
target_orientation.setRPY(0, tau / 2.0, tau / 4.0);
323245
target_pose.pose.orientation = tf2::toMsg(target_orientation);
324246
// To keep some distance to the box, we use a small offset:
325247
target_pose.pose.position.z = 0.01;
326-
showFrames(target_pose, "cylinder/tip");
327-
moveToCartPose(target_pose, group, "cylinder/tip");
248+
moveToCartesianPose(target_pose, group, "cylinder/tip");
328249
// END_SUB_TUTORIAL
329250
}
330251
// BEGIN_SUB_TUTORIAL move_example
@@ -333,42 +254,22 @@ int main(int argc, char** argv)
333254
{
334255
ROS_INFO_STREAM("Moving to top of box with cylinder tip");
335256
target_pose.header.frame_id = "box/top";
336-
target_orientation.setRPY(tau / 2, 0, tau / 4);
257+
target_orientation.setRPY(tau / 2.0, 0, tau / 4.0);
337258
target_pose.pose.orientation = tf2::toMsg(target_orientation);
338259
target_pose.pose.position.z = 0.01;
339-
showFrames(target_pose, "cylinder/tip");
340-
moveToCartPose(target_pose, group, "cylinder/tip");
260+
moveToCartesianPose(target_pose, group, "cylinder/tip");
341261
}
342262
// END_SUB_TUTORIAL
343263
else if (character_input == 3)
344264
{
345-
ROS_INFO_STREAM("Moving to corner1 of box with cylinder tip");
346-
target_pose.header.frame_id = "box/corner_1";
347-
target_orientation.setRPY(0, tau / 2, tau / 4);
265+
ROS_INFO_STREAM("Moving to box corner with cylinder tip");
266+
target_pose.header.frame_id = "box/corner";
267+
target_orientation.setRPY(tau / 2.0, 0, 0);
348268
target_pose.pose.orientation = tf2::toMsg(target_orientation);
349269
target_pose.pose.position.z = 0.01;
350-
showFrames(target_pose, "cylinder/tip");
351-
moveToCartPose(target_pose, group, "cylinder/tip");
352-
}
353-
else if (character_input == 4)
354-
{
355-
target_pose.header.frame_id = "box/corner_2";
356-
target_orientation.setRPY(0, tau / 2, tau / 4);
357-
target_pose.pose.orientation = tf2::toMsg(target_orientation);
358-
target_pose.pose.position.z = 0.01;
359-
showFrames(target_pose, "cylinder/tip");
360-
moveToCartPose(target_pose, group, "cylinder/tip");
270+
moveToCartesianPose(target_pose, group, "cylinder/tip");
361271
}
362272
else if (character_input == 5)
363-
{
364-
target_pose.header.frame_id = "box/side";
365-
target_orientation.setRPY(0, tau / 2, tau / 4);
366-
target_pose.pose.orientation = tf2::toMsg(target_orientation);
367-
target_pose.pose.position.z = 0.01;
368-
showFrames(target_pose, "cylinder/tip");
369-
moveToCartPose(target_pose, group, "cylinder/tip");
370-
}
371-
else if (character_input == 6)
372273
{
373274
// Go to neutral home pose
374275
group.clearPoseTargets();
@@ -378,14 +279,21 @@ int main(int argc, char** argv)
378279
else if (character_input == 7)
379280
{
380281
ROS_INFO_STREAM("Moving to a pose with robot wrist");
381-
showFrames(fixed_pose, "panda_hand");
382-
moveToCartPose(fixed_pose, group, "panda_hand");
282+
moveToCartesianPose(fixed_pose, group, "panda_hand");
383283
}
384284
else if (character_input == 8)
385285
{
386286
ROS_INFO_STREAM("Moving to a pose with cylinder tip");
387-
showFrames(fixed_pose, "cylinder/tip");
388-
moveToCartPose(fixed_pose, group, "cylinder/tip");
287+
moveToCartesianPose(fixed_pose, group, "cylinder/tip");
288+
}
289+
else if (character_input == 9)
290+
{
291+
target_pose.header.frame_id = "box/bottom";
292+
target_orientation.setRPY(0, tau / 2.0, 0);
293+
target_pose.pose.orientation = tf2::toMsg(target_orientation);
294+
target_pose.pose.position.z = 0.15;
295+
ROS_INFO_STREAM("Moving to box bottom with panda link 8");
296+
moveToCartesianPose(target_pose, group, "panda_link8");
389297
}
390298
else if (character_input == 10)
391299
{
@@ -458,3 +366,5 @@ int main(int argc, char** argv)
458366
// CALL_SUB_TUTORIAL orientation
459367
//
460368
// END_TUTORIAL
369+
370+
// TODO(felixvd): Add explanation about the TfPublisher MoveGroupCapability.

0 commit comments

Comments
 (0)