mrs_lib
Various reusable classes, functions and utilities for use in MRS projects
Loading...
Searching...
No Matches
param_loader.hpp
1// clang: MatousFormat
2#pragma once
3
4#include <mrs_lib/param_loader.h>
5
6namespace mrs_lib
7{
8
9 /* printValue function and overloads //{ */
10
11 template <typename T>
12 void ParamLoader::printValue(const resolved_name_t& name, const T& value) const
13 {
14 if (m_node_name.empty())
15 std::cout << "\t" << name << ":\t" << value << std::endl;
16 else
17 RCLCPP_INFO_STREAM(m_node->get_logger(), "[" << m_node_name << "]: parameter '" << name << "':\t" << value);
18 }
19
20 template <typename T>
21 std::ostream& operator<<(std::ostream& os, const Eigen::MatrixX<T>& var)
22 {
23 /* const Eigen::IOFormat fmt(4, 0, ", ", "\n", "\t\t[", "]"); */
24 /* strstr << value.format(fmt); */
25 const Eigen::IOFormat fmt;
26 return os << var.format(fmt);
27 }
28 //}
29
30 /* loading helper functions //{ */
31
32 /* helper functions for loading dynamic Eigen matrices //{ */
33 // loadMatrixX helper function for loading dynamic Eigen matrices //{
34 template <typename T>
35 std::pair<ParamLoader::MatrixX<T>, bool> ParamLoader::loadMatrixX(const std::string& name, const MatrixX<T>& default_value, int rows, int cols,
36 optional_t optional, unique_t unique, swap_t swap, bool printValues)
37 {
38 const auto resolved_name = m_pp.resolveName(name);
39 MatrixX<T> loaded = default_value;
40 bool used_rosparam_value = false;
41 // first, check if the user already tried to load this parameter
42 if (unique && check_duplicit_loading(resolved_name))
43 return {loaded, used_rosparam_value};
44
45 // this function only accepts dynamic columns (you can always transpose the matrix afterward)
46 if (rows < 0)
47 {
48 // if the parameter was compulsory, alert the user and set the flag
49 printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved_name.str);
50 m_load_successful = false;
51 return {loaded, used_rosparam_value};
52 }
53 const bool expect_zero_matrix = rows == 0;
54 if (expect_zero_matrix)
55 {
56 if (cols > 0)
57 {
58 printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved_name.str
59 + ". One dimension indicates zero matrix, but other expects non-zero.");
60 m_load_successful = false;
61 return {loaded, used_rosparam_value};
62 }
63 }
64
65 bool cur_load_successful = true;
66 bool check_size_exact = true;
67 if (cols <= 0) // this means that the cols dimension is dynamic or a zero matrix is expected
68 check_size_exact = false;
69
70 std::vector<T> tmp_vec;
71 // try to load the parameter
72 const bool success = m_pp.getParam(resolved_name, tmp_vec);
73 // check if the loaded vector has correct length
74 bool correct_size = (int)tmp_vec.size() == rows * cols;
75 if (!check_size_exact && !expect_zero_matrix)
76 correct_size = (int)tmp_vec.size() % rows == 0; // if the cols dimension is dynamic, the size just has to be divisable by rows
77
78 if (success && correct_size)
79 {
80 // if successfully loaded, everything is in order
81 // transform the vector to the matrix
82 if (cols <= 0 && rows > 0)
83 cols = tmp_vec.size() / rows;
84 if (swap)
85 std::swap(rows, cols);
86 loaded = Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>, Eigen::Unaligned>(tmp_vec.data(), rows, cols);
87 used_rosparam_value = true;
88 } else
89 {
90 if (success && !correct_size)
91 {
92 // warn the user that this parameter was not successfully loaded because of wrong vector length (might be an oversight)
93 std::string warning =
94 std::string("Matrix parameter ") + resolved_name.str
95 + std::string(" could not be loaded because the vector has a wrong length " + std::to_string(tmp_vec.size()) + " instead of expected ");
96 // process the message correctly based on whether the loaded matrix should be dynamic or static
97 if (cols <= 0) // for dynamic matrices
98 warning = warning + std::string("number divisible by ") + std::to_string(rows);
99 else // for static matrices
100 warning = warning + std::to_string(rows * cols);
101 printWarning(warning);
102 }
103 // if it was not loaded, the default value is used (set at the beginning of the function)
104 if (!optional)
105 {
106 // if the parameter was compulsory, alert the user and set the flag
107 printError(std::string("Could not load non-optional parameter ") + resolved_name.str);
108 cur_load_successful = false;
109 }
110 }
111
112 // check if load was a success
113 if (cur_load_successful)
114 {
115 if (m_print_values && printValues)
116 printValue(resolved_name, loaded);
117 m_loaded_params.insert(resolved_name);
118 } else
119 {
120 m_load_successful = false;
121 }
122 // finally, return the resulting value
123 return {loaded, used_rosparam_value};
124 }
125 //}
126
127 /* loadMatrixStatic_internal helper function for loading static Eigen matrices //{ */
128 template <int rows, int cols, typename T>
129 std::pair<Eigen::Matrix<T, rows, cols>, bool>
130 ParamLoader::loadMatrixStatic_internal(const std::string& name, const Eigen::Matrix<T, rows, cols>& default_value, optional_t optional, unique_t unique)
131 {
132 const auto [dynamic, loaded_ok] = loadMatrixX(name, MatrixX<T>(default_value), rows, cols, optional, unique, NO_SWAP);
133 return {dynamic, loaded_ok};
134 }
135 //}
136
137 /* loadMatrixKnown_internal helper function for loading EigenXd matrices with known dimensions //{ */
138 template <typename T>
139 std::pair<ParamLoader::MatrixX<T>, bool> ParamLoader::loadMatrixKnown_internal(const std::string& name, const MatrixX<T>& default_value, int rows, int cols,
140 optional_t optional, unique_t unique)
141 {
142 MatrixX<T> loaded = default_value;
143 // first, check that at least one dimension is set
144 if (rows <= 0 || cols <= 0)
145 {
146 printError(std::string("Invalid expected matrix dimensions for parameter ") + m_pp.resolveName(name).str + std::string(" (use loadMatrixDynamic?)"));
147 m_load_successful = false;
148 return {loaded, false};
149 }
150
151 return loadMatrixX(name, default_value, rows, cols, optional, unique, NO_SWAP);
152 }
153 //}
154
155 /* loadMatrixDynamic_internal helper function for loading Eigen matrices with one dynamic (unspecified) dimension //{ */
156 template <typename T>
157 std::pair<ParamLoader::MatrixX<T>, bool> ParamLoader::loadMatrixDynamic_internal(const std::string& name, const MatrixX<T>& default_value, int rows, int cols,
158 optional_t optional, unique_t unique)
159 {
160 MatrixX<T> loaded = default_value;
161
162 // next, check that at least one dimension is set
163 if (rows <= 0 && cols <= 0)
164 {
165 printError(std::string("Invalid expected matrix dimensions for parameter ") + m_pp.resolveName(name).str
166 + std::string(" (at least one dimension must be specified)"));
167 m_load_successful = false;
168 return {loaded, false};
169 }
170
171 swap_t swap = NO_SWAP;
172 if (rows <= 0)
173 {
174 std::swap(rows, cols);
175 swap = SWAP;
176 }
177 return loadMatrixX(name, default_value, rows, cols, optional, unique, swap);
178 }
179 //}
180
181 /* loadMatrixArray_internal helper function for loading an array of EigenXd matrices with known dimensions //{ */
182 template <typename T>
183 std::vector<ParamLoader::MatrixX<T>> ParamLoader::loadMatrixArray_internal(const std::string& name, const std::vector<MatrixX<T>>& default_value,
184 optional_t optional, unique_t unique)
185 {
186 const auto resolved_name = m_pp.resolveName(name);
187 int rows;
188 std::vector<long int> cols;
189 bool success = true;
190 success = success && m_pp.getParam(resolved_name_t(resolved_name.str + "/rows"), rows);
191 success = success && m_pp.getParam(resolved_name_t(resolved_name.str + "/cols"), cols);
192
193 std::vector<MatrixX<T>> loaded;
194 loaded.reserve(cols.size());
195
196 int total_cols = 0;
197 /* check correctness of loaded parameters so far calculate the total dimension //{ */
198
199 if (!success)
200 {
201 printError(std::string("Failed to load ") + resolved_name.str + std::string("/rows or ") + resolved_name.str + std::string("/cols"));
202 m_load_successful = false;
203 return default_value;
204 }
205 if (rows < 0)
206 {
207 printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved_name.str + std::string(" (rows and cols must be >= 0)"));
208 m_load_successful = false;
209 return default_value;
210 }
211 for (const auto& col : cols)
212 {
213 if (col < 0)
214 {
215 printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved_name.str + std::string(" (rows and cols must be >= 0)"));
216 m_load_successful = false;
217 return default_value;
218 }
219 total_cols += col;
220 }
221
222 //}
223
224 const auto [loaded_matrix, loaded_ok] = loadMatrixX(name + "/data", MatrixX<T>(), rows, total_cols, optional, unique, NO_SWAP, false);
225 /* std::cout << "loaded_matrix: " << loaded_matrix << std::endl; */
226 /* std::cout << "loaded_matrix: " << loaded_matrix.rows() << "x" << loaded_matrix.cols() << std::endl; */
227 /* std::cout << "expected dims: " << rows << "x" << total_cols << std::endl; */
228 if (loaded_matrix.rows() != rows || loaded_matrix.cols() != total_cols)
229 {
230 m_load_successful = false;
231 return default_value;
232 }
233
234 int cols_loaded = 0;
235 for (unsigned it = 0; it < cols.size(); it++)
236 {
237 const int cur_cols = cols.at(it);
238 const MatrixX<T> cur_mat = loaded_matrix.block(0, cols_loaded, rows, cur_cols);
239 /* std::cout << "cur_mat: " << cur_mat << std::endl; */
240 loaded.push_back(cur_mat);
241 cols_loaded += cur_cols;
242 printValue(resolved_name_t(resolved_name.str + "/matrix#" + std::to_string(it)), cur_mat);
243 }
244 return loaded;
245 }
246 //}
247
248 //}
249
250 /* load helper function for generic types //{ */
251 // This function tries to load a parameter with name 'name' and a default value.
252 // You can use the flag 'optional' to not throw a ROS_ERROR when the parameter
253 // cannot be loaded and the flag 'printValues' to set whether the loaded
254 // value and name of the parameter should be printed to cout.
255 // If 'optional' is set to false and the parameter could not be loaded,
256 // the flag 'load_successful' is set to false and a ROS_ERROR message
257 // is printer.
258 // If 'unique' flag is set to false then the parameter is not checked
259 // for being loaded twice.
260 // Returns a tuple, containing either the loaded or the default value and a bool,
261 // indicating if the value was loaded (true) or the default value was used (false).
262 template <typename T>
263 std::pair<T, bool> ParamLoader::load(const std::string& name, const T& default_value, optional_t optional, unique_t unique)
264 {
265 const auto resolved_name = m_pp.resolveName(name);
266 T loaded = default_value;
267 if (unique && check_duplicit_loading(resolved_name))
268 return {loaded, false};
269
270 bool cur_load_successful = true;
271 // try to load the parameter
272 const bool success = m_pp.getParam(resolved_name, loaded);
273 if (!success)
274 {
275 // if it was not loaded, set the default value
276 loaded = default_value;
277 if (!optional)
278 {
279 // if the parameter was compulsory, alert the user and set the flag
280 printError(std::string("Could not load non-optional parameter ") + resolved_name.str);
281 cur_load_successful = false;
282 }
283 }
284
285 if (cur_load_successful)
286 {
287 // everything is fine and just print the resolved_name and value if required
288 if (m_print_values)
289 printValue(resolved_name, loaded);
290 // mark the param resolved_name as successfully loaded
291 m_loaded_params.insert(resolved_name);
292 } else
293 {
294 m_load_successful = false;
295 }
296 // finally, return the resulting value
297 return {loaded, success};
298 }
299 //}
300 //}
301
302 /* loadParam function for optional parameters //{ */
303 template <typename T>
304 bool ParamLoader::loadParam(const std::string& name, T& out_value, const T& default_value)
305 {
306 const auto [ret, success] = load<T>(name, default_value, OPTIONAL, UNIQUE);
307 out_value = ret;
308 return success;
309 }
321 template <typename T>
322 T ParamLoader::loadParam2(const std::string& name, const T& default_value)
323 {
324 const auto loaded = load<T>(name, default_value, OPTIONAL, UNIQUE);
325 return loaded.first;
326 }
339 template <typename T>
340 bool ParamLoader::loadParamReusable(const std::string& name, T& out_value, const T& default_value)
341 {
342 const auto [ret, success] = load<T>(name, default_value, OPTIONAL, REUSABLE);
343 out_value = ret;
344 return success;
345 }
357 template <typename T>
358 T ParamLoader::loadParamReusable2(const std::string& name, const T& default_value)
359 {
360 const auto [ret, success] = load<T>(name, default_value, OPTIONAL, REUSABLE);
361 return ret;
362 }
363 //}
364
365 /* loadParam function for compulsory parameters //{ */
377 template <typename T>
378 bool ParamLoader::loadParam(const std::string& name, T& out_value)
379 {
380 const auto [ret, success] = load<T>(name, T(), COMPULSORY, UNIQUE);
381 out_value = ret;
382 return success;
383 }
394 template <typename T>
395 T ParamLoader::loadParam2(const std::string& name)
396 {
397 const auto [ret, success] = load<T>(name, T(), COMPULSORY, UNIQUE);
398 return ret;
399 }
411 template <typename T>
412 bool ParamLoader::loadParamReusable(const std::string& name, T& out_value)
413 {
414 const auto [ret, success] = load<T>(name, T(), COMPULSORY, REUSABLE);
415 out_value = ret;
416 return success;
417 }
428 template <typename T>
429 T ParamLoader::loadParamReusable2(const std::string& name)
430 {
431 const auto [ret, success] = load<T>(name, T(), COMPULSORY, REUSABLE);
432 return ret;
433 }
434 //}
435
436 /* loadParam specializations and convenience functions for Eigen dynamic matrix type //{ */
437
452 template <typename T>
453 bool ParamLoader::loadParam(const std::string& name, MatrixX<T>& mat, const MatrixX<T>& default_value)
454 {
455 const int rows = default_value.rows();
456 const int cols = default_value.cols();
457 const bool loaded_ok = loadMatrixDynamic(name, mat, default_value, rows, cols);
458 return loaded_ok;
459 }
460
474 template <typename T>
475 ParamLoader::MatrixX<T> ParamLoader::loadParam2(const std::string& name, const MatrixX<T>& default_value)
476 {
477 MatrixX<T> ret;
478 loadParam(name, ret, default_value);
479 return ret;
480 }
481
482 //}
483
484 // loadMatrixStatic function for loading of static Eigen::Matrices //{
485
503 template <int rows, int cols, typename T>
504 bool ParamLoader::loadMatrixStatic(const std::string& name, Eigen::Matrix<T, rows, cols>& mat)
505 {
506 const auto [ret, loaded_ok] = loadMatrixStatic_internal<rows, cols, T>(name, Eigen::Matrix<T, rows, cols>::Zero(), COMPULSORY, UNIQUE);
507 mat = ret;
508 return loaded_ok;
509 }
510
528 template <int rows, int cols, typename T, typename Derived>
529 bool ParamLoader::loadMatrixStatic(const std::string& name, Eigen::Matrix<T, rows, cols>& mat, const Eigen::MatrixBase<Derived>& default_value)
530 {
531 const auto [ret, loaded_ok] = loadMatrixStatic_internal<rows, cols, T>(name, Eigen::Matrix<T, rows, cols>(default_value), OPTIONAL, UNIQUE);
532 mat = ret;
533 return loaded_ok;
534 }
535
552 template <int rows, int cols, typename T>
553 Eigen::Matrix<T, rows, cols> ParamLoader::loadMatrixStatic2(const std::string& name)
554 {
555 Eigen::Matrix<T, rows, cols> ret;
556 loadMatrixStatic(name, ret);
557 return ret;
558 }
559
576 template <int rows, int cols, typename T, typename Derived>
577 Eigen::Matrix<T, rows, cols> ParamLoader::loadMatrixStatic2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value)
578 {
579 Eigen::Matrix<T, rows, cols> ret;
580 loadMatrixStatic(name, ret, default_value);
581 return ret;
582 }
583 //}
584
585 // loadMatrixKnown function for loading of Eigen matrices with known dimensions //{
586
602 template <typename T>
603 bool ParamLoader::loadMatrixKnown(const std::string& name, MatrixX<T>& mat, int rows, int cols)
604 {
605 const auto [ret, loaded_ok] = loadMatrixKnown_internal(name, MatrixX<T>(), rows, cols, COMPULSORY, UNIQUE);
606 mat = ret;
607 return loaded_ok;
608 }
609
625 template <typename T, typename Derived>
626 bool ParamLoader::loadMatrixKnown(const std::string& name, MatrixX<T>& mat, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
627 {
628 const auto [ret, loaded_ok] = loadMatrixKnown_internal(name, MatrixX<T>(default_value), rows, cols, OPTIONAL, UNIQUE);
629 mat = ret;
630 return loaded_ok;
631 }
632
647 template <typename T>
648 ParamLoader::MatrixX<T> ParamLoader::loadMatrixKnown2(const std::string& name, int rows, int cols)
649 {
650 MatrixX<T> ret;
651 loadMatrixKnown(name, ret, rows, cols);
652 return ret;
653 }
654
669 template <typename T, typename Derived>
670 ParamLoader::MatrixX<T> ParamLoader::loadMatrixKnown2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
671 {
672 MatrixX<T> ret;
673 loadMatrixKnown(name, ret, default_value, rows, cols);
674 return ret;
675 }
676 //}
677
678 // loadMatrixDynamic function for half-dynamic loading of MatrixX<T> //{
679
695 template <typename T>
696 bool ParamLoader::loadMatrixDynamic(const std::string& name, MatrixX<T>& mat, int rows, int cols)
697 {
698 const auto [ret, loaded_ok] = loadMatrixDynamic_internal(name, MatrixX<T>(), rows, cols, COMPULSORY, UNIQUE);
699 mat = ret;
700 return loaded_ok;
701 }
702
719 template <typename T, typename Derived>
720 bool ParamLoader::loadMatrixDynamic(const std::string& name, MatrixX<T>& mat, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
721 {
722 const auto [ret, loaded_ok] = loadMatrixDynamic_internal(name, MatrixX<T>(default_value), rows, cols, OPTIONAL, UNIQUE);
723 mat = ret;
724 return loaded_ok;
725 }
726
741 template <typename T>
742 ParamLoader::MatrixX<T> ParamLoader::loadMatrixDynamic2(const std::string& name, int rows, int cols)
743 {
744 MatrixX<T> ret;
745 loadMatrixDynamic(name, ret, rows, cols);
746 return ret;
747 }
748
763 template <typename T, typename Derived>
764 ParamLoader::MatrixX<T> ParamLoader::loadMatrixDynamic2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
765 {
766 MatrixX<T> ret;
767 loadMatrixDynamic(name, ret, default_value, rows, cols);
768 return ret;
769 }
770
771 //}
772
773 // loadMatrixArray function for loading of an array of MatrixX<T> with known dimensions //{
806 template <typename T>
807 void ParamLoader::loadMatrixArray(const std::string& name, std::vector<MatrixX<T>>& mat)
808 {
809 mat = loadMatrixArray2<double>(name);
810 }
811
823 template <typename T>
824 void ParamLoader::loadMatrixArray(const std::string& name, std::vector<MatrixX<T>>& mat, const std::vector<MatrixX<T>>& default_value)
825 {
826 mat = loadMatrixArray2(name, default_value);
827 }
828
839 template <typename T>
840 std::vector<ParamLoader::MatrixX<T>> ParamLoader::loadMatrixArray2(const std::string& name)
841 {
842 return loadMatrixArray_internal(name, std::vector<MatrixX<T>>(), COMPULSORY, UNIQUE);
843 }
844
856 template <typename T>
857 std::vector<ParamLoader::MatrixX<T>> ParamLoader::loadMatrixArray2(const std::string& name, const std::vector<MatrixX<T>>& default_value)
858 {
859 return loadMatrixArray_internal(name, default_value, OPTIONAL, UNIQUE);
860 }
861 //}
862
863} // namespace mrs_lib
bool loadMatrixKnown(const std::string &name, MatrixX< T > &mat, int rows, int cols)
Specialized method for loading compulsory Eigen matrix parameters.
Definition param_loader.hpp:603
std::vector< MatrixX< T > > loadMatrixArray2(const std::string &name)
Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matric...
Definition param_loader.hpp:840
void loadMatrixArray(const std::string &name, std::vector< MatrixX< T > > &mat)
Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matric...
Definition param_loader.hpp:807
T loadParam2(const std::string &name, const T &default_value)
Loads a parameter from the rosparam server with a default value.
Definition param_loader.hpp:322
Eigen::Matrix< T, rows, cols > loadMatrixStatic2(const std::string &name)
Specialized method for loading compulsory Eigen matrix parameters.
Definition param_loader.hpp:553
bool loadParam(const std::string &name, T &out_value, const T &default_value)
Loads a parameter from the rosparam server with a default value.
Definition param_loader.hpp:304
bool loadMatrixStatic(const std::string &name, Eigen::Matrix< T, rows, cols > &mat)
Specialized method for loading compulsory Eigen matrix parameters.
Definition param_loader.hpp:504
MatrixX< T > loadMatrixKnown2(const std::string &name, int rows, int cols)
Specialized method for loading compulsory Eigen matrix parameters.
Definition param_loader.hpp:648
bool loadMatrixDynamic(const std::string &name, MatrixX< T > &mat, int rows, int cols)
Specialized method for loading compulsory dynamic Eigen matrix parameters.
Definition param_loader.hpp:696
bool loadParamReusable(const std::string &name, T &out_value, const T &default_value)
Loads a parameter from the rosparam server with a default value.
Definition param_loader.hpp:340
MatrixX< T > loadMatrixDynamic2(const std::string &name, int rows, int cols)
Specialized method for loading compulsory dynamic Eigen matrix parameters.
Definition param_loader.hpp:742
T loadParamReusable2(const std::string &name, const T &default_value)
Loads an optional reusable parameter from the rosparam server.
Definition param_loader.hpp:358
resolved_name_t resolveName(const std::string &param_name) const
Returns the parameter name with prefixes and subnode namespaces.
Definition param_provider.cpp:160
bool getParam(const std::string &param_name, T &value_out) const
Gets the value of a parameter.
Definition param_provider.hpp:83
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24
std::ostream & operator<<(std::ostream &os, const Eigen::MatrixX< T > &var)
Helper overload for printing of Eigen matrices.
Definition param_loader.hpp:21