ROS 2 rclcpp + rcl - rolling  rolling-b14af74a
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  return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
184 }
185 
186 static
187 std::string
188 format_range_reason(const std::string & name, const char * range_type)
189 {
190  std::ostringstream ss;
191  ss << "Parameter {" << name << "} doesn't comply with " << range_type << " range.";
192  return ss.str();
193 }
194 
195 RCLCPP_LOCAL
196 rcl_interfaces::msg::SetParametersResult
197 __check_integer_range(
198  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
199  const int64_t value)
200 {
201  rcl_interfaces::msg::SetParametersResult result;
202  result.successful = true;
203  auto integer_range = descriptor.integer_range.at(0);
204  if (value == integer_range.from_value || value == integer_range.to_value) {
205  return result;
206  }
207  if ((value < integer_range.from_value) || (value > integer_range.to_value)) {
208  result.successful = false;
209  result.reason = format_range_reason(descriptor.name, "integer");
210  return result;
211  }
212  if (integer_range.step == 0) {
213  return result;
214  }
215  if (((value - integer_range.from_value) % integer_range.step) == 0) {
216  return result;
217  }
218  result.successful = false;
219  result.reason = format_range_reason(descriptor.name, "integer");
220  return result;
221 }
222 
223 RCLCPP_LOCAL
224 rcl_interfaces::msg::SetParametersResult
225 __check_double_range(
226  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
227  const double value)
228 {
229  rcl_interfaces::msg::SetParametersResult result;
230  result.successful = true;
231  auto fp_range = descriptor.floating_point_range.at(0);
232  if (__are_doubles_equal(value, fp_range.from_value) || __are_doubles_equal(value,
233  fp_range.to_value))
234  {
235  return result;
236  }
237  if ((value < fp_range.from_value) || (value > fp_range.to_value)) {
238  result.successful = false;
239  result.reason = format_range_reason(descriptor.name, "floating point");
240  return result;
241  }
242  if (fp_range.step == 0.0) {
243  return result;
244  }
245  double rounded_div = std::round((value - fp_range.from_value) / fp_range.step);
246  if (__are_doubles_equal(value, fp_range.from_value + rounded_div * fp_range.step)) {
247  return result;
248  }
249  result.successful = false;
250  result.reason = format_range_reason(descriptor.name, "floating point");
251  return result;
252 }
253 
254 RCLCPP_LOCAL
255 rcl_interfaces::msg::SetParametersResult
256 __check_parameter_value_in_range(
257  const rcl_interfaces::msg::ParameterDescriptor & descriptor,
258  const rclcpp::ParameterValue & value)
259 {
260  rcl_interfaces::msg::SetParametersResult result;
261  result.successful = true;
262  if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
263  result = __check_integer_range(descriptor, value.get<int64_t>());
264  return result;
265  }
266 
267  if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER_ARRAY) {
268  std::vector<int64_t> val_array = value.get<std::vector<int64_t>>();
269  for (const int64_t & val : val_array) {
270  result = __check_integer_range(descriptor, val);
271  if (!result.successful) {
272  return result;
273  }
274  }
275  return result;
276  }
277 
278  if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
279  result = __check_double_range(descriptor, value.get<double>());
280  return result;
281  }
282 
283  if (!descriptor.floating_point_range.empty() &&
284  value.get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
285  {
286  std::vector<double> val_array = value.get<std::vector<double>>();
287  for (const double & val : val_array) {
288  result = __check_double_range(descriptor, val);
289  if (!result.successful) {
290  return result;
291  }
292  }
293  return result;
294  }
295 
296  return result;
297 }
298 
299 static
300 std::string
301 format_type_reason(
302  const std::string & name, const std::string & old_type, const std::string & new_type)
303 {
304  std::ostringstream ss;
305  // WARN: A condition later depends on this message starting with "Wrong parameter type",
306  // check `declare_parameter` if you modify this!
307  ss << "Wrong parameter type, parameter {" << name << "} is of type {" << old_type <<
308  "}, setting it to {" << new_type << "} is not allowed.";
309  return ss.str();
310 }
311 
312 // Return true if parameter values comply with the descriptors in parameter_infos.
313 RCLCPP_LOCAL
314 rcl_interfaces::msg::SetParametersResult
315 __check_parameters(
316  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
317  const std::vector<rclcpp::Parameter> & parameters,
318  bool allow_undeclared)
319 {
320  rcl_interfaces::msg::SetParametersResult result;
321  result.successful = true;
322  for (const rclcpp::Parameter & parameter : parameters) {
323  std::string name = parameter.get_name();
324  rcl_interfaces::msg::ParameterDescriptor descriptor;
325  if (allow_undeclared) {
326  auto it = parameter_infos.find(name);
327  if (it != parameter_infos.cend()) {
328  descriptor = it->second.descriptor;
329  } else {
330  // implicitly declared parameters are dinamically typed!
331  descriptor.dynamic_typing = true;
332  }
333  } else {
334  descriptor = parameter_infos[name].descriptor;
335  }
336  if (descriptor.name.empty()) {
337  descriptor.name = name;
338  }
339  const auto new_type = parameter.get_type();
340  const auto specified_type = static_cast<rclcpp::ParameterType>(descriptor.type);
341  result.successful = descriptor.dynamic_typing || specified_type == new_type;
342  if (!result.successful) {
343  result.reason = format_type_reason(
344  name, rclcpp::to_string(specified_type), rclcpp::to_string(new_type));
345  return result;
346  }
347  result = __check_parameter_value_in_range(
348  descriptor,
349  parameter.get_parameter_value());
350  if (!result.successful) {
351  return result;
352  }
353  }
354  return result;
355 }
356 
357 using PreSetParametersCallbackType =
358  rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
361 using PreSetCallbacksHandleContainer =
362  rclcpp::node_interfaces::NodeParameters::PreSetCallbacksHandleContainer;
363 
364 using OnSetParametersCallbackType =
365  rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
368 using OnSetCallbacksHandleContainer =
369  rclcpp::node_interfaces::NodeParameters::OnSetCallbacksHandleContainer;
370 
371 using PostSetParametersCallbackType =
372  rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
375 using PostSetCallbacksHandleContainer =
376  rclcpp::node_interfaces::NodeParameters::PostSetCallbacksHandleContainer;
377 
378 RCLCPP_LOCAL
379 void
380 __call_pre_set_parameters_callbacks(
381  std::vector<rclcpp::Parameter> & parameters,
382  PreSetCallbacksHandleContainer & callback_container)
383 {
384  if (callback_container.empty()) {
385  return;
386  }
387 
388  auto it = callback_container.begin();
389  while (it != callback_container.end()) {
390  auto shared_handle = it->lock();
391  if (nullptr != shared_handle) {
392  shared_handle->callback(parameters);
393  it++;
394  } else {
395  it = callback_container.erase(it);
396  }
397  }
398 }
399 
400 RCLCPP_LOCAL
401 rcl_interfaces::msg::SetParametersResult
402 __call_on_set_parameters_callbacks(
403  const std::vector<rclcpp::Parameter> & parameters,
404  OnSetCallbacksHandleContainer & callback_container)
405 {
406  rcl_interfaces::msg::SetParametersResult result;
407  result.successful = true;
408  auto it = callback_container.begin();
409  while (it != callback_container.end()) {
410  auto shared_handle = it->lock();
411  if (nullptr != shared_handle) {
412  result = shared_handle->callback(parameters);
413  if (!result.successful) {
414  return result;
415  }
416  it++;
417  } else {
418  it = callback_container.erase(it);
419  }
420  }
421  return result;
422 }
423 
424 RCLCPP_LOCAL
425 void __call_post_set_parameters_callbacks(
426  const std::vector<rclcpp::Parameter> & parameters,
427  PostSetCallbacksHandleContainer & callback_container)
428 {
429  if (callback_container.empty()) {
430  return;
431  }
432 
433  auto it = callback_container.begin();
434  while (it != callback_container.end()) {
435  auto shared_handle = it->lock();
436  if (nullptr != shared_handle) {
437  shared_handle->callback(parameters);
438  it++;
439  } else {
440  it = callback_container.erase(it);
441  }
442  }
443 }
444 
445 RCLCPP_LOCAL
446 rcl_interfaces::msg::SetParametersResult
447 __set_parameters_atomically_common(
448  const std::vector<rclcpp::Parameter> & parameters,
449  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
450  OnSetCallbacksHandleContainer & on_set_callback_container,
451  PostSetCallbacksHandleContainer & post_set_callback_container,
452  bool allow_undeclared = false)
453 {
454  // Check if the value being set complies with the descriptor.
455  rcl_interfaces::msg::SetParametersResult result = __check_parameters(
456  parameter_infos, parameters, allow_undeclared);
457  if (!result.successful) {
458  return result;
459  }
460  // Call the user callbacks to see if the new value(s) are allowed.
461  result =
462  __call_on_set_parameters_callbacks(parameters, on_set_callback_container);
463  if (!result.successful) {
464  return result;
465  }
466  // If accepted, actually set the values.
467  if (result.successful) {
468  for (size_t i = 0; i < parameters.size(); ++i) {
469  const std::string & name = parameters[i].get_name();
470  parameter_infos[name].descriptor.name = parameters[i].get_name();
471  parameter_infos[name].descriptor.type = parameters[i].get_type();
472  parameter_infos[name].value = parameters[i].get_parameter_value();
473  }
474  // Call the user post set parameter callback
475  __call_post_set_parameters_callbacks(parameters, post_set_callback_container);
476  }
477 
478  // Either way, return the result.
479  return result;
480 }
481 
482 RCLCPP_LOCAL
483 rcl_interfaces::msg::SetParametersResult
484 __declare_parameter_common(
485  const std::string & name,
486  const rclcpp::ParameterValue & default_value,
487  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
488  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
489  const std::map<std::string, rclcpp::ParameterValue> & overrides,
490  OnSetCallbacksHandleContainer & on_set_callback_container,
491  PostSetCallbacksHandleContainer & post_set_callback_container,
492  rcl_interfaces::msg::ParameterEvent * parameter_event_out,
493  bool ignore_override = false)
494 {
496  std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
497  parameter_infos.at(name).descriptor = parameter_descriptor;
498 
499  // Use the value from the overrides if available, otherwise use the default.
500  const rclcpp::ParameterValue * initial_value = &default_value;
501  auto overrides_it = overrides.find(name);
502  if (!ignore_override && overrides_it != overrides.end()) {
503  initial_value = &overrides_it->second;
504  }
505 
506  // If there is no initial value, then skip initialization
507  if (initial_value->get_type() == rclcpp::PARAMETER_NOT_SET) {
508  // Add declared parameters to storage (without a value)
509  parameter_infos[name].descriptor.name = name;
510  if (parameter_descriptor.dynamic_typing) {
511  parameter_infos[name].descriptor.type = rclcpp::PARAMETER_NOT_SET;
512  } else {
513  parameter_infos[name].descriptor.type = parameter_descriptor.type;
514  }
515  parameters_out[name] = parameter_infos.at(name);
516  rcl_interfaces::msg::SetParametersResult result;
517  result.successful = true;
518  return result;
519  }
520 
521  // Check with the user's callbacks to see if the initial value can be set.
522  std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
523  // This function also takes care of default vs initial value.
524  auto result = __set_parameters_atomically_common(
525  parameter_wrappers,
526  parameter_infos,
527  on_set_callback_container,
528  post_set_callback_container
529  );
530 
531  if (!result.successful) {
532  return result;
533  }
534 
535  // Add declared parameters to storage.
536  parameters_out[name] = parameter_infos.at(name);
537 
538  // Extend the given parameter event, if valid.
539  if (parameter_event_out) {
540  parameter_event_out->new_parameters.push_back(parameter_wrappers[0].to_parameter_msg());
541  }
542 
543  return result;
544 }
545 
546 static
548 declare_parameter_helper(
549  const std::string & name,
550  rclcpp::ParameterType type,
551  const rclcpp::ParameterValue & default_value,
552  rcl_interfaces::msg::ParameterDescriptor parameter_descriptor,
553  bool ignore_override,
554  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
555  const std::map<std::string, rclcpp::ParameterValue> & overrides,
556  OnSetCallbacksHandleContainer & on_set_callback_container,
557  PostSetCallbacksHandleContainer & post_set_callback_container,
559  const std::string & combined_name,
561 {
562  // TODO(sloretz) parameter name validation
563  if (name.empty()) {
564  throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
565  }
566 
567  // Error if this parameter has already been declared and is different
568  if (__lockless_has_parameter(parameters, name)) {
570  "parameter '" + name + "' has already been declared");
571  }
572 
573  if (!parameter_descriptor.dynamic_typing) {
574  if (rclcpp::PARAMETER_NOT_SET == type) {
575  type = default_value.get_type();
576  }
577  if (rclcpp::PARAMETER_NOT_SET == type) {
579  name,
580  "cannot declare a statically typed parameter with an uninitialized value"
581  };
582  }
583  parameter_descriptor.type = static_cast<uint8_t>(type);
584  }
585 
586  rcl_interfaces::msg::ParameterEvent parameter_event;
587  auto result = __declare_parameter_common(
588  name,
589  default_value,
590  parameter_descriptor,
591  parameters,
592  overrides,
593  on_set_callback_container,
594  post_set_callback_container,
595  &parameter_event,
596  ignore_override);
597 
598  // If it failed to be set, then throw an exception.
599  if (!result.successful) {
600  constexpr const char type_error_msg_start[] = "Wrong parameter type";
601  if (
602  0u == std::strncmp(
603  result.reason.c_str(), type_error_msg_start, sizeof(type_error_msg_start) - 1))
604  {
605  // TODO(ivanpauno): Refactor the logic so we don't need the above `strncmp` and we can
606  // detect between both exceptions more elegantly.
607  throw rclcpp::exceptions::InvalidParameterTypeException(name, result.reason);
608  }
610  "parameter '" + name + "' could not be set: " + result.reason);
611  }
612 
613  // Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
614  if (nullptr != events_publisher) {
615  parameter_event.node = combined_name;
616  parameter_event.stamp = node_clock.get_clock()->now();
617  events_publisher->publish(parameter_event);
618  }
619 
620  return parameters.at(name).value;
621 }
622 
625  const std::string & name,
626  const rclcpp::ParameterValue & default_value,
627  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
628  bool ignore_override)
629 {
630  std::lock_guard<std::recursive_mutex> lock(mutex_);
631  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
632 
633  return declare_parameter_helper(
634  name,
635  rclcpp::PARAMETER_NOT_SET,
636  default_value,
637  parameter_descriptor,
638  ignore_override,
639  parameters_,
640  parameter_overrides_,
641  on_set_parameters_callback_container_,
642  post_set_parameters_callback_container_,
643  events_publisher_.get(),
644  combined_name_,
645  *node_clock_);
646 }
647 
650  const std::string & name,
651  rclcpp::ParameterType type,
652  const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
653  bool ignore_override)
654 {
655  std::lock_guard<std::recursive_mutex> lock(mutex_);
656  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
657 
658  if (rclcpp::PARAMETER_NOT_SET == type) {
659  throw std::invalid_argument{
660  "declare_parameter(): the provided parameter type cannot be rclcpp::PARAMETER_NOT_SET"};
661  }
662 
663  if (parameter_descriptor.dynamic_typing == true) {
664  throw std::invalid_argument{
665  "declare_parameter(): cannot declare parameter of specific type and pass descriptor"
666  "with `dynamic_typing=true`"};
667  }
668 
669  return declare_parameter_helper(
670  name,
671  type,
673  parameter_descriptor,
674  ignore_override,
675  parameters_,
676  parameter_overrides_,
677  on_set_parameters_callback_container_,
678  post_set_parameters_callback_container_,
679  events_publisher_.get(),
680  combined_name_,
681  *node_clock_);
682 }
683 
684 void
685 NodeParameters::undeclare_parameter(const std::string & name)
686 {
687  std::lock_guard<std::recursive_mutex> lock(mutex_);
688 
689  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
690 
691  auto parameter_info = parameters_.find(name);
692  if (parameter_info == parameters_.end()) {
694  "cannot undeclare parameter '" + name + "' which has not yet been declared");
695  }
696 
697  if (parameter_info->second.descriptor.read_only) {
699  "cannot undeclare parameter '" + name + "' because it is read-only");
700  }
701  if (!parameter_info->second.descriptor.dynamic_typing) {
703  name, "cannot undeclare a statically typed parameter"};
704  }
705 
706  parameters_.erase(parameter_info);
707 }
708 
709 bool
710 NodeParameters::has_parameter(const std::string & name) const
711 {
712  std::lock_guard<std::recursive_mutex> lock(mutex_);
713 
714  return __lockless_has_parameter(parameters_, name);
715 }
716 
717 std::vector<rcl_interfaces::msg::SetParametersResult>
718 NodeParameters::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
719 {
720  std::vector<rcl_interfaces::msg::SetParametersResult> results;
721  results.reserve(parameters.size());
722 
723  for (const auto & p : parameters) {
724  auto result = set_parameters_atomically({{p}});
725  results.push_back(result);
726  }
727 
728  return results;
729 }
730 
731 template<typename ParameterVectorType>
732 auto
733 __find_parameter_by_name(
734  ParameterVectorType & parameters,
735  const std::string & name)
736 {
737  return std::find_if(
738  parameters.begin(),
739  parameters.end(),
740  [&](auto parameter) {return parameter.get_name() == name;});
741 }
742 
743 rcl_interfaces::msg::SetParametersResult
744 NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
745 {
746  std::lock_guard<std::recursive_mutex> lock(mutex_);
747 
748  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
749 
750  rcl_interfaces::msg::SetParametersResult result;
751 
752  // call any user registered pre set parameter callbacks
753  // this callback can make changes to the original parameters list
754  // also check if the changed parameter list is empty or not, if empty return
755  std::vector<rclcpp::Parameter> parameters_after_pre_set_callback(parameters);
756  __call_pre_set_parameters_callbacks(
757  parameters_after_pre_set_callback,
758  pre_set_parameters_callback_container_);
759 
760  if (parameters_after_pre_set_callback.empty()) {
761  result.successful = false;
762  result.reason = "parameter list cannot be empty, this might be due to "
763  "pre_set_parameters_callback modifying the original parameters list.";
764  return result;
765  }
766 
767  // Check if any of the parameters are read-only, or if any parameters are not
768  // declared.
769  // If not declared, keep track of them in order to declare them later, when
770  // undeclared parameters are allowed, and if they're not allowed, fail.
771  std::vector<const rclcpp::Parameter *> parameters_to_be_declared;
772  for (const auto & parameter : parameters_after_pre_set_callback) {
773  const std::string & name = parameter.get_name();
774 
775  // Check to make sure the parameter name is valid.
776  if (name.empty()) {
777  throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
778  }
779 
780  // Check to see if it is declared.
781  auto parameter_info = parameters_.find(name);
782  if (parameter_info == parameters_.end()) {
783  // If not check to see if undeclared paramaters are allowed, ...
784  if (allow_undeclared_) {
785  // If so, mark the parameter to be declared for the user implicitly.
786  parameters_to_be_declared.push_back(&parameter);
787  // continue as it cannot be read-only, and because the declare will
788  // implicitly set the parameter and parameter_infos is for setting only.
789  continue;
790  } else {
791  // If not, then throw the exception as documented.
793  "parameter '" + name + "' cannot be set because it was not declared");
794  }
795  }
796 
797  // Check to see if it is read-only.
798  if (parameter_info->second.descriptor.read_only) {
799  result.successful = false;
800  result.reason = "parameter '" + name + "' cannot be set because it is read-only";
801  return result;
802  }
803  }
804 
805  // Declare parameters into a temporary "staging area", incase one of the declares fail.
806  // We will use the staged changes as input to the "set atomically" action.
807  // We explicitly avoid calling the user callbacks here, so that it may be called once, with
808  // all the other parameters to be set (already declared parameters).
809  std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
810  rcl_interfaces::msg::ParameterEvent parameter_event_msg;
811  parameter_event_msg.node = combined_name_;
812  OnSetCallbacksHandleContainer empty_on_set_callback_container;
813  PostSetCallbacksHandleContainer empty_post_set_callback_container;
814 
815  // Implicit declare uses dynamic type descriptor.
816  rcl_interfaces::msg::ParameterDescriptor descriptor;
817  descriptor.dynamic_typing = true;
818  for (auto parameter_to_be_declared : parameters_to_be_declared) {
819  // This should not throw, because we validated the name and checked that
820  // the parameter was not already declared.
821  result = __declare_parameter_common(
822  parameter_to_be_declared->get_name(),
823  parameter_to_be_declared->get_parameter_value(),
824  descriptor,
825  staged_parameter_changes,
826  parameter_overrides_,
827  // Only call callbacks once below
828  empty_on_set_callback_container, // callback_container is explicitly empty
829  empty_post_set_callback_container, // callback_container is explicitly empty
830  &parameter_event_msg,
831  true);
832  if (!result.successful) {
833  // Declare failed, return knowing that nothing was changed because the
834  // staged changes were not applied.
835  return result;
836  }
837  }
838 
839  // If there were implicitly declared parameters, then we may need to copy the input parameters
840  // and then assign the value that was selected after the declare (could be affected by the
841  // initial parameter values).
842  const std::vector<rclcpp::Parameter> * parameters_to_be_set = &parameters_after_pre_set_callback;
843  std::vector<rclcpp::Parameter> parameters_copy;
844  if (0 != staged_parameter_changes.size()) { // If there were any implicitly declared parameters.
845  bool any_initial_values_used = false;
846  for (const auto & staged_parameter_change : staged_parameter_changes) {
847  auto it = __find_parameter_by_name(
848  parameters_after_pre_set_callback,
849  staged_parameter_change.first);
850  if (it->get_parameter_value() != staged_parameter_change.second.value) {
851  // In this case, the value of the staged parameter differs from the
852  // input from the user, and therefore we need to update things before setting.
853  any_initial_values_used = true;
854  // No need to search further since at least one initial value needs to be used.
855  break;
856  }
857  }
858  if (any_initial_values_used) {
859  parameters_copy = parameters_after_pre_set_callback;
860  for (const auto & staged_parameter_change : staged_parameter_changes) {
861  auto it = __find_parameter_by_name(parameters_copy, staged_parameter_change.first);
862  *it = Parameter(staged_parameter_change.first, staged_parameter_change.second.value);
863  }
864  parameters_to_be_set = &parameters_copy;
865  }
866  }
867 
868  // Collect parameters who will have had their type changed to
869  // rclcpp::PARAMETER_NOT_SET so they can later be implicitly undeclared.
870  std::vector<const rclcpp::Parameter *> parameters_to_be_undeclared;
871  for (const auto & parameter : *parameters_to_be_set) {
872  if (rclcpp::PARAMETER_NOT_SET == parameter.get_type()) {
873  auto it = parameters_.find(parameter.get_name());
874  if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
875  if (!it->second.descriptor.dynamic_typing) {
876  result.reason = "cannot undeclare a statically typed parameter";
877  result.successful = false;
878  return result;
879  }
880  parameters_to_be_undeclared.push_back(&parameter);
881  }
882  }
883  }
884 
885  // Set all of the parameters including the ones declared implicitly above.
886  result = __set_parameters_atomically_common(
887  // either the original parameters given by the user, or ones updated with initial values
888  *parameters_to_be_set,
889  // they are actually set on the official parameter storage
890  parameters_,
891  // These callbacks are called once. When a callback returns an unsuccessful result,
892  // the remaining aren't called
893  on_set_parameters_callback_container_,
894  post_set_parameters_callback_container_,
895  allow_undeclared_); // allow undeclared
896 
897  // If not successful, then stop here.
898  if (!result.successful) {
899  return result;
900  }
901 
902  // If successful, then update the parameter infos from the implicitly declared parameter's.
903  for (const auto & kv_pair : staged_parameter_changes) {
904  // assumption: the parameter is already present in parameters_ due to the above "set"
905  assert(__lockless_has_parameter(parameters_, kv_pair.first));
906  // assumption: the value in parameters_ is the same as the value resulting from the declare
907  assert(parameters_[kv_pair.first].value == kv_pair.second.value);
908  // This assignment should not change the name, type, or value, but may
909  // change other things from the ParameterInfo.
910  parameters_[kv_pair.first] = kv_pair.second;
911  }
912 
913  // Undeclare parameters that need to be.
914  for (auto parameter_to_undeclare : parameters_to_be_undeclared) {
915  auto it = parameters_.find(parameter_to_undeclare->get_name());
916  // assumption: the parameter to be undeclared should be in the parameter infos map
917  assert(it != parameters_.end());
918  if (it != parameters_.end()) {
919  // Update the parameter event message and remove it.
920  parameter_event_msg.deleted_parameters.push_back(
921  rclcpp::Parameter(it->first, it->second.value).to_parameter_msg());
922  parameters_.erase(it);
923  }
924  }
925 
926  // Update the parameter event message for any parameters which were only set,
927  // and not either declared or undeclared.
928  for (const auto & parameter : *parameters_to_be_set) {
929  if (staged_parameter_changes.find(parameter.get_name()) != staged_parameter_changes.end()) {
930  // This parameter was declared.
931  continue;
932  }
933  auto it = std::find_if(
934  parameters_to_be_undeclared.begin(),
935  parameters_to_be_undeclared.end(),
936  [&parameter](const auto & p) {return p->get_name() == parameter.get_name();});
937  if (it != parameters_to_be_undeclared.end()) {
938  // This parameter was undeclared (deleted).
939  continue;
940  }
941  // This parameter was neither declared nor undeclared.
942  parameter_event_msg.changed_parameters.push_back(parameter.to_parameter_msg());
943  }
944 
945  // Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
946  if (nullptr != events_publisher_) {
947  parameter_event_msg.stamp = node_clock_->get_clock()->now();
948  events_publisher_->publish(parameter_event_msg);
949  }
950  return result;
951 }
952 
953 std::vector<rclcpp::Parameter>
954 NodeParameters::get_parameters(const std::vector<std::string> & names) const
955 {
956  std::vector<rclcpp::Parameter> results;
957  results.reserve(names.size());
958 
959  std::lock_guard<std::recursive_mutex> lock(mutex_);
960  for (auto & name : names) {
961  results.emplace_back(this->get_parameter(name));
962  }
963  return results;
964 }
965 
967 NodeParameters::get_parameter(const std::string & name) const
968 {
969  std::lock_guard<std::recursive_mutex> lock(mutex_);
970 
971  auto param_iter = parameters_.find(name);
972  if (parameters_.end() != param_iter) {
973  if (
974  param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
975  param_iter->second.descriptor.dynamic_typing)
976  {
977  return rclcpp::Parameter{name, param_iter->second.value};
978  }
980  } else if (this->allow_undeclared_) {
981  return rclcpp::Parameter{name};
982  } else {
984  }
985 }
986 
987 bool
989  const std::string & name,
990  rclcpp::Parameter & parameter) const
991 {
992  std::lock_guard<std::recursive_mutex> lock(mutex_);
993 
994  auto param_iter = parameters_.find(name);
995  if (
996  parameters_.end() != param_iter &&
997  param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
998  {
999  parameter = {name, param_iter->second.value};
1000  return true;
1001  } else {
1002  return false;
1003  }
1004 }
1005 
1006 bool
1008  const std::string & prefix,
1009  std::map<std::string, rclcpp::Parameter> & parameters) const
1010 {
1011  std::lock_guard<std::recursive_mutex> lock(mutex_);
1012 
1013  std::string prefix_with_dot = prefix.empty() ? prefix : prefix + ".";
1014  bool ret = false;
1015 
1016  for (const auto & param : parameters_) {
1017  if (param.first.find(prefix_with_dot) == 0 && param.first.length() > prefix_with_dot.length()) {
1018  // Found one!
1019  parameters[param.first.substr(prefix_with_dot.length())] = rclcpp::Parameter(param.second);
1020  ret = true;
1021  }
1022  }
1023 
1024  return ret;
1025 }
1026 
1027 std::vector<rcl_interfaces::msg::ParameterDescriptor>
1028 NodeParameters::describe_parameters(const std::vector<std::string> & names) const
1029 {
1030  std::lock_guard<std::recursive_mutex> lock(mutex_);
1031  std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
1032  results.reserve(names.size());
1033 
1034  for (const auto & name : names) {
1035  auto it = parameters_.find(name);
1036  if (it != parameters_.cend()) {
1037  results.push_back(it->second.descriptor);
1038  } else if (allow_undeclared_) {
1039  // parameter not found, but undeclared allowed, so return empty
1040  rcl_interfaces::msg::ParameterDescriptor default_description;
1041  default_description.name = name;
1042  results.push_back(default_description);
1043  } else {
1045  }
1046  }
1047 
1048  if (results.size() != names.size()) {
1049  throw std::runtime_error("results and names unexpectedly different sizes");
1050  }
1051 
1052  return results;
1053 }
1054 
1055 std::vector<uint8_t>
1056 NodeParameters::get_parameter_types(const std::vector<std::string> & names) const
1057 {
1058  std::lock_guard<std::recursive_mutex> lock(mutex_);
1059  std::vector<uint8_t> results;
1060  results.reserve(names.size());
1061 
1062  for (const auto & name : names) {
1063  auto it = parameters_.find(name);
1064  if (it != parameters_.cend()) {
1065  results.push_back(it->second.value.get_type());
1066  } else if (allow_undeclared_) {
1067  // parameter not found, but undeclared allowed, so return not set
1068  results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
1069  } else {
1071  }
1072  }
1073 
1074  if (results.size() != names.size()) {
1075  throw std::runtime_error("results and names unexpectedly different sizes");
1076  }
1077 
1078  return results;
1079 }
1080 
1081 rcl_interfaces::msg::ListParametersResult
1082 NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
1083 {
1084  std::lock_guard<std::recursive_mutex> lock(mutex_);
1085  rcl_interfaces::msg::ListParametersResult result;
1086 
1087  // TODO(mikaelarguedas) define parameter separator different from "/" to avoid ambiguity
1088  // using "." for now
1089  const char * separator = ".";
1090 
1091  auto separators_less_than_depth = [&depth, &separator](const std::string & str) -> bool {
1092  return static_cast<uint64_t>(std::count(str.begin(), str.end(), *separator)) < depth;
1093  };
1094 
1095  bool recursive = (prefixes.size() == 0) &&
1096  (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE);
1097 
1098  for (const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
1099  if (!recursive) {
1100  bool get_all = (prefixes.size() == 0) && separators_less_than_depth(kv.first);
1101  if (!get_all) {
1102  bool prefix_matches = std::any_of(
1103  prefixes.cbegin(), prefixes.cend(),
1104  [&kv, &depth, &separator, &separators_less_than_depth](const std::string & prefix) {
1105  if (kv.first == prefix) {
1106  return true;
1107  } else if (kv.first.find(prefix + separator) == 0) {
1108  if (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) {
1109  return true;
1110  }
1111  std::string substr = kv.first.substr(prefix.length() + 1);
1112  return separators_less_than_depth(substr);
1113  }
1114  return false;
1115  });
1116 
1117  if (!prefix_matches) {
1118  continue;
1119  }
1120  }
1121  }
1122 
1123  result.names.push_back(kv.first);
1124  size_t last_separator = kv.first.find_last_of(separator);
1125  if (std::string::npos != last_separator) {
1126  std::string prefix = kv.first.substr(0, last_separator);
1127  if (
1128  std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
1129  result.prefixes.cend())
1130  {
1131  result.prefixes.push_back(prefix);
1132  }
1133  }
1134  }
1135  return result;
1136 }
1137 
1138 void
1140  const PreSetParametersCallbackHandle * const handle)
1141 {
1142  std::lock_guard<std::recursive_mutex> lock(mutex_);
1143  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1144 
1145  auto it = std::find_if(
1146  pre_set_parameters_callback_container_.begin(),
1147  pre_set_parameters_callback_container_.end(),
1148  [handle](const auto & weak_handle) {
1149  return handle == weak_handle.lock().get();
1150  });
1151  if (it != pre_set_parameters_callback_container_.end()) {
1152  pre_set_parameters_callback_container_.erase(it);
1153  } else {
1154  throw std::runtime_error("Pre set parameter callback doesn't exist");
1155  }
1156 }
1157 
1158 void
1160  const OnSetParametersCallbackHandle * const handle)
1161 {
1162  std::lock_guard<std::recursive_mutex> lock(mutex_);
1163  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1164 
1165  auto it = std::find_if(
1166  on_set_parameters_callback_container_.begin(),
1167  on_set_parameters_callback_container_.end(),
1168  [handle](const auto & weak_handle) {
1169  return handle == weak_handle.lock().get();
1170  });
1171  if (it != on_set_parameters_callback_container_.end()) {
1172  on_set_parameters_callback_container_.erase(it);
1173  } else {
1174  throw std::runtime_error("On set parameter callback doesn't exist");
1175  }
1176 }
1177 
1178 void
1180  const PostSetParametersCallbackHandle * const handle)
1181 {
1182  std::lock_guard<std::recursive_mutex> lock(mutex_);
1183  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1184 
1185  auto it = std::find_if(
1186  post_set_parameters_callback_container_.begin(),
1187  post_set_parameters_callback_container_.end(),
1188  [handle](const auto & weak_handle) {
1189  return handle == weak_handle.lock().get();
1190  });
1191  if (it != post_set_parameters_callback_container_.end()) {
1192  post_set_parameters_callback_container_.erase(it);
1193  } else {
1194  throw std::runtime_error("Post set parameter callback doesn't exist");
1195  }
1196 }
1197 
1198 PreSetParametersCallbackHandle::SharedPtr
1199 NodeParameters::add_pre_set_parameters_callback(PreSetParametersCallbackType callback)
1200 {
1201  std::lock_guard<std::recursive_mutex> lock(mutex_);
1202  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1203 
1204  auto handle = std::make_shared<PreSetParametersCallbackHandle>();
1205  handle->callback = callback;
1206  // the last callback registered is executed first.
1207  pre_set_parameters_callback_container_.emplace_front(handle);
1208  return handle;
1209 }
1210 
1211 OnSetParametersCallbackHandle::SharedPtr
1212 NodeParameters::add_on_set_parameters_callback(OnSetParametersCallbackType callback)
1213 {
1214  std::lock_guard<std::recursive_mutex> lock(mutex_);
1215  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1216 
1217  auto handle = std::make_shared<OnSetParametersCallbackHandle>();
1218  handle->callback = callback;
1219  // the last callback registered is executed first.
1220  on_set_parameters_callback_container_.emplace_front(handle);
1221  return handle;
1222 }
1223 
1224 PostSetParametersCallbackHandle::SharedPtr
1226  PostSetParametersCallbackType callback)
1227 {
1228  std::lock_guard<std::recursive_mutex> lock(mutex_);
1229  ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
1230 
1231  auto handle = std::make_shared<PostSetParametersCallbackHandle>();
1232  handle->callback = callback;
1233  // the last callback registered is executed first.
1234  post_set_parameters_callback_container_.emplace_front(handle);
1235  return handle;
1236 }
1237 
1238 const std::map<std::string, rclcpp::ParameterValue> &
1240 {
1241  return parameter_overrides_;
1242 }
1243 
1244 void
1246 {
1247  std::lock_guard<std::recursive_mutex> lock(mutex_);
1248  parameter_modification_enabled_ = true;
1249 }
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:435
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.