ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
parameter_client.cpp
1 // Copyright 2015 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/parameter_client.hpp"
16 
17 #include <algorithm>
18 #include <chrono>
19 #include <functional>
20 #include <future>
21 #include <iterator>
22 #include <memory>
23 #include <stdexcept>
24 #include <string>
25 #include <vector>
26 
27 #include "./parameter_service_names.hpp"
28 
31 
32 AsyncParametersClient::AsyncParametersClient(
33  const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
34  const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
35  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
36  const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
37  const std::string & remote_node_name,
38  const rmw_qos_profile_t & qos_profile,
39  rclcpp::CallbackGroup::SharedPtr group)
40 : node_topics_interface_(node_topics_interface)
41 {
42  if (remote_node_name != "") {
43  remote_node_name_ = remote_node_name;
44  } else {
45  remote_node_name_ = node_base_interface->get_fully_qualified_name();
46  }
47 
49  options.qos = qos_profile;
50 
51  using rclcpp::Client;
52  using rclcpp::ClientBase;
53 
55  node_base_interface.get(),
56  node_graph_interface,
57  remote_node_name_ + "/" + parameter_service_names::get_parameters,
58  options);
59  auto get_parameters_base = std::dynamic_pointer_cast<ClientBase>(get_parameters_client_);
60  node_services_interface->add_client(get_parameters_base, group);
61 
63  node_base_interface.get(),
64  node_graph_interface,
65  remote_node_name_ + "/" + parameter_service_names::get_parameter_types,
66  options);
67  auto get_parameter_types_base =
68  std::dynamic_pointer_cast<ClientBase>(get_parameter_types_client_);
69  node_services_interface->add_client(get_parameter_types_base, group);
70 
72  node_base_interface.get(),
73  node_graph_interface,
74  remote_node_name_ + "/" + parameter_service_names::set_parameters,
75  options);
76  auto set_parameters_base = std::dynamic_pointer_cast<ClientBase>(set_parameters_client_);
77  node_services_interface->add_client(set_parameters_base, group);
78 
79  set_parameters_atomically_client_ =
81  node_base_interface.get(),
82  node_graph_interface,
83  remote_node_name_ + "/" + parameter_service_names::set_parameters_atomically,
84  options);
85  auto set_parameters_atomically_base = std::dynamic_pointer_cast<ClientBase>(
86  set_parameters_atomically_client_);
87  node_services_interface->add_client(set_parameters_atomically_base, group);
88 
90  node_base_interface.get(),
91  node_graph_interface,
92  remote_node_name_ + "/" + parameter_service_names::list_parameters,
93  options);
94  auto list_parameters_base = std::dynamic_pointer_cast<ClientBase>(list_parameters_client_);
95  node_services_interface->add_client(list_parameters_base, group);
96 
98  node_base_interface.get(),
99  node_graph_interface,
100  remote_node_name_ + "/" + parameter_service_names::describe_parameters,
101  options);
102  auto describe_parameters_base =
103  std::dynamic_pointer_cast<ClientBase>(describe_parameters_client_);
104  node_services_interface->add_client(describe_parameters_base, group);
105 }
106 
107 std::shared_future<std::vector<rclcpp::Parameter>>
108 AsyncParametersClient::get_parameters(
109  const std::vector<std::string> & names,
110  std::function<
111  void(std::shared_future<std::vector<rclcpp::Parameter>>)
112  > callback)
113 {
114  auto promise_result =
115  std::make_shared<std::promise<std::vector<rclcpp::Parameter>>>();
116  auto future_result = promise_result->get_future().share();
117 
118  auto request = std::make_shared<rcl_interfaces::srv::GetParameters::Request>();
119  request->names = names;
120 
121  get_parameters_client_->async_send_request(
122  request,
123  [request, promise_result, future_result, callback](
124  rclcpp::Client<rcl_interfaces::srv::GetParameters>::SharedFuture cb_f)
125  {
126  std::vector<rclcpp::Parameter> parameters;
127  auto & pvalues = cb_f.get()->values;
128 
129  for (auto & pvalue : pvalues) {
130  auto i = static_cast<size_t>(&pvalue - &pvalues[0]);
131  rcl_interfaces::msg::Parameter parameter;
132  parameter.name = request->names[i];
133  parameter.value = pvalue;
134  parameters.push_back(rclcpp::Parameter::from_parameter_msg(parameter));
135  }
136 
137  promise_result->set_value(parameters);
138  if (callback != nullptr) {
139  callback(future_result);
140  }
141  }
142  );
143 
144  return future_result;
145 }
146 
147 std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
148 AsyncParametersClient::describe_parameters(
149  const std::vector<std::string> & names,
150  std::function<
151  void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
152  > callback)
153 {
154  auto promise_result =
155  std::make_shared<std::promise<std::vector<rcl_interfaces::msg::ParameterDescriptor>>>();
156  auto future_result = promise_result->get_future().share();
157 
158  auto request = std::make_shared<rcl_interfaces::srv::DescribeParameters::Request>();
159  request->names = names;
160 
161  describe_parameters_client_->async_send_request(
162  request,
163  [promise_result, future_result, callback](
164  rclcpp::Client<rcl_interfaces::srv::DescribeParameters>::SharedFuture cb_f)
165  {
166  promise_result->set_value(cb_f.get()->descriptors);
167  if (callback != nullptr) {
168  callback(future_result);
169  }
170  }
171  );
172 
173  return future_result;
174 }
175 
176 std::shared_future<std::vector<rclcpp::ParameterType>>
177 AsyncParametersClient::get_parameter_types(
178  const std::vector<std::string> & names,
179  std::function<
180  void(std::shared_future<std::vector<rclcpp::ParameterType>>)
181  > callback)
182 {
183  auto promise_result =
184  std::make_shared<std::promise<std::vector<rclcpp::ParameterType>>>();
185  auto future_result = promise_result->get_future().share();
186 
187  auto request = std::make_shared<rcl_interfaces::srv::GetParameterTypes::Request>();
188  request->names = names;
189 
190  get_parameter_types_client_->async_send_request(
191  request,
192  [promise_result, future_result, callback](
193  rclcpp::Client<rcl_interfaces::srv::GetParameterTypes>::SharedFuture cb_f)
194  {
195  std::vector<rclcpp::ParameterType> types;
196  auto & pts = cb_f.get()->types;
197  for (auto & pt : pts) {
198  types.push_back(static_cast<rclcpp::ParameterType>(pt));
199  }
200  promise_result->set_value(types);
201  if (callback != nullptr) {
202  callback(future_result);
203  }
204  }
205  );
206 
207  return future_result;
208 }
209 
210 std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
211 AsyncParametersClient::set_parameters(
212  const std::vector<rclcpp::Parameter> & parameters,
213  std::function<
214  void(std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>)
215  > callback)
216 {
217  auto promise_result =
218  std::make_shared<std::promise<std::vector<rcl_interfaces::msg::SetParametersResult>>>();
219  auto future_result = promise_result->get_future().share();
220 
221  auto request = std::make_shared<rcl_interfaces::srv::SetParameters::Request>();
222 
223  std::transform(
224  parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
225  [](rclcpp::Parameter p) {return p.to_parameter_msg();}
226  );
227 
228  set_parameters_client_->async_send_request(
229  request,
230  [promise_result, future_result, callback](
231  rclcpp::Client<rcl_interfaces::srv::SetParameters>::SharedFuture cb_f)
232  {
233  promise_result->set_value(cb_f.get()->results);
234  if (callback != nullptr) {
235  callback(future_result);
236  }
237  }
238  );
239 
240  return future_result;
241 }
242 
243 std::shared_future<rcl_interfaces::msg::SetParametersResult>
244 AsyncParametersClient::set_parameters_atomically(
245  const std::vector<rclcpp::Parameter> & parameters,
246  std::function<
247  void(std::shared_future<rcl_interfaces::msg::SetParametersResult>)
248  > callback)
249 {
250  auto promise_result =
251  std::make_shared<std::promise<rcl_interfaces::msg::SetParametersResult>>();
252  auto future_result = promise_result->get_future().share();
253 
254  auto request = std::make_shared<rcl_interfaces::srv::SetParametersAtomically::Request>();
255 
256  std::transform(
257  parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
258  [](rclcpp::Parameter p) {return p.to_parameter_msg();}
259  );
260 
261  set_parameters_atomically_client_->async_send_request(
262  request,
263  [promise_result, future_result, callback](
264  rclcpp::Client<rcl_interfaces::srv::SetParametersAtomically>::SharedFuture cb_f)
265  {
266  promise_result->set_value(cb_f.get()->result);
267  if (callback != nullptr) {
268  callback(future_result);
269  }
270  }
271  );
272 
273  return future_result;
274 }
275 
276 std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
278  const std::vector<std::string> & parameters_names)
279 {
280  std::vector<rclcpp::Parameter> parameters;
281  for (const std::string & name : parameters_names) {
282  parameters.push_back(rclcpp::Parameter(name));
283  }
284  auto future_result = set_parameters(parameters);
285 
286  return future_result;
287 }
288 
289 std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
291  const std::string & yaml_filename)
292 {
293  rclcpp::ParameterMap parameter_map = rclcpp::parameter_map_from_yaml_file(yaml_filename);
294  return this->load_parameters(parameter_map);
295 }
296 
297 std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
299  const rclcpp::ParameterMap & parameter_map)
300 {
301  std::vector<rclcpp::Parameter> parameters;
302  std::string remote_name = remote_node_name_.substr(remote_node_name_.substr(1).find("/") + 2);
303  for (const auto & params : parameter_map) {
304  std::string node_full_name = params.first;
305  std::string node_name = node_full_name.substr(node_full_name.find("/*/") + 3);
306  if (node_full_name == remote_node_name_ ||
307  node_full_name == "/**" ||
308  (node_name == remote_name))
309  {
310  for (const auto & param : params.second) {
311  parameters.push_back(param);
312  }
313  }
314  }
315 
316  if (parameters.size() == 0) {
317  throw rclcpp::exceptions::InvalidParametersException("No valid parameter");
318  }
319  auto future_result = set_parameters(parameters);
320 
321  return future_result;
322 }
323 
324 
325 std::shared_future<rcl_interfaces::msg::ListParametersResult>
326 AsyncParametersClient::list_parameters(
327  const std::vector<std::string> & prefixes,
328  uint64_t depth,
329  std::function<
330  void(std::shared_future<rcl_interfaces::msg::ListParametersResult>)
331  > callback)
332 {
333  auto promise_result =
334  std::make_shared<std::promise<rcl_interfaces::msg::ListParametersResult>>();
335  auto future_result = promise_result->get_future().share();
336 
337  auto request = std::make_shared<rcl_interfaces::srv::ListParameters::Request>();
338  request->prefixes = prefixes;
339  request->depth = depth;
340 
341  list_parameters_client_->async_send_request(
342  request,
343  [promise_result, future_result, callback](
344  rclcpp::Client<rcl_interfaces::srv::ListParameters>::SharedFuture cb_f)
345  {
346  promise_result->set_value(cb_f.get()->result);
347  if (callback != nullptr) {
348  callback(future_result);
349  }
350  }
351  );
352 
353  return future_result;
354 }
355 
356 bool
358 {
359  return
360  get_parameters_client_->service_is_ready() &&
361  get_parameter_types_client_->service_is_ready() &&
362  set_parameters_client_->service_is_ready() &&
363  list_parameters_client_->service_is_ready() &&
364  describe_parameters_client_->service_is_ready();
365 }
366 
367 bool
368 AsyncParametersClient::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
369 {
370  const std::vector<std::shared_ptr<rclcpp::ClientBase>> clients = {
371  get_parameters_client_,
372  get_parameter_types_client_,
373  set_parameters_client_,
374  list_parameters_client_,
375  describe_parameters_client_
376  };
377  for (auto & client : clients) {
378  auto stamp = std::chrono::steady_clock::now();
379  if (!client->wait_for_service(timeout)) {
380  return false;
381  }
382  if (timeout > std::chrono::nanoseconds::zero()) {
383  timeout -= std::chrono::duration_cast<std::chrono::nanoseconds>(
384  std::chrono::steady_clock::now() - stamp);
385  if (timeout < std::chrono::nanoseconds::zero()) {
386  timeout = std::chrono::nanoseconds::zero();
387  }
388  }
389  }
390  return true;
391 }
392 
393 std::vector<rclcpp::Parameter>
394 SyncParametersClient::get_parameters(
395  const std::vector<std::string> & parameter_names,
396  std::chrono::nanoseconds timeout)
397 {
398  auto f = async_parameters_client_->get_parameters(parameter_names);
399  using rclcpp::executors::spin_node_until_future_complete;
400  if (
401  spin_node_until_future_complete(
402  *executor_, node_base_interface_, f,
403  timeout) == rclcpp::FutureReturnCode::SUCCESS)
404  {
405  return f.get();
406  }
407  // Return an empty vector if unsuccessful
408  return std::vector<rclcpp::Parameter>();
409 }
410 
411 bool
412 SyncParametersClient::has_parameter(const std::string & parameter_name)
413 {
414  std::vector<std::string> names;
415  names.push_back(parameter_name);
416  auto vars = list_parameters(names, 1);
417  return vars.names.size() > 0;
418 }
419 
420 std::vector<rcl_interfaces::msg::ParameterDescriptor>
421 SyncParametersClient::describe_parameters(
422  const std::vector<std::string> & parameter_names,
423  std::chrono::nanoseconds timeout)
424 {
425  auto f = async_parameters_client_->describe_parameters(parameter_names);
426 
427  using rclcpp::executors::spin_node_until_future_complete;
428  rclcpp::FutureReturnCode future =
429  spin_node_until_future_complete(*executor_, node_base_interface_, f, timeout);
430  if (future == rclcpp::FutureReturnCode::SUCCESS) {
431  return f.get();
432  }
433  return std::vector<rcl_interfaces::msg::ParameterDescriptor>();
434 }
435 
436 std::vector<rclcpp::ParameterType>
437 SyncParametersClient::get_parameter_types(
438  const std::vector<std::string> & parameter_names,
439  std::chrono::nanoseconds timeout)
440 {
441  auto f = async_parameters_client_->get_parameter_types(parameter_names);
442 
443  using rclcpp::executors::spin_node_until_future_complete;
444  if (
445  spin_node_until_future_complete(
446  *executor_, node_base_interface_, f,
447  timeout) == rclcpp::FutureReturnCode::SUCCESS)
448  {
449  return f.get();
450  }
451  return std::vector<rclcpp::ParameterType>();
452 }
453 
454 std::vector<rcl_interfaces::msg::SetParametersResult>
455 SyncParametersClient::set_parameters(
456  const std::vector<rclcpp::Parameter> & parameters,
457  std::chrono::nanoseconds timeout)
458 {
459  auto f = async_parameters_client_->set_parameters(parameters);
460 
461  using rclcpp::executors::spin_node_until_future_complete;
462  if (
463  spin_node_until_future_complete(
464  *executor_, node_base_interface_, f,
465  timeout) == rclcpp::FutureReturnCode::SUCCESS)
466  {
467  return f.get();
468  }
469  return std::vector<rcl_interfaces::msg::SetParametersResult>();
470 }
471 
472 std::vector<rcl_interfaces::msg::SetParametersResult>
474  const std::vector<std::string> & parameters_names,
475  std::chrono::nanoseconds timeout)
476 {
477  auto f = async_parameters_client_->delete_parameters(parameters_names);
478 
479  using rclcpp::executors::spin_node_until_future_complete;
480  if (
481  spin_node_until_future_complete(
482  *executor_, node_base_interface_, f,
483  timeout) == rclcpp::FutureReturnCode::SUCCESS)
484  {
485  return f.get();
486  }
487  return std::vector<rcl_interfaces::msg::SetParametersResult>();
488 }
489 
490 std::vector<rcl_interfaces::msg::SetParametersResult>
492  const std::string & yaml_filename,
493  std::chrono::nanoseconds timeout)
494 {
495  auto f = async_parameters_client_->load_parameters(yaml_filename);
496 
497  using rclcpp::executors::spin_node_until_future_complete;
498  if (
499  spin_node_until_future_complete(
500  *executor_, node_base_interface_, f,
501  timeout) == rclcpp::FutureReturnCode::SUCCESS)
502  {
503  return f.get();
504  }
505  return std::vector<rcl_interfaces::msg::SetParametersResult>();
506 }
507 
508 rcl_interfaces::msg::SetParametersResult
509 SyncParametersClient::set_parameters_atomically(
510  const std::vector<rclcpp::Parameter> & parameters,
511  std::chrono::nanoseconds timeout)
512 {
513  auto f = async_parameters_client_->set_parameters_atomically(parameters);
514 
515  using rclcpp::executors::spin_node_until_future_complete;
516  if (
517  spin_node_until_future_complete(
518  *executor_, node_base_interface_, f,
519  timeout) == rclcpp::FutureReturnCode::SUCCESS)
520  {
521  return f.get();
522  }
523 
524  throw std::runtime_error("Unable to get result of set parameters service call.");
525 }
526 
527 rcl_interfaces::msg::ListParametersResult
528 SyncParametersClient::list_parameters(
529  const std::vector<std::string> & parameter_prefixes,
530  uint64_t depth,
531  std::chrono::nanoseconds timeout)
532 {
533  auto f = async_parameters_client_->list_parameters(parameter_prefixes, depth);
534 
535  using rclcpp::executors::spin_node_until_future_complete;
536  if (
537  spin_node_until_future_complete(
538  *executor_, node_base_interface_, f,
539  timeout) == rclcpp::FutureReturnCode::SUCCESS)
540  {
541  return f.get();
542  }
543 
544  throw std::runtime_error("Unable to get result of list parameters service call.");
545 }
RCLCPP_PUBLIC std::shared_future< std::vector< rcl_interfaces::msg::SetParametersResult > > load_parameters(const std::string &yaml_filename)
Load parameters from yaml file.
RCLCPP_PUBLIC bool service_is_ready() const
Return if the parameter services are ready.
RCLCPP_PUBLIC std::shared_future< std::vector< rcl_interfaces::msg::SetParametersResult > > delete_parameters(const std::vector< std::string > &parameters_names)
Delete several parameters at once.
RCLCPP_PUBLIC bool service_is_ready() const
Return if the service is ready.
Definition: client.cpp:109
FutureAndRequestId async_send_request(SharedRequest request)
Send a request to the service server.
Definition: client.hpp:608
Structure to store an arbitrary parameter with templated get/set methods.
Definition: parameter.hpp:53
static RCLCPP_PUBLIC Parameter from_parameter_msg(const rcl_interfaces::msg::Parameter &parameter)
Convert a parameter message in a Parameter class object.
Definition: parameter.cpp:145
std::vector< rcl_interfaces::msg::SetParametersResult > delete_parameters(const std::vector< std::string > &parameters_names, std::chrono::duration< RepT, RatioT > timeout=std::chrono::duration< RepT, RatioT >(-1))
Delete several parameters at once.
std::vector< rcl_interfaces::msg::SetParametersResult > load_parameters(const std::string &yaml_filename, std::chrono::duration< RepT, RatioT > timeout=std::chrono::duration< RepT, RatioT >(-1))
Load parameters from yaml file.
Thrown if passed parameters are inconsistent or invalid.
Definition: exceptions.hpp:227
RCL_PUBLIC RCL_WARN_UNUSED rcl_client_options_t rcl_client_get_default_options(void)
Return the default client options in a rcl_client_options_t.
Definition: client.c:199
RCLCPP_PUBLIC ParameterMap parameter_map_from_yaml_file(const std::string &yaml_filename)
FutureReturnCode
Return codes to be used with spin_until_future_complete.
std::unordered_map< std::string, std::vector< Parameter > > ParameterMap
A map of fully qualified node names to a list of parameters.
Options available for a rcl_client_t.
Definition: client.h:44
rmw_qos_profile_t qos
Middleware quality of service settings for the client.
Definition: client.h:46