15 #include "rclcpp/node_interfaces/node_parameters.hpp"
17 #include <rcl_yaml_param_parser/parser.h>
32 #include "rcl_interfaces/srv/list_parameters.hpp"
33 #include "rclcpp/create_publisher.hpp"
34 #include "rclcpp/parameter_map.hpp"
35 #include "rcutils/logging_macros.h"
36 #include "rmw/qos_profiles.h"
38 #include "../detail/resolve_parameter_overrides.hpp"
44 local_perform_automatically_declare_parameters_from_overrides(
45 const std::map<std::string, rclcpp::ParameterValue> & parameter_overrides,
46 std::function<
bool(
const std::string &)> has_parameter,
50 const rcl_interfaces::msg::ParameterDescriptor &,
54 rcl_interfaces::msg::ParameterDescriptor descriptor;
55 descriptor.dynamic_typing =
true;
56 for (
const auto & pair : parameter_overrides) {
57 if (!has_parameter(pair.first)) {
67 NodeParameters::NodeParameters(
68 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
69 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
70 rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
71 const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
72 const rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
73 const std::vector<rclcpp::Parameter> & parameter_overrides,
74 bool start_parameter_services,
75 bool start_parameter_event_publisher,
78 bool allow_undeclared_parameters,
79 bool automatically_declare_parameters_from_overrides)
80 : allow_undeclared_(allow_undeclared_parameters),
81 events_publisher_(nullptr),
82 node_logging_(node_logging),
83 node_clock_(node_clock)
85 using MessageT = rcl_interfaces::msg::ParameterEvent;
87 using AllocatorT = std::allocator<void>;
90 parameter_event_publisher_options);
91 publisher_options.
allocator = std::make_shared<AllocatorT>();
93 if (start_parameter_services) {
94 parameter_service_ = std::make_shared<ParameterService>(node_base, node_services,
this);
97 if (start_parameter_event_publisher) {
99 events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
107 const rcl_node_t * node = node_base->get_rcl_node_handle();
108 if (
nullptr == node) {
109 throw std::runtime_error(
"Need valid node handle in NodeParameters");
112 if (
nullptr == options) {
113 throw std::runtime_error(
"Need valid node options in NodeParameters");
118 auto context_ptr = node_base->get_context()->get_rcl_context();
119 global_args = &(context_ptr->global_arguments);
121 combined_name_ = node_base->get_fully_qualified_name();
123 parameter_overrides_ = rclcpp::detail::resolve_parameter_overrides(
124 combined_name_, parameter_overrides, &options->
arguments, global_args);
128 if (automatically_declare_parameters_from_overrides) {
129 using namespace std::placeholders;
130 local_perform_automatically_declare_parameters_from_overrides(
134 const std::string & name,
136 const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
137 bool ignore_override)
140 name, default_value, parameter_descriptor, ignore_override);
147 NodeParameters::perform_automatically_declare_parameters_from_overrides()
149 local_perform_automatically_declare_parameters_from_overrides(
151 [
this](
const std::string & name) {
155 const std::string & name,
157 const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
158 bool ignore_override)
161 name, default_value, parameter_descriptor, ignore_override);
166 NodeParameters::~NodeParameters()
171 __lockless_has_parameter(
172 const std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
173 const std::string & name)
175 return parameters.find(name) != parameters.end();
181 __are_doubles_equal(
double x,
double y,
double ulp = 100.0)
183 if (!std::isfinite(x) || !std::isfinite(y)) {
186 return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
191 format_range_reason(
const std::string & name,
const char * range_type)
193 std::ostringstream ss;
194 ss <<
"Parameter {" << name <<
"} doesn't comply with " << range_type <<
" range.";
200 format_range_type_reason(
201 const std::string & name,
202 const char * range_type,
203 rclcpp::ParameterType parameter_type)
205 std::ostringstream ss;
206 ss <<
"Parameter {" << name <<
"} of type {" <<
rclcpp::to_string(parameter_type) <<
207 "} cannot use " << range_type <<
" range constraints.";
212 rcl_interfaces::msg::SetParametersResult
213 __check_parameter_type_supports_range(
214 const rcl_interfaces::msg::ParameterDescriptor & descriptor,
215 rclcpp::ParameterType parameter_type)
217 rcl_interfaces::msg::SetParametersResult result;
218 result.successful =
true;
220 if (parameter_type == rclcpp::PARAMETER_NOT_SET) {
225 !descriptor.integer_range.empty() &&
226 parameter_type != rclcpp::PARAMETER_INTEGER &&
227 parameter_type != rclcpp::PARAMETER_INTEGER_ARRAY)
229 result.successful =
false;
230 result.reason = format_range_type_reason(descriptor.name,
"integer", parameter_type);
235 !descriptor.floating_point_range.empty() &&
236 parameter_type != rclcpp::PARAMETER_DOUBLE &&
237 parameter_type != rclcpp::PARAMETER_DOUBLE_ARRAY)
239 result.successful =
false;
240 result.reason = format_range_type_reason(descriptor.name,
"floating point", parameter_type);
247 rcl_interfaces::msg::SetParametersResult
248 __check_integer_range(
249 const rcl_interfaces::msg::ParameterDescriptor & descriptor,
252 rcl_interfaces::msg::SetParametersResult result;
253 result.successful =
true;
254 auto integer_range = descriptor.integer_range.at(0);
255 if (value == integer_range.from_value || value == integer_range.to_value) {
258 if ((value < integer_range.from_value) || (value > integer_range.to_value)) {
259 result.successful =
false;
260 result.reason = format_range_reason(descriptor.name,
"integer");
263 if (integer_range.step == 0) {
266 if (((value - integer_range.from_value) % integer_range.step) == 0) {
269 result.successful =
false;
270 result.reason = format_range_reason(descriptor.name,
"integer");
275 rcl_interfaces::msg::SetParametersResult
276 __check_double_range(
277 const rcl_interfaces::msg::ParameterDescriptor & descriptor,
280 rcl_interfaces::msg::SetParametersResult result;
281 result.successful =
true;
282 auto fp_range = descriptor.floating_point_range.at(0);
283 if (__are_doubles_equal(value, fp_range.from_value) || __are_doubles_equal(value,
288 if (!(value >= fp_range.from_value && value <= fp_range.to_value)) {
289 result.successful =
false;
290 result.reason = format_range_reason(descriptor.name,
"floating point");
293 if (fp_range.step == 0.0) {
296 double rounded_div = std::round((value - fp_range.from_value) / fp_range.step);
297 if (__are_doubles_equal(value, fp_range.from_value + rounded_div * fp_range.step)) {
300 result.successful =
false;
301 result.reason = format_range_reason(descriptor.name,
"floating point");
306 rcl_interfaces::msg::SetParametersResult
307 __check_parameter_value_in_range(
308 const rcl_interfaces::msg::ParameterDescriptor & descriptor,
311 auto result = __check_parameter_type_supports_range(descriptor, value.
get_type());
312 if (!result.successful) {
316 if (!descriptor.integer_range.empty() && value.
get_type() == rclcpp::PARAMETER_INTEGER) {
317 result = __check_integer_range(descriptor, value.get<int64_t>());
321 if (!descriptor.integer_range.empty() && value.
get_type() == rclcpp::PARAMETER_INTEGER_ARRAY) {
322 std::vector<int64_t> val_array = value.get<std::vector<int64_t>>();
323 for (
const int64_t & val : val_array) {
324 result = __check_integer_range(descriptor, val);
325 if (!result.successful) {
332 if (!descriptor.floating_point_range.empty() && value.
get_type() == rclcpp::PARAMETER_DOUBLE) {
333 result = __check_double_range(descriptor, value.get<
double>());
337 if (!descriptor.floating_point_range.empty() &&
338 value.
get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
340 std::vector<double> val_array = value.get<std::vector<double>>();
341 for (
const double & val : val_array) {
342 result = __check_double_range(descriptor, val);
343 if (!result.successful) {
356 const std::string & name,
const std::string & old_type,
const std::string & new_type)
358 std::ostringstream ss;
361 ss <<
"Wrong parameter type, parameter {" << name <<
"} is of type {" << old_type <<
362 "}, setting it to {" << new_type <<
"} is not allowed.";
368 rcl_interfaces::msg::SetParametersResult
370 std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
371 const std::vector<rclcpp::Parameter> & parameters,
372 bool allow_undeclared)
374 rcl_interfaces::msg::SetParametersResult result;
375 result.successful =
true;
377 std::string name = parameter.get_name();
378 rcl_interfaces::msg::ParameterDescriptor descriptor;
379 if (allow_undeclared) {
380 auto it = parameter_infos.find(name);
381 if (it != parameter_infos.cend()) {
382 descriptor = it->second.descriptor;
385 descriptor.dynamic_typing =
true;
388 descriptor = parameter_infos[name].descriptor;
390 if (descriptor.name.empty()) {
391 descriptor.name = name;
393 const auto new_type = parameter.get_type();
394 const auto specified_type =
static_cast<rclcpp::ParameterType
>(descriptor.type);
395 result.successful = descriptor.dynamic_typing || specified_type == new_type;
396 if (!result.successful) {
397 result.reason = format_type_reason(
401 result = __check_parameter_value_in_range(
403 parameter.get_parameter_value());
404 if (!result.successful) {
411 using PreSetParametersCallbackType =
412 rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
415 using PreSetCallbacksHandleContainer =
416 rclcpp::node_interfaces::NodeParameters::PreSetCallbacksHandleContainer;
418 using OnSetParametersCallbackType =
419 rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
422 using OnSetCallbacksHandleContainer =
423 rclcpp::node_interfaces::NodeParameters::OnSetCallbacksHandleContainer;
425 using PostSetParametersCallbackType =
426 rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
429 using PostSetCallbacksHandleContainer =
430 rclcpp::node_interfaces::NodeParameters::PostSetCallbacksHandleContainer;
434 __call_pre_set_parameters_callbacks(
435 std::vector<rclcpp::Parameter> & parameters,
436 PreSetCallbacksHandleContainer & callback_container)
438 if (callback_container.empty()) {
442 auto it = callback_container.begin();
443 while (it != callback_container.end()) {
444 auto shared_handle = it->lock();
445 if (
nullptr != shared_handle) {
446 shared_handle->callback(parameters);
449 it = callback_container.erase(it);
455 rcl_interfaces::msg::SetParametersResult
456 __call_on_set_parameters_callbacks(
457 const std::vector<rclcpp::Parameter> & parameters,
458 OnSetCallbacksHandleContainer & callback_container)
460 rcl_interfaces::msg::SetParametersResult result;
461 result.successful =
true;
462 auto it = callback_container.begin();
463 while (it != callback_container.end()) {
464 auto shared_handle = it->lock();
465 if (
nullptr != shared_handle) {
466 result = shared_handle->callback(parameters);
467 if (!result.successful) {
472 it = callback_container.erase(it);
479 void __call_post_set_parameters_callbacks(
480 const std::vector<rclcpp::Parameter> & parameters,
481 PostSetCallbacksHandleContainer & callback_container)
483 if (callback_container.empty()) {
487 auto it = callback_container.begin();
488 while (it != callback_container.end()) {
489 auto shared_handle = it->lock();
490 if (
nullptr != shared_handle) {
491 shared_handle->callback(parameters);
494 it = callback_container.erase(it);
500 rcl_interfaces::msg::SetParametersResult
501 __set_parameters_atomically_common(
502 const std::vector<rclcpp::Parameter> & parameters,
503 std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
504 OnSetCallbacksHandleContainer & on_set_callback_container,
505 PostSetCallbacksHandleContainer & post_set_callback_container,
506 bool allow_undeclared =
false)
509 rcl_interfaces::msg::SetParametersResult result = __check_parameters(
510 parameter_infos, parameters, allow_undeclared);
511 if (!result.successful) {
516 __call_on_set_parameters_callbacks(parameters, on_set_callback_container);
517 if (!result.successful) {
521 if (result.successful) {
522 for (
size_t i = 0; i < parameters.size(); ++i) {
523 const std::string & name = parameters[i].get_name();
524 parameter_infos[name].descriptor.name = parameters[i].get_name();
525 parameter_infos[name].descriptor.type = parameters[i].get_type();
526 parameter_infos[name].value = parameters[i].get_parameter_value();
529 __call_post_set_parameters_callbacks(parameters, post_set_callback_container);
537 rcl_interfaces::msg::SetParametersResult
538 __declare_parameter_common(
539 const std::string & name,
541 const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
542 std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
543 const std::map<std::string, rclcpp::ParameterValue> & overrides,
544 OnSetCallbacksHandleContainer & on_set_callback_container,
545 PostSetCallbacksHandleContainer & post_set_callback_container,
546 rcl_interfaces::msg::ParameterEvent * parameter_event_out,
547 bool ignore_override =
false)
550 std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
551 parameter_infos.at(name).
descriptor = parameter_descriptor;
555 auto overrides_it = overrides.find(name);
556 if (!ignore_override && overrides_it != overrides.end()) {
557 initial_value = &overrides_it->second;
561 if (initial_value->
get_type() == rclcpp::PARAMETER_NOT_SET) {
562 rcl_interfaces::msg::SetParametersResult result;
563 if (!parameter_descriptor.dynamic_typing) {
564 auto descriptor = parameter_descriptor;
565 descriptor.name = name;
566 result = __check_parameter_type_supports_range(
567 descriptor,
static_cast<rclcpp::ParameterType
>(descriptor.type));
568 if (!result.successful) {
574 parameter_infos[name].descriptor.name = name;
575 if (parameter_descriptor.dynamic_typing) {
576 parameter_infos[name].descriptor.type = rclcpp::PARAMETER_NOT_SET;
578 parameter_infos[name].descriptor.type = parameter_descriptor.type;
580 parameters_out[name] = parameter_infos.at(name);
581 result.successful =
true;
586 std::vector<rclcpp::Parameter> parameter_wrappers {
rclcpp::Parameter(name, *initial_value)};
588 auto result = __set_parameters_atomically_common(
591 on_set_callback_container,
592 post_set_callback_container
595 if (!result.successful) {
600 parameters_out[name] = parameter_infos.at(name);
603 if (parameter_event_out) {
604 parameter_event_out->new_parameters.push_back(parameter_wrappers[0].to_parameter_msg());
612 declare_parameter_helper(
613 const std::string & name,
614 rclcpp::ParameterType type,
616 rcl_interfaces::msg::ParameterDescriptor parameter_descriptor,
617 bool ignore_override,
618 std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
619 const std::map<std::string, rclcpp::ParameterValue> & overrides,
620 OnSetCallbacksHandleContainer & on_set_callback_container,
621 PostSetCallbacksHandleContainer & post_set_callback_container,
623 const std::string & combined_name,
632 if (__lockless_has_parameter(parameters, name)) {
634 "parameter '" + name +
"' has already been declared");
637 if (!parameter_descriptor.dynamic_typing) {
638 if (rclcpp::PARAMETER_NOT_SET == type) {
641 if (rclcpp::PARAMETER_NOT_SET == type) {
644 "cannot declare a statically typed parameter with an uninitialized value"
647 parameter_descriptor.type =
static_cast<uint8_t
>(type);
650 rcl_interfaces::msg::ParameterEvent parameter_event;
651 auto result = __declare_parameter_common(
654 parameter_descriptor,
657 on_set_callback_container,
658 post_set_callback_container,
663 if (!result.successful) {
664 constexpr
const char type_error_msg_start[] =
"Wrong parameter type";
667 result.reason.c_str(), type_error_msg_start,
sizeof(type_error_msg_start) - 1))
674 "parameter '" + name +
"' could not be set: " + result.reason);
678 if (
nullptr != events_publisher) {
679 parameter_event.node = combined_name;
680 parameter_event.stamp = node_clock.
get_clock()->now();
681 events_publisher->
publish(parameter_event);
684 return parameters.at(name).value;
689 const std::string & name,
691 const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
692 bool ignore_override)
694 std::lock_guard<std::recursive_mutex> lock(mutex_);
697 return declare_parameter_helper(
699 rclcpp::PARAMETER_NOT_SET,
701 parameter_descriptor,
704 parameter_overrides_,
705 on_set_parameters_callback_container_,
706 post_set_parameters_callback_container_,
707 events_publisher_.get(),
714 const std::string & name,
715 rclcpp::ParameterType type,
716 const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
717 bool ignore_override)
719 std::lock_guard<std::recursive_mutex> lock(mutex_);
722 if (rclcpp::PARAMETER_NOT_SET == type) {
723 throw std::invalid_argument{
724 "declare_parameter(): the provided parameter type cannot be rclcpp::PARAMETER_NOT_SET"};
727 if (parameter_descriptor.dynamic_typing ==
true) {
728 throw std::invalid_argument{
729 "declare_parameter(): cannot declare parameter of specific type and pass descriptor"
730 "with `dynamic_typing=true`"};
733 return declare_parameter_helper(
737 parameter_descriptor,
740 parameter_overrides_,
741 on_set_parameters_callback_container_,
742 post_set_parameters_callback_container_,
743 events_publisher_.get(),
751 std::lock_guard<std::recursive_mutex> lock(mutex_);
755 auto parameter_info = parameters_.find(name);
756 if (parameter_info == parameters_.end()) {
758 "cannot undeclare parameter '" + name +
"' which has not yet been declared");
761 if (parameter_info->second.descriptor.read_only) {
763 "cannot undeclare parameter '" + name +
"' because it is read-only");
765 if (!parameter_info->second.descriptor.dynamic_typing) {
767 name,
"cannot undeclare a statically typed parameter"};
770 parameters_.erase(parameter_info);
776 std::lock_guard<std::recursive_mutex> lock(mutex_);
778 return __lockless_has_parameter(parameters_, name);
781 std::vector<rcl_interfaces::msg::SetParametersResult>
784 std::vector<rcl_interfaces::msg::SetParametersResult> results;
785 results.reserve(parameters.size());
787 for (
const auto & p : parameters) {
789 results.push_back(result);
795 template<
typename ParameterVectorType>
797 __find_parameter_by_name(
798 ParameterVectorType & parameters,
799 const std::string & name)
804 [&](
auto parameter) {return parameter.get_name() == name;});
807 rcl_interfaces::msg::SetParametersResult
810 std::lock_guard<std::recursive_mutex> lock(mutex_);
814 rcl_interfaces::msg::SetParametersResult result;
819 std::vector<rclcpp::Parameter> parameters_after_pre_set_callback(parameters);
820 __call_pre_set_parameters_callbacks(
821 parameters_after_pre_set_callback,
822 pre_set_parameters_callback_container_);
824 if (parameters_after_pre_set_callback.empty()) {
825 result.successful =
false;
826 result.reason =
"parameter list cannot be empty, this might be due to "
827 "pre_set_parameters_callback modifying the original parameters list.";
835 std::vector<const rclcpp::Parameter *> parameters_to_be_declared;
836 for (
const auto & parameter : parameters_after_pre_set_callback) {
837 const std::string & name = parameter.get_name();
845 auto parameter_info = parameters_.find(name);
846 if (parameter_info == parameters_.end()) {
848 if (allow_undeclared_) {
850 parameters_to_be_declared.push_back(¶meter);
857 "parameter '" + name +
"' cannot be set because it was not declared");
862 if (parameter_info->second.descriptor.read_only) {
863 result.successful =
false;
864 result.reason =
"parameter '" + name +
"' cannot be set because it is read-only";
873 std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
874 rcl_interfaces::msg::ParameterEvent parameter_event_msg;
875 parameter_event_msg.node = combined_name_;
876 OnSetCallbacksHandleContainer empty_on_set_callback_container;
877 PostSetCallbacksHandleContainer empty_post_set_callback_container;
880 rcl_interfaces::msg::ParameterDescriptor descriptor;
881 descriptor.dynamic_typing =
true;
882 for (
auto parameter_to_be_declared : parameters_to_be_declared) {
885 result = __declare_parameter_common(
886 parameter_to_be_declared->get_name(),
887 parameter_to_be_declared->get_parameter_value(),
889 staged_parameter_changes,
890 parameter_overrides_,
892 empty_on_set_callback_container,
893 empty_post_set_callback_container,
894 ¶meter_event_msg,
896 if (!result.successful) {
906 const std::vector<rclcpp::Parameter> * parameters_to_be_set = ¶meters_after_pre_set_callback;
907 std::vector<rclcpp::Parameter> parameters_copy;
908 if (0 != staged_parameter_changes.size()) {
909 bool any_initial_values_used =
false;
910 for (
const auto & staged_parameter_change : staged_parameter_changes) {
911 auto it = __find_parameter_by_name(
912 parameters_after_pre_set_callback,
913 staged_parameter_change.first);
914 if (it->get_parameter_value() != staged_parameter_change.second.value) {
917 any_initial_values_used =
true;
922 if (any_initial_values_used) {
923 parameters_copy = parameters_after_pre_set_callback;
924 for (
const auto & staged_parameter_change : staged_parameter_changes) {
925 auto it = __find_parameter_by_name(parameters_copy, staged_parameter_change.first);
926 *it =
Parameter(staged_parameter_change.first, staged_parameter_change.second.value);
928 parameters_to_be_set = ¶meters_copy;
934 std::vector<const rclcpp::Parameter *> parameters_to_be_undeclared;
935 for (
const auto & parameter : *parameters_to_be_set) {
936 if (rclcpp::PARAMETER_NOT_SET == parameter.get_type()) {
937 auto it = parameters_.find(parameter.get_name());
938 if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
939 if (!it->second.descriptor.dynamic_typing) {
940 result.reason =
"cannot undeclare a statically typed parameter";
941 result.successful =
false;
944 parameters_to_be_undeclared.push_back(¶meter);
950 result = __set_parameters_atomically_common(
952 *parameters_to_be_set,
957 on_set_parameters_callback_container_,
958 post_set_parameters_callback_container_,
962 if (!result.successful) {
967 for (
const auto & kv_pair : staged_parameter_changes) {
969 assert(__lockless_has_parameter(parameters_, kv_pair.first));
971 assert(parameters_[kv_pair.first].value == kv_pair.second.value);
974 parameters_[kv_pair.first] = kv_pair.second;
978 for (
auto parameter_to_undeclare : parameters_to_be_undeclared) {
979 auto it = parameters_.find(parameter_to_undeclare->get_name());
981 assert(it != parameters_.end());
982 if (it != parameters_.end()) {
984 parameter_event_msg.deleted_parameters.push_back(
986 parameters_.erase(it);
992 for (
const auto & parameter : *parameters_to_be_set) {
993 if (staged_parameter_changes.find(parameter.get_name()) != staged_parameter_changes.end()) {
997 auto it = std::find_if(
998 parameters_to_be_undeclared.begin(),
999 parameters_to_be_undeclared.end(),
1000 [¶meter](
const auto & p) {return p->get_name() == parameter.get_name();});
1001 if (it != parameters_to_be_undeclared.end()) {
1006 parameter_event_msg.changed_parameters.push_back(parameter.to_parameter_msg());
1010 if (
nullptr != events_publisher_) {
1011 parameter_event_msg.stamp = node_clock_->get_clock()->now();
1012 events_publisher_->
publish(parameter_event_msg);
1017 std::vector<rclcpp::Parameter>
1020 std::vector<rclcpp::Parameter> results;
1021 results.reserve(names.size());
1023 std::lock_guard<std::recursive_mutex> lock(mutex_);
1024 for (
auto & name : names) {
1033 std::lock_guard<std::recursive_mutex> lock(mutex_);
1035 auto param_iter = parameters_.find(name);
1036 if (parameters_.end() != param_iter) {
1038 param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
1039 param_iter->second.descriptor.dynamic_typing)
1044 }
else if (this->allow_undeclared_) {
1053 const std::string & name,
1056 std::lock_guard<std::recursive_mutex> lock(mutex_);
1058 auto param_iter = parameters_.find(name);
1060 parameters_.end() != param_iter &&
1061 param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
1063 parameter = {name, param_iter->second.value};
1072 const std::string & prefix,
1073 std::map<std::string, rclcpp::Parameter> & parameters)
const
1075 std::lock_guard<std::recursive_mutex> lock(mutex_);
1077 std::string prefix_with_dot = prefix.empty() ? prefix : prefix +
".";
1080 for (
const auto & param : parameters_) {
1081 if (param.first.find(prefix_with_dot) == 0 && param.first.length() > prefix_with_dot.length()) {
1083 parameters[param.first.substr(prefix_with_dot.length())] =
rclcpp::Parameter(param.second);
1091 std::vector<rcl_interfaces::msg::ParameterDescriptor>
1092 NodeParameters::describe_parameters(
const std::vector<std::string> & names)
const
1094 std::lock_guard<std::recursive_mutex> lock(mutex_);
1095 std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
1096 results.reserve(names.size());
1098 for (
const auto & name : names) {
1099 auto it = parameters_.find(name);
1100 if (it != parameters_.cend()) {
1101 results.push_back(it->second.descriptor);
1102 }
else if (allow_undeclared_) {
1104 rcl_interfaces::msg::ParameterDescriptor default_description;
1105 default_description.name = name;
1106 results.push_back(default_description);
1112 if (results.size() != names.size()) {
1113 throw std::runtime_error(
"results and names unexpectedly different sizes");
1119 std::vector<uint8_t>
1120 NodeParameters::get_parameter_types(
const std::vector<std::string> & names)
const
1122 std::lock_guard<std::recursive_mutex> lock(mutex_);
1123 std::vector<uint8_t> results;
1124 results.reserve(names.size());
1126 for (
const auto & name : names) {
1127 auto it = parameters_.find(name);
1128 if (it != parameters_.cend()) {
1129 results.push_back(it->second.value.get_type());
1130 }
else if (allow_undeclared_) {
1132 results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
1138 if (results.size() != names.size()) {
1139 throw std::runtime_error(
"results and names unexpectedly different sizes");
1145 rcl_interfaces::msg::ListParametersResult
1146 NodeParameters::list_parameters(
const std::vector<std::string> & prefixes, uint64_t depth)
const
1148 std::lock_guard<std::recursive_mutex> lock(mutex_);
1149 rcl_interfaces::msg::ListParametersResult result;
1153 const char * separator =
".";
1155 auto separators_less_than_depth = [&depth, &separator](
const std::string & str) ->
bool {
1156 return static_cast<uint64_t
>(std::count(str.begin(), str.end(), *separator)) < depth;
1159 bool recursive = (prefixes.size() == 0) &&
1160 (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE);
1162 for (
const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
1164 bool get_all = (prefixes.size() == 0) && separators_less_than_depth(kv.first);
1166 bool prefix_matches = std::any_of(
1167 prefixes.cbegin(), prefixes.cend(),
1168 [&kv, &depth, &separator, &separators_less_than_depth](
const std::string & prefix) {
1169 if (kv.first == prefix) {
1171 }
else if (kv.first.find(prefix + separator) == 0) {
1172 if (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) {
1175 std::string substr = kv.first.substr(prefix.length() + 1);
1176 return separators_less_than_depth(substr);
1181 if (!prefix_matches) {
1187 result.names.push_back(kv.first);
1188 size_t last_separator = kv.first.find_last_of(separator);
1189 if (std::string::npos != last_separator) {
1190 std::string prefix = kv.first.substr(0, last_separator);
1192 std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
1193 result.prefixes.cend())
1195 result.prefixes.push_back(prefix);
1206 std::lock_guard<std::recursive_mutex> lock(mutex_);
1209 auto it = std::find_if(
1210 pre_set_parameters_callback_container_.begin(),
1211 pre_set_parameters_callback_container_.end(),
1212 [handle](
const auto & weak_handle) {
1213 return handle == weak_handle.lock().get();
1215 if (it != pre_set_parameters_callback_container_.end()) {
1216 pre_set_parameters_callback_container_.erase(it);
1218 throw std::runtime_error(
"Pre set parameter callback doesn't exist");
1226 std::lock_guard<std::recursive_mutex> lock(mutex_);
1229 auto it = std::find_if(
1230 on_set_parameters_callback_container_.begin(),
1231 on_set_parameters_callback_container_.end(),
1232 [handle](
const auto & weak_handle) {
1233 return handle == weak_handle.lock().get();
1235 if (it != on_set_parameters_callback_container_.end()) {
1236 on_set_parameters_callback_container_.erase(it);
1238 throw std::runtime_error(
"On set parameter callback doesn't exist");
1246 std::lock_guard<std::recursive_mutex> lock(mutex_);
1249 auto it = std::find_if(
1250 post_set_parameters_callback_container_.begin(),
1251 post_set_parameters_callback_container_.end(),
1252 [handle](
const auto & weak_handle) {
1253 return handle == weak_handle.lock().get();
1255 if (it != post_set_parameters_callback_container_.end()) {
1256 post_set_parameters_callback_container_.erase(it);
1258 throw std::runtime_error(
"Post set parameter callback doesn't exist");
1262 PreSetParametersCallbackHandle::SharedPtr
1265 std::lock_guard<std::recursive_mutex> lock(mutex_);
1268 auto handle = std::make_shared<PreSetParametersCallbackHandle>();
1269 handle->callback = callback;
1271 pre_set_parameters_callback_container_.emplace_front(handle);
1275 OnSetParametersCallbackHandle::SharedPtr
1278 std::lock_guard<std::recursive_mutex> lock(mutex_);
1281 auto handle = std::make_shared<OnSetParametersCallbackHandle>();
1282 handle->callback = callback;
1284 on_set_parameters_callback_container_.emplace_front(handle);
1288 PostSetParametersCallbackHandle::SharedPtr
1290 PostSetParametersCallbackType callback)
1292 std::lock_guard<std::recursive_mutex> lock(mutex_);
1295 auto handle = std::make_shared<PostSetParametersCallbackHandle>();
1296 handle->callback = callback;
1298 post_set_parameters_callback_container_.emplace_front(handle);
1302 const std::map<std::string, rclcpp::ParameterValue> &
1305 return parameter_overrides_;
1311 std::lock_guard<std::recursive_mutex> lock(mutex_);
1312 parameter_modification_enabled_ =
true;
Store the type and value of a parameter.
RCLCPP_PUBLIC ParameterType get_type() const
Return an enum indicating the type of the set value.
Structure to store an arbitrary parameter with templated get/set methods.
RCLCPP_PUBLIC rcl_interfaces::msg::Parameter to_parameter_msg() const
Convert the class in a parameter message.
A publisher publishes messages of any type to a topic.
std::enable_if_t< rosidl_generator_traits::is_message< T >::value &&std::is_same< T, ROSMessageType >::value > publish(std::unique_ptr< T, ROSMessageTypeDeleter > msg)
Publish a message on the topic.
Encapsulation of Quality of Service settings.
Thrown if requested parameter type is invalid.
Thrown if passed parameter value is invalid.
Thrown if passed parameters are inconsistent or invalid.
Thrown if parameter is already declared.
Thrown if parameter is immutable and therefore cannot be undeclared.
Thrown if parameter is not declared, e.g. either set or get was called without first declaring.
Thrown when an uninitialized parameter is accessed.
Pure virtual interface class for the NodeClock part of the Node API.
virtual RCLCPP_PUBLIC rclcpp::Clock::SharedPtr get_clock()=0
Get a ROS clock which will be kept up to date by the node.
Implementation of the NodeParameters part of the Node API.
RCLCPP_PUBLIC RCUTILS_WARN_UNUSED PostSetParametersCallbackHandle::SharedPtr add_post_set_parameters_callback(PostSetParametersCallbackType callback) override
Add a callback that gets triggered after parameters are set successfully.
RCLCPP_PUBLIC const std::map< std::string, rclcpp::ParameterValue > & get_parameter_overrides() const override
Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC void remove_on_set_parameters_callback(const OnSetParametersCallbackHandle *const handler) override
Remove a callback registered with add_on_set_parameters_callback.
RCLCPP_PUBLIC std::vector< rclcpp::Parameter > get_parameters(const std::vector< std::string > &names) const override
Get descriptions of parameters given their names.
RCLCPP_PUBLIC void undeclare_parameter(const std::string &name) override
Undeclare a parameter.
RCLCPP_PUBLIC const rclcpp::ParameterValue & declare_parameter(const std::string &name, const rclcpp::ParameterValue &default_value, const rcl_interfaces::msg::ParameterDescriptor ¶meter_descriptor=rcl_interfaces::msg::ParameterDescriptor{}, bool ignore_override=false) override
Declare and initialize a parameter.
RCLCPP_PUBLIC RCUTILS_WARN_UNUSED OnSetParametersCallbackHandle::SharedPtr add_on_set_parameters_callback(OnSetParametersCallbackType callback) override
Add a callback to validate parameters before they are set.
RCLCPP_PUBLIC bool get_parameters_by_prefix(const std::string &prefix, std::map< std::string, rclcpp::Parameter > ¶meters) const override
Get all parameters that have the specified prefix into the parameters map.
RCLCPP_PUBLIC std::vector< rcl_interfaces::msg::SetParametersResult > set_parameters(const std::vector< rclcpp::Parameter > ¶meters) override
Set one or more parameters, one at a time.
RCLCPP_PUBLIC void remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle *const handler) override
Remove a callback registered with add_pre_set_parameters_callback.
RCLCPP_PUBLIC void enable_parameter_modification() override
Enable parameter modification recursively during parameter callbacks.
RCLCPP_PUBLIC rcl_interfaces::msg::SetParametersResult set_parameters_atomically(const std::vector< rclcpp::Parameter > ¶meters) override
Set one or more parameters, all at once.
RCLCPP_PUBLIC RCUTILS_WARN_UNUSED PreSetParametersCallbackHandle::SharedPtr add_pre_set_parameters_callback(PreSetParametersCallbackType callback) override
Add a callback that gets triggered before parameters are validated.
RCLCPP_PUBLIC rclcpp::Parameter get_parameter(const std::string &name) const override
Get the description of one parameter given a name.
RCLCPP_PUBLIC void remove_post_set_parameters_callback(const PostSetParametersCallbackHandle *const handler) override
Remove a callback registered with add_post_set_parameters_callback.
RCLCPP_PUBLIC bool has_parameter(const std::string &name) const override
Return true if the parameter has been declared, otherwise false.
RCLCPP_PUBLIC std::string to_string(const FutureReturnCode &future_return_code)
String conversion function for FutureReturnCode.
RCL_PUBLIC RCL_WARN_UNUSED const rcl_node_options_t * rcl_node_get_options(const rcl_node_t *node)
Return the rcl node options.
Hold output of parsing command line arguments.
Structure which encapsulates the options for creating a rcl_node_t.
bool use_global_arguments
If false then only use arguments in this struct, otherwise use global arguments also.
rcl_arguments_t arguments
Command line arguments that apply only to this node.
Structure which encapsulates a ROS Node.
Non-templated part of PublisherOptionsWithAllocator<Allocator>.
Structure containing optional configuration for Publishers.
std::shared_ptr< Allocator > allocator
Optional custom allocator.
rcl_interfaces::msg::ParameterDescriptor descriptor
A description of the parameter.