Component.cpp
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  * @package Navigation::ArmarXObjects::ControlMemory
17  * @author Fabian Reister ( fabian dot reister at kit dot edu )
18  * @date 2021
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #include "Component.h"
24 
25 // STD / STL
26 #include <filesystem>
27 #include <fstream>
28 #include <iostream>
29 
34 
41 
44 // #include <armarx/navigation/algorithms/Costmap.h>
45 // #include <armarx/navigation/memory/constants.h>
46 // #include <armarx/navigation/algorithms/aron/Costmap.aron.generated.h>
47 // #include <armarx/navigation/core/Graph.h>
48 // #include <armarx/navigation/core/aron/Graph.aron.generated.h>
49 // #include <armarx/navigation/core/aron/Location.aron.generated.h>
50 // #include <armarx/navigation/core/aron/Trajectory.aron.generated.h>
51 // #include <armarx/navigation/core/aron/Twist.aron.generated.h>
52 // #include <armarx/navigation/graph/constants.h>
53 // #include <armarx/navigation/location/constants.h>
54 
55 #include <armarx/control/common/control_law/aron/TaskspaceImpedanceControllerConfig.aron.generated.h>
56 // #include <armarx/control/njoint_qp_controller/aron_conversions.h>
57 
58 // #include <simox/control/method/examples/json_conversions.h>
59 
61 {
62 
63 
66  {
69 
70  // Publish to a topic (passing the TopicListenerPrx).
71  // def->topic(myTopicListener);
72 
73  // Subscribe to a topic (passing the topic name).
74  // def->topic<PlatformUnitListener>("MyTopic");
75 
76  // Use (and depend on) another component (passing the ComponentInterfacePrx).
77  // def->component(myComponentProxy)
78 
79 
81  def->optional(properties.snapshotToLoad,
82  "p.snapshotToLoad",
83  "Memory snapshot to load at start up \n"
84  "(e.g. 'PriorKnowledgeData/navigation-graphs/snapshot').");
85 
86  def->optional(properties.locationGraph.visuFrequency,
87  "p.locationGraph.visuFrequency",
88  "Visualization frequeny of locations and graph edges [Hz].");
89 
90  return def;
91  }
92 
93 
94  void
96  {
97  // Topics and properties defined above are automagically registered.
98 
99  // Keep debug observer data until calling `sendDebugObserverBatch()`.
100  // (Requies the armarx::DebugObserverComponentPluginUser.)
101  // setDebugObserverBatchModeEnabled(true);
102 
105 
108 
109 
110  /*
111  if (not properties.snapshotToLoad.empty())
112  {
113  std::filesystem::path snapshotToLoadPath(
114  ArmarXDataPath::resolvePath(properties.snapshotToLoad));
115  if (std::filesystem::is_directory(snapshotToLoadPath))
116  {
117  // This section loads the snapshot specified by the scenario parameters
118  // resolve the paths for the locations and graphs
119  const std::filesystem::path graph = snapshotToLoadPath / "Graph";
120  const std::filesystem::path location = snapshotToLoadPath / "Location";
121 
122  // remove date from folder name (if present)
123  // Sometimes, we use the date before the snapshotname and use a symlink to the real data (e.g. R003 and 2022-03-01_R003)
124  auto splitted = simox::alg::split(snapshotToLoadPath.filename().string(), "_");
125  ARMARX_CHECK_GREATER(splitted.size(), 0);
126  const std::string providerName = splitted[splitted.size() - 1];
127 
128  // This if statement loads the location. Each location is a single file (without extension). The filename is the name of the location.
129  // The file contains json with the globalRobotPose (4x4 matrix) and relativeToObject information
130  if (std::filesystem::is_directory(location))
131  {
132  armem::Commit c;
133  armem::MemoryID providerID = workingMemory().id();
134  providerID.coreSegmentName = "Location";
135  providerID.providerSegmentName = providerName;
136  for (const auto& subdir : std::filesystem::directory_iterator(
137  location)) // iterate over all files in folder (the locations)
138  {
139  const std::filesystem::path location = subdir.path();
140  if (std::filesystem::is_regular_file(
141  location)) // check if its a file (otherwise skip)
142  {
143  std::ifstream ifs(location);
144  const std::string content((std::istreambuf_iterator<char>(ifs)),
145  (std::istreambuf_iterator<char>()));
146 
147  // parse location as json. All files in Location folder must be valid json objects!
148  nlohmann::json j = nlohmann::json::parse(content);
149 
150  if (j.find("globalRobotPose") == j.end())
151  {
152  ARMARX_WARNING
153  << "The file '" << location.string()
154  << "' has no 'globalRobotPose' member. Skipping this file.";
155  continue;
156  }
157 
158  if (j.find("relativeToObject") == j.end())
159  {
160  ARMARX_WARNING
161  << "The file '" << location.string()
162  << "' has no 'relativeToObject' member. Skipping this file.";
163  continue;
164  }
165 
166  std::vector<float> p = j.at("globalRobotPose");
167  ARMARX_CHECK_EQUAL(p.size(), 16);
168 
169  navigation::location::arondto::Location loc;
170  loc.globalRobotPose << p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
171  p[8], p[9], p[10], p[11], p[12], p[13], p[14],
172  p[15]; // load the 4x4 matrix
173 
174  // TODO: All location I have seen were null.
175  // I don't know how this member should look like (von @Fabian Peller to @Fabian Reister)
176  loc.relativeToObject = std::nullopt;
177 
178  // send commit to memory
179  auto& up = c.add();
180  up.confidence = 1.0;
181  up.referencedTime = armem::Time::Now();
182  up.timeSent = armem::Time::Now();
183  up.timeArrived = armem::Time::Now();
184  up.entityID = providerID.withEntityName(location.filename().string());
185  up.instancesData = {loc.toAron()};
186  }
187  }
188 
189  // commit all locations at once
190  iceAdapter().commit(c);
191  }
192 
193  // Next we load the graphs. The graph folder may contain several graphs, represented by different folders.
194  // Each of those graphs contains a list of files representing the vertices. The filename is the vertice id (ideally starting at 0).
195  // The file contains a json with the corresponding location name (as path) and the adjacent vertives (representing the directed outgoing edges).
196  if (std::filesystem::is_directory(graph))
197  {
198  armem::Commit c;
199  armem::MemoryID providerID = workingMemory().id();
200  providerID.coreSegmentName = memory::constants::GraphCoreSegmentName;
201  providerID.providerSegmentName = providerName;
202 
203  for (const auto& graphdir : std::filesystem::directory_iterator(
204  graph)) // iterate over the different graphs (subfolders)
205  {
206  const std::filesystem::path singleGraph = graphdir.path();
207  if (std::filesystem::is_directory(
208  singleGraph)) // assure that its a folder. otherwise skip
209  {
210  navigation::core::arondto::Graph g;
211 
212  for (const auto& subdir : std::filesystem::directory_iterator(
213  singleGraph)) // iterate over all files in the graph
214  {
215  const std::filesystem::path vertice = subdir.path();
216  if (std::filesystem::is_regular_file(
217  vertice)) // assure its a file. otherwise skip
218  {
219  std::ifstream ifs(vertice);
220  const std::string content((std::istreambuf_iterator<char>(ifs)),
221  (std::istreambuf_iterator<char>()));
222 
223  // parse vertice. Each vertice must be a valid json object
224  nlohmann::json j = nlohmann::json::parse(content);
225  if (j.find("location") == j.end())
226  {
227  ARMARX_WARNING
228  << "The file '" << vertice.string()
229  << "' has no 'location' member. Skipping this file.";
230  continue;
231  }
232 
233  if (j.find("outgoingEdges") == j.end())
234  {
235  ARMARX_WARNING << "The file '" << vertice.string()
236  << "' has no 'outgoingEdges' member. "
237  "Skipping this file.";
238  continue;
239  }
240 
241  std::string location = j.at("location");
242  int id = std::stoi(vertice.filename());
243 
244  auto split = simox::alg::split(location, "/");
245  ARMARX_CHECK_EQUAL(
246  split.size(),
247  4); // the location is always a path like Navigation/Location/XXX/YYY
248 
249  armarx::control::core::arondto::Vertex v;
250  v.vertexID = id;
251  v.locationID.memoryName = split[0];
252  v.locationID.coreSegmentName = split[1];
253  v.locationID.providerSegmentName = split[2];
254  v.locationID.entityName = split[3];
255  toAron(v.locationID.timestamp, armem::Time::Invalid());
256  v.locationID.instanceIndex = 0;
257 
258  g.vertices.push_back(v);
259 
260  // add edges of this vertice to graph
261  std::vector<float> edges = j.at("outgoingEdges");
262 
263  for (const auto edge_id : edges)
264  {
265  armarx::control::core::arondto::Edge e;
266  e.sourceVertexID = id;
267  e.targetVertexID = edge_id;
268  g.edges.push_back(e);
269  }
270  }
271  }
272 
273  auto& up = c.add();
274  up.confidence = 1.0;
275  up.referencedTime = armem::Time::Now();
276  up.timeSent = armem::Time::Now();
277  up.timeArrived = armem::Time::Now();
278  up.entityID =
279  providerID.withEntityName(singleGraph.filename().string());
280  up.instancesData = {g.toAron()};
281  }
282  }
283 
284  // send graph to memory
285  iceAdapter().commit(c);
286  }
287 
288  // LEGACY CODE (Not working anymore since the wm json export changed due to ltm updates and aron updates)
289  // armem::wm::Memory memory = armem::server::ltm::disk::load(path.value());
290  //armem::server::ltm::disk::Memory ltm(path.value());
291  //armem::wm::Memory memory;
292  //ltm.loadAll(memory);
293  //workingMemory().update(armem::toCommit(memory));
294  ARMARX_INFO << "Loaded ControlMemory '" << properties.snapshotToLoad << "'";
295  }
296  else
297  {
298  ARMARX_WARNING << "Could not load ControlMemory '" << properties.snapshotToLoad
299  << "'. Continue with empty memory.";
300  }
301  }
302  */
303 
304  loadDefaultConfigs();
305  }
306 
307 
308  void
309  Component::loadDefaultConfigs()
310  {
311  // std::string filename;
312  // ArmarXDataPath::getAbsolutePath("armarx_control/controller_config/default/"
313  // "njoint_controller/impedance_controller_config.json",
314  // filename);
315 
316  // std::ifstream ifs{filename};
317 
318  // nlohmann::json defaultConfig;
319  // ifs >> defaultConfig;
320 
321  // {
322 
323  // common::control_law::arondto::TaskSpaceImpedanceControllerConfig cfg;
324  // // TODO load
325 
326  // armem::Commit c;
327  // armem::MemoryID providerID = workingMemory().id();
328  // providerID.coreSegmentName = memory::constants::DefaultParameterizationCoreSegmentName;
329  // providerID.providerSegmentName =
330  // common::ControllerTypeNames.to_name(common::ControllerType::TSImp);
331 
332 
333  // auto& up = c.add();
334  // up.confidence = 1.0;
335  // up.referencedTime = up.timeSent = up.timeArrived = armem::Time::Now();
336 
337  // up.entityID = providerID.withEntityName("default");
338  // up.instancesData = {cfg.toAron()};
339 
340  // iceAdapter().commit(c);
341  // }
342 
343  // {
344  // njoint_qp_controller::impedance::arondto::WholeBodyImpedanceControllerConfig cfg;
345 
346  // // "kpImpedance": [300, 300, 300, 3, 3, 3],
347  // // "kdImpedance": [ 50, 50, 50, 1, 1, 1],
348  // // "kpNullspace": [25.0, 15.0, 15.0, 5.0, 5.0, 5.0, 5.0, 5.0],
349  // // "kdNullspace": [4.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0],
350  // // "desiredNullspaceJointAngles": [],
351  // // "torqueLimit": 20,
352  // // "qvelFilter": 0.9
353 
354 
355  // cfg.leftArmImpedanceConfig.kpImpedance << 300, 300, 300, 3, 3, 3;
356  // cfg.leftArmImpedanceConfig.kdImpedance << 50, 50, 50, 1, 1, 1;
357  // cfg.leftArmImpedanceConfig.kpNullspace << 25.0, 15.0, 15.0, 5.0, 5.0, 5.0, 5.0, 5.0;
358  // cfg.leftArmImpedanceConfig.kdNullspace << 4.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0;
359  // // cfg.leftArmImpedanceConfig.desiredNullspaceJointAngles;
360  // cfg.leftArmImpedanceConfig.torqueLimit = 20;
361  // cfg.leftArmImpedanceConfig.qvelFilter = 0.9;
362 
363  // cfg.rightArmImpedanceConfig = cfg.leftArmImpedanceConfig;
364 
365 
366  // // TODO load
367 
368  // armem::Commit c;
369  // armem::MemoryID providerID = workingMemory().id();
370  // providerID.coreSegmentName = memory::constants::DefaultParameterizationCoreSegmentName;
371  // providerID.providerSegmentName =
372  // common::ControllerTypeNames.to_name(common::ControllerType::QPWholeBodyImpedance);
373 
374 
375  // auto& up = c.add();
376  // up.confidence = 1.0;
377  // up.referencedTime = up.timeSent = up.timeArrived = armem::Time::Now();
378 
379  // up.entityID = providerID.withEntityName("default");
380  // up.instancesData = {cfg.toAron()};
381 
382  // iceAdapter().commit(c);
383  // }
384 
385  // CMakePackageFinder pkg_finder("armarx_control");
386  // const std::filesystem::path pkgDataDir{pkg_finder.getDataDir()};
387 
388  // const std::filesystem::path configBasePath =
389  // pkgDataDir / "armarx_control/controller_config";
390 
391  // for (auto const& dir_entry : std::filesystem::directory_iterator{
392  // configBasePath /
393  // common::ControllerTypeNames.to_name(common::ControllerType::QPWholeBodyVelocity)})
394  // {
395  // if (not dir_entry.is_regular_file())
396  // {
397  // continue;
398  // }
399 
400  // const std::string filename = dir_entry.path();
401 
402  // ARMARX_INFO << "Loading config from file `" << filename << "`";
403  // std::ifstream ifs{filename};
404 
405  // nlohmann::json jsonConfig;
406  // ifs >> jsonConfig;
407 
408  // njoint_qp_controller::velocity::WholeBodyVelocityControllerConfig cfg;
409  // cfg.params.weights = jsonConfig.at("weights");
410  // cfg.params.kinematicConstraints = jsonConfig.at("kinematicConstraints");
411 
412  // njoint_qp_controller::velocity::arondto::WholeBodyVelocityControllerConfig aronCfg;
413  // toAron(aronCfg, cfg);
414 
415 
416  // armem::Commit c;
417  // armem::MemoryID providerID = workingMemory().id();
418  // providerID.coreSegmentName = memory::constants::DefaultParameterizationCoreSegmentName;
419  // providerID.providerSegmentName =
420  // common::ControllerTypeNames.to_name(common::ControllerType::QPWholeBodyVelocity);
421 
422 
423  // auto& up = c.add();
424  // up.confidence = 1.0;
425  // up.referencedTime = up.timeSent = up.timeArrived = armem::Time::Now();
426 
427  // up.entityID = providerID.withEntityName("default");
428  // up.instancesData = {aronCfg.toAron()};
429 
430  // iceAdapter().commit(c);
431  // }
432  }
433 
434 
435  void
437  {
438  // Do things after connecting to topics and components.
439 
440 
441  /* (Requies the armarx::DebugObserverComponentPluginUser.)
442  // Use the debug observer to log data over time.
443  // The data can be viewed in the ObserverView and the LivePlotter.
444  // (Before starting any threads, we don't need to lock mutexes.)
445  {
446  setDebugObserverDatafield("numBoxes", properties.numBoxes);
447  setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
448  sendDebugObserverBatch();
449  }
450  */
451 
452  // Setup the remote GUI.
453  {
456  }
457 
458  tasks.visuTask = new SimpleRunningTask<>([this]() { this->visuRun(); }, "Visualization");
459  tasks.visuTask->start();
460  }
461 
462 
463  void
465  {
466  }
467 
468 
469  void
471  {
472  }
473 
474 
475  std::string
477  {
478  return GetDefaultName();
479  }
480 
481  std::string
483  {
484  return "ControlMemory";
485  }
486 
487 
488  void
490  {
491  using namespace armarx::RemoteGui::Client;
492 
493  // Setup the widgets.
494  tab.locationGraph.setup(*this);
495 
496 
497  // Setup the layout.
498  VBoxLayout root = {tab.locationGraph.group, VSpacer()};
499  RemoteGui_createTab(getName(), root, &tab);
500  }
501 
502 
503  void
505  {
506  tab.locationGraph.update(*this);
507  }
508 
509 
510  void
512  {
513  using namespace armarx::RemoteGui::Client;
514  GridLayout grid;
515  int row = 0;
516  {
517  visuLocations.setValue(owner.properties.locationGraph.visuLocations);
518  visuGraphEdges.setValue(owner.properties.locationGraph.visuLocations);
519 
520  grid.add(Label("Visualize Locations"), {row, 0}).add(visuLocations, {row, 1});
521  ++row;
522 
523  grid.add(Label("Visualize Graph Edges"), {row, 0}).add(visuGraphEdges, {row, 1});
524  ++row;
525  }
526 
527  group = GroupBox({grid});
528  }
529 
530 
531  void
533  {
534  if (visuLocations.hasValueChanged() or visuGraphEdges.hasValueChanged())
535  {
536  std::scoped_lock lock(owner.propertiesMutex);
537  owner.properties.locationGraph.visuLocations = visuLocations.getValue();
538  owner.properties.locationGraph.visuGraphEdges = visuGraphEdges.getValue();
539  }
540  }
541 
542 
543  void
544  Component::visuRun()
545  {
546  // memory::Visu visu{arviz,
547  // workingMemory().getCoreSegment(navigation::location::coreSegmentID),
548  // workingMemory().getCoreSegment(navigation::graph::coreSegmentID)};
549 
550  // Properties::LocationGraph p;
551  // {
552  // std::scoped_lock lock(propertiesMutex);
553  // p = properties.locationGraph;
554  // }
555 
556  // CycleUtil cycle(static_cast<int>(1000 / p.visuFrequency));
557  // while (tasks.visuTask and not tasks.visuTask->isStopped())
558  // {
559  // {
560  // std::scoped_lock lock(propertiesMutex);
561  // p = properties.locationGraph;
562  // }
563 
564  // std::vector<viz::Layer> layers;
565 
566  // // Locations
567  // visu.drawLocations(layers, p.visuLocations);
568 
569  // // Graph Edges
570  // visu.drawGraphs(layers, p.visuGraphEdges);
571 
572  // arviz.commit(layers);
573 
574  // cycle.waitForCycleDuration();
575  // }
576  }
577 
579 
580 
581 } // namespace armarx::control::components::control_memory
armarx::SimpleRunningTask
Usage:
Definition: TaskUtil.h:70
armarx::control::memory::constants::DefaultParameterizationCoreSegmentName
const std::string DefaultParameterizationCoreSegmentName
Definition: constants.h:29
query.h
armarx::RemoteGui::Client::VBoxLayout
Definition: Widgets.h:167
armarx::control::components::control_memory::Component::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: Component.cpp:65
armarx::RemoteGui::Client::GridLayout::add
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
Definition: Widgets.cpp:412
armarx::control::components::control_memory::Component::onExitComponent
void onExitComponent() override
Definition: Component.cpp:470
armarx::control::components::control_memory::Component::onInitComponent
void onInitComponent() override
Definition: Component.cpp:95
armarx::armem::base::MemoryBase::name
std::string & name()
Definition: MemoryBase.h:92
armarx::control::memory::constants::ParameterizationCoreSegmentName
const std::string ParameterizationCoreSegmentName
Definition: constants.h:30
armarx::control::components::control_memory
Definition: Component.cpp:60
armarx::control::components::control_memory::Component::RemoteGui_update
void RemoteGui_update() override
Definition: Component.cpp:504
armarx::armem::server::plugins::ReadWritePluginUser::workingMemory
server::wm::Memory & workingMemory()
Definition: ReadWritePluginUser.cpp:106
armarx::RemoteGui::Client::VSpacer
Definition: Widgets.h:204
type.h
armarx::control::components::control_memory::ARMARX_REGISTER_COMPONENT_EXECUTABLE
ARMARX_REGISTER_COMPONENT_EXECUTABLE(Component, Component::GetDefaultName())
json_conversions.h
armarx::control::components::control_memory::Component::onDisconnectComponent
void onDisconnectComponent() override
Definition: Component.cpp:464
memory_definitions.h
visionx::voxelgrid::Label
uint32_t Label
Type of an object label.
Definition: types.h:7
armarx::control::memory::constants::MemoryName
const std::string MemoryName
Definition: constants.h:27
armarx::RemoteGui::Client::GridLayout
Definition: Widgets.h:186
armarx::control::components::control_memory::Component::RemoteGuiTab::LocationGraph::update
void update(Component &owner)
Definition: Component.cpp:532
Component.h
armarx::RemoteGui::Client::GroupBox
Definition: Widgets.h:193
armarx::control::components::control_memory::Component::onConnectComponent
void onConnectComponent() override
Definition: Component.cpp:436
armarx::control::components::control_memory::Component
Definition: Component.h:52
armarx::armem::base::MemoryBase::addCoreSegment
CoreSegmentT & addCoreSegment(const std::string &name, aron::type::ObjectPtr coreSegmentType=nullptr, const std::vector< PredictionEngine > &predictionEngines={})
Add an empty core segment with the given name, type and prediction engines.
Definition: MemoryBase.h:259
operations.h
armarx::control::components::control_memory::Component::getDefaultName
std::string getDefaultName() const override
Definition: Component.cpp:476
aron_conversions.h
armarx::LightweightRemoteGuiComponentPluginUser::RemoteGui_startRunningTask
void RemoteGui_startRunningTask()
Definition: LightweightRemoteGuiComponentPlugin.cpp:110
CycleUtil.h
Memory.h
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:74
Decoupled.h
constants.h
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:70
armarx::control::components::control_memory::Component::RemoteGuiTab::LocationGraph::setup
void setup(Component &owner)
Definition: Component.cpp:511
armarx::LightweightRemoteGuiComponentPluginUser::RemoteGui_createTab
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
Definition: LightweightRemoteGuiComponentPlugin.cpp:95
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::control::components::control_memory::Component::GetDefaultName
static std::string GetDefaultName()
Definition: Component.cpp:482
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:107
armarx::RemoteGui::Client
Definition: EigenWidgets.cpp:8
ArmarXDataPath.h
armarx::control::components::control_memory::Component::createRemoteGuiTab
void createRemoteGuiTab()
Definition: Component.cpp:489
PackagePath.h