ed
robot_plugin.cpp
Go to the documentation of this file.
1 #include "robot_plugin.h"
2 
3 #include <kdl_parser/kdl_parser.hpp>
4 
5 #include <ros/node_handle.h>
6 
7 #include <ed/entity.h>
8 #include <ed/update_request.h>
9 #include <ed/world_model.h>
10 #include <ed/models/shape_loader.h>
11 
12 #include <geolib/CompositeShape.h>
13 
14 // URDF shape loading
15 #include <ros/package.h>
16 #include <geolib/io/import.h>
17 #include <geolib/Box.h>
18 
20 
21 #include <tuple>
22 
23 // ----------------------------------------------------------------------------------------------------
24 
26 {
28  joint_pos_cache_.getLowerUpper(t, it_low, it_up);
29 
30  float joint_pos;
31 
32  if (it_low == joint_pos_cache_.end())
33  {
34  if (it_up == joint_pos_cache_.end())
35  // No upper or lower bound (cache is empty)
36  return false;
37 
38  // Requested time is in the past
39  joint_pos = it_up->second;
40  }
41  else
42  {
43  if (it_up == joint_pos_cache_.end())
44  {
45  // Requested time is in the future
46  joint_pos = it_low->second;
47  }
48  else
49  {
50  // Interpolate
51  float p1 = it_low->second;
52  float p2 = it_up->second;
53 
54  float dt1 = t.seconds() - it_low->first.seconds();
55  float dt2 = it_up->first.seconds() - t.seconds();
56 
57  // Linearly interpolate joint positions
58  joint_pos = (p1 * dt2 + p2 * dt1) / (dt1 + dt2);
59  }
60  }
61 
62  // Calculate joint pose for this joint position
63  KDL::Frame pose_kdl = segment_.pose(joint_pos);
64 
65  // Convert to geolib transform
66  tf.R = geo::Matrix3(pose_kdl.M.data);
67  tf.t = geo::Vector3(pose_kdl.p.data);
68 
69  return true;
70 }
71 
72 // ----------------------------------------------------------------------------------------------------
73 
74 geo::ShapePtr URDFGeometryToShape(const urdf::GeometrySharedPtr& geom)
75 {
76  geo::ShapePtr shape;
77 
78  if (geom->type == urdf::Geometry::MESH)
79  {
80  urdf::Mesh* mesh = static_cast<urdf::Mesh*>(geom.get());
81  if (!mesh)
82  {
83  ROS_WARN_NAMED("RobotPlugin", "[RobotPlugin] Robot model error: No mesh geometry defined");
84  return shape;
85  }
86 
87  std::string pkg_prefix = "package://";
88  if (mesh->filename.substr(0, pkg_prefix.size()) == pkg_prefix)
89  {
90  std::string str = mesh->filename.substr(pkg_prefix.size());
91  size_t i_slash = str.find("/");
92 
93  std::string pkg = str.substr(0, i_slash);
94  std::string rel_filename = str.substr(i_slash + 1);
95  std::string pkg_path = ros::package::getPath(pkg);
96  std::string abs_filename = pkg_path + "/" + rel_filename;
97 
98  shape = geo::io::readMeshFile(abs_filename, mesh->scale.x);
99 
100  if (!shape)
101  ROS_ERROR_STREAM_NAMED("RobotPlugin", "[RobotPlugin] Could not load mesh shape from '" << abs_filename << "'");
102  }
103  }
104  else if (geom->type == urdf::Geometry::BOX)
105  {
106  urdf::Box* box = static_cast<urdf::Box*>(geom.get());
107  if (!box)
108  {
109  ROS_WARN_NAMED("RobotPlugin", "[RobotPlugin] Robot model error: No box geometry defined");
110  return shape;
111  }
112 
113  double hx = box->dim.x / 2;
114  double hy = box->dim.y / 2;
115  double hz = box->dim.z / 2;
116 
117  shape.reset(new geo::Box(geo::Vector3(-hx, -hy, -hz), geo::Vector3(hx, hy, hz)));
118  }
119  else if (geom->type == urdf::Geometry::CYLINDER)
120  {
121  urdf::Cylinder* cyl = static_cast<urdf::Cylinder*>(geom.get());
122  if (!cyl)
123  {
124  ROS_WARN_NAMED("RobotPlugin", "[RobotPlugin] Robot model error: No cylinder geometry defined");
125  return shape;
126  }
127 
128  shape.reset(new geo::Shape());
129  ed::models::createCylinder(*shape, cyl->radius, cyl->length, 20);
130  }
131  else if (geom->type == urdf::Geometry::SPHERE)
132  {
133  urdf::Sphere* sphere = static_cast<urdf::Sphere*>(geom.get());
134  if (!sphere)
135  {
136  ROS_WARN_NAMED("RobotPlugin", "[RobotPlugin] Robot model error: No sphere geometry defined");
137  return shape;
138  }
139 
140  shape.reset(new geo::Shape());
141  ed::models::createSphere(*shape, sphere->radius);
142  }
143 
144  return shape;
145 }
146 
147 // ----------------------------------------------------------------------------------------------------
148 
150 {
151  geo::CompositeShapePtr visual, collision;
152 
153  for (urdf::VisualSharedPtr& vis : link->visual_array)
154  {
155  const urdf::GeometrySharedPtr& geom = vis->geometry;
156  if (!geom)
157  {
158  ROS_WARN_STREAM_NAMED("RobotPlugin" ,"[RobotPlugin] Robot model error: missing geometry for visual in link: '" << link->name << "'");
159  continue;
160  }
161 
162  geo::Pose3D offset;
163  const urdf::Pose& o = vis->origin;
164  offset.t = geo::Vector3(o.position.x, o.position.y, o.position.z);
165  offset.R.setRotation(geo::Quaternion(o.rotation.x, o.rotation.y, o.rotation.z, o.rotation.w));
166 
167  geo::ShapePtr subshape = URDFGeometryToShape(geom);
168  if (!subshape)
169  continue;
170 
171  if (!visual)
172  visual.reset(new geo::CompositeShape());
173  visual->addShape(*subshape, offset);
174  }
175 
176  for (urdf::CollisionSharedPtr& col : link->collision_array)
177  {
178  const urdf::GeometrySharedPtr& geom = col->geometry;
179  if (!geom)
180  {
181  ROS_WARN_STREAM_NAMED("RobotPlugin" ,"[RobotPlugin] Robot model error: missing geometry for collision in link: '" << link->name << "'");
182  continue;
183  }
184 
185  geo::Pose3D offset;
186  const urdf::Pose& o = col->origin;
187  offset.t = geo::Vector3(o.position.x, o.position.y, o.position.z);
188  offset.R.setRotation(geo::Quaternion(o.rotation.x, o.rotation.y, o.rotation.z, o.rotation.w));
189 
190  geo::ShapePtr subshape = URDFGeometryToShape(geom);
191  if (!subshape)
192  continue;
193 
194  if (!collision)
195  collision.reset(new geo::CompositeShape());
196  collision->addShape(*subshape, offset);
197  }
198 
199  return {visual, collision};
200 }
201 
202 // ----------------------------------------------------------------------------------------------------
203 
204 RobotPlugin::RobotPlugin() : model_initialized_(true)
205 {
206 }
207 
208 // ----------------------------------------------------------------------------------------------------
209 
211 {
212 }
213 
214 // ----------------------------------------------------------------------------------------------------
215 
216 void RobotPlugin::constructRobot(const ed::UUID& parent_id, const KDL::SegmentMap::const_iterator& it_segment, ed::UpdateRequest& req)
217 {
218  const KDL::Segment& segment = it_segment->second.segment;
219 
220  // Child ID is the segment (link) name
221  ed::UUID child_id = segment.getName();
222  if (child_id.str().find(robot_name_) == std::string::npos)
223  child_id = robot_name_ + "/" + segment.getName();
224 
225  // Set the entity type (robot_link) and flag (self)
226  req.setType(child_id, "robot_link");
227  req.setFlag(child_id, "self");
228 
229  // Create a joint relation and add id
230  boost::shared_ptr<JointRelation> r(new JointRelation(segment));
231  r->setCacheSize(joint_cache_size_);
232  r->insert(0, 0);
233  req.setRelation(parent_id, child_id, r);
234 
235  // Generate relation info that will be used to update the relation
236  RelationInfo& rel_info = joint_name_to_rel_info_[segment.getJoint().getName()];
237  rel_info.parent_id = parent_id;
238  rel_info.child_id = child_id;
239  rel_info.r_idx = ed::INVALID_IDX;
240  rel_info.last_rel = r;
241 
242  // Recursively add all children
243  const std::vector<KDL::SegmentMap::const_iterator>& children = it_segment->second.children;
244  for (unsigned int i = 0; i < children.size(); i++)
245  constructRobot(child_id, children[i], req);
246 }
247 
248 // ----------------------------------------------------------------------------------------------------
249 
250 void RobotPlugin::jointCallback(const sensor_msgs::JointState::ConstPtr& msg)
251 {
252  if (msg->name.size() != msg->position.size())
253  {
254  ROS_ERROR("[ED RobotPlugin] On joint callback: name and position vector must be of equal length.");
255  return;
256  }
257 
258  for(unsigned int i = 0; i < msg->name.size(); ++i)
259  {
260  const std::string& name = msg->name[i];
261  double pos = msg->position[i];
262 
264  if (it_r != joint_name_to_rel_info_.end())
265  {
266  RelationInfo& info = it_r->second;
267 
268  // Make a copy of the last relation
269  boost::shared_ptr<JointRelation> r(new JointRelation(*info.last_rel));
270  r->setCacheSize(joint_cache_size_);
271 
272  r->insert(msg->header.stamp.toSec(), pos);
273 
274  update_req_->setRelation(info.parent_id, info.child_id, r);
275 
276  info.last_rel = r;
277  }
278  else
279  {
280  ROS_ERROR_STREAM("[ED RobotPlugin] On joint callback: unknown joint name '" << name << "'.");
281  }
282  }
283 }
284 
285 // ----------------------------------------------------------------------------------------------------
286 
288 {
289  std::string urdf_rosparam;
290  config.value("urdf_rosparam", urdf_rosparam);
291 
292  config.value("robot_name", robot_name_);
293 
294  ros::NodeHandle nh;
295 
296  if (config.readArray("joint_topics"))
297  {
298  while(config.nextArrayItem())
299  {
300  std::string topic;
301  config.value("topic", topic);
302  ROS_DEBUG_STREAM("[RobotPlugin] Topic: " << topic);
303 
304  ros::SubscribeOptions sub_options = ros::SubscribeOptions::create<sensor_msgs::JointState>
305  (topic, 10, boost::bind(&RobotPlugin::jointCallback, this, _1), ros::VoidPtr(), &cb_queue_);
306 
307  joint_subscribers_[topic] = nh.subscribe(sub_options);
308  }
309 
310  config.endArray();
311  }
312 
313  if (config.hasError())
314  return;
315 
316  std::string urdf_xml;
317  if (!nh.getParam(urdf_rosparam, urdf_xml))
318  {
319  config.addError("No such ROS parameter: '" + urdf_rosparam + "'.");
320  return;
321  }
322 
323  if (!kdl_parser::treeFromString(urdf_xml, tree_))
324  {
325  config.addError("Could not initialize KDL tree object.");
326  return;
327  }
328 
329  if (!robot_model_.initString(urdf_xml))
330  {
331  config.addError("Could not load robot model.");
332  return;
333  }
334 
335  joint_cache_size_ = 100; // TODO: remove magic number
336 
337  model_initialized_ = false;
338 }
339 
340 // ----------------------------------------------------------------------------------------------------
341 
343 {
344 }
345 
346 // ----------------------------------------------------------------------------------------------------
347 
349 {
350  if (!model_initialized_)
351  {
352  // Create the links
354  robot_model_.getLinks(links);
355 
356  for(std::vector<urdf::LinkSharedPtr >::const_iterator it = links.begin(); it != links.end(); ++it)
357  {
358  const urdf::LinkSharedPtr& link = *it;
359 
360  geo::ShapePtr visual, collision;
361  std::tie(visual, collision) = LinkToShapes(link);
362  if (visual || collision)
363  {
364  std::string id = link->name;
365  if (link->name.find(robot_name_) == std::string::npos)
366  id = robot_name_ + "/" + link->name;
367  if (visual)
368  req.setVisual(id, visual);
369  if (collision)
370  req.setCollision(id, collision);
371  }
372  }
373 
374  // Create the joints
376  model_initialized_ = true;
377 
378  req.setType(robot_name_, "robot");
379 
380  return;
381  }
382 
383  update_req_ = &req;
384  cb_queue_.callAvailable();
385 
386  ed::EntityConstPtr e_robot = world.getEntity(robot_name_);
387  if (e_robot && e_robot->has_pose())
388  {
389  // Calculate absolute poses
390  for(ed::world_model::TransformCrawler tc(world, robot_name_, ros::Time::now().toSec()); tc.hasNext(); tc.next())
391  {
392  const ed::EntityConstPtr& e = tc.entity();
393  req.setPose(e->id(), e_robot->pose() * tc.transform());
394  req.setFlag(e->id(), "self"); // mark as self
395  }
396  }
397 }
398 
399 // ----------------------------------------------------------------------------------------------------
400 
transform_crawler.h
geo::Vector3
Vec3 Vector3
geo::Mat3T::setRotation
void setRotation(const QuaternionT< T > &q)
ed::WorldModel::getEntity
EntityConstPtr getEntity(const ed::UUID &id) const
Definition: world_model.h:76
KDL::Vector::data
double data[3]
ed::WorldModel
Definition: world_model.h:21
ed::UpdateRequest
Definition: update_request.h:24
geo::QuaternionT
std::string
std::shared_ptr
ed::TimeCache::getLowerUpper
void getLowerUpper(const Time &t, const_iterator &lower, const_iterator &upper) const
Definition: time_cache.h:29
RobotPlugin::initialize
void initialize()
Definition: robot_plugin.cpp:342
KDL::Tree::getRootSegment
SegmentMap::const_iterator getRootSegment() const
entity.h
t
Timer t
RobotPlugin::configure
void configure(tue::Configuration config)
Definition: robot_plugin.cpp:287
RelationInfo::last_rel
boost::shared_ptr< const JointRelation > last_rel
Definition: robot_plugin.h:52
ED_REGISTER_PLUGIN
#define ED_REGISTER_PLUGIN(Derived)
Definition: plugin.h:5
KDL::Segment::getJoint
const Joint & getJoint() const
import.h
std::vector
std::string::find
T find(T... args)
std::string::size
T size(T... args)
KDL::Frame::p
Vector p
RobotPlugin::jointCallback
void jointCallback(const sensor_msgs::JointState::ConstPtr &msg)
Definition: robot_plugin.cpp:250
geo::Box
URDFGeometryToShape
geo::ShapePtr URDFGeometryToShape(const urdf::GeometrySharedPtr &geom)
Definition: robot_plugin.cpp:74
RelationInfo::child_id
ed::UUID child_id
Definition: robot_plugin.h:50
tuple
geo::Transform3T
robot_plugin.h
ed::Time
Definition: time.h:9
std::shared_ptr::reset
T reset(T... args)
ed::EntityConstPtr
shared_ptr< const Entity > EntityConstPtr
Definition: types.h:37
KDL::Joint::getName
const std::string & getName() const
tue::config::ReaderWriter::readArray
bool readArray(const std::string &name, const RequiredOrOptional opt=OPTIONAL)
ed::TimeCache::const_iterator
std::map< Time, T >::const_iterator const_iterator
Definition: time_cache.h:16
std::tie
T tie(T... args)
tue::config::ReaderWriter
RobotPlugin
Definition: robot_plugin.h:57
update_request.h
ed::UpdateRequest::setFlag
void setFlag(const UUID &id, const std::string &flag)
Definition: update_request.h:201
ed::log::info
std::ostream & info()
Definition: logging.cpp:30
KDL::Segment::pose
Frame pose(const double &q) const
KDL::Frame
ed::UpdateRequest::setPose
void setPose(const UUID &id, const geo::Pose3D &pose)
Definition: update_request.h:132
geo::io::readMeshFile
ShapePtr readMeshFile(const std::string &filename, const geo::Vec3 &scale)
geo::Transform3T::t
Vec3T< T > t
JointRelation::segment_
KDL::Segment segment_
Definition: robot_plugin.h:40
ed::INVALID_IDX
static const Idx INVALID_IDX
Definition: types.h:22
ed::UpdateRequest::setCollision
void setCollision(const UUID &id, const geo::ShapeConstPtr &collision)
Definition: update_request.h:57
ed::UUID
Definition: uuid.h:10
RobotPlugin::tree_
KDL::Tree tree_
Definition: robot_plugin.h:78
RobotPlugin::model_initialized_
bool model_initialized_
Definition: robot_plugin.h:76
CompositeShape.h
geo::Vector3
std::map
RelationInfo::parent_id
ed::UUID parent_id
Definition: robot_plugin.h:49
JointRelation::joint_pos_cache_
ed::TimeCache< float > joint_pos_cache_
Definition: robot_plugin.h:39
RelationInfo::r_idx
ed::Idx r_idx
Definition: robot_plugin.h:51
ed::UpdateRequest::setType
void setType(const UUID &id, const std::string &type)
Definition: update_request.h:106
tue::config::ReaderWriter::endArray
bool endArray()
std::string::substr
T substr(T... args)
KDL::Segment
RobotPlugin::constructRobot
void constructRobot(const ed::UUID &parent_id, const KDL::SegmentMap::const_iterator &it_segment, ed::UpdateRequest &req)
Definition: robot_plugin.cpp:216
ed::UpdateRequest::setVisual
void setVisual(const UUID &id, const geo::ShapeConstPtr &visual)
Definition: update_request.h:53
RobotPlugin::joint_cache_size_
unsigned int joint_cache_size_
Definition: robot_plugin.h:86
KDL::Rotation::data
double data[9]
tue::config::ReaderWriter::addError
void addError(const std::string &msg)
ed::models::createCylinder
void createCylinder(geo::Shape &shape, double radius, double height, int num_corners=12)
createCylinder create a mesh from radius and height
Definition: shape_loader.cpp:884
geo::CompositeShape
tue::config::ReaderWriter::value
bool value(const std::string &name, T &value, RequiredOrOptional opt=REQUIRED)
ed::UpdateRequest::setRelation
void setRelation(const UUID &id1, const UUID &id2, const RelationConstPtr &r)
Definition: update_request.h:141
RobotPlugin::joint_name_to_rel_info_
std::map< std::string, RelationInfo > joint_name_to_rel_info_
Definition: robot_plugin.h:82
ed::models::createSphere
void createSphere(geo::Shape &shape, double radius, uint recursion_level=2)
createSphere Create a shape of sphere
Definition: shape_loader.cpp:953
RobotPlugin::process
void process(const ed::WorldModel &world, ed::UpdateRequest &req)
Definition: robot_plugin.cpp:348
RobotPlugin::update_req_
ed::UpdateRequest * update_req_
Definition: robot_plugin.h:84
JointRelation
Definition: robot_plugin.h:22
shape_loader.h
std::vector::begin
T begin(T... args)
ed::world_model::TransformCrawler::hasNext
bool hasNext() const
Definition: transform_crawler.h:40
KDL::Frame::M
Rotation M
KDL::Segment::getName
const std::string & getName() const
geo::Transform3T::R
Mat3T< T > R
LinkToShapes
std::tuple< geo::ShapePtr, geo::ShapePtr > LinkToShapes(const urdf::LinkSharedPtr &link)
Definition: robot_plugin.cpp:149
Box.h
RobotPlugin::joint_subscribers_
std::map< std::string, ros::Subscriber > joint_subscribers_
Definition: robot_plugin.h:95
std::map::end
T end(T... args)
ed::world_model::TransformCrawler
The TransformCrawler class.
Definition: transform_crawler.h:23
RobotPlugin::cb_queue_
ros::CallbackQueue cb_queue_
Definition: robot_plugin.h:93
JointRelation::calculateTransform
bool calculateTransform(const ed::Time &t, geo::Pose3D &tf) const
Definition: robot_plugin.cpp:25
ed::Plugin::name
const std::string & name() const
Definition: plugin.h:46
RobotPlugin::robot_name_
std::string robot_name_
Definition: robot_plugin.h:74
RobotPlugin::robot_model_
urdf::Model robot_model_
Definition: robot_plugin.h:80
RelationInfo
Definition: robot_plugin.h:47
geo::Matrix3
Mat3 Matrix3
RobotPlugin::~RobotPlugin
virtual ~RobotPlugin()
Definition: robot_plugin.cpp:210
ed::TimeCache::end
const_iterator end() const
Definition: time_cache.h:53
tue::config::ReaderWriter::nextArrayItem
bool nextArrayItem()
ed::UUID::str
const std::string & str() const
Definition: uuid.h:27
geo::Shape
config
tue::config::ReaderWriter config
RobotPlugin::RobotPlugin
RobotPlugin()
Definition: robot_plugin.cpp:204
world_model.h
tue::config::ReaderWriter::hasError
bool hasError() const