2 #include <geometry_msgs/TransformStamped.h> 3 #include <tf2_msgs/TFMessage.h> 15 if (s.length() > 0 && s[0] ==
'/')
29 this->nh.
param(
"buffer_size", buffer_size, 120.0);
31 bool publish_frame_service;
32 this->nh.
param(
"publish_frame_service", publish_frame_service,
false);
35 bool use_node_namespace;
36 this->nh.
param(
"use_node_namespace", use_node_namespace,
false);
37 std::string node_name;
38 if (use_node_namespace)
44 node_name =
"tf2_buffer_server";
47 this->pnh.
setParam(
"supports_transform_streams",
true);
50 this->pnh.
param(
"initial_streams_wait_time", duration, 1.0);
53 this->pnh.
param(
"transforms_update_period", duration, 1.0);
57 std::make_unique<tf2_ros::Buffer>(
ros::Duration(buffer_size), publish_frame_service);
58 this->
listener = std::make_unique<tf2_ros::TransformListener>(*
buffer, this->
nh);
59 this->
server = std::make_unique<tf2_ros::BufferServer>(*
buffer, node_name,
false);
69 this->pnh.
getParam(
"streams", initialStreamsParam);
72 ROS_ERROR(
"Parameter streams has to be a dictionary");
76 for (
const auto initialStream : initialStreamsParam)
78 const std::string streamName = initialStream.first;
82 ROS_ERROR(
"The definition of stream %s has to be a dictionary", streamName.c_str());
86 auto streamDef = initialStream.second;
87 RequestTransformStreamRequest req;
88 req.requested_topic_name = streamName;
89 req.publisher_queue_size = 10;
91 if (streamDef.hasMember(
"parent_frame"))
92 req.parent_frame = static_cast<std::string>(streamDef[
"parent_frame"]);
93 if (streamDef.hasMember(
"intermediate_frames"))
94 req.intermediate_frames = static_cast<bool>(streamDef[
"intermediate_frames"]);
95 if (streamDef.hasMember(
"publication_period"))
99 period = static_cast<int>(streamDef[
"publication_period"]);
101 period = static_cast<double>(streamDef[
"publication_period"]);
104 if (streamDef.hasMember(
"publisher_queue_size"))
105 req.publisher_queue_size = static_cast<int>(streamDef[
"publisher_queue_size"]);
106 if (streamDef.hasMember(
"allow_transforms_update"))
107 req.allow_transforms_update = static_cast<bool>(streamDef[
"allow_transforms_update"]);
108 if (streamDef.hasMember(
"child_frames"))
112 ROS_ERROR(
"child_frames of stream %s have to be an array", streamName.c_str());
116 for (
size_t i = 0; i < streamDef[
"child_frames"].size(); ++i)
118 req.child_frames.push_back(streamDef[
"child_frames"][i]);
142 bool operator==(
const tf2_msgs::TFMessage& lhs,
const tf2_msgs::TFMessage& rhs)
144 if (lhs.transforms.size() != rhs.transforms.size())
147 for (
size_t i = 0; i < lhs.transforms.size(); ++i)
149 const auto& lt = lhs.transforms[i];
150 const auto& rt = rhs.transforms[i];
152 if (lt.header.stamp != rt.header.stamp)
return false;
153 if (lt.header.frame_id != rt.header.frame_id)
return false;
154 if (lt.child_frame_id != rt.child_frame_id)
return false;
155 if (lt.transform.translation.x != rt.transform.translation.x)
return false;
156 if (lt.transform.translation.y != rt.transform.translation.y)
return false;
157 if (lt.transform.translation.z != rt.transform.translation.z)
return false;
158 if (lt.transform.rotation.x != rt.transform.rotation.x)
return false;
159 if (lt.transform.rotation.y != rt.transform.rotation.y)
return false;
160 if (lt.transform.rotation.z != rt.transform.rotation.z)
return false;
161 if (lt.transform.rotation.w != rt.transform.rotation.w)
return false;
167 bool operator!=(
const tf2_msgs::TFMessage& lhs,
const tf2_msgs::TFMessage& rhs)
169 return !(lhs == rhs);
173 RequestTransformStreamResponse &resp)
177 std::lock_guard<std::mutex> streamsLock(this->
streamsMutex);
180 if (topics.first.empty() || topics.second.empty())
186 const auto topicName = resp.topic_name = topics.first;
187 const auto staticTopicName = resp.static_topic_name = topics.second;
189 std::lock_guard<std::mutex> lock(this->
mutex);
194 if (framesList->empty() && !req.allow_transforms_update)
195 throw std::runtime_error(
"Could not find any child frames of frame " + req.parent_frame);
197 this->
frames[req] = std::move(framesList);
211 this->
nh.
advertise<tf2_msgs::TFMessage>(topicName, req.publisher_queue_size,
219 this->
nh.
advertise<tf2_msgs::TFMessage>(staticTopicName, req.publisher_queue_size,
229 const RequestTransformStreamRequest &request,
232 std::lock_guard<std::mutex> lock(this->
mutex);
234 if (this->
frames[request]->empty())
237 const ros::Duration timeout(request.publication_period.toSec() * 0.9 / this->
frames[request]->size());
238 tf2_msgs::TFMessage msg;
239 tf2_msgs::TFMessage staticMsg;
241 for (
const auto& frame : *this->
frames[request])
245 const auto transform = this->
buffer->lookupTransform(frame.first, frame.second,
ros::Time(0), timeout);
246 if (transform.header.stamp !=
ros::Time(0, 0))
247 msg.transforms.push_back(transform);
249 staticMsg.transforms.push_back(transform);
271 if (request.requested_topic_name.empty() && !request.requested_static_topic_name.empty())
273 throw std::runtime_error(
"when requested_static_topic_name is filled, " 274 "requested_topic_name has to be filled, too");
276 else if (!request.requested_topic_name.empty())
280 const auto topicName = this->
pnh.
resolveName(request.requested_topic_name);
283 !request.requested_static_topic_name.empty() ? request.requested_static_topic_name :
285 const TopicsSpec topics = std::make_pair(topicName, staticTopicName);
287 const auto existingStream = this->
streams.find(topics);
288 if (existingStream == this->
streams.end())
298 const auto existingRequest = (*existingStream).second;
299 const auto streamsCompatible = comp.
equals(request, existingRequest);
301 if (streamsCompatible)
304 throw std::runtime_error(std::string(
"TF stream requested on topics ") + topicName +
305 " and " + staticTopicName +
"is not compatible with the already existing stream on these topics.");
310 for (
const auto& stream : this->
streams)
312 const auto& topics = stream.first;
313 const auto& existingRequest = stream.second;
315 const auto streamsCompatible = comp.
equals(request, existingRequest);
317 if (streamsCompatible)
325 TopicsSpec topics = std::make_pair(std::string(
""), std::string(
""));
327 bool topicNameFound =
false;
328 for (
size_t i = 0; i < 10000; ++i)
334 topicNameFound =
true;
341 ROS_ERROR(
"Could not generate topic name for transform stream. Name validation error of last " 342 "tried name '%s' is: %s", topics.first.c_str(), error.c_str());
343 topics.first = topics.second =
"";
358 bool staticTopicNameFound =
false;
359 for (
size_t i = 0; i < 10000; ++i)
365 staticTopicNameFound =
true;
370 if (!staticTopicNameFound)
372 ROS_ERROR(
"Could not generate static topic name for transform stream. Name validation error of last " 373 "tried name '%s' is: %s", topics.second.c_str(), error.c_str());
374 topics.first = topics.second =
"";
386 auto result = std::make_unique<TF2Server::FramesList>();
389 if (!this->
buffer->_frameExists(req.parent_frame))
391 if (!req.allow_transforms_update)
397 if (!req.intermediate_frames)
399 result->reserve(req.child_frames.size());
400 for (
const auto& child : req.child_frames)
402 if (!this->
buffer->_frameExists(child))
404 if (!req.allow_transforms_update)
405 ROS_WARN(
"Frame %s doesn't exist, it won't be streamed.", child.c_str());
408 result->emplace_back(req.parent_frame, child);
413 std::vector<std::string> chainFrames;
414 std::vector<std::string> childFrames;
416 if (!req.child_frames.empty())
418 for (
const auto& child : req.child_frames)
420 if (!this->
buffer->_frameExists(child))
422 if (!req.allow_transforms_update)
423 ROS_WARN(
"Frame %s doesn't exist, it won't be streamed.", child.c_str());
426 childFrames.push_back(child);
431 std::vector<std::string> allFrames;
432 this->
buffer->_getFrameStrings(allFrames);
434 std::string parentParent;
435 if (!this->
buffer->_getParent(req.parent_frame,
ros::Time(0), parentParent))
438 for (
const auto& frame : allFrames)
440 if (frame == req.parent_frame)
455 ROS_ERROR(
"Error while searching TF tree: %s", e.what());
461 if (chainFrames[1] != parentParent)
462 childFrames.push_back(frame);
468 std::set<TF2Server::FrameSpec> framePairs;
469 for (
const auto& child : childFrames)
474 if (chainFrames.size() <= 1)
477 for (
size_t i = 1; i < chainFrames.size(); ++i)
478 framePairs.emplace(chainFrames[i-1], chainFrames[i]);
481 result->insert(result->begin(), framePairs.begin(), framePairs.end());
494 std::lock_guard<std::mutex> lock(this->
mutex);
497 for (
auto &frame : this->
frames)
499 const auto &req = frame.first;
500 if (req.allow_transforms_update)
514 ROS_INFO(
"Started streaming %s, %s", topics.first.c_str(), topics.second.c_str());
516 this->
timers[topics].start();
526 ROS_INFO(
"Stopped streaming %s, %s", topics.first.c_str(), topics.second.c_str());
527 this->
timers[topics].stop();
537 RequestTransformStreamResponse resp;
540 ROS_INFO(
"Stream %s, %s ready", resp.topic_name.c_str(), resp.static_topic_name.c_str());
542 ROS_ERROR(
"There was an error setting up transform stream %s", req.requested_topic_name.c_str());
544 catch (std::runtime_error &e)
546 ROS_ERROR(
"There was an error setting up transform stream %s: %s", req.requested_topic_name.c_str(), e.what());
552 const tf2_server::RequestTransformStreamRequest &r1,
553 const tf2_server::RequestTransformStreamRequest &r2)
const 555 if (r1.intermediate_frames != r2.intermediate_frames)
556 return r1.intermediate_frames < r2.intermediate_frames;
557 else if (r1.allow_transforms_update != r2.allow_transforms_update)
558 return r1.allow_transforms_update < r2.allow_transforms_update;
559 else if (r1.parent_frame != r2.parent_frame)
560 return r1.parent_frame < r2.parent_frame;
561 else if (r1.child_frames.size() != r2.child_frames.size())
562 return r1.child_frames.size() < r2.child_frames.size();
565 for (
size_t i = 0; i < r1.child_frames.size(); ++i)
567 if (r1.child_frames[i] != r2.child_frames[i])
568 return r1.child_frames[i] < r2.child_frames[i];
575 const tf2_server::RequestTransformStreamRequest &r1,
576 const tf2_server::RequestTransformStreamRequest &r2)
const 578 return !this->operator()(r1, r2) && !this->operator()(r2, r1);
582 const tf2_server::RequestTransformStreamRequest &r1,
583 const tf2_server::RequestTransformStreamRequest &r2)
const 585 if (r1.intermediate_frames != r2.intermediate_frames)
586 return r1.intermediate_frames < r2.intermediate_frames;
587 else if (r1.allow_transforms_update != r2.allow_transforms_update)
588 return r1.allow_transforms_update < r2.allow_transforms_update;
589 else if (r1.publication_period != r2.publication_period)
590 return r1.publication_period < r2.publication_period;
591 else if (r1.publisher_queue_size != r2.publisher_queue_size)
592 return r1.publisher_queue_size < r2.publisher_queue_size;
593 else if (r1.parent_frame != r2.parent_frame)
594 return r1.parent_frame < r2.parent_frame;
595 else if (r1.child_frames.size() != r2.child_frames.size())
596 return r1.child_frames.size() < r2.child_frames.size();
599 for (
size_t i = 0; i < r1.child_frames.size(); ++i)
601 if (r1.child_frames[i] != r2.child_frames[i])
602 return r1.child_frames[i] < r2.child_frames[i];
610 const tf2_server::RequestTransformStreamRequest &r1,
611 const tf2_server::RequestTransformStreamRequest &r2)
const 613 return !this->operator()(r1, r2) && !this->operator()(r2, r1);
std::map< TopicsSpec, size_t > subscriberNumbers
std::string stripLeadingSlash(const std::string &s, const bool warn)
boost::shared_ptr< void const > VoidConstPtr
#define ROS_ERROR_STREAM_THROTTLE(period, args)
bool operator()(const tf2_server::RequestTransformStreamRequest &r1, const tf2_server::RequestTransformStreamRequest &r2) const
bool operator!=(const tf2_msgs::TFMessage &lhs, const tf2_msgs::TFMessage &rhs)
std::unique_ptr< tf2_ros::Buffer > buffer
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
std::map< RequestTransformStreamRequest, std::unique_ptr< FramesList >, RequestComparatorByFrames > frames
virtual void onSubscriberDisconnected(const TopicsSpec &topics)
std::map< TopicsSpec, ros::Timer > timers
std::unique_ptr< tf2_ros::TransformListener > listener
ROSCPP_DECL bool validate(const std::string &name, std::string &error)
TF2Server(ros::NodeHandle &nh, ros::NodeHandle &pnh)
virtual std::unique_ptr< FramesList > getFramesList(const RequestTransformStreamRequest &req) const
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void warnLeadingSlash(const std::string &s)
ros::Duration initialStreamsWaitTime
std::vector< RequestTransformStreamRequest > initialStreams
bool operator==(const tf2_msgs::TFMessage &lhs, const tf2_msgs::TFMessage &rhs)
ros::Timer initialStreamsTimer
bool equals(const tf2_server::RequestTransformStreamRequest &r1, const tf2_server::RequestTransformStreamRequest &r2) const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
Type const & getType() const
std::map< TopicsSpec, RequestTransformStreamRequest > streams
bool operator()(const tf2_server::RequestTransformStreamRequest &r1, const tf2_server::RequestTransformStreamRequest &r2) const
virtual void updateFramesLists()
bool getParam(const std::string &key, std::string &s) const
ros::Duration transformsUpdatePeriod
virtual TopicsSpec getTopicsNames(const RequestTransformStreamRequest &request)
std::map< std::string, ros::Publisher > staticPublishers
std::string resolveName(const std::string &name, bool remap=true) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool equals(const tf2_server::RequestTransformStreamRequest &r1, const tf2_server::RequestTransformStreamRequest &r2) const
#define ROS_WARN_STREAM(args)
bool hasParam(const std::string &key) const
ros::ServiceServer requestTransformStreamServer
std::pair< std::string, std::string > TopicsSpec
void registerInitialStreams()
ros::Time lastTransformsUpdateTime
std::map< std::string, ros::Publisher > publishers
const std::string & getNamespace() const
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
virtual void onSubscriberConnected(const TopicsSpec &topics)
std::unordered_set< std::string > topicNames
virtual void streamTransform(const ros::TimerEvent &event, const RequestTransformStreamRequest &request, const TopicsSpec &topics)
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
std::map< std::string, tf2_msgs::TFMessage > lastStaticTransforms
std::unique_ptr< tf2_ros::BufferServer > server
virtual bool onRequestTransformStream(RequestTransformStreamRequest &req, RequestTransformStreamResponse &resp)
std::mutex subscriberMutex