Robowflex  v0.1
Making MoveIt Easy
openrave.cpp
Go to the documentation of this file.
1 /* Author: Bryce Willey */
2 
3 #include <algorithm>
4 #include <stack>
5 
6 #include <tinyxml2.h>
7 
8 #include <ros/console.h>
9 
10 #include <geometry_msgs/Pose.h>
11 
12 #include <moveit_msgs/CollisionObject.h>
13 
14 #include <geometric_shapes/shape_operations.h>
15 
18 #include <robowflex_library/io.h>
19 #include <robowflex_library/log.h>
21 #include <robowflex_library/tf.h>
22 
23 using namespace robowflex;
24 using namespace robowflex::openrave;
25 
26 namespace
27 {
28  struct SceneParsingContext
29  {
30  RobotPose robot_offset;
32  std::stack<std::string> directory_stack;
33  };
34 
35  double toRadians(double v)
36  {
37  return v * constants::pi / 180.;
38  }
39 
40  template <typename T>
41  tinyxml2::XMLElement *getFirstChild(T *elem, const std::string &name = "")
42  {
43  tinyxml2::XMLHandle handle(elem);
44  tinyxml2::XMLElement *child;
45  if (name.empty())
46  child = handle.FirstChildElement().ToElement();
47  else
48  child = handle.FirstChildElement(name.c_str()).ToElement();
49 
50  return child;
51  }
52 
53  RobotPose TFfromXML(tinyxml2::XMLElement *transElem, tinyxml2::XMLElement *rotationElem,
54  tinyxml2::XMLElement *quatElem)
55  {
56  RobotPose tf = RobotPose::Identity();
57  if (transElem)
58  {
59  auto trans = IO::tokenize<double>(std::string(transElem->GetText()));
60  tf.translation() = Eigen::Vector3d(trans[0], trans[1], trans[2]);
61  }
62 
63  if (rotationElem)
64  {
65  auto rot = IO::tokenize<double>(std::string(rotationElem->GetText()));
66 
67  Eigen::Vector3d axis(rot[0], rot[1], rot[2]);
68  axis.normalize();
69 
70  tf.linear() = Eigen::AngleAxisd(toRadians(rot[3]), axis).toRotationMatrix();
71  }
72 
73  if (quatElem)
74  {
75  auto quat = IO::tokenize<double>(std::string(quatElem->GetText()));
76 
77  Eigen::Quaterniond q(quat[0], quat[1], quat[2], quat[3]);
78  q.normalize();
79 
80  tf.linear() = q.toRotationMatrix();
81  }
82 
83  return tf;
84  }
85 
86  bool parseKinbody(SceneParsingContext &load_struct, tinyxml2::XMLElement *elem, const RobotPose &tf,
87  moveit_msgs::PlanningScene &planning_scene)
88  {
89  if (not elem)
90  {
91  RBX_ERROR("Ran into element that does not exist!");
92  return false;
93  }
94 
95  auto *trans_elem = getFirstChild(elem, "Translation");
96  auto *rot_elem = getFirstChild(elem, "Rotation");
97  RobotPose this_tf = TFfromXML(trans_elem, rot_elem, nullptr);
98 
99  const char *filename = elem->Attribute("file");
100  if (filename)
101  {
102  // We need to read in another file to get the actual info.
103  std::string full_path = load_struct.directory_stack.top() + "/" + std::string(filename);
104  tinyxml2::XMLDocument doc;
105  if (!doc.LoadFile(full_path.c_str()))
106  {
107  RBX_ERROR("Cannot load file %s", full_path);
108  return false;
109  }
110 
111  load_struct.directory_stack.push(IO::resolveParent(full_path));
112  return parseKinbody(load_struct, getFirstChild(&doc, "KinBody"), tf * this_tf, planning_scene);
113  }
114 
115  tinyxml2::XMLElement *body_elem = getFirstChild(elem);
116  for (; body_elem; body_elem = body_elem->NextSiblingElement())
117  {
118  if (std::string(body_elem->Value()) == "Body")
119  {
120  moveit_msgs::CollisionObject coll_obj;
121  coll_obj.id = body_elem->Attribute("name");
122  coll_obj.header.frame_id = "world";
123 
124  tinyxml2::XMLElement *geom = getFirstChild(body_elem, "Geom");
125  if (not geom)
126  {
127  RBX_ERROR("Malformed File: No Geom attribute?");
128  return false;
129  }
130 
131  // Set Offset
132  RobotPose offset =
133  this_tf * tf *
134  TFfromXML(getFirstChild(geom, "translation"), nullptr, getFirstChild(geom, "quat"));
135 
136  geometry_msgs::Pose pose_msg = TF::poseEigenToMsg(offset);
137 
138  // Set type.
139  const char *geom_type = geom->Attribute("type");
140  if (not geom_type)
141  {
142  RBX_ERROR("Malformed File: No type attribute in geom element");
143  return false;
144  }
145 
146  std::string geom_str = std::string(geom_type);
147 
148  // Set Dimensions
149  if (geom_str == "trimesh")
150  {
151  // Set resource
152  Eigen::Vector3d dimensions{1, 1, 1};
153 
154  tinyxml2::XMLElement *data = getFirstChild(geom, "Data");
155  std::string resource_path;
156  if (data)
157  resource_path =
158  load_struct.directory_stack.top() + "/" + std::string(data->GetText());
159 
160  else
161  {
162  tinyxml2::XMLElement *render = getFirstChild(geom, "Render");
163  if (render)
164  resource_path =
165  load_struct.directory_stack.top() + "/" + std::string(data->GetText());
166  else
167  {
168  RBX_ERROR("Malformed File: No Data or Render Elements inside a trimesh Geom.");
169  return false;
170  }
171  }
172  auto mesh = Geometry::makeMesh(resource_path, dimensions);
173 
174  coll_obj.meshes.push_back(mesh->getMeshMsg());
175  coll_obj.mesh_poses.push_back(pose_msg);
176  }
177 
178  if (geom_str == "box")
179  {
180  tinyxml2::XMLElement *extents_elem = getFirstChild(geom, "extents_elem");
181  if (not extents_elem)
182  {
183  RBX_ERROR("Malformed File: No extents_elem in a box geometry.");
184  return false;
185  }
186 
187  auto extents = IO::tokenize<double>(extents_elem->GetText());
188  shapes::Shape *shape =
189  new shapes::Box(extents[0] * 2.0, extents[1] * 2.0, extents[2] * 2.0);
190  shapes::ShapeMsg msg;
191  shapes::constructMsgFromShape(shape, msg);
192  coll_obj.primitives.push_back(boost::get<shape_msgs::SolidPrimitive>(msg));
193  coll_obj.primitive_poses.push_back(pose_msg);
194  }
195 
196  coll_obj.operation = moveit_msgs::CollisionObject::ADD;
197 
198  load_struct.coll_objects.push_back(coll_obj);
199  planning_scene.world.collision_objects.push_back(coll_obj);
200  }
201  }
202 
203  load_struct.directory_stack.pop();
204  return true;
205  }
206 } // namespace
207 
208 bool openrave::fromXMLFile(moveit_msgs::PlanningScene &planning_scene, const std::string &file,
209  const std::string &model_dir)
210 {
211  SceneParsingContext load_struct;
212  load_struct.directory_stack.push(model_dir);
213 
214  // Hardcoded offset on WAM (see wam7.kinbody.xml)
215  RobotPose tf;
216  tf.translation() = Eigen::Vector3d(0.0, 0.0, -0.346);
217  tf.linear() = Eigen::Quaterniond::Identity().toRotationMatrix();
218  load_struct.robot_offset = tf;
219 
220  tinyxml2::XMLDocument doc;
221  if (!doc.LoadFile(IO::resolvePath(file).c_str()))
222  {
223  RBX_ERROR("Cannot load file %s", file);
224  return false;
225  }
226 
227  auto *env = getFirstChild(&doc, "Environment");
228  auto *robot = getFirstChild(env, "Robot");
229  if (robot)
230  load_struct.robot_offset =
231  load_struct.robot_offset * TFfromXML(getFirstChild(robot, "Translation"), //
232  getFirstChild(robot, "RotationAxis"), nullptr);
233 
234  auto *elem = getFirstChild(env);
235  if (not elem)
236  {
237  RBX_ERROR("There is no/an empty environment element in this openrave scene.");
238  return false;
239  }
240 
241  for (; elem; elem = elem->NextSiblingElement())
242  {
243  const std::string p_key = std::string(elem->Value());
244  if (p_key == "KinBody")
245  {
246  if (!parseKinbody(load_struct, elem, load_struct.robot_offset.inverse(), planning_scene))
247  return false;
248  }
249  else
250  RBX_INFO("Ignoring elements of value %s", p_key);
251  }
252 
253  if (not load_struct.coll_objects.empty())
254  planning_scene.is_diff = true;
255 
256  return true;
257 }
T c_str(T... args)
static GeometryPtr makeMesh(const std::string &resource, const Eigen::Vector3d &scale={1, 1, 1})
Create a mesh from resource file.
Definition: geometry.cpp:91
#define RBX_ERROR(fmt,...)
Output a error logging message.
Definition: log.h:102
#define RBX_INFO(fmt,...)
Output a info logging message.
Definition: log.h:118
Functions for loading and animating robots in Blender.
std::string resolveParent(const std::string &path)
Resolves package:// URLs to get the directory this path is in.
std::string resolvePath(const std::string &path)
Resolves package:// URLs and relative file paths to their canonical form.
double toRadians(double v)
Convert an angle to radians.
Definition: tf.cpp:308
geometry_msgs::Pose poseEigenToMsg(const RobotPose &pose)
Converts an RobotPose to a pose message.
Definition: tf.cpp:120
static const double pi
Definition: constants.h:21
bool fromXMLFile(moveit_msgs::PlanningScene &planning_scene, const std::string &file, const std::string &model_dir)
Loads a planning_scene from an OpenRAVE Environment XML.
Definition: openrave.cpp:208
Main namespace. Contains all library classes and functions.
Definition: scene.cpp:25
std::decay< decltype(std::declval< moveit::core::Transforms >().getTransform("")) >::type RobotPose
A pose (point in SE(3)) used in various functions. Defined from what MoveIt! uses.
Definition: adapter.h:24