ControllerBuilder.h
Go to the documentation of this file.
1 /**
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @author Fabian Reister ( fabian dot reister at kit dot edu )
17  * @date 2022
18  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19  * GNU General Public License
20  */
21 
22 #pragma once
23 
24 #include <filesystem>
25 #include <optional>
26 #include <fstream>
27 #include <type_traits>
28 #include <SimoxUtility/json/json.hpp>
29 
33 #include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h>
34 
38 #include <armarx/control/memory/config/Writer.h>
39 #include <armarx/control/memory/config/Reader.h>
41 #include <armarx/control/interface/ConfigurableNJointControllerInterface.h>
42 #include <armarx/control/core/Controller.h>
43 
45 
47 {
48 
49 
50  template <auto T>
51  class ControllerBuilder //: public AbstractControllerBuilder
52  {
53  public:
55 
56  // static constexpr auto ControllerType = ct;
57  using AronDTO = typename ControllerDescriptionType::AronDTO;
58  // using AronType = AronDTO;
59 
60  static_assert(
62  "asdf");
63 
65  const memory::config::Reader& configProvider,
66  const memory::config::Writer& configWriter,
67  const std::string& controllerNamePrefix) :
68  controllerCreator(controllerCreator),
69  configReader(configProvider),
70  configWriter(configWriter),
71  controllerNamePrefix(controllerNamePrefix)
72  {
73  ARMARX_CHECK_NOT_EMPTY(controllerNamePrefix)
74  << "By convention, the controller name prefix must exist. This ensures that "
75  "in between components, no naming clashes occur.";
76  }
77 
79  withDefaultConfig(const std::string& name = "default")
80  {
81  if (auto cfg = configReader.getDefaultConfig(ControllerDescriptionType::name, name))
82  {
83  dto = AronDTO::FromAron(cfg);
84  }
85  else
86  {
87  ARMARX_WARNING << "Failed to obtain default config";
88  }
89 
90  return *this;
91  }
92 
95  {
96  auto cfg = configReader.getConfig(memoryId);
97  dto = AronDTO::FromAron(cfg);
98 
99  return *this;
100  }
101 
103  withConfig(const std::filesystem::path& filename)
104  {
105  ARMARX_CHECK(std::filesystem::is_regular_file(filename)) << filename;
106 
107  ARMARX_INFO << "Loading config from file `" << filename << "`.";
108  std::ifstream ifs{filename};
109 
110  nlohmann::json jsonConfig;
111  ifs >> jsonConfig;
112 
113  ARMARX_INFO << "Initializing config";
114  if(not this->dto.has_value())
115  {
116  this->dto = AronDTO();
117  }
118 
120 
121  ARMARX_CHECK(this->dto.has_value());
122 
123  ARMARX_INFO << "reading file.";
124  this->dto->read(reader, jsonConfig);
125 
126  return *this;
127  }
128 
130  withConfig(const AronDTO& dto)
131  {
132  this->dto = dto;
133  return *this;
134  }
135 
136  AronDTO&
138  {
139  ensureInitialized();
140 
141  return dto.value();
142  }
143 
145  withNodeSet(const std::string& nodeSetName)
146  {
147  this->nodeSetName = nodeSetName;
148  return *this;
149  }
150 
152  withNamePrefix(const std::string& namePrefix)
153  {
154  if (namePrefix.empty())
155  return *this;
156  this->controllerNamePrefix = this->controllerNamePrefix + "_" + namePrefix;
157  return *this;
158  }
159 
160  /**
161  * @brief Creates the controller with the default name
162  *
163  * @return std::optional<ControllerWrapper<AronDTO, ct>>
164  */
165  std::optional<ControllerWrapper<T>>
167  {
168  const std::string controllerClassName = ControllerDescriptionType::name;
169  return create(controllerClassName);
170  }
171 
172 
173  std::optional<ControllerWrapper<T>>
174  create(const std::string& name)
175  {
176  if (not ensureInitialized())
177  {
178  return std::nullopt;
179  }
180 
181  ::armarx::control::ConfigurableNJointControllerConfigPtr config =
182  new ::armarx::control::ConfigurableNJointControllerConfig;
183  config->config = dto.value().toAronDTO();
184 
185  if (not nodeSetName.has_value())
186  {
187  ARMARX_WARNING << "You forgot to set the node set name!";
188  return std::nullopt;
189  }
190  config->nodeSetName = nodeSetName.value();
191 
192  controllerName = controllerNamePrefix + "_" + nodeSetName.value() + "_" + name;
193  const std::string controllerClassName = ControllerDescriptionType::name;
194 
195  // reuse or create controller
196 
197  armarx::NJointControllerInterfacePrx controller =
198  controllerCreator->getNJointController(controllerName);
199 
200 
201  const bool canReuseController = [&]() -> bool
202  {
203  if (not controller)
204  {
205  ARMARX_INFO << "Controller does not exist yet.";
206  return false;
207  }
208 
209  if(not allowReuse_)
210  {
211  ARMARX_INFO << "Not allowed to reuse controller.";
212  return false;
213  }
214 
215  // check if controller has correct type
216  if (controller->getClassName() != controllerClassName)
217  {
218  ARMARX_INFO << "Controller class does not match.";
219  return false;
220  }
221 
222  // TODO: check if kinematic chains match
223  // if (controller->getNodeSetName() != nodeSetName)
224  // {
225  // return false;
226  // }
227 
228  return true;
229  }();
230 
231  if((not allowReuse_) and controller)
232  {
233  ARMARX_TRACE;
234 
235  ARMARX_INFO << "Deleting existing controller `" << controllerName << "`";
236  try
237  {
238  ARMARX_TRACE;
239  controllerCreator->deactivateAndDeleteNJointController(controllerName);
240  }
241  catch(...)
242  {
244  }
245 
246  ARMARX_INFO << "Done deleting";
247 
249  }
250 
251  if((not allowReuse_) and controller)
252  {
253  ARMARX_TRACE;
254 
255  ARMARX_INFO << "Deleting existing controller `" << controllerName << "`";
256  try
257  {
258  ARMARX_TRACE;
259  controllerCreator->deactivateAndDeleteNJointController(controllerName);
260  }
261  catch(...)
262  {
264  }
265 
266  ARMARX_INFO << "Done deleting";
267 
269  }
270 
271  // create controller if necessary
272  if (not canReuseController)
273  {
274  ARMARX_TRACE;
275 
276  ARMARX_INFO << "Creating controller `" << controllerName << "`";
277 
278  controller = controllerCreator->createNJointController(
279  controllerClassName, controllerName, config);
281  }
282 
283  if (not controller)
284  {
285  ARMARX_WARNING << "Failed to create controller of type `" << controllerClassName
286  << "`";
287  return std::nullopt;
288  }
289 
290  auto ctrl =
291  armarx::control::ConfigurableNJointControllerInterfacePrx::checkedCast(controller);
292 
293  auto ctrlWrapper =
294  ControllerWrapper<T>(ctrl, controllerName, configWriter, dto.value());
295 
296  // Sends the data to the memory and updates the controller config.
297  // This is especially important, if the controller is reused.
298  ctrlWrapper.updateConfig();
299 
300  return std::move(ctrlWrapper);
301  }
302 
304  {
305  this->allowReuse_ = allowReuse;
306  return *this;
307  }
308 
309  std::string getControllerName()
310  {
311  return controllerName;
312  }
313 
314  private:
315  bool
316  initDefaultConfig()
317  {
318  if (auto cfg = configReader.getDefaultConfig(ControllerDescriptionType::name))
319  {
320  dto = AronDTO::FromAron(cfg);
321  return true;
322  }
323 
324  ARMARX_WARNING << "Failed to obtain default config";
325  return false;
326  }
327 
328  bool
329  ensureInitialized()
330  {
331  if (not dto.has_value())
332  {
333  return initDefaultConfig();
334  }
335 
336  return true;
337  }
338 
339 
340  armarx::RobotUnitInterfacePrx controllerCreator;
341 
342  const memory::config::Reader configReader;
343  const memory::config::Writer configWriter;
344 
345  std::optional<AronDTO> dto;
346 
347  std::optional<std::string> nodeSetName;
348 
349  std::string controllerNamePrefix;
350  std::string controllerName;
351 
352  bool allowReuse_ = false;
353  };
354 } // namespace armarx::control::client
armarx::control::client::ControllerBuilder::config
AronDTO & config()
Definition: ControllerBuilder.h:137
LocalException.h
armarx::core::time::Clock::WaitFor
static void WaitFor(const Duration &duration)
Wait for a certain duration on the virtual clock.
Definition: Clock.cpp:104
NlohmannJSONReaderWithoutTypeCheck.h
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
armarx::control::client::ControllerBuilder::ControllerBuilder
ControllerBuilder(const armarx::RobotUnitInterfacePrx &controllerCreator, const memory::config::Reader &configProvider, const memory::config::Writer &configWriter, const std::string &controllerNamePrefix)
Definition: ControllerBuilder.h:64
armarx::control::client::ControllerBuilder::withDefaultConfig
ControllerBuilder & withDefaultConfig(const std::string &name="default")
Definition: ControllerBuilder.h:79
armarx::control::client::ControllerBuilder::AronDTO
typename ControllerDescriptionType::AronDTO AronDTO
Definition: ControllerBuilder.h:57
armarx::control::client
This file is part of ArmarX.
Definition: ComponentPlugin.cpp:20
ARMARX_CHECK_NOT_EMPTY
#define ARMARX_CHECK_NOT_EMPTY(c)
Definition: ExpressionException.h:224
armarx::control::client::ControllerBuilder::withNodeSet
ControllerBuilder & withNodeSet(const std::string &nodeSetName)
Definition: ControllerBuilder.h:145
armarx::control::client::ControllerBuilder
Definition: ControllerBuilder.h:51
armarx::control::client::ControllerDescription
Definition: ControllerDescription.h:28
armarx::control::client::ControllerWrapper
Definition: ControllerWrapper.h:40
armarx::control::client::ControllerBuilder::allowReuse
ControllerBuilder & allowReuse(const bool allowReuse)
Definition: ControllerBuilder.h:303
type.h
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
Clock.h
armarx::GetHandledExceptionString
std::string GetHandledExceptionString()
Definition: Exception.cpp:147
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:69
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
controller
Definition: AddOperation.h:39
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::aron::data::reader::NlohmannJSONReaderWithoutTypeCheck
Definition: NlohmannJSONReaderWithoutTypeCheck.h:35
ControllerDescription.h
filename
std::string filename
Definition: VisualizationRobot.cpp:84
armarx::control::client::ControllerBuilder::withNamePrefix
ControllerBuilder & withNamePrefix(const std::string &namePrefix)
Definition: ControllerBuilder.h:152
armarx::control::client::ControllerBuilder::getControllerName
std::string getControllerName()
Definition: ControllerBuilder.h:309
armarx::control::client::ControllerBuilder::create
std::optional< ControllerWrapper< T > > create(const std::string &name)
Definition: ControllerBuilder.h:174
constants.h
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
armarx::control::client::ControllerBuilder::withConfig
ControllerBuilder & withConfig(const AronDTO &dto)
Definition: ControllerBuilder.h:130
IceInternal::ProxyHandle<::IceProxy::armarx::RobotUnitInterface >
armarx::control::client::ControllerBuilder::withConfig
ControllerBuilder & withConfig(const std::filesystem::path &filename)
Definition: ControllerBuilder.h:103
armarx::control::client::ControllerBuilder::withConfig
ControllerBuilder & withConfig(const armarx::armem::MemoryID &memoryId)
Definition: ControllerBuilder.h:94
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::control::client::ControllerBuilder::create
std::optional< ControllerWrapper< T > > create()
Creates the controller with the default name.
Definition: ControllerBuilder.h:166
AronGeneratedClass.h
armarx::core::time::Duration::MilliSeconds
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition: Duration.cpp:55
ControllerWrapper.h