17 #include <unordered_set>
21 #include "builtin_interfaces/msg/time.hpp"
25 #include "rclcpp/clock.hpp"
26 #include "rclcpp/exceptions.hpp"
27 #include "rclcpp/logging.hpp"
28 #include "rclcpp/node.hpp"
29 #include "rclcpp/parameter_client.hpp"
30 #include "rclcpp/parameter_events_filter.hpp"
31 #include "rclcpp/time.hpp"
32 #include "rclcpp/time_source.hpp"
46 void enable_ros_time()
48 if (ros_time_active_) {
54 ros_time_active_ =
true;
57 set_all_clocks(last_time_msg_,
true);
61 void disable_ros_time()
63 if (!ros_time_active_) {
69 ros_time_active_ =
false;
72 builtin_interfaces::msg::Time msg;
73 set_all_clocks(msg,
false);
77 bool is_ros_time_active()
const
79 return ros_time_active_;
83 void attachClock(
const rclcpp::Clock::SharedPtr & clock)
86 std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
87 if (clock->get_clock_type() !=
RCL_ROS_TIME && ros_time_active_) {
88 throw std::invalid_argument(
89 "ros_time_active_ can't be true while clock is not of RCL_ROS_TIME type");
92 std::lock_guard<std::mutex> guard(clock_list_lock_);
93 associated_clocks_.insert(clock);
95 set_clock(last_time_msg_, ros_time_active_, clock);
99 void detachClock(
const rclcpp::Clock::SharedPtr & clock)
101 std::lock_guard<std::mutex> guard(clock_list_lock_);
102 auto removed = associated_clocks_.erase(clock);
104 RCLCPP_ERROR(logger_,
"failed to remove clock");
109 static void set_clock(
110 const builtin_interfaces::msg::Time & msg,
111 bool set_ros_time_enabled,
112 const rclcpp::Clock::SharedPtr & clock)
114 std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
118 if (!set_ros_time_enabled && clock->ros_time_is_active()) {
121 rclcpp::exceptions::throw_from_rcl_error(
122 ret,
"Failed to disable ros_time_override_status");
124 }
else if (set_ros_time_enabled && !clock->ros_time_is_active()) {
127 rclcpp::exceptions::throw_from_rcl_error(
128 ret,
"Failed to enable ros_time_override_status");
133 clock->get_clock_handle(),
136 rclcpp::exceptions::throw_from_rcl_error(
137 ret,
"Failed to set ros_time_override_status");
139 }
else if (set_ros_time_enabled) {
140 throw std::invalid_argument(
141 "set_ros_time_enabled can't be true while clock is not of RCL_ROS_TIME type");
147 const builtin_interfaces::msg::Time & msg,
148 bool set_ros_time_enabled)
150 std::lock_guard<std::mutex> guard(clock_list_lock_);
151 for (
auto it = associated_clocks_.begin(); it != associated_clocks_.end(); ++it) {
152 set_clock(msg, set_ros_time_enabled, *it);
157 void cache_last_msg(
const builtin_interfaces::msg::Time & msg)
159 last_time_msg_ = msg;
162 bool are_all_clocks_rcl_ros_time()
164 std::lock_guard<std::mutex> guard(clock_list_lock_);
165 for (
auto & clock : associated_clocks_) {
166 std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
179 std::mutex clock_list_lock_;
181 std::unordered_set<rclcpp::Clock::SharedPtr> associated_clocks_;
185 bool ros_time_active_{
false};
187 builtin_interfaces::msg::Time last_time_msg_{};
194 : use_clock_thread_(use_clock_thread),
203 node_base_ || node_topics_ || node_graph_ || node_services_ ||
204 node_logging_ || node_clock_ || node_parameters_)
211 bool get_use_clock_thread()
213 return use_clock_thread_;
217 void set_use_clock_thread(
bool use_clock_thread)
219 use_clock_thread_ = use_clock_thread;
223 bool clock_thread_is_joinable()
225 return clock_executor_thread_.joinable();
230 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
231 rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
232 rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
233 rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
234 rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_interface,
235 rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_interface,
236 rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface)
238 std::lock_guard<std::mutex> guard(node_base_lock_);
239 node_base_ = std::move(node_base_interface);
240 node_topics_ = std::move(node_topics_interface);
241 node_graph_ = std::move(node_graph_interface);
242 node_services_ = std::move(node_services_interface);
243 node_logging_ = std::move(node_logging_interface);
244 node_clock_ = std::move(node_clock_interface);
245 node_parameters_ = std::move(node_parameters_interface);
248 logger_ = node_logging_->get_logger();
254 const std::string use_sim_time_name =
"use_sim_time";
255 if (!node_parameters_->has_parameter(use_sim_time_name)) {
256 use_sim_time_param = node_parameters_->declare_parameter(
260 use_sim_time_param = node_parameters_->get_parameter(use_sim_time_name).get_parameter_value();
262 if (use_sim_time_param.
get_type() == rclcpp::PARAMETER_BOOL) {
263 if (use_sim_time_param.get<
bool>()) {
264 sim_time_parameter_state_ =
true;
265 clocks_state_.enable_ros_time();
270 logger_,
"Invalid type '%s' for parameter 'use_sim_time', should be 'bool'",
272 throw std::invalid_argument(
"Invalid type for parameter 'use_sim_time', should be 'bool'");
275 on_set_parameters_callback_ = node_parameters_->add_on_set_parameters_callback(
276 std::bind(&TimeSource::NodeState::on_set_parameters,
this, std::placeholders::_1));
278 post_set_parameters_callback_ = node_parameters_->add_post_set_parameters_callback(
279 std::bind(&TimeSource::NodeState::post_set_parameters,
this, std::placeholders::_1));
288 std::lock_guard<std::mutex> guard(node_base_lock_);
289 clocks_state_.disable_ros_time();
290 if (on_set_parameters_callback_) {
291 node_parameters_->remove_on_set_parameters_callback(on_set_parameters_callback_.get());
293 if (post_set_parameters_callback_) {
294 node_parameters_->remove_post_set_parameters_callback(post_set_parameters_callback_.get());
296 on_set_parameters_callback_.reset();
297 post_set_parameters_callback_.reset();
299 node_topics_.reset();
301 node_services_.reset();
302 node_logging_.reset();
304 node_parameters_.reset();
307 void attachClock(
const std::shared_ptr<rclcpp::Clock> & clock)
309 clocks_state_.attachClock(clock);
312 void detachClock(
const std::shared_ptr<rclcpp::Clock> & clock)
314 clocks_state_.detachClock(clock);
321 bool use_clock_thread_;
322 std::thread clock_executor_thread_;
325 std::mutex node_base_lock_;
326 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_{
nullptr};
327 rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_{
nullptr};
328 rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_{
nullptr};
329 rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_{
nullptr};
330 rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_{
nullptr};
331 rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_{
nullptr};
332 rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_{
nullptr};
342 std::shared_ptr<SubscriptionT> clock_subscription_{
nullptr};
343 std::mutex clock_sub_lock_;
344 rclcpp::CallbackGroup::SharedPtr clock_callback_group_;
345 rclcpp::executors::SingleThreadedExecutor::SharedPtr clock_executor_;
348 void clock_cb(
const std::shared_ptr<const rosgraph_msgs::msg::Clock> & msg)
350 if (!clocks_state_.is_ros_time_active() && sim_time_parameter_state_) {
351 clocks_state_.enable_ros_time();
354 clocks_state_.cache_last_msg(msg->clock);
356 if (sim_time_parameter_state_) {
357 clocks_state_.set_all_clocks(msg->clock,
true);
362 void create_clock_sub()
364 std::lock_guard<std::mutex> guard(clock_sub_lock_);
365 if (clock_subscription_) {
373 rclcpp::QosPolicyKind::Depth,
374 rclcpp::QosPolicyKind::Durability,
375 rclcpp::QosPolicyKind::History,
376 rclcpp::QosPolicyKind::Reliability,
379 if (use_clock_thread_) {
380 clock_callback_group_ = node_base_->create_callback_group(
381 rclcpp::CallbackGroupType::MutuallyExclusive,
386 exec_options.context = node_base_->get_context();
388 std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
389 if (!clock_executor_thread_.joinable()) {
390 clock_executor_thread_ = std::thread(
392 clock_executor_->add_callback_group(clock_callback_group_, node_base_);
393 clock_executor_->spin();
399 clock_subscription_ = rclcpp::create_subscription<rosgraph_msgs::msg::Clock>(
404 [
this](
const std::shared_ptr<const rosgraph_msgs::msg::Clock> & msg) {
405 bool execute_cb =
false;
407 std::lock_guard<std::mutex> guard(node_base_lock_);
410 execute_cb = node_base_ !=
nullptr;
421 void destroy_clock_sub()
423 std::lock_guard<std::mutex> guard(clock_sub_lock_);
424 if (clock_executor_thread_.joinable()) {
425 clock_executor_->cancel();
426 clock_executor_thread_.join();
427 clock_executor_->remove_callback_group(clock_callback_group_);
429 clock_subscription_.reset();
433 node_interfaces::OnSetParametersCallbackHandle::SharedPtr on_set_parameters_callback_{
nullptr};
436 node_interfaces::PostSetParametersCallbackHandle::SharedPtr
437 post_set_parameters_callback_{
nullptr};
440 rcl_interfaces::msg::SetParametersResult on_set_parameters(
441 const std::vector<rclcpp::Parameter> & parameters)
443 rcl_interfaces::msg::SetParametersResult result;
444 result.successful =
true;
445 for (
const auto & param : parameters) {
446 if (param.get_name() ==
"use_sim_time" && param.get_type() == rclcpp::PARAMETER_BOOL) {
447 if (param.as_bool() && !(clocks_state_.are_all_clocks_rcl_ros_time())) {
448 result.successful =
false;
450 "use_sim_time parameter can't be true while clocks are not all of RCL_ROS_TIME type";
453 "use_sim_time parameter can't be true while clocks are not all of RCL_ROS_TIME type");
461 void post_set_parameters(
const std::vector<rclcpp::Parameter> & parameters)
464 for (
const auto & param : parameters) {
465 if (param.get_name() ==
"use_sim_time") {
466 if (param.as_bool()) {
467 sim_time_parameter_state_ =
true;
468 clocks_state_.enable_ros_time();
471 sim_time_parameter_state_ =
false;
473 clocks_state_.disable_ros_time();
479 bool sim_time_parameter_state_ =
false;
483 const std::shared_ptr<rclcpp::Node> & node,
485 bool use_clock_thread)
493 bool use_clock_thread)
494 : constructed_use_clock_thread_(use_clock_thread),
495 constructed_qos_(qos)
497 node_state_ = std::make_shared<NodeState>(qos, use_clock_thread);
502 node_state_->set_use_clock_thread(node->get_node_options().use_clock_thread());
504 node->get_node_base_interface(),
505 node->get_node_topics_interface(),
506 node->get_node_graph_interface(),
507 node->get_node_services_interface(),
508 node->get_node_logging_interface(),
509 node->get_node_clock_interface(),
510 node->get_node_parameters_interface());
514 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
515 rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
516 rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
517 rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
518 rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_interface,
519 rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_interface,
520 rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface)
522 node_state_->attachNode(
523 std::move(node_base_interface),
524 std::move(node_topics_interface),
525 std::move(node_graph_interface),
526 std::move(node_services_interface),
527 std::move(node_logging_interface),
528 std::move(node_clock_interface),
529 std::move(node_parameters_interface));
535 node_state_ = std::make_shared<NodeState>(
537 constructed_use_clock_thread_);
542 node_state_->attachClock(clock);
547 node_state_->detachClock(clock);
552 return node_state_->get_use_clock_thread();
557 node_state_->set_use_clock_thread(use_clock_thread);
562 return node_state_->clock_thread_is_joinable();
Store the type and value of a parameter.
RCLCPP_PUBLIC ParameterType get_type() const
Return an enum indicating the type of the set value.
Encapsulation of Quality of Service settings.
Options that are passed in subscription/publisher constructor to specify QoSConfigurability.
Subscription implementation, templated on the type of message this subscription receives.
RCLCPP_PUBLIC bool get_use_clock_thread()
Get whether a separate clock thread is used or not.
RCLCPP_PUBLIC void attachNode(const rclcpp::Node::SharedPtr &node)
Attach node to the time source.
RCLCPP_PUBLIC void set_use_clock_thread(bool use_clock_thread)
Set whether to use a separate clock thread or not.
RCLCPP_PUBLIC bool clock_thread_is_joinable()
Check if the clock thread is joinable.
RCLCPP_PUBLIC ~TimeSource()
TimeSource Destructor.
RCLCPP_PUBLIC void attachClock(const rclcpp::Clock::SharedPtr &clock)
Attach a clock to the time source to be updated.
RCLCPP_PUBLIC void detachNode()
Detach the node from the time source.
RCLCPP_PUBLIC TimeSource(const rclcpp::Node::SharedPtr &node, const rclcpp::QoS &qos=rclcpp::ClockQoS(), bool use_clock_thread=true)
Constructor.
RCLCPP_PUBLIC void detachClock(const rclcpp::Clock::SharedPtr &clock)
Detach a clock from the time source.
RCLCPP_PUBLIC rcl_time_point_value_t nanoseconds() const
Get the nanoseconds since epoch.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string to_string(const FutureReturnCode &future_return_code)
String conversion function for FutureReturnCode.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Options to be passed to the executor constructor.
rclcpp::CallbackGroup::SharedPtr callback_group
The callback group for this subscription. NULL to use the default callback group.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_enable_ros_time_override(rcl_clock_t *clock)
Enable the ROS time abstraction override.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_disable_ros_time_override(rcl_clock_t *clock)
Disable the ROS time abstraction override.
@ RCL_ROS_TIME
Use ROS time.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_set_ros_time_override(rcl_clock_t *clock, rcl_time_point_value_t time_value)
Set the current time for this RCL_ROS_TIME time source.
#define RCL_RET_OK
Success return code.