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;
81 template <
typename NodeT>
83 NodeT && node,
const std::string & topic_name,
const rclcpp::QoS & qos,
84 const rclcpp::PublisherOptions & options = rclcpp::PublisherOptions())
87 return rclcpp::create_publisher<MessageT>(
88 std::forward<NodeT>(node), topic_name, qos, options);
103 initialize([&]() {
return publisher; });
107 "Use constructor with rclcpp::Publisher<T>::SharedPtr instead - this class does not make sense "
108 "without a real publisher")]]
110 : is_running_(false), keep_running_(false), turn_(State::LOOP_NOT_STARTED)
117 RCLCPP_DEBUG(rclcpp::get_logger(
"realtime_tools"),
"Waiting for publishing thread to stop....");
119 while (is_running()) {
120 std::this_thread::sleep_for(std::chrono::microseconds(100));
123 rclcpp::get_logger(
"realtime_tools"),
"Publishing thread stopped, joining thread....");
124 if (thread_.joinable()) {
139 std::unique_lock<std::mutex>
lock(msg_mutex_);
140 keep_running_ =
false;
142 updated_cond_.notify_one();
155 return turn_.load(std::memory_order_acquire) == State::REALTIME && msg_mutex_.try_lock();
165 std::unique_lock<std::mutex>
lock(msg_mutex_, std::try_to_lock);
180 std::unique_lock<std::mutex>
lock(msg_mutex_, std::try_to_lock);
183 std::unique_lock<std::mutex> scoped_lock(std::move(
lock));
185 turn_.store(State::NON_REALTIME, std::memory_order_release);
187 updated_cond_.notify_one();
205 "Use try_publish() method instead of this method. This method may be removed in future "
221 turn_.store(State::NON_REALTIME, std::memory_order_release);
231 void lock() { msg_mutex_.lock(); }
240 updated_cond_.notify_one();
243 std::thread & get_thread() {
return thread_; }
245 const std::thread & get_thread()
const {
return thread_; }
247 const MessageT & get_msg()
const {
return msg_; }
249 std::mutex & get_mutex() {
return msg_mutex_; }
251 const std::mutex & get_mutex()
const {
return msg_mutex_; }
254 template <
typename PublisherCreator>
255 void initialize(PublisherCreator && creator)
257 publisher_ = creator();
259 keep_running_ =
true;
260 turn_ = State::LOOP_NOT_STARTED;
262 thread_ = std::thread(&RealtimePublisher::publishingLoop,
this);
267 while (!thread_.joinable() ||
268 turn_.load(std::memory_order_acquire) == State::LOOP_NOT_STARTED) {
269 std::this_thread::sleep_for(std::chrono::microseconds(100));
281 return turn_.load(std::memory_order_acquire) == State::REALTIME &&
lock.owns_lock();
288 bool is_running()
const {
return is_running_; }
301 void publishingLoop()
305 while (keep_running_) {
309 turn_.store(State::REALTIME, std::memory_order_release);
311 std::unique_lock<std::mutex> lock_(msg_mutex_);
312 updated_cond_.wait(lock_, [&] {
return turn_ == State::NON_REALTIME || !keep_running_; });
318 publisher_->publish(outgoing);
324 PublisherSharedPtr publisher_;
325 std::atomic<bool> is_running_;
326 std::atomic<bool> keep_running_;
330 mutable std::mutex msg_mutex_;
331 std::condition_variable updated_cond_;
333 enum class State :
int { REALTIME, NON_REALTIME, LOOP_NOT_STARTED };
334 std::atomic<State> turn_;
337template <
class MessageT>
338using RealtimePublisherSharedPtr = std::shared_ptr<RealtimePublisher<MessageT>>;