37#ifndef REALTIME_TOOLS__REALTIME_PUBLISHER_HPP_
38#define REALTIME_TOOLS__REALTIME_PUBLISHER_HPP_
42#include <condition_variable>
49#include "rclcpp/create_publisher.hpp"
50#include "rclcpp/publisher.hpp"
54template <
class MessageT>
60 using PublisherSharedPtr =
typename rclcpp::Publisher<MessageT>::SharedPtr;
62 using PublishedType =
typename rclcpp::TypeAdapter<MessageT>::custom_type;
63 using ROSMessageType =
typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
79 template <
typename NodeT>
81 NodeT && node,
const std::string & topic_name,
const rclcpp::QoS & qos,
82 const rclcpp::PublisherOptions & options = rclcpp::PublisherOptions())
85 return rclcpp::create_publisher<MessageT>(
86 std::forward<NodeT>(node), topic_name, qos, options);
99 [[deprecated(
"Use the constructor that creates the publisher internally instead.")]]
102 initialize([&]() {
return publisher; });
108 RCLCPP_DEBUG(rclcpp::get_logger(
"realtime_tools"),
"Waiting for publishing thread to stop....");
110 while (is_running()) {
111 std::this_thread::sleep_for(std::chrono::microseconds(100));
114 rclcpp::get_logger(
"realtime_tools"),
"Publishing thread stopped, joining thread....");
115 if (thread_.joinable()) {
130 std::unique_lock<std::mutex> lock(msg_mutex_);
131 keep_running_ =
false;
133 updated_cond_.notify_one();
142 std::unique_lock<std::mutex> lock(msg_mutex_, std::try_to_lock);
157 std::unique_lock<std::mutex> lock(msg_mutex_, std::try_to_lock);
160 std::unique_lock<std::mutex> scoped_lock(std::move(lock));
162 turn_.store(State::NON_REALTIME, std::memory_order_release);
164 updated_cond_.notify_one();
192 const std::mutex &
get_mutex()
const {
return msg_mutex_; }
195 template <
typename PublisherCreator>
196 void initialize(PublisherCreator && creator)
198 publisher_ = creator();
200 keep_running_ =
true;
201 turn_ = State::LOOP_NOT_STARTED;
203 thread_ = std::thread(&RealtimePublisher::publishingLoop,
this);
208 while (!thread_.joinable() ||
209 turn_.load(std::memory_order_acquire) == State::LOOP_NOT_STARTED) {
210 std::this_thread::sleep_for(std::chrono::microseconds(100));
219 bool can_publish(std::unique_lock<std::mutex> & lock)
const
221 return turn_.load(std::memory_order_acquire) == State::REALTIME && lock.owns_lock();
228 bool is_running()
const {
return is_running_; }
241 void publishingLoop()
245 while (keep_running_) {
249 turn_.store(State::REALTIME, std::memory_order_release);
251 std::unique_lock<std::mutex> lock_(msg_mutex_);
252 updated_cond_.wait(lock_, [&] {
return turn_ == State::NON_REALTIME || !keep_running_; });
258 publisher_->publish(outgoing);
264 PublisherSharedPtr publisher_;
265 std::atomic<bool> is_running_;
266 std::atomic<bool> keep_running_;
272 mutable std::mutex msg_mutex_;
273 std::condition_variable updated_cond_;
275 enum class State :
int { REALTIME, NON_REALTIME, LOOP_NOT_STARTED };
276 std::atomic<State> turn_;
279template <
class MessageT>
280using RealtimePublisherSharedPtr = std::shared_ptr<RealtimePublisher<MessageT>>;