16 #ifndef NAV2_ROS_COMMON__NODE_UTILS_HPP_
17 #define NAV2_ROS_COMMON__NODE_UTILS_HPP_
24 #include "rclcpp/version.h"
25 #include "rclcpp/rclcpp.hpp"
26 #include "rcl_interfaces/srv/list_parameters.hpp"
27 #include "pluginlib/exceptions.hpp"
28 #if RCLCPP_VERSION_GTE(30, 1, 4)
29 #include "ament_index_cpp/get_package_share_path.hpp"
31 #include "ament_index_cpp/get_package_share_directory.hpp"
36 #include <mach/mach.h>
37 #include <mach/thread_policy.h>
43 using std::chrono::high_resolution_clock;
46 using std::replace_if;
62 inline std::string sanitize_node_name(
const std::string & potential_node_name)
64 string node_name(potential_node_name);
68 begin(node_name), end(node_name),
69 [](
auto c) {
return !isalnum(c);},
80 inline std::string add_namespaces(
const std::string & top_ns,
const std::string & sub_ns =
"")
82 if (!top_ns.empty() && top_ns.back() ==
'/') {
83 if (top_ns.front() ==
'/') {
84 return top_ns + sub_ns;
86 return "/" + top_ns + sub_ns;
90 return top_ns +
"/" + sub_ns;
102 inline std::string time_to_string(
size_t len)
104 string output(len,
'0');
105 auto timepoint = high_resolution_clock::now();
106 auto timecount = timepoint.time_since_epoch().count();
107 auto timestring = to_string(timecount);
108 if (timestring.length() >= len) {
113 timestring.length() - len, len);
117 len - timestring.length(), timestring.length(),
119 0, timestring.length());
135 inline std::string generate_internal_node_name(
const std::string & prefix =
"")
137 return sanitize_node_name(prefix) +
"_" + time_to_string(8);
150 inline rclcpp::Node::SharedPtr generate_internal_node(
const std::string & prefix =
"")
153 rclcpp::NodeOptions()
154 .start_parameter_services(
false)
155 .start_parameter_event_publisher(
false)
156 .arguments({
"--ros-args",
"-r",
"__node:=" + generate_internal_node_name(prefix),
"--"});
157 return rclcpp::Node::make_shared(
"_", options);
160 using ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor;
171 template<
typename NodeT>
172 inline void declare_parameter_if_not_declared(
174 const std::string & parameter_name,
175 const rclcpp::ParameterValue & default_value,
176 const ParameterDescriptor & parameter_descriptor = ParameterDescriptor())
178 if (!node->has_parameter(parameter_name)) {
179 node->declare_parameter(parameter_name, default_value, parameter_descriptor);
191 template<
typename NodeT>
192 inline void declare_parameter_if_not_declared(
194 const std::string & parameter_name,
195 const rclcpp::ParameterType & param_type,
196 const ParameterDescriptor & parameter_descriptor = ParameterDescriptor())
198 if (!node->has_parameter(parameter_name)) {
199 node->declare_parameter(parameter_name, param_type, parameter_descriptor);
214 template<
typename ParameterT,
typename NodeT>
215 inline ParameterT declare_or_get_parameter(
217 const std::string & parameter_name,
218 const ParameterDescriptor & parameter_descriptor = ParameterDescriptor())
220 if (node->has_parameter(parameter_name)) {
221 return node->get_parameter(parameter_name).template get_value<ParameterT>();
223 auto param_type = rclcpp::ParameterValue{ParameterT{}}.get_type();
224 auto parameter = node->declare_parameter(parameter_name, param_type, parameter_descriptor);
225 if (parameter.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET) {
226 std::string description =
"Parameter " + parameter_name +
" not in overrides";
227 throw rclcpp::exceptions::InvalidParameterValueException(description.c_str());
229 return parameter.template get<ParameterT>();
232 using NodeParamInterfacePtr = rclcpp::node_interfaces::NodeParametersInterface::SharedPtr;
250 template<
typename ParamType>
251 inline ParamType declare_or_get_parameter(
252 const rclcpp::Logger & logger, NodeParamInterfacePtr param_interface,
253 const std::string & parameter_name,
const ParamType & default_value,
254 bool warn_if_no_override =
false,
bool strict_param_loading =
false,
255 const ParameterDescriptor & parameter_descriptor = ParameterDescriptor())
257 if (param_interface->has_parameter(parameter_name)) {
258 rclcpp::Parameter param(parameter_name, default_value);
259 param_interface->get_parameter(parameter_name, param);
260 return param.get_value<ParamType>();
263 auto return_value = param_interface
265 parameter_name, rclcpp::ParameterValue{default_value},
266 parameter_descriptor)
269 const bool no_param_override = param_interface->get_parameter_overrides().find(parameter_name) ==
270 param_interface->get_parameter_overrides().end();
271 if (no_param_override) {
272 if (warn_if_no_override) {
275 "Failed to get param " << parameter_name <<
" from overrides, using default value.");
277 if (strict_param_loading) {
278 std::string description =
"Parameter " + parameter_name +
279 " not in overrides and strict_param_loading is True";
280 throw rclcpp::exceptions::InvalidParameterValueException(description.c_str());
302 template<
typename ParamType,
typename NodeT>
303 inline ParamType declare_or_get_parameter(
304 NodeT node,
const std::string & parameter_name,
305 const ParamType & default_value,
306 const ParameterDescriptor & parameter_descriptor = ParameterDescriptor())
308 declare_parameter_if_not_declared(node,
"warn_on_missing_params", rclcpp::ParameterValue(
false));
309 bool warn_if_no_override{
false};
310 node->get_parameter(
"warn_on_missing_params", warn_if_no_override);
311 declare_parameter_if_not_declared(node,
"strict_param_loading", rclcpp::ParameterValue(
false));
312 bool strict_param_loading{
false};
313 node->get_parameter(
"strict_param_loading", strict_param_loading);
314 return declare_or_get_parameter(
315 node->get_logger(), node->get_node_parameters_interface(),
316 parameter_name, default_value, warn_if_no_override, strict_param_loading, parameter_descriptor);
328 template<
typename NodeT>
329 inline std::string get_plugin_type_param(
331 const std::string & plugin_name)
333 declare_parameter_if_not_declared(node, plugin_name +
".plugin", rclcpp::PARAMETER_STRING);
334 std::string plugin_type;
336 if (!node->get_parameter(plugin_name +
".plugin", plugin_type)) {
338 node->get_logger(),
"Can not get 'plugin' param value for %s", plugin_name.c_str());
339 throw pluginlib::PluginlibException(
"No 'plugin' param for param ns!");
341 }
catch (rclcpp::exceptions::ParameterUninitializedException & ex) {
342 RCLCPP_FATAL(node->get_logger(),
"'plugin' param not defined for %s", plugin_name.c_str());
343 throw pluginlib::PluginlibException(
"No 'plugin' param for param ns!");
354 inline void setSoftRealTimePriority()
358 thread_port_t thread = pthread_mach_thread_np(pthread_self());
360 thread_time_constraint_policy_data_t policy;
361 policy.period = 1000;
362 policy.computation = 800;
363 policy.constraint = 1000;
364 policy.preemptible = 1;
366 kern_return_t result = thread_policy_set(
368 THREAD_TIME_CONSTRAINT_POLICY,
369 (thread_policy_t)&policy,
370 THREAD_TIME_CONSTRAINT_POLICY_COUNT
373 if (result != KERN_SUCCESS) {
375 "Failed to set THREAD_TIME_CONSTRAINT_POLICY on macOS. "
376 "Thread remains at default priority. Mach Error Code: " +
377 std::to_string(result);
378 throw std::runtime_error(errmsg);
383 sch.sched_priority = 49;
384 if (sched_setscheduler(0, SCHED_FIFO, &sch) == -1) {
386 "Cannot set as real-time thread. Users must set: <username> hard rtprio 99 and "
387 "<username> soft rtprio 99 in /etc/security/limits.conf to enable "
388 "realtime prioritization! Error: ");
389 throw std::runtime_error(errmsg + std::strerror(errno));
394 template<
typename InterfaceT>
395 inline void setIntrospectionMode(
396 InterfaceT & ros_interface,
397 rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface,
398 rclcpp::Clock::SharedPtr clock)
400 #if RCLCPP_VERSION_GTE(29, 0, 0)
401 rcl_service_introspection_state_t introspection_state = RCL_SERVICE_INTROSPECTION_OFF;
402 if (!node_parameters_interface->has_parameter(
"introspection_mode")) {
403 node_parameters_interface->declare_parameter(
404 "introspection_mode", rclcpp::ParameterValue(
"disabled"));
406 std::string introspection_mode =
407 node_parameters_interface->get_parameter(
"introspection_mode").as_string();
408 if (introspection_mode ==
"metadata") {
409 introspection_state = RCL_SERVICE_INTROSPECTION_METADATA;
410 }
else if (introspection_mode ==
"contents") {
411 introspection_state = RCL_SERVICE_INTROSPECTION_CONTENTS;
414 ros_interface->configure_introspection(clock, rclcpp::ServicesQoS(), introspection_state);
417 (void)node_parameters_interface;
427 inline void replaceOrAddArgument(
428 std::vector<std::string> & arguments,
const std::string & option,
429 const std::string & arg_name,
const std::string & new_argument)
431 auto argument = std::find_if(
432 arguments.begin(), arguments.end(),
433 [arg_name](
const std::string & value) {return value.find(arg_name) != std::string::npos;});
434 if (argument != arguments.end()) {
435 *argument = new_argument;
437 arguments.push_back(
"--ros-args");
438 arguments.push_back(option);
439 arguments.push_back(new_argument);
443 inline std::string get_package_share_directory(
const std::string & package_name)
445 #if RCLCPP_VERSION_GTE(30, 1, 4)
446 std::filesystem::path pkg_share_dir = ament_index_cpp::get_package_share_path(package_name);
447 return pkg_share_dir.string();
449 return ament_index_cpp::get_package_share_directory(package_name);