ROS 2 rclcpp + rcl - lyrical  lyrical
ROS 2 C++ Client Library with ROS Client Library
node_parameters.cpp
1 // Copyright 2016 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "rclcpp/node_interfaces/node_parameters.hpp"
16 
17 #include <rcl_yaml_param_parser/parser.h>
18 
19 #include <array>
20 #include <cmath>
21 #include <cstdlib>
22 #include <cstring>
23 #include <functional>
24 #include <limits>
25 #include <map>
26 #include <memory>
27 #include <sstream>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
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"
37 
38 #include "../detail/resolve_parameter_overrides.hpp"
39 
41 
42 RCLCPP_LOCAL
43 void
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,
47  std::function<void(
48  const std::string &,
49  const rclcpp::ParameterValue &,
50  const rcl_interfaces::msg::ParameterDescriptor &,
51  bool)>
52  declare_parameter)
53 {
54  rcl_interfaces::msg::ParameterDescriptor descriptor;
55  descriptor.dynamic_typing = true;
56  for (const auto & pair : parameter_overrides) {
57  if (!has_parameter(pair.first)) {
58  declare_parameter(
59  pair.first,
60  pair.second,
61  descriptor,
62  true);
63  }
64  }
65 }
66 
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,
76  const rclcpp::QoS & parameter_event_qos,
77  const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
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)
84 {
85  using MessageT = rcl_interfaces::msg::ParameterEvent;
86  using PublisherT = rclcpp::Publisher<MessageT>;
87  using AllocatorT = std::allocator<void>;
88  // TODO(wjwwood): expose this allocator through the Parameter interface.
90  parameter_event_publisher_options);
91  publisher_options.allocator = std::make_shared<AllocatorT>();
92 
93  if (start_parameter_services) {
94  parameter_service_ = std::make_shared<ParameterService>(node_base, node_services, this);
95  }
96 
97  if (start_parameter_event_publisher) {
98  // TODO(ivanpauno): Qos of the `/parameters_event` topic should be somehow overridable.
99  events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
100  node_topics,
101  "/parameter_events",
102  parameter_event_qos,
103  publisher_options);
104  }
105 
106  // Get the node options
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");
110  }
111  const rcl_node_options_t * options = rcl_node_get_options(node);
112  if (nullptr == options) {
113  throw std::runtime_error("Need valid node options in NodeParameters");
114  }
115 
116  const rcl_arguments_t * global_args = nullptr;
117  if (options->use_global_arguments) {
118  auto context_ptr = node_base->get_context()->get_rcl_context();
119  global_args = &(context_ptr->global_arguments);
120  }
121  combined_name_ = node_base->get_fully_qualified_name();
122 
123  parameter_overrides_ = rclcpp::detail::resolve_parameter_overrides(
124  combined_name_, parameter_overrides, &options->arguments, global_args);
125 
126  // If asked, initialize any parameters that ended up in the initial parameter values,
127  // but did not get declared explcitily by this point.
128  if (automatically_declare_parameters_from_overrides) {
129  using namespace std::placeholders;
130  local_perform_automatically_declare_parameters_from_overrides(
131  this->get_parameter_overrides(),
132  std::bind(&NodeParameters::has_parameter, this, _1),
133  [this](
134  const std::string & name,
135  const rclcpp::ParameterValue & default_value,
136  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
137  bool ignore_override)
138  {
140  name, default_value, parameter_descriptor, ignore_override);
141  }
142  );
143  }
144 }
145 
146 void
147 NodeParameters::perform_automatically_declare_parameters_from_overrides()
148 {
149  local_perform_automatically_declare_parameters_from_overrides(
150  this->get_parameter_overrides(),
151  [this](const std::string & name) {
152  return this->has_parameter(name);
153  },
154  [this](
155  const std::string & name,
156  const rclcpp::ParameterValue & default_value,
157  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
158  bool ignore_override)
159  {
160  this->declare_parameter(
161  name, default_value, parameter_descriptor, ignore_override);
162  }
163  );
164 }
165 
166 NodeParameters::~NodeParameters()
167 {}
168 
169 RCLCPP_LOCAL
170 bool
171 __lockless_has_parameter(
172  const std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
173  const std::string & name)
174 {
175  return parameters.find(name) != parameters.end();
176 }
177 
178 // see https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
179 RCLCPP_LOCAL
180 bool
181 __are_doubles_equal(double x, double y, double ulp = 100.0)
182 {
183  if (!std::isfinite(x) || !std::isfinite(y)) {
184  return x == y;
185  }
186  return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
187 }
188 
189 static
190 std::string
191 format_range_reason(const std::string & name, const char * range_type)
192 {
193  std::ostringstream ss;
194  ss << "Parameter {" << name << "} doesn't comply with " << range_type << " range.";
195  return ss.str();
196 }
197 
198 static
199 std::string
200 format_range_type_reason(
201  const std::string & name,
202  const char * range_type,
203  rclcpp::ParameterType parameter_type)
204 {
205  std::ostringstream ss;
206  ss << "Parameter {" << name << "} of type {" << rclcpp::to_string(parameter_type) <<
207  "} cannot use " << range_type << " range constraints.";
208  return ss.str();
209 }
210 
211 RCLCPP_LOCAL
212 rcl_interfaces::msg::SetParametersResult
213 __check_parameter_type_supports_range(
214  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
215  rclcpp::ParameterType parameter_type)
216 {
217  rcl_interfaces::msg::SetParametersResult result;
218  result.successful = true;
219 
220  if (parameter_type == rclcpp::PARAMETER_NOT_SET) {
221  return result;
222  }
223 
224  if (
225  !descriptor.integer_range.empty() &&
226  parameter_type != rclcpp::PARAMETER_INTEGER &&
227  parameter_type != rclcpp::PARAMETER_INTEGER_ARRAY)
228  {
229  result.successful = false;
230  result.reason = format_range_type_reason(descriptor.name, "integer", parameter_type);
231  return result;
232  }
233 
234  if (
235  !descriptor.floating_point_range.empty() &&
236  parameter_type != rclcpp::PARAMETER_DOUBLE &&
237  parameter_type != rclcpp::PARAMETER_DOUBLE_ARRAY)
238  {
239  result.successful = false;
240  result.reason = format_range_type_reason(descriptor.name, "floating point", parameter_type);
241  }
242 
243  return result;
244 }
245 
246 RCLCPP_LOCAL
247 rcl_interfaces::msg::SetParametersResult
248 __check_integer_range(
249  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
250  const int64_t value)
251 {
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) {
256  return result;
257  }
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");
261  return result;
262  }
263  if (integer_range.step == 0) {
264  return result;
265  }
266  if (((value - integer_range.from_value) % integer_range.step) == 0) {
267  return result;
268  }
269  result.successful = false;
270  result.reason = format_range_reason(descriptor.name, "integer");
271  return result;
272 }
273 
274 RCLCPP_LOCAL
275 rcl_interfaces::msg::SetParametersResult
276 __check_double_range(
277  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
278  const double value)
279 {
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,
284  fp_range.to_value))
285  {
286  return result;
287  }
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");
291  return result;
292  }
293  if (fp_range.step == 0.0) {
294  return result;
295  }
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)) {
298  return result;
299  }
300  result.successful = false;
301  result.reason = format_range_reason(descriptor.name, "floating point");
302  return result;
303 }
304 
305 RCLCPP_LOCAL
306 rcl_interfaces::msg::SetParametersResult
307 __check_parameter_value_in_range(
308  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
309  const rclcpp::ParameterValue & value)
310 {
311  auto result = __check_parameter_type_supports_range(descriptor, value.get_type());
312  if (!result.successful) {
313  return result;
314  }
315 
316  if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
317  result = __check_integer_range(descriptor, value.get<int64_t>());
318  return result;
319  }
320 
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) {
326  return result;
327  }
328  }
329  return result;
330  }
331 
332  if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
333  result = __check_double_range(descriptor, value.get<double>());
334  return result;
335  }
336 
337  if (!descriptor.floating_point_range.empty() &&
338  value.get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
339  {
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) {
344  return result;
345  }
346  }
347  return result;
348  }
349 
350  return result;
351 }
352 
353 static
354 std::string
355 format_type_reason(
356  const std::string & name, const std::string & old_type, const std::string & new_type)
357 {
358  std::ostringstream ss;
359  // WARN: A condition later depends on this message starting with "Wrong parameter type",
360  // check `declare_parameter` if you modify this!
361  ss << "Wrong parameter type, parameter {" << name << "} is of type {" << old_type <<
362  "}, setting it to {" << new_type << "} is not allowed.";
363  return ss.str();
364 }
365 
366 // Return true if parameter values comply with the descriptors in parameter_infos.
367 RCLCPP_LOCAL
368 rcl_interfaces::msg::SetParametersResult
369 __check_parameters(
370  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
371  const std::vector<rclcpp::Parameter> & parameters,
372  bool allow_undeclared)
373 {
374  rcl_interfaces::msg::SetParametersResult result;
375  result.successful = true;
376  for (const rclcpp::Parameter & parameter : parameters) {
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;
383  } else {
384  // implicitly declared parameters are dinamically typed!
385  descriptor.dynamic_typing = true;
386  }
387  } else {
388  descriptor = parameter_infos[name].descriptor;
389  }
390  if (descriptor.name.empty()) {
391  descriptor.name = name;
392  }
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(
398  name, rclcpp::to_string(specified_type), rclcpp::to_string(new_type));
399  return result;
400  }
401  result = __check_parameter_value_in_range(
402  descriptor,
403  parameter.get_parameter_value());
404  if (!result.successful) {
405  return result;
406  }
407  }
408  return result;
409 }
410 
411 using PreSetParametersCallbackType =
412  rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
415 using PreSetCallbacksHandleContainer =
416  rclcpp::node_interfaces::NodeParameters::PreSetCallbacksHandleContainer;
417 
418 using OnSetParametersCallbackType =
419  rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
422 using OnSetCallbacksHandleContainer =
423  rclcpp::node_interfaces::NodeParameters::OnSetCallbacksHandleContainer;
424 
425 using PostSetParametersCallbackType =
426  rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
429 using PostSetCallbacksHandleContainer =
430  rclcpp::node_interfaces::NodeParameters::PostSetCallbacksHandleContainer;
431 
432 RCLCPP_LOCAL
433 void
434 __call_pre_set_parameters_callbacks(
435  std::vector<rclcpp::Parameter> & parameters,
436  PreSetCallbacksHandleContainer & callback_container)
437 {
438  if (callback_container.empty()) {
439  return;
440  }
441 
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);
447  it++;
448  } else {
449  it = callback_container.erase(it);
450  }
451  }
452 }
453 
454 RCLCPP_LOCAL
455 rcl_interfaces::msg::SetParametersResult
456 __call_on_set_parameters_callbacks(
457  const std::vector<rclcpp::Parameter> & parameters,
458  OnSetCallbacksHandleContainer & callback_container)
459 {
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) {
468  return result;
469  }
470  it++;
471  } else {
472  it = callback_container.erase(it);
473  }
474  }
475  return result;
476 }
477 
478 RCLCPP_LOCAL
479 void __call_post_set_parameters_callbacks(
480  const std::vector<rclcpp::Parameter> & parameters,
481  PostSetCallbacksHandleContainer & callback_container)
482 {
483  if (callback_container.empty()) {
484  return;
485  }
486 
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);
492  it++;
493  } else {
494  it = callback_container.erase(it);
495  }
496  }
497 }
498 
499 RCLCPP_LOCAL
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)
507 {
508  // Check if the value being set complies with the descriptor.
509  rcl_interfaces::msg::SetParametersResult result = __check_parameters(
510  parameter_infos, parameters, allow_undeclared);
511  if (!result.successful) {
512  return result;
513  }
514  // Call the user callbacks to see if the new value(s) are allowed.
515  result =
516  __call_on_set_parameters_callbacks(parameters, on_set_callback_container);
517  if (!result.successful) {
518  return result;
519  }
520  // If accepted, actually set the values.
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();
527  }
528  // Call the user post set parameter callback
529  __call_post_set_parameters_callbacks(parameters, post_set_callback_container);
530  }
531 
532  // Either way, return the result.
533  return result;
534 }
535 
536 RCLCPP_LOCAL
537 rcl_interfaces::msg::SetParametersResult
538 __declare_parameter_common(
539  const std::string & name,
540  const rclcpp::ParameterValue & default_value,
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)
548 {
550  std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
551  parameter_infos.at(name).descriptor = parameter_descriptor;
552 
553  // Use the value from the overrides if available, otherwise use the default.
554  const rclcpp::ParameterValue * initial_value = &default_value;
555  auto overrides_it = overrides.find(name);
556  if (!ignore_override && overrides_it != overrides.end()) {
557  initial_value = &overrides_it->second;
558  }
559 
560  // If there is no initial value, then skip initialization
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) {
569  return result;
570  }
571  }
572 
573  // Add declared parameters to storage (without a value)
574  parameter_infos[name].descriptor.name = name;
575  if (parameter_descriptor.dynamic_typing) {
576  parameter_infos[name].descriptor.type = rclcpp::PARAMETER_NOT_SET;
577  } else {
578  parameter_infos[name].descriptor.type = parameter_descriptor.type;
579  }
580  parameters_out[name] = parameter_infos.at(name);
581  result.successful = true;
582  return result;
583  }
584 
585  // Check with the user's callbacks to see if the initial value can be set.
586  std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
587  // This function also takes care of default vs initial value.
588  auto result = __set_parameters_atomically_common(
589  parameter_wrappers,
590  parameter_infos,
591  on_set_callback_container,
592  post_set_callback_container
593  );
594 
595  if (!result.successful) {
596  return result;
597  }
598 
599  // Add declared parameters to storage.
600  parameters_out[name] = parameter_infos.at(name);
601 
602  // Extend the given parameter event, if valid.
603  if (parameter_event_out) {
604  parameter_event_out->new_parameters.push_back(parameter_wrappers[0].to_parameter_msg());
605  }
606 
607  return result;
608 }
609 
610 static
612 declare_parameter_helper(
613  const std::string & name,
614  rclcpp::ParameterType type,
615  const rclcpp::ParameterValue & default_value,
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,
625 {
626  // TODO(sloretz) parameter name validation
627  if (name.empty()) {
628  throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
629  }
630 
631  // Error if this parameter has already been declared and is different
632  if (__lockless_has_parameter(parameters, name)) {
634  "parameter '" + name + "' has already been declared");
635  }
636 
637  if (!parameter_descriptor.dynamic_typing) {
638  if (rclcpp::PARAMETER_NOT_SET == type) {
639  type = default_value.get_type();
640  }
641  if (rclcpp::PARAMETER_NOT_SET == type) {
643  name,
644  "cannot declare a statically typed parameter with an uninitialized value"
645  };
646  }
647  parameter_descriptor.type = static_cast<uint8_t>(type);
648  }
649 
650  rcl_interfaces::msg::ParameterEvent parameter_event;
651  auto result = __declare_parameter_common(
652  name,
653  default_value,
654  parameter_descriptor,
655  parameters,
656  overrides,
657  on_set_callback_container,
658  post_set_callback_container,
659  &parameter_event,
660  ignore_override);
661 
662  // If it failed to be set, then throw an exception.
663  if (!result.successful) {
664  constexpr const char type_error_msg_start[] = "Wrong parameter type";
665  if (
666  0u == std::strncmp(
667  result.reason.c_str(), type_error_msg_start, sizeof(type_error_msg_start) - 1))
668  {
669  // TODO(ivanpauno): Refactor the logic so we don't need the above `strncmp` and we can
670  // detect between both exceptions more elegantly.
671  throw rclcpp::exceptions::InvalidParameterTypeException(name, result.reason);
672  }
674  "parameter '" + name + "' could not be set: " + result.reason);
675  }
676 
677  // Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
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);
682  }
683 
684  return parameters.at(name).value;
685 }
686 
689  const std::string & name,
690  const rclcpp::ParameterValue & default_value,
691  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
692  bool ignore_override)
693 {
694  std::lock_guard<std::recursive_mutex> lock(mutex_);
695  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
696 
697  return declare_parameter_helper(
698  name,
699  rclcpp::PARAMETER_NOT_SET,
700  default_value,
701  parameter_descriptor,
702  ignore_override,
703  parameters_,
704  parameter_overrides_,
705  on_set_parameters_callback_container_,
706  post_set_parameters_callback_container_,
707  events_publisher_.get(),
708  combined_name_,
709  *node_clock_);
710 }
711 
714  const std::string & name,
715  rclcpp::ParameterType type,
716  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
717  bool ignore_override)
718 {
719  std::lock_guard<std::recursive_mutex> lock(mutex_);
720  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
721 
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"};
725  }
726 
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`"};
731  }
732 
733  return declare_parameter_helper(
734  name,
735  type,
737  parameter_descriptor,
738  ignore_override,
739  parameters_,
740  parameter_overrides_,
741  on_set_parameters_callback_container_,
742  post_set_parameters_callback_container_,
743  events_publisher_.get(),
744  combined_name_,
745  *node_clock_);
746 }
747 
748 void
749 NodeParameters::undeclare_parameter(const std::string & name)
750 {
751  std::lock_guard<std::recursive_mutex> lock(mutex_);
752 
753  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
754 
755  auto parameter_info = parameters_.find(name);
756  if (parameter_info == parameters_.end()) {
758  "cannot undeclare parameter '" + name + "' which has not yet been declared");
759  }
760 
761  if (parameter_info->second.descriptor.read_only) {
763  "cannot undeclare parameter '" + name + "' because it is read-only");
764  }
765  if (!parameter_info->second.descriptor.dynamic_typing) {
767  name, "cannot undeclare a statically typed parameter"};
768  }
769 
770  parameters_.erase(parameter_info);
771 }
772 
773 bool
774 NodeParameters::has_parameter(const std::string & name) const
775 {
776  std::lock_guard<std::recursive_mutex> lock(mutex_);
777 
778  return __lockless_has_parameter(parameters_, name);
779 }
780 
781 std::vector<rcl_interfaces::msg::SetParametersResult>
782 NodeParameters::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
783 {
784  std::vector<rcl_interfaces::msg::SetParametersResult> results;
785  results.reserve(parameters.size());
786 
787  for (const auto & p : parameters) {
788  auto result = set_parameters_atomically({{p}});
789  results.push_back(result);
790  }
791 
792  return results;
793 }
794 
795 template<typename ParameterVectorType>
796 auto
797 __find_parameter_by_name(
798  ParameterVectorType & parameters,
799  const std::string & name)
800 {
801  return std::find_if(
802  parameters.begin(),
803  parameters.end(),
804  [&](auto parameter) {return parameter.get_name() == name;});
805 }
806 
807 rcl_interfaces::msg::SetParametersResult
808 NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
809 {
810  std::lock_guard<std::recursive_mutex> lock(mutex_);
811 
812  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
813 
814  rcl_interfaces::msg::SetParametersResult result;
815 
816  // call any user registered pre set parameter callbacks
817  // this callback can make changes to the original parameters list
818  // also check if the changed parameter list is empty or not, if empty return
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_);
823 
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.";
828  return result;
829  }
830 
831  // Check if any of the parameters are read-only, or if any parameters are not
832  // declared.
833  // If not declared, keep track of them in order to declare them later, when
834  // undeclared parameters are allowed, and if they're not allowed, fail.
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();
838 
839  // Check to make sure the parameter name is valid.
840  if (name.empty()) {
841  throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
842  }
843 
844  // Check to see if it is declared.
845  auto parameter_info = parameters_.find(name);
846  if (parameter_info == parameters_.end()) {
847  // If not check to see if undeclared paramaters are allowed, ...
848  if (allow_undeclared_) {
849  // If so, mark the parameter to be declared for the user implicitly.
850  parameters_to_be_declared.push_back(&parameter);
851  // continue as it cannot be read-only, and because the declare will
852  // implicitly set the parameter and parameter_infos is for setting only.
853  continue;
854  } else {
855  // If not, then throw the exception as documented.
857  "parameter '" + name + "' cannot be set because it was not declared");
858  }
859  }
860 
861  // Check to see if it is read-only.
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";
865  return result;
866  }
867  }
868 
869  // Declare parameters into a temporary "staging area", incase one of the declares fail.
870  // We will use the staged changes as input to the "set atomically" action.
871  // We explicitly avoid calling the user callbacks here, so that it may be called once, with
872  // all the other parameters to be set (already declared parameters).
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;
878 
879  // Implicit declare uses dynamic type descriptor.
880  rcl_interfaces::msg::ParameterDescriptor descriptor;
881  descriptor.dynamic_typing = true;
882  for (auto parameter_to_be_declared : parameters_to_be_declared) {
883  // This should not throw, because we validated the name and checked that
884  // the parameter was not already declared.
885  result = __declare_parameter_common(
886  parameter_to_be_declared->get_name(),
887  parameter_to_be_declared->get_parameter_value(),
888  descriptor,
889  staged_parameter_changes,
890  parameter_overrides_,
891  // Only call callbacks once below
892  empty_on_set_callback_container, // callback_container is explicitly empty
893  empty_post_set_callback_container, // callback_container is explicitly empty
894  &parameter_event_msg,
895  true);
896  if (!result.successful) {
897  // Declare failed, return knowing that nothing was changed because the
898  // staged changes were not applied.
899  return result;
900  }
901  }
902 
903  // If there were implicitly declared parameters, then we may need to copy the input parameters
904  // and then assign the value that was selected after the declare (could be affected by the
905  // initial parameter values).
906  const std::vector<rclcpp::Parameter> * parameters_to_be_set = &parameters_after_pre_set_callback;
907  std::vector<rclcpp::Parameter> parameters_copy;
908  if (0 != staged_parameter_changes.size()) { // If there were any implicitly declared parameters.
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) {
915  // In this case, the value of the staged parameter differs from the
916  // input from the user, and therefore we need to update things before setting.
917  any_initial_values_used = true;
918  // No need to search further since at least one initial value needs to be used.
919  break;
920  }
921  }
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);
927  }
928  parameters_to_be_set = &parameters_copy;
929  }
930  }
931 
932  // Collect parameters who will have had their type changed to
933  // rclcpp::PARAMETER_NOT_SET so they can later be implicitly undeclared.
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;
942  return result;
943  }
944  parameters_to_be_undeclared.push_back(&parameter);
945  }
946  }
947  }
948 
949  // Set all of the parameters including the ones declared implicitly above.
950  result = __set_parameters_atomically_common(
951  // either the original parameters given by the user, or ones updated with initial values
952  *parameters_to_be_set,
953  // they are actually set on the official parameter storage
954  parameters_,
955  // These callbacks are called once. When a callback returns an unsuccessful result,
956  // the remaining aren't called
957  on_set_parameters_callback_container_,
958  post_set_parameters_callback_container_,
959  allow_undeclared_); // allow undeclared
960 
961  // If not successful, then stop here.
962  if (!result.successful) {
963  return result;
964  }
965 
966  // If successful, then update the parameter infos from the implicitly declared parameter's.
967  for (const auto & kv_pair : staged_parameter_changes) {
968  // assumption: the parameter is already present in parameters_ due to the above "set"
969  assert(__lockless_has_parameter(parameters_, kv_pair.first));
970  // assumption: the value in parameters_ is the same as the value resulting from the declare
971  assert(parameters_[kv_pair.first].value == kv_pair.second.value);
972  // This assignment should not change the name, type, or value, but may
973  // change other things from the ParameterInfo.
974  parameters_[kv_pair.first] = kv_pair.second;
975  }
976 
977  // Undeclare parameters that need to be.
978  for (auto parameter_to_undeclare : parameters_to_be_undeclared) {
979  auto it = parameters_.find(parameter_to_undeclare->get_name());
980  // assumption: the parameter to be undeclared should be in the parameter infos map
981  assert(it != parameters_.end());
982  if (it != parameters_.end()) {
983  // Update the parameter event message and remove it.
984  parameter_event_msg.deleted_parameters.push_back(
985  rclcpp::Parameter(it->first, it->second.value).to_parameter_msg());
986  parameters_.erase(it);
987  }
988  }
989 
990  // Update the parameter event message for any parameters which were only set,
991  // and not either declared or undeclared.
992  for (const auto & parameter : *parameters_to_be_set) {
993  if (staged_parameter_changes.find(parameter.get_name()) != staged_parameter_changes.end()) {
994  // This parameter was declared.
995  continue;
996  }
997  auto it = std::find_if(
998  parameters_to_be_undeclared.begin(),
999  parameters_to_be_undeclared.end(),
1000  [&parameter](const auto & p) {return p->get_name() == parameter.get_name();});
1001  if (it != parameters_to_be_undeclared.end()) {
1002  // This parameter was undeclared (deleted).
1003  continue;
1004  }
1005  // This parameter was neither declared nor undeclared.
1006  parameter_event_msg.changed_parameters.push_back(parameter.to_parameter_msg());
1007  }
1008 
1009  // Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
1010  if (nullptr != events_publisher_) {
1011  parameter_event_msg.stamp = node_clock_->get_clock()->now();
1012  events_publisher_->publish(parameter_event_msg);
1013  }
1014  return result;
1015 }
1016 
1017 std::vector<rclcpp::Parameter>
1018 NodeParameters::get_parameters(const std::vector<std::string> & names) const
1019 {
1020  std::vector<rclcpp::Parameter> results;
1021  results.reserve(names.size());
1022 
1023  std::lock_guard<std::recursive_mutex> lock(mutex_);
1024  for (auto & name : names) {
1025  results.emplace_back(this->get_parameter(name));
1026  }
1027  return results;
1028 }
1029 
1031 NodeParameters::get_parameter(const std::string & name) const
1032 {
1033  std::lock_guard<std::recursive_mutex> lock(mutex_);
1034 
1035  auto param_iter = parameters_.find(name);
1036  if (parameters_.end() != param_iter) {
1037  if (
1038  param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
1039  param_iter->second.descriptor.dynamic_typing)
1040  {
1041  return rclcpp::Parameter{name, param_iter->second.value};
1042  }
1044  } else if (this->allow_undeclared_) {
1045  return rclcpp::Parameter{name};
1046  } else {
1048  }
1049 }
1050 
1051 bool
1053  const std::string & name,
1054  rclcpp::Parameter & parameter) const
1055 {
1056  std::lock_guard<std::recursive_mutex> lock(mutex_);
1057 
1058  auto param_iter = parameters_.find(name);
1059  if (
1060  parameters_.end() != param_iter &&
1061  param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
1062  {
1063  parameter = {name, param_iter->second.value};
1064  return true;
1065  } else {
1066  return false;
1067  }
1068 }
1069 
1070 bool
1072  const std::string & prefix,
1073  std::map<std::string, rclcpp::Parameter> & parameters) const
1074 {
1075  std::lock_guard<std::recursive_mutex> lock(mutex_);
1076 
1077  std::string prefix_with_dot = prefix.empty() ? prefix : prefix + ".";
1078  bool ret = false;
1079 
1080  for (const auto & param : parameters_) {
1081  if (param.first.find(prefix_with_dot) == 0 && param.first.length() > prefix_with_dot.length()) {
1082  // Found one!
1083  parameters[param.first.substr(prefix_with_dot.length())] = rclcpp::Parameter(param.second);
1084  ret = true;
1085  }
1086  }
1087 
1088  return ret;
1089 }
1090 
1091 std::vector<rcl_interfaces::msg::ParameterDescriptor>
1092 NodeParameters::describe_parameters(const std::vector<std::string> & names) const
1093 {
1094  std::lock_guard<std::recursive_mutex> lock(mutex_);
1095  std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
1096  results.reserve(names.size());
1097 
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_) {
1103  // parameter not found, but undeclared allowed, so return empty
1104  rcl_interfaces::msg::ParameterDescriptor default_description;
1105  default_description.name = name;
1106  results.push_back(default_description);
1107  } else {
1109  }
1110  }
1111 
1112  if (results.size() != names.size()) {
1113  throw std::runtime_error("results and names unexpectedly different sizes");
1114  }
1115 
1116  return results;
1117 }
1118 
1119 std::vector<uint8_t>
1120 NodeParameters::get_parameter_types(const std::vector<std::string> & names) const
1121 {
1122  std::lock_guard<std::recursive_mutex> lock(mutex_);
1123  std::vector<uint8_t> results;
1124  results.reserve(names.size());
1125 
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_) {
1131  // parameter not found, but undeclared allowed, so return not set
1132  results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
1133  } else {
1135  }
1136  }
1137 
1138  if (results.size() != names.size()) {
1139  throw std::runtime_error("results and names unexpectedly different sizes");
1140  }
1141 
1142  return results;
1143 }
1144 
1145 rcl_interfaces::msg::ListParametersResult
1146 NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
1147 {
1148  std::lock_guard<std::recursive_mutex> lock(mutex_);
1149  rcl_interfaces::msg::ListParametersResult result;
1150 
1151  // TODO(mikaelarguedas) define parameter separator different from "/" to avoid ambiguity
1152  // using "." for now
1153  const char * separator = ".";
1154 
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;
1157  };
1158 
1159  bool recursive = (prefixes.size() == 0) &&
1160  (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE);
1161 
1162  for (const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
1163  if (!recursive) {
1164  bool get_all = (prefixes.size() == 0) && separators_less_than_depth(kv.first);
1165  if (!get_all) {
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) {
1170  return true;
1171  } else if (kv.first.find(prefix + separator) == 0) {
1172  if (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) {
1173  return true;
1174  }
1175  std::string substr = kv.first.substr(prefix.length() + 1);
1176  return separators_less_than_depth(substr);
1177  }
1178  return false;
1179  });
1180 
1181  if (!prefix_matches) {
1182  continue;
1183  }
1184  }
1185  }
1186 
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);
1191  if (
1192  std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
1193  result.prefixes.cend())
1194  {
1195  result.prefixes.push_back(prefix);
1196  }
1197  }
1198  }
1199  return result;
1200 }
1201 
1202 void
1204  const PreSetParametersCallbackHandle * const handle)
1205 {
1206  std::lock_guard<std::recursive_mutex> lock(mutex_);
1207  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1208 
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();
1214  });
1215  if (it != pre_set_parameters_callback_container_.end()) {
1216  pre_set_parameters_callback_container_.erase(it);
1217  } else {
1218  throw std::runtime_error("Pre set parameter callback doesn't exist");
1219  }
1220 }
1221 
1222 void
1224  const OnSetParametersCallbackHandle * const handle)
1225 {
1226  std::lock_guard<std::recursive_mutex> lock(mutex_);
1227  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1228 
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();
1234  });
1235  if (it != on_set_parameters_callback_container_.end()) {
1236  on_set_parameters_callback_container_.erase(it);
1237  } else {
1238  throw std::runtime_error("On set parameter callback doesn't exist");
1239  }
1240 }
1241 
1242 void
1244  const PostSetParametersCallbackHandle * const handle)
1245 {
1246  std::lock_guard<std::recursive_mutex> lock(mutex_);
1247  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1248 
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();
1254  });
1255  if (it != post_set_parameters_callback_container_.end()) {
1256  post_set_parameters_callback_container_.erase(it);
1257  } else {
1258  throw std::runtime_error("Post set parameter callback doesn't exist");
1259  }
1260 }
1261 
1262 PreSetParametersCallbackHandle::SharedPtr
1263 NodeParameters::add_pre_set_parameters_callback(PreSetParametersCallbackType callback)
1264 {
1265  std::lock_guard<std::recursive_mutex> lock(mutex_);
1266  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1267 
1268  auto handle = std::make_shared<PreSetParametersCallbackHandle>();
1269  handle->callback = callback;
1270  // the last callback registered is executed first.
1271  pre_set_parameters_callback_container_.emplace_front(handle);
1272  return handle;
1273 }
1274 
1275 OnSetParametersCallbackHandle::SharedPtr
1276 NodeParameters::add_on_set_parameters_callback(OnSetParametersCallbackType callback)
1277 {
1278  std::lock_guard<std::recursive_mutex> lock(mutex_);
1279  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1280 
1281  auto handle = std::make_shared<OnSetParametersCallbackHandle>();
1282  handle->callback = callback;
1283  // the last callback registered is executed first.
1284  on_set_parameters_callback_container_.emplace_front(handle);
1285  return handle;
1286 }
1287 
1288 PostSetParametersCallbackHandle::SharedPtr
1290  PostSetParametersCallbackType callback)
1291 {
1292  std::lock_guard<std::recursive_mutex> lock(mutex_);
1293  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1294 
1295  auto handle = std::make_shared<PostSetParametersCallbackHandle>();
1296  handle->callback = callback;
1297  // the last callback registered is executed first.
1298  post_set_parameters_callback_container_.emplace_front(handle);
1299  return handle;
1300 }
1301 
1302 const std::map<std::string, rclcpp::ParameterValue> &
1304 {
1305  return parameter_overrides_;
1306 }
1307 
1308 void
1310 {
1311  std::lock_guard<std::recursive_mutex> lock(mutex_);
1312  parameter_modification_enabled_ = true;
1313 }
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.
Definition: parameter.hpp:53
RCLCPP_PUBLIC rcl_interfaces::msg::Parameter to_parameter_msg() const
Convert the class in a parameter message.
Definition: parameter.cpp:151
A publisher publishes messages of any type to a topic.
Definition: publisher.hpp:81
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.
Definition: publisher.hpp:223
Encapsulation of Quality of Service settings.
Definition: qos.hpp:116
Thrown if requested parameter type is invalid.
Definition: exceptions.hpp:271
Thrown if passed parameter value is invalid.
Definition: exceptions.hpp:260
Thrown if passed parameters are inconsistent or invalid.
Definition: exceptions.hpp:252
Thrown if parameter is already declared.
Definition: exceptions.hpp:303
Thrown if parameter is immutable and therefore cannot be undeclared.
Definition: exceptions.hpp:317
Thrown if parameter is not declared, e.g. either set or get was called without first declaring.
Definition: exceptions.hpp:310
Thrown when an uninitialized parameter is accessed.
Definition: exceptions.hpp:331
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 &parameter_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 > &parameters) 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 > &parameters) 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 > &parameters) 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.
Definition: node.c:443
Hold output of parsing command line arguments.
Definition: arguments.h:36
Structure which encapsulates the options for creating a rcl_node_t.
Definition: node_options.h:35
bool use_global_arguments
If false then only use arguments in this struct, otherwise use global arguments also.
Definition: node_options.h:47
rcl_arguments_t arguments
Command line arguments that apply only to this node.
Definition: node_options.h:50
Structure which encapsulates a ROS Node.
Definition: node.h:45
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.