rtt_tf-component.cpp
Go to the documentation of this file.
1 /* (C) 2011 Ruben Smits, ruben.smits@mech.kuleuven.be, Department of Mechanical
2  * Engineering, Katholieke Universiteit Leuven, Belgium.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /*
20  * Copyright (c) 2008, Willow Garage, Inc.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions are met:
25  *
26  * * Redistributions of source code must retain the above copyright
27  * notice, this list of conditions and the following disclaimer.
28  * * Redistributions in binary form must reproduce the above copyright
29  * notice, this list of conditions and the following disclaimer in the
30  * documentation and/or other materials provided with the distribution.
31  * * Neither the name of the Willow Garage, Inc. nor the names of its
32  * contributors may be used to endorse or promote products derived from
33  * this software without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
39  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45  * POSSIBILITY OF SUCH DAMAGE.
46  */
47 
48 #include "rtt_tf-component.hpp"
49 #include <rtt/Component.hpp>
50 #include <ros/ros.h>
51 
52 #include <tf/tf.h>
53 #include <tf2/exceptions.h>
54 
55 #include <geometry_msgs/TransformStamped.h>
56 
57 #include <algorithm>
58 
59 namespace rtt_tf
60 {
61  // Functor for resolving the tf prefix when broadcasting multiple transforms.
63  {
64  public:
65  PrefixResolver(const std::string& prefix) : prefix_(prefix) { }
66 
67  geometry_msgs::TransformStamped operator()(const geometry_msgs::TransformStamped& elem)
68  {
69  geometry_msgs::TransformStamped result = elem;
70  result.header.frame_id = tf::resolve(prefix_, result.header.frame_id);
71  result.child_frame_id = tf::resolve(prefix_, result.child_frame_id);
72  return result;
73  }
74 
75  private:
76  const std::string& prefix_;
77  };
78 
79  tf2_msgs::TFMessage transformsToMessage(const std::vector<geometry_msgs::TransformStamped>& tforms, const std::string& prefix)
80  {
81  tf2_msgs::TFMessage msg;
82  // resolve names and copy transforms to message
83  msg.transforms.reserve(tforms.size());
84  std::transform(tforms.begin(), tforms.end(), msg.transforms.begin(), PrefixResolver(prefix));
85  return msg;
86  }
87 
88  using namespace RTT;
89 
90  RTT_TF::RTT_TF(const std::string& name) :
91  TaskContext(name, PreOperational),
92  tf2::BufferCore( ros::Duration(BufferCore::DEFAULT_CACHE_TIME) ),
93  prop_cache_time( BufferCore::DEFAULT_CACHE_TIME ),
94  prop_buffer_size(DEFAULT_BUFFER_SIZE)
95  {
96  this->addProperty("cache_time", prop_cache_time);
97  this->addProperty("buffer_size", prop_buffer_size);
98  this->addProperty("tf_prefix", prop_tf_prefix);
99  this->addEventPort("tf_in", port_tf_in);
100  this->addEventPort("tf_static_in", port_tf_static_in);
101  this->addPort("tf_out", port_tf_out);
102 
103  this->addTFOperations(this->provides());
104  this->addTFOperations(this->provides("tf"));
105  }
106 
108  {
109  service->addOperation("lookupTransform", &RTT_TF::lookupTransform, this)
110  .doc("Lookup the most recent transform from source to target.")
111  .arg("target", "target frame")
112  .arg("source", "source frame");
113 
114  service->addOperation("lookupTransformAtTime", &RTT_TF::lookupTransformAtTime, this)
115  .doc("Lookup the most recent transform from source to target at a specific time.")
116  .arg("target", "Target frame")
117  .arg("source", "Source frame")
118  .arg("common_time", "[ros::Time] The common time at which the transform should be computed");
119 
120  service->addOperation("broadcastTransform", &RTT_TF::broadcastTransform, this, RTT::OwnThread)
121  .doc("Broadcast a stamped transform immediately.")
122  .arg("transform", "[geometry_msgs::TransformStamped]");
123 
124  service->addOperation("broadcastTransforms", &RTT_TF::broadcastTransforms, this, RTT::OwnThread)
125  .doc("Broadcast stamped transforms immediately.")
126  .arg("transforms", "[std::vector<geometry_msgs::TransformStamped>]");
127 
128  service->addOperation("broadcastStaticTransform", &RTT_TF::broadcastStaticTransform, this, RTT::OwnThread)
129  .doc("Broadcast a stamped transform as a static transform immediately.")
130  .arg("transform", "[geometry_msgs::TransformStamped]");
131 
132  service->addOperation("broadcastStaticTransforms", &RTT_TF::broadcastStaticTransforms, this, RTT::OwnThread)
133  .doc("Broadcast stamped transforms as static transforms immediately.")
134  .arg("transforms", "[std::vector<geometry_msgs::TransformStamped>]");
135 
136  service->addOperation("canTransform", &RTT_TF::canTransform, this)
137  .doc("Check if the transform from source to target can be resolved.")
138  .arg("target", "Target frame")
139  .arg("source", "Source frame");
140 
141  service->addOperation("canTransformAtTime", &RTT_TF::canTransformAtTime, this)
142  .doc("Check if the transform from source to target can be resolved for a given common time.")
143  .arg("target", "Target frame")
144  .arg("source", "Source frame")
145  .arg("common_time", "[ros::Time] The common time for which the transform would resolve");
146  }
147 
149  {
150  Logger::In(this->getName());
151 
152  // Get tf prefix rosparam
153  ros::NodeHandle nh("~");
154  std::string tf_prefix_param_key;
155  if(nh.searchParam("tf_prefix",tf_prefix_param_key)) {
156  nh.getParam(tf_prefix_param_key, prop_tf_prefix);
157  }
158 
159  // Connect to tf topic
161  cp.transport = 3; //3=ROS
162  cp.name_id = "/tf";
163 
164  // Connect to tf_static topic
166  cp.transport = 3; //3=ROS
167  cp.name_id = "/tf_static";
168 
169  bool configured = port_tf_static_in.createStream(cp_static)
170  && port_tf_in.createStream(cp)
172  && port_tf_static_out.createStream(cp_static);
173 
174  if (!configured) {
175  cleanupHook();
176  }
177 
178  return configured;
179  }
180 
181  void RTT_TF::internalUpdate(tf2_msgs::TFMessage& msg, RTT::InputPort<tf2_msgs::TFMessage>& port, bool is_static)
182  {
183  // tf2::BufferCore::setTransform (see #68) has a non-defaulted authority argument,
184  // but there is no __connection_header to extract it from.
185  const std::string authority = "unknown_authority";
186 
187  while (port.read(msg) == NewData) {
188  for (std::size_t i = 0; i < msg.transforms.size(); ++i) {
189  try {
190  this->setTransform(msg.transforms[i], authority, is_static);
191  } catch (tf2::TransformException& ex) {
192  log(Error) << "Failure to set received transform from "
193  << msg.transforms[i].child_frame_id << " to "
194  << msg.transforms[i].header.frame_id
195  << " with error: " << ex.what() << endlog();
196  }
197  }
198  }
199  }
200 
202  {
203  Logger::In(this->getName());
204 #ifndef NDEBUG
205  //log(Debug) << "In update" << endlog();
206 #endif
207  try
208  {
209  tf2_msgs::TFMessage msg_in;
210  internalUpdate(msg_in, port_tf_in, false);
211  internalUpdate(msg_in, port_tf_static_in, true);
212  }
213  catch (std::exception& ex)
214  {
215  log(Error) << ex.what() << endlog();
216  }
217  }
218 
220  {
225  }
226 
228  const std::string& target,
229  const std::string& source) const
230  {
231  ros::Time common_time;
232 
233  tf2::CompactFrameID target_id = _lookupFrameNumber(target);
234  tf2::CompactFrameID source_id = _lookupFrameNumber(source);
235 
236  _getLatestCommonTime(source_id, target_id, common_time, NULL);
237 
238  return common_time;
239  }
240 
241  geometry_msgs::TransformStamped RTT_TF::lookupTransform(
242  const std::string& target,
243  const std::string& source) const
244  {
245  return tf2::BufferCore::lookupTransform(target, source, ros::Time());
246  }
247 
249  const std::string& target,
250  const std::string& source) const
251  {
252  return tf2::BufferCore::canTransform(target, source, ros::Time());
253  }
254 
256  const std::string& target,
257  const std::string& source,
258  const ros::Time& common_time) const
259  {
260  return tf2::BufferCore::canTransform(target, source, common_time);
261  }
262 
263  geometry_msgs::TransformStamped RTT_TF::lookupTransformAtTime(
264  const std::string& target,
265  const std::string& source,
266  const ros::Time& common_time) const
267  {
268  return tf2::BufferCore::lookupTransform(target, source, common_time);
269  }
270 
271  void RTT_TF::broadcastTransform(const geometry_msgs::TransformStamped& tform)
272  {
273  const std::vector<geometry_msgs::TransformStamped> tforms(1, tform);
274  tf2_msgs::TFMessage msg_out = transformsToMessage(tforms, prop_tf_prefix);
275  port_tf_out.write(msg_out);
276  }
277 
278  void RTT_TF::broadcastTransforms(const std::vector<geometry_msgs::TransformStamped>& tform)
279  {
280  tf2_msgs::TFMessage msg_out = transformsToMessage(tform, prop_tf_prefix);
281  port_tf_out.write(msg_out);
282  }
283 
284  void RTT_TF::broadcastStaticTransform(const geometry_msgs::TransformStamped& tform)
285  {
286  const std::vector<geometry_msgs::TransformStamped> tforms(1, tform);
287  tf2_msgs::TFMessage msg_out = transformsToMessage(tforms, prop_tf_prefix);
288  port_tf_static_out.write(msg_out);
289  }
290 
291  void RTT_TF::broadcastStaticTransforms(const std::vector<geometry_msgs::TransformStamped>& tform)
292  {
293  tf2_msgs::TFMessage msg_out = transformsToMessage(tform, prop_tf_prefix);
294  port_tf_static_out.write(msg_out);
295  }
296 
297 }//namespace
298 
299 /*
300  * Using this macro, only one component may live
301  * in one library *and* you may *not* link this library
302  * with another component library. Use
303  * ORO_CREATE_COMPONENT_TYPE()
304  * ORO_LIST_COMPONENT_TYPE(Rtt_tf)
305  * In case you want to link with another library that
306  * already contains components.
307  *
308  * If you have put your component class
309  * in a namespace, don't forget to add it here too:
310  */
Property< T > & addProperty(const std::string &name, T &attr)
bool canTransform(const std::string &target, const std::string &source) const
void addTFOperations(RTT::Service::shared_ptr service)
uint32_t CompactFrameID
geometry_msgs::TransformStamped lookupTransform(const std::string &target, const std::string &source) const
ORO_CREATE_COMPONENT(BroadcasterComponent)
Service::shared_ptr provides()
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
base::InputPortInterface & addEventPort(const std::string &name, base::InputPortInterface &port, SlotFunction callback=SlotFunction())
ros::Time getLatestCommonTime(const std::string &target, const std::string &source) const
RTT::OutputPort< tf2_msgs::TFMessage > port_tf_static_out
FlowStatus read(base::DataSourceBase::shared_ptr source)
std::string resolve(const std::string &prefix, const std::string &frame_name)
bool searchParam(const std::string &key, std::string &result) const
bool canTransformAtTime(const std::string &target, const std::string &source, const ros::Time &common_time) const
RTT::OutputPort< tf2_msgs::TFMessage > port_tf_out
base::PortInterface & addPort(const std::string &name, base::PortInterface &port)
virtual bool createStream(ConnPolicy const &policy)
void broadcastTransform(const geometry_msgs::TransformStamped &tform)
const std::string & prefix_
bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, std::string *error_msg=NULL) const
static ConnPolicy buffer(int size, int lock_policy=LOCK_FREE, bool init_connection=false, bool pull=false)
WriteStatus write(const T &sample)
RTT::InputPort< tf2_msgs::TFMessage > port_tf_static_in
CompactFrameID _lookupFrameNumber(const std::string &frameid_str) const
RTT::InputPort< tf2_msgs::TFMessage > port_tf_in
void internalUpdate(tf2_msgs::TFMessage &msg, RTT::InputPort< tf2_msgs::TFMessage > &port, bool is_static)
PrefixResolver(const std::string &prefix)
int _getLatestCommonTime(CompactFrameID target_frame, CompactFrameID source_frame, ros::Time &time, std::string *error_string) const
void broadcastTransforms(const std::vector< geometry_msgs::TransformStamped > &tforms)
void broadcastStaticTransforms(const std::vector< geometry_msgs::TransformStamped > &tforms)
bool getParam(const std::string &key, std::string &s) const
void broadcastStaticTransform(const geometry_msgs::TransformStamped &tform)
tf2_msgs::TFMessage transformsToMessage(const std::vector< geometry_msgs::TransformStamped > &tforms, const std::string &prefix)
geometry_msgs::TransformStamped operator()(const geometry_msgs::TransformStamped &elem)
std::string name_id
RTT_TF(std::string const &name)
geometry_msgs::TransformStamped lookupTransformAtTime(const std::string &target, const std::string &source, const ros::Time &common_time) const
std::string prop_tf_prefix
geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time) const
virtual bool createStream(ConnPolicy const &policy)
virtual const std::string & getName() const


rtt_tf
Author(s): Ruben Smits
autogenerated on Sat Jun 8 2019 18:06:38