|
| 1 | +// Copyright (c) 2021, Stogl Robotics Consulting UG (haftungsbeschränkt) |
| 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 | +/// \author: Denis Stogl |
| 16 | + |
| 17 | +#ifndef CONTROLLER_INTERFACE__CONTROLLER_PARAMETERS_HPP_ |
| 18 | +#define CONTROLLER_INTERFACE__CONTROLLER_PARAMETERS_HPP_ |
| 19 | + |
| 20 | +#include <limits> |
| 21 | +#include <string> |
| 22 | +#include <utility> |
| 23 | +#include <vector> |
| 24 | + |
| 25 | +#include "rclcpp/node.hpp" |
| 26 | +#include "rcutils/logging_macros.h" |
| 27 | + |
| 28 | +namespace controller_interface |
| 29 | +{ |
| 30 | +struct Parameter |
| 31 | +{ |
| 32 | + Parameter() = default; |
| 33 | + |
| 34 | + explicit Parameter(const std::string & name, bool configurable = false) |
| 35 | + : name(name), configurable(configurable) |
| 36 | + { |
| 37 | + } |
| 38 | + |
| 39 | + std::string name; |
| 40 | + bool configurable; |
| 41 | +}; |
| 42 | + |
| 43 | +class ControllerParameters |
| 44 | +{ |
| 45 | +public: |
| 46 | + ControllerParameters( |
| 47 | + int nr_bool_params = 0, int nr_double_params = 0, int nr_string_params = 0, |
| 48 | + int nr_string_list_params = 0); |
| 49 | + |
| 50 | + virtual ~ControllerParameters() = default; |
| 51 | + |
| 52 | + virtual void declare_parameters(rclcpp::Node::SharedPtr node); |
| 53 | + |
| 54 | + /** |
| 55 | + * Gets all defined parameters from. |
| 56 | + * |
| 57 | + * \param[node] shared pointer to the node where parameters should be read. |
| 58 | + * \return true if all parameters are read Successfully, false if a parameter is not provided or |
| 59 | + * parameter configuration is wrong. |
| 60 | + */ |
| 61 | + virtual bool get_parameters(rclcpp::Node::SharedPtr node, bool check_validity = true); |
| 62 | + |
| 63 | + virtual rcl_interfaces::msg::SetParametersResult set_parameter_callback( |
| 64 | + const std::vector<rclcpp::Parameter> & parameters); |
| 65 | + |
| 66 | + /** |
| 67 | + * Default implementation of parameter check. No check is done. Always returns true. |
| 68 | + * |
| 69 | + * \return true |
| 70 | + */ |
| 71 | + virtual bool check_if_parameters_are_valid() { return true; } |
| 72 | + |
| 73 | + virtual void update() = 0; |
| 74 | + |
| 75 | + // TODO(destogl): Test this: "const rclcpp::Node::SharedPtr & node" |
| 76 | + |
| 77 | +protected: |
| 78 | + void add_bool_parameter( |
| 79 | + const std::string & name, bool configurable = false, bool default_value = false) |
| 80 | + { |
| 81 | + bool_parameters_.push_back({Parameter(name, configurable), default_value}); |
| 82 | + } |
| 83 | + |
| 84 | + void add_double_parameter( |
| 85 | + const std::string & name, bool configurable = false, |
| 86 | + double default_value = std::numeric_limits<double>::quiet_NaN()) |
| 87 | + { |
| 88 | + double_parameters_.push_back({Parameter(name, configurable), default_value}); |
| 89 | + } |
| 90 | + |
| 91 | + void add_string_parameter( |
| 92 | + const std::string & name, bool configurable = false, const std::string & default_value = "") |
| 93 | + { |
| 94 | + string_parameters_.push_back({Parameter(name, configurable), default_value}); |
| 95 | + } |
| 96 | + |
| 97 | + void add_string_list_parameter( |
| 98 | + const std::string & name, bool configurable = false, |
| 99 | + const std::vector<std::string> & default_value = {}) |
| 100 | + { |
| 101 | + string_list_parameters_.push_back({Parameter(name, configurable), default_value}); |
| 102 | + } |
| 103 | + |
| 104 | + template <typename ParameterT> |
| 105 | + bool get_parameters_from_list( |
| 106 | + const rclcpp::Node::SharedPtr node, std::vector<std::pair<Parameter, ParameterT>> & parameters) |
| 107 | + { |
| 108 | + bool ret = true; |
| 109 | + for (auto & parameter : parameters) |
| 110 | + { |
| 111 | + try |
| 112 | + { |
| 113 | + rclcpp::Parameter input_parameter; // TODO(destogl): will this be allocated each time? |
| 114 | + ret = node->get_parameter(parameter.first.name, input_parameter); |
| 115 | + parameter.second = input_parameter.get_value<ParameterT>(); |
| 116 | + } |
| 117 | + catch (rclcpp::ParameterTypeException & e) |
| 118 | + { |
| 119 | + RCUTILS_LOG_ERROR_NAMED( |
| 120 | + logger_name_.c_str(), "'%s' parameter has wrong type", parameter.first.name.c_str()); |
| 121 | + ret = false; |
| 122 | + break; |
| 123 | + } |
| 124 | + } |
| 125 | + return ret; |
| 126 | + } |
| 127 | + |
| 128 | + template <typename ParameterT> |
| 129 | + bool empty_parameter_in_list(const std::vector<std::pair<Parameter, ParameterT>> & parameters) |
| 130 | + { |
| 131 | + bool ret = false; |
| 132 | + for (const auto & parameter : parameters) |
| 133 | + { |
| 134 | + if (parameter.second.empty()) |
| 135 | + { |
| 136 | + RCUTILS_LOG_ERROR_NAMED( |
| 137 | + logger_name_.c_str(), "'%s' parameter is empty", parameter.first.name.c_str()); |
| 138 | + ret = true; |
| 139 | + } |
| 140 | + } |
| 141 | + return ret; |
| 142 | + } |
| 143 | + |
| 144 | + bool empty_parameter_in_list(const std::vector<std::pair<Parameter, double>> & parameters) |
| 145 | + { |
| 146 | + bool ret = false; |
| 147 | + for (const auto & parameter : parameters) |
| 148 | + { |
| 149 | + if (std::isnan(parameter.second)) |
| 150 | + { |
| 151 | + RCUTILS_LOG_ERROR_NAMED( |
| 152 | + logger_name_.c_str(), "'%s' parameter is not set", parameter.first.name.c_str()); |
| 153 | + ret = true; |
| 154 | + } |
| 155 | + } |
| 156 | + return ret; |
| 157 | + } |
| 158 | + |
| 159 | + template <typename ParameterT> |
| 160 | + bool find_and_assign_parameter_value( |
| 161 | + std::vector<std::pair<Parameter, ParameterT>> & parameter_list, |
| 162 | + const rclcpp::Parameter & input_parameter) |
| 163 | + { |
| 164 | + auto is_in_list = [&](const auto & parameter) |
| 165 | + { return parameter.first.name == input_parameter.get_name(); }; |
| 166 | + |
| 167 | + auto it = std::find_if(parameter_list.begin(), parameter_list.end(), is_in_list); |
| 168 | + |
| 169 | + if (it != parameter_list.end()) |
| 170 | + { |
| 171 | + if (!it->first.configurable) |
| 172 | + { |
| 173 | + throw std::runtime_error( |
| 174 | + "Parameter " + input_parameter.get_name() + " is not configurable."); |
| 175 | + } |
| 176 | + else |
| 177 | + { |
| 178 | + it->second = input_parameter.get_value<ParameterT>(); |
| 179 | + RCUTILS_LOG_ERROR_NAMED( |
| 180 | + logger_name_.c_str(), "'%s' parameter is updated to value: %s", it->first.name.c_str(), |
| 181 | + input_parameter.value_to_string().c_str()); |
| 182 | + return true; |
| 183 | + } |
| 184 | + } |
| 185 | + else |
| 186 | + { |
| 187 | + return false; |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + std::vector<std::pair<Parameter, bool>> bool_parameters_; |
| 192 | + std::vector<std::pair<Parameter, double>> double_parameters_; |
| 193 | + std::vector<std::pair<Parameter, std::string>> string_parameters_; |
| 194 | + std::vector<std::pair<Parameter, std::vector<std::string>>> string_list_parameters_; |
| 195 | + |
| 196 | + std::string logger_name_; |
| 197 | + |
| 198 | +private: |
| 199 | + template <typename ParameterT> |
| 200 | + void declare_parameters_from_list( |
| 201 | + rclcpp::Node::SharedPtr node, const std::vector<std::pair<Parameter, ParameterT>> & parameters) |
| 202 | + { |
| 203 | + for (const auto & parameter : parameters) |
| 204 | + { |
| 205 | + node->declare_parameter<ParameterT>(parameter.first.name, parameter.second); |
| 206 | + } |
| 207 | + } |
| 208 | +}; |
| 209 | + |
| 210 | +} // namespace controller_interface |
| 211 | + |
| 212 | +#endif // CONTROLLER_INTERFACE__CONTROLLER_PARAMETERS_HPP_ |
0 commit comments