Ariles
demo_api_v2_ros2.cpp
Go to the documentation of this file.
1 /**
2  @file
3  @author Alexander Sherikov
4 
5  @copyright 2024 Alexander Sherikov, Licensed under the Apache License, Version 2.0.
6  (see @ref LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
7 
8  @brief
9 */
10 // cppcheck-suppress-file duplInheritedMember
11 
12 
13 // ============================================================================
14 // HEADER INCLUSION
15 // ============================================================================
16 
17 // `visitor` is an Ariles component which provides integration with a particular
18 // 3rd party library.
21 
22 // `adapter` is an Ariles component which adds support for serialization of
23 // certain type(s), e.g. Eigen types or Boost pointers.
24 #include <ariles2/adapters/basic.h>
25 #include <ariles2/adapters/eigen.h>
28 #include <ariles2/ariles.h>
29 
30 
31 
32 // ===============================================================
33 // DEFINING TYPES
34 // ===============================================================
35 namespace
36 {
38  // must inherit from ariles2::DefaultBase
39  : public ariles2::DefaultBase
40  {
41 // Declare entries, in this case two numbers
42 #define ARILES2_ENTRIES(v) \
43  ARILES2_TYPED_ENTRY(v, real_member, double) \
44  ARILES2_TYPED_ENTRY_(v, integer_member, int)
45 // underscore ^ indicates that the name of the entry must be
46 // 'integer_member_' instead of 'integer_member', this is useful if your
47 // naming convention requires trailing underscores for member variables.
48 
49 // Initialize ariles
50 #include ARILES2_INITIALIZE
51 
52  public:
53  virtual ~ArilesBaseClass() = default; // added to suppress compiler warnings
54 
55  // This method is called every time you deserialize a class. If
56  // omitted, the default automatically generated method is used.
57  void arilesVisit(const ariles2::Defaults & /*visitor*/, const ariles2::Defaults::Parameters & /*param*/)
58  {
59  real_member = 0.0;
60  integer_member_ = 12;
61  }
62  };
63 
64 
66  {
67  public:
68  // Eigen types are supported too, see below
69  Eigen::Vector3d eigen_vector_;
70  };
71 
72 
73  class MyClass : public ArilesBaseClass, // no need to inherit from ariles2::DefaultBase directly.
74  public NonArilesBaseClass
75  {
76 // Declare entries, in this case we indicate inheritance from another
77 // Ariles class (ArilesBaseClass) and a member from a non-Ariles class
78 // (NonArilesBaseClass)
79 #define ARILES2_ENTRIES(v) \
80  ARILES2_PARENT(v, ArilesBaseClass) \
81  ARILES2_ENTRY_(v, eigen_vector)
82  // Here ^ Ariles should not declare the inherited member, therefore we
83  // use 'ARILES2_ENTRY_' instead of 'ARILES2_TYPED_ENTRY_'.
84 
85 #include ARILES2_INITIALIZE
86 
87 
88  public:
89  ~MyClass() override = default; // added to suppress compiler warnings
90 
91 
92  void arilesVisit(const ariles2::Defaults &visitor, const ariles2::Defaults::Parameters &param)
93  {
94  // If you use your own method to initialize member variables,
95  // it is up to you to properly initialize all entries and
96  // parent classes.
97  // all parents at once
98  arilesVisitParents(visitor, param);
99  // or one by one (either option is sufficient)
100  ArilesBaseClass::arilesVisit(visitor, param);
101 
102  // custom default values for some members
103  real_member = 100.0;
104  eigen_vector_.setZero();
105  }
106  };
107 
108 
110  {
111  // Some of the standard containers can be used with Ariles types.
112 #define ARILES2_ENTRIES(v) \
113  ARILES2_TYPED_ENTRY_(v, my_class_vector, std::vector<MyClass>) \
114  ARILES2_TYPED_ENTRY_(v, ptr, std::shared_ptr<MyClass>)
115 #include ARILES2_INITIALIZE
116 
117  public:
118  virtual ~MyContainerClass() = default;
119  };
120 } // namespace
121 
122 
123 // ===============================================================
124 // SERIALIZATION & DESERIALIZATION
125 // ===============================================================
126 
127 #include <iostream> // std::cout
128 
129 
130 // run with "demo_api_v2_ros2 --ros-args --params-file /demo_api_v2_ros2.yaml"
131 int main(int argc, char *argv[])
132 {
133  try
134  {
135  rclcpp::init(argc, argv);
136  const rclcpp::Node::SharedPtr nh = rclcpp::Node::make_shared(
137  "demo_api_v2_ros2",
138  // although ariles provides Declarator visitor, declaring
139  // parameters in general case is not possible since generic
140  // arrays are stored as maps with indices used as keys: size of
141  // such array is not know in advance so it is not possible to
142  // declare all the necessary indices
143  rclcpp::NodeOptions().allow_undeclared_parameters(true).automatically_declare_parameters_from_overrides(
144  true));
145 
146  // read parameters loaded from file (demo_api_v2_ros2.yaml)
147  {
148  MyContainerClass my_container_class;
149 
150  // access members as usual
151  my_container_class.my_class_vector_.emplace_back();
152  ariles2::apply<ariles2::Defaults>(my_container_class.my_class_vector_[0]);
153 
154  /*
155  * output
156  my_class_vector:
157  - real_member: 100
158  integer_member: 12
159  eigen_vector: [0, 0, 0]
160  ptr:
161  is_null: true
162  */
163  ariles2::apply<ariles2::yaml_cpp::Writer>(std::cout, my_container_class);
164 
165  // see demo_api_v2_ros2.yaml
166  ariles2::apply<ariles2::ros2param::Reader>(nh->get_node_parameters_interface(), my_container_class);
167 
168  /*
169  * output
170  my_class_vector:
171  - real_member: 100
172  integer_member: 12
173  eigen_vector: [0, 0, 0]
174  - real_member: 110
175  integer_member: 1
176  eigen_vector: [0, 1, 0]
177  - real_member: 111
178  integer_member: 21
179  eigen_vector: [1, 1, 0]
180  ptr:
181  is_null: true
182  */
183  ariles2::apply<ariles2::yaml_cpp::Writer>(std::cout, my_container_class);
184  }
185 
186  // writing & reading
187  {
188  MyContainerClass my_container_class;
189  my_container_class.ptr_ = std::make_shared<MyClass>();
190  ariles2::apply<ariles2::Defaults>(*my_container_class.ptr_);
191 
192  my_container_class.my_class_vector_.emplace_back();
193  ariles2::apply<ariles2::Defaults>(my_container_class.my_class_vector_[0]);
194  my_container_class.my_class_vector_[0].real_member = 200;
195 
196  ariles2::apply<ariles2::ros2param::Writer>(nh->get_node_parameters_interface(), my_container_class);
197  ariles2::apply<ariles2::ros2param::Reader>(nh->get_node_parameters_interface(), my_container_class);
198 
199  /*
200  * output:
201  * - note that parameters loaded from file are preserved
202  * - it would be nice to drop old parameters, but it is impossible to undeclare them
203  my_class_vector:
204  - real_member: 200 # overridden
205  integer_member: 12
206  eigen_vector: [0, 0, 0]
207  - real_member: 110
208  integer_member: 1
209  eigen_vector: [0, 1, 0]
210  - real_member: 111
211  integer_member: 21
212  eigen_vector: [1, 1, 0]
213  ptr:
214  is_null: false # overridden
215  value: # added
216  real_member: 100
217  integer_member: 12
218  eigen_vector: [0, 0, 0]
219  */
220  ariles2::apply<ariles2::yaml_cpp::Writer>(std::cout, my_container_class);
221  }
222 
223  // declaring
224  // - hardly useful, is going to declare my_class_vector_ to have only one member
225  // - declarator does not read parameters into an Ariles class, a
226  // separate pass with Reader visitor is needed
227  {
228  MyContainerClass my_container_class;
229  my_container_class.my_class_vector_.emplace_back();
230  ariles2::apply<ariles2::Defaults>(my_container_class.my_class_vector_[0]);
231  ariles2::apply<ariles2::ros2param::Declarator>(nh->get_node_parameters_interface(), my_container_class);
232  }
233 
234  // missing parameters
235  // - an attempt to read missing parameters results in an exception
236  {
237  MyClass my_class;
238  try
239  {
240  ariles2::apply<ariles2::ros2param::Reader>(nh->get_node_parameters_interface(), my_class);
241  }
242  catch (const std::exception &e)
243  {
244  // "... Configuration file does not contain entry 'real_member'."
245  std::cout << e.what() << std::endl;
246  }
247  }
248  }
249  catch (const std::exception &e)
250  {
251  std::cout << e.what() << std::endl;
252  return (EXIT_FAILURE);
253  }
254 
255  return (EXIT_SUCCESS);
256 }
void arilesVisit(const ariles2::Defaults &, const ariles2::Defaults::Parameters &)
void arilesVisit(const ariles2::Defaults &visitor, const ariles2::Defaults::Parameters &param)
int main(int argc, char *argv[])