Skip to content

Commit b950c7e

Browse files
authored
Backport of #673 ("Adding static transform listener") to jazzy with ABI compatibility preserved (#927)
Signed-off-by: Taiga Arai <araitaiga2020.service@gmail.com>
1 parent 1137702 commit b950c7e

3 files changed

Lines changed: 327 additions & 1 deletion

File tree

tf2_ros/include/tf2_ros/transform_listener.hpp

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ class TransformListener
9393
TF2_ROS_PUBLIC
9494
explicit TransformListener(tf2::BufferCore & buffer, bool spin_thread = true);
9595

96+
/** \brief Simplified constructor for transform listener with static_only option.
97+
*
98+
* This constructor will create a new ROS 2 node under the hood.
99+
* If you already have access to a ROS 2 node and you want to associate the TransformListener
100+
* to it, then it's recommended to use one of the other constructors.
101+
*/
102+
TF2_ROS_PUBLIC
103+
explicit TransformListener(
104+
tf2::BufferCore & buffer,
105+
bool spin_thread,
106+
bool static_only);
107+
96108
/** \brief Node constructor */
97109
template<class NodeT, class AllocatorT = std::allocator<void>>
98110
TransformListener(
@@ -118,6 +130,31 @@ class TransformListener
118130
static_options)
119131
{}
120132

133+
/** \brief Node constructor with static_only option */
134+
template<class NodeT, class AllocatorT = std::allocator<void>>
135+
TransformListener(
136+
tf2::BufferCore & buffer,
137+
NodeT && node,
138+
bool spin_thread,
139+
const rclcpp::QoS & qos,
140+
const rclcpp::QoS & static_qos,
141+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
142+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & static_options,
143+
bool static_only)
144+
: TransformListener(
145+
buffer,
146+
node->get_node_base_interface(),
147+
node->get_node_logging_interface(),
148+
node->get_node_parameters_interface(),
149+
node->get_node_topics_interface(),
150+
spin_thread,
151+
qos,
152+
static_qos,
153+
options,
154+
static_options,
155+
static_only)
156+
{}
157+
121158
/** \brief Node interface constructor */
122159
template<class AllocatorT = std::allocator<void>>
123160
TransformListener(
@@ -147,6 +184,35 @@ class TransformListener
147184
static_options);
148185
}
149186

187+
/** \brief Node interface constructor with static_only option */
188+
template<class AllocatorT = std::allocator<void>>
189+
TransformListener(
190+
tf2::BufferCore & buffer,
191+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
192+
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
193+
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
194+
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
195+
bool spin_thread,
196+
const rclcpp::QoS & qos,
197+
const rclcpp::QoS & static_qos,
198+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
199+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & static_options,
200+
bool static_only)
201+
: buffer_(buffer)
202+
{
203+
init(
204+
node_base,
205+
node_logging,
206+
node_parameters,
207+
node_topics,
208+
spin_thread,
209+
qos,
210+
static_qos,
211+
options,
212+
static_options,
213+
static_only);
214+
}
215+
150216
TF2_ROS_PUBLIC
151217
virtual ~TransformListener();
152218

@@ -216,6 +282,71 @@ class TransformListener
216282
}
217283
}
218284

285+
// Overload of init() with the static_only flag
286+
template<class AllocatorT = std::allocator<void>>
287+
void init(
288+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
289+
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
290+
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
291+
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
292+
bool spin_thread,
293+
const rclcpp::QoS & qos,
294+
const rclcpp::QoS & static_qos,
295+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
296+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & static_options,
297+
bool static_only)
298+
{
299+
if (!static_only) {
300+
init(
301+
node_base,
302+
node_logging,
303+
node_parameters,
304+
node_topics,
305+
spin_thread,
306+
qos,
307+
static_qos,
308+
options,
309+
static_options);
310+
return;
311+
}
312+
313+
spin_thread_ = spin_thread;
314+
node_base_interface_ = node_base;
315+
node_logging_interface_ = node_logging;
316+
317+
using callback_t = std::function<void (tf2_msgs::msg::TFMessage::ConstSharedPtr)>;
318+
callback_t static_cb = std::bind(
319+
&TransformListener::subscription_callback, this, std::placeholders::_1, true);
320+
321+
if (spin_thread_) {
322+
callback_group_ = node_base_interface_->create_callback_group(
323+
rclcpp::CallbackGroupType::MutuallyExclusive, false);
324+
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> tf_static_options = static_options;
325+
tf_static_options.callback_group = callback_group_;
326+
327+
message_subscription_tf_static_ = rclcpp::create_subscription<tf2_msgs::msg::TFMessage>(
328+
node_parameters,
329+
node_topics,
330+
"/tf_static",
331+
static_qos,
332+
std::move(static_cb),
333+
tf_static_options);
334+
335+
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
336+
executor_->add_callback_group(callback_group_, node_base_interface_);
337+
dedicated_listener_thread_ = std::make_unique<std::thread>([&]() {executor_->spin();});
338+
buffer_.setUsingDedicatedThread(true);
339+
} else {
340+
message_subscription_tf_static_ = rclcpp::create_subscription<tf2_msgs::msg::TFMessage>(
341+
node_parameters,
342+
node_topics,
343+
"/tf_static",
344+
static_qos,
345+
std::move(static_cb),
346+
static_options);
347+
}
348+
}
349+
219350
bool spin_thread_{false};
220351
std::unique_ptr<std::thread> dedicated_listener_thread_ {nullptr};
221352
rclcpp::Executor::SharedPtr executor_ {nullptr};
@@ -231,6 +362,78 @@ class TransformListener
231362
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_ {nullptr};
232363
rclcpp::CallbackGroup::SharedPtr callback_group_{nullptr};
233364
};
365+
366+
/** \brief Convenience class for subscribing to static-only transforms
367+
*
368+
* While users can achieve the same thing with a normal TransformListener, the number of parameters that must be
369+
* provided is unwieldy.
370+
*/
371+
class StaticTransformListener : public TransformListener
372+
{
373+
public:
374+
/** \brief Simplified constructor for a static transform listener
375+
* \see the simplified TransformListener documentation
376+
*/
377+
TF2_ROS_PUBLIC
378+
explicit StaticTransformListener(tf2::BufferCore & buffer, bool spin_thread = true)
379+
: TransformListener(buffer, spin_thread, true)
380+
{
381+
}
382+
383+
/** \brief Node constructor */
384+
template<class NodeT, class AllocatorT = std::allocator<void>>
385+
StaticTransformListener(
386+
tf2::BufferCore & buffer,
387+
NodeT && node,
388+
bool spin_thread = true,
389+
const rclcpp::QoS & static_qos = StaticListenerQoS(),
390+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & static_options =
391+
detail::get_default_transform_listener_static_sub_options<AllocatorT>())
392+
: TransformListener(
393+
buffer,
394+
node,
395+
spin_thread,
396+
rclcpp::QoS(1),
397+
static_qos,
398+
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>(),
399+
static_options,
400+
true)
401+
{
402+
}
403+
404+
/** \brief Node interface constructor */
405+
template<class AllocatorT = std::allocator<void>>
406+
StaticTransformListener(
407+
tf2::BufferCore & buffer,
408+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
409+
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
410+
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
411+
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
412+
bool spin_thread = true,
413+
const rclcpp::QoS & static_qos = StaticListenerQoS(),
414+
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & static_options =
415+
detail::get_default_transform_listener_static_sub_options<AllocatorT>())
416+
: TransformListener(
417+
buffer,
418+
node_base,
419+
node_logging,
420+
node_parameters,
421+
node_topics,
422+
spin_thread,
423+
rclcpp::QoS(1),
424+
static_qos,
425+
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>(),
426+
static_options,
427+
true)
428+
{
429+
}
430+
431+
TF2_ROS_PUBLIC
432+
virtual ~StaticTransformListener()
433+
{
434+
}
435+
};
436+
234437
} // namespace tf2_ros
235438

236439
#endif // TF2_ROS__TRANSFORM_LISTENER_HPP_

tf2_ros/src/transform_listener.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,34 @@ TransformListener::TransformListener(tf2::BufferCore & buffer, bool spin_thread)
6666
detail::get_default_transform_listener_static_sub_options());
6767
}
6868

69+
TransformListener::TransformListener(tf2::BufferCore & buffer, bool spin_thread, bool static_only)
70+
: buffer_(buffer)
71+
{
72+
rclcpp::NodeOptions options;
73+
// create a unique name for the node
74+
// but specify its name in .arguments to override any __node passed on the command line.
75+
// avoiding sstream because it's behavior can be overridden by external libraries.
76+
// See this issue: https://github.com/ros2/geometry2/issues/540
77+
char node_name[42];
78+
snprintf(
79+
node_name, sizeof(node_name), "transform_listener_impl_%zx",
80+
reinterpret_cast<size_t>(this)
81+
);
82+
options.arguments({"--ros-args", "-r", "__node:=" + std::string(node_name)});
83+
options.start_parameter_event_publisher(false);
84+
options.start_parameter_services(false);
85+
optional_default_node_ = rclcpp::Node::make_shared("_", options);
86+
init(
87+
optional_default_node_->get_node_base_interface(),
88+
optional_default_node_->get_node_logging_interface(),
89+
optional_default_node_->get_node_parameters_interface(),
90+
optional_default_node_->get_node_topics_interface(),
91+
spin_thread, DynamicListenerQoS(), StaticListenerQoS(),
92+
detail::get_default_transform_listener_sub_options(),
93+
detail::get_default_transform_listener_static_sub_options(),
94+
static_only);
95+
}
96+
6997
TransformListener::~TransformListener()
7098
{
7199
if (spin_thread_) {

0 commit comments

Comments
 (0)