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::dynamic_distance_to_obstacle_costmap_provider
17  * @author Fabian Reister ( fabian dot reister at kit dot edu )
18  * @date 2022
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 
24 #include "Component.h"
25 
26 #include <SimoxUtility/algorithm/apply.hpp>
27 #include <SimoxUtility/algorithm/vector.hpp>
28 #include <SimoxUtility/color/cmaps/colormaps.h>
29 
34 
35 #include <RobotAPI/interface/ArViz/Elements.h>
38 
44 
45 // Include headers you only need in function definitions in the .cpp.
46 
47 // #include <Eigen/Core>
48 
49 // #include <SimoxUtility/color/Color.h>
50 
51 
53 {
54 
55  const std::string Component::defaultName = "dynamic_distance_to_obstacle_costmap_provider";
56 
59  {
62 
63  // Publish to a topic (passing the TopicListenerPrx).
64  // def->topic(myTopicListener);
65 
66  // Subscribe to a topic (passing the topic name).
67  // def->topic<PlatformUnitListener>("MyTopic");
68 
69  // Use (and depend on) another component (passing the ComponentInterfacePrx).
70  // def->component(myComponentProxy)
71 
72 
73  // Add a required property. (The component won't start without a value being set.)
74  // def->required(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
75 
76  // Add an optionalproperty.
77  // def->optional(
78  // properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
79  def->optional(properties.updatePeriodMs, "p.updatePeriodMs", "");
80  def->optional(properties.staticCostmap.name, "p.staticCostmap.name", "");
81  def->required(properties.staticCostmap.providerName, "p.staticCostmap.providerName", "");
82 
83  def->optional(properties.laserScannerFeatures.name, "p.laserScannerFeatures.name", "");
84  def->optional(properties.laserScannerFeatures.providerName,
85  "p.laserScannerFeatures.providerName",
86  "");
87 
88  def->optional(properties.robot.name, "p.robot.name", "");
89 
90 
91  costmapReader.registerPropertyDefinitions(def);
92  costmapWriter.registerPropertyDefinitions(def);
93  laserScannerFeaturesReader.registerPropertyDefinitions(def);
94 
95  return def;
96  }
97 
99  robotReader(), costmapReader(), costmapWriter(), laserScannerFeaturesReader()
100  {
101  }
102 
103  void
105  {
106  // Topics and properties defined above are automagically registered.
107 
108  // Keep debug observer data until calling `sendDebugObserverBatch()`.
109  // (Requies the armarx::DebugObserverComponentPluginUser.)
110  // setDebugObserverBatchModeEnabled(true);
111  }
112 
113  void
115  {
116  // Do things after connecting to topics and components.
117 
118  /* (Requies the armarx::DebugObserverComponentPluginUser.)
119  // Use the debug observer to log data over time.
120  // The data can be viewed in the ObserverView and the LivePlotter.
121  // (Before starting any threads, we don't need to lock mutexes.)
122  {
123  setDebugObserverDatafield("numBoxes", properties.numBoxes);
124  setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
125  sendDebugObserverBatch();
126  }
127  */
128 
129  /* (Requires the armarx::ArVizComponentPluginUser.)
130  // Draw boxes in ArViz.
131  // (Before starting any threads, we don't need to lock mutexes.)
132  drawBoxes(properties, arviz);
133  */
134 
135  /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
136  // Setup the remote GUI.
137  {
138  createRemoteGuiTab();
139  RemoteGui_startRunningTask();
140  }
141  */
142 
143  // connect memory readers and writers
144  ARMARX_INFO << "Connecting to robot state memory";
145  robotReader.connect(memoryNameSystem());
146 
147  ARMARX_INFO << "Connecting to costmap segments";
148  costmapReader.connect(memoryNameSystem());
149  costmapWriter.connect(memoryNameSystem());
150 
151  ARMARX_INFO << "Connecting to laser scanner features segment";
152  laserScannerFeaturesReader.connect(memoryNameSystem());
153 
155 
156  updateCostmapTask =
157  new PeriodicTask<Component>(this, &Component::updateCostmap, properties.updatePeriodMs);
158 
159  updateCostmapTask->start();
160  }
161 
162  bool
164  {
165 
166  while (true)
167  {
169  .providerName = properties.staticCostmap.providerName,
170  .name = properties.staticCostmap.name,
171  .timestamp = armarx::core::time::Clock::Now()};
172 
173  const auto result = costmapReader.query(query);
174 
175  if (result.costmap.has_value())
176  {
177  staticCostmap.emplace(result.costmap.value());
178  return true;
179  }
180 
181  ARMARX_INFO << deactivateSpam(1) << "Static costmap not available yet";
182  }
183 
184  // return false;
185  }
186 
187  void
188  fillCostmap(const std::vector<memory::LaserScannerFeatures>& features,
189  algorithms::Costmap& costmap)
190  {
191 
192  std::vector<util::geometry::polygon_type> obstacles;
193 
194  for (const auto& f : features)
195  {
196  const auto& global_T_sens = f.frameGlobalPose;
197  for (const auto& ff : f.features)
198  {
199 
200  std::vector<Eigen::Vector2f> hull = ff.convexHull;
201  for (auto& h : hull)
202  {
203  h = conv::to2D(global_T_sens * conv::to3D(h));
204  }
205 
206  obstacles.push_back(util::geometry::toPolygon(hull));
207  }
208  }
209 
210  ARMARX_VERBOSE << "Found " << obstacles.size() << " obstacles/polygons.";
211 
212 
213  for (int r = 0; r < costmap.getGrid().rows(); r++)
214  {
215  for (int c = 0; c < costmap.getGrid().cols(); c++)
216  {
218  const auto pos = costmap.toPositionGlobal(idx);
219 
220  // if(costmap.getMask().has_value())
221  // {
222  // costmap.getMutableMask().value()(r,c) = true; // validate this cell
223  // }
224 
225  if (costmap.isInCollision(pos))
226  {
227  continue;
228  }
229 
230  constexpr float robotRadius = 500;
231 
232  const float dist = util::geometry::computeDistance(obstacles, pos) - robotRadius;
233 
234  if (dist <= 0) // in collision?
235  {
236  if (costmap.getMask().has_value())
237  {
238  costmap.getMutableMask().value()(r, c) = false; // invalidate this cell
239  }
240  }
241 
242  // update the costmap. combine static and dynamic distances
243  costmap.getMutableGrid()(r, c) =
244  std::min(costmap.getGrid()(r, c), std::max(dist, 0.F));
245  // costmap.getMutableGrid()(r, c) = std::max(dist, 0.F);
246  }
247  }
248  }
249 
250  void
252  const std::string& name,
253  const float heightOffset)
254  {
255  const auto cmap = simox::color::cmaps::viridis();
256  const float vmax = costmap.getGrid().maxCoeff();
257 
258  ARMARX_VERBOSE << "Grid `" << name << "` max value is " << vmax;
259 
260  const auto asColor = [&cmap, &vmax](const float distance) -> armarx::viz::data::Color
261  {
262  const auto color = cmap.at(distance, 0.F, vmax);
263  return {color.a, color.r, color.g, color.b};
264  };
265 
266  const armarx::viz::data::Color colorInvalid(0, 0, 0, 0);
267 
268  auto layer = arviz.layer("costmap_" + name);
269 
270  const std::int64_t cols = costmap.getGrid().cols();
271  const std::int64_t rows = costmap.getGrid().rows();
272 
273  auto mesh = armarx::viz::Mesh("");
274 
275  const Eigen::Vector3f heightOffsetV = Eigen::Vector3f::UnitZ() * heightOffset;
276 
277  std::vector<std::vector<Eigen::Vector3f>> vertices;
278  std::vector<std::vector<armarx::viz::data::Color>> colors;
279 
280  for (int r = 0; r < rows; r++)
281  {
282  auto& verticesRow = vertices.emplace_back(cols);
283  auto& colorsRow = colors.emplace_back(cols);
284  for (int c = 0; c < cols; c++)
285  {
286  verticesRow.at(c) =
288  heightOffsetV;
289 
290  colorsRow.at(c) = [&]()
291  {
292  if (costmap.isValid({r, c}))
293  {
294  return asColor(costmap.getGrid()(r, c));
295  }
296 
297  return colorInvalid;
298  }();
299  }
300  }
301 
302  mesh.grid2D(vertices, colors);
303 
304  layer.add(mesh);
305 
306  arviz.commit(layer);
307  }
308 
309  void
311  {
312 
313  ARMARX_CHECK(staticCostmap.has_value());
314 
315  const auto timestamp = armarx::core::time::Clock::Now();
316 
318  .providerName = properties.laserScannerFeatures.providerName,
319  .name = properties.laserScannerFeatures.name,
320  .timestamp = timestamp};
321 
322  const auto result = laserScannerFeaturesReader.queryData(query);
323 
324  if (result.status != result.Success)
325  {
326  ARMARX_WARNING << "Failed to retrieve data from memory";
327  return;
328  }
329 
330  for (const auto& e : result.features)
331  {
332  ARMARX_VERBOSE << "Number of laser scanner clusters for sensor " << e.frame << ": "
333  << e.features.size();
334  }
335 
336  // copy the static costmap. masked out regions don't need to be updated.
337  auto dynamicCostmap = staticCostmap.value();
338 
339  // create costmap and store it in memory
340  {
341  const auto start = armarx::core::time::Clock::Now();
342  fillCostmap(result.features, dynamicCostmap);
343  const auto end = armarx::core::time::Clock::Now();
344 
345  ARMARX_INFO << deactivateSpam(1) << "Creation of dynamic costmap (filling) took "
346  << (end - start).toMilliSecondsDouble() << " milliseconds";
347  }
348 
349 
350  costmapWriter.store(dynamicCostmap, "dynamic_distance_to_obstacles", getName(), timestamp);
351 
352  const auto timestamp1 = armarx::core::time::Clock::Now();
353  const auto navigationCostmap = computeNavigationCostmap(dynamicCostmap);
354  const auto timestamp2 = armarx::core::time::Clock::Now();
355 
356  ARMARX_INFO << deactivateSpam(1) << "Navigation costmap. Computation took "
357  << (timestamp2 - timestamp1).toMilliSecondsDouble() << "ms";
358 
359 
360  // drawing
361  drawCostmap(dynamicCostmap, "dynamic_costmap", 10);
362  drawCostmap(navigationCostmap, "navigation_costmap", 20);
363  }
364 
367  {
368 
369  const armem::robot::RobotDescription robotDescription{.name = properties.robot.name};
370 
371  const auto globalPose = robotReader.queryGlobalPose(robotDescription, armarx::Clock::Now());
372  ARMARX_CHECK(globalPose.has_value());
373 
374  const Eigen::Vector2f globalRobotPosition = globalPose->translation().head<2>();
375 
376  // navigation costs
378  spfaParams;
380  obstacleDistancesCostmap, spfaParams);
381 
383  spfa.spfa(globalRobotPosition);
384 
385  ARMARX_VERBOSE << "max distance " << result.distances.maxCoeff();
386 
387  // here, we again treat the result as a costmap
388  const armarx::navigation::algorithms::Costmap navigationPlanningCostmap(
389  result.distances,
390  obstacleDistancesCostmap.params(),
391  obstacleDistancesCostmap.getLocalSceneBounds(),
392  result.reachable);
393 
394  return navigationPlanningCostmap;
395  }
396 
397  void
399  {
400  }
401 
402  void
404  {
405  }
406 
407  std::string
409  {
410  return Component::defaultName;
411  }
412 
413  std::string
415  {
416  return Component::defaultName;
417  }
418 
420 
421 } // namespace armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider
armarx::navigation::algorithms::Costmap::getMask
const std::optional< Mask > & getMask() const noexcept
Definition: Costmap.cpp:392
armarx::viz::Client::commit
CommitResult commit(StagedCommit const &commit)
Definition: Client.cpp:80
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm::Parameters
Definition: ShortestPathFasterAlgorithm.h:36
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:180
armarx::navigation::algorithms::Costmap::Index
Eigen::Array2i Index
Definition: Costmap.h:44
armarx::armem::robot_state::RobotReader::queryGlobalPose
std::optional< robot::RobotState::Pose > queryGlobalPose(const robot::RobotDescription &description, const armem::Time &timestamp) const
Definition: RobotReader.cpp:365
armarx::navigation::algorithms::Costmap::getMutableMask
std::optional< Costmap::Mask > & getMutableMask() noexcept
Definition: Costmap.cpp:398
armarx::navigation::util::geometry::toPolygon
polygon_type toPolygon(const std::vector< Eigen::Vector2f > &hull)
Definition: geometry.cpp:30
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::updateCostmap
void updateCostmap()
Definition: Component.cpp:310
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::onDisconnectComponent
void onDisconnectComponent() override
Definition: Component.cpp:398
armarx::navigation::memory::client::costmap::Writer::store
bool store(const algorithms::Costmap &grid, const std::string &name, const std::string &providerName, const armem::Time &timestamp)
Definition: Writer.cpp:13
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::ARMARX_REGISTER_COMPONENT_EXECUTABLE
ARMARX_REGISTER_COMPONENT_EXECUTABLE(Component, Component::GetDefaultName())
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::GetDefaultName
static std::string GetDefaultName()
Get the component's default name.
Definition: Component.cpp:414
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm::spfa
Result spfa(const Eigen::Vector2f &start, bool checkStartForCollision=true) const
Definition: ShortestPathFasterAlgorithm.cpp:139
armarx::armem::client::plugins::PluginUser::memoryNameSystem
MemoryNameSystem & memoryNameSystem()
Definition: PluginUser.cpp:22
armarx::navigation::memory::client::laser_scanner_features::Reader::queryData
Result queryData(const Query &query) const
Definition: Reader.cpp:130
armarx::viz::Mesh
Definition: Mesh.h:28
armarx::armem::client::util::SimpleReaderBase::registerPropertyDefinitions
void registerPropertyDefinitions(armarx::PropertyDefinitionsPtr &def)
Definition: SimpleReaderBase.cpp:14
Reader.h
PeriodicTask.h
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::onConnectComponent
void onConnectComponent() override
Definition: Component.cpp:114
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
armarx::armem::robot_state::RobotReader::connect
virtual void connect(armem::client::MemoryNameSystem &memoryNameSystem)
Definition: RobotReader.cpp:49
armarx::navigation::memory::client::laser_scanner_features::Reader::Query::providerName
std::string providerName
Definition: Reader.h:58
armarx::navigation::util::geometry::computeDistance
float computeDistance(const std::vector< polygon_type > &obstacles, const Eigen::Vector2f &pt)
Definition: geometry.cpp:12
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::fillCostmap
void fillCostmap(const std::vector< memory::LaserScannerFeatures > &features, algorithms::Costmap &costmap)
Definition: Component.cpp:188
armarx::navigation::memory::client::costmap::Reader::query
Result query(const Query &query) const
Definition: Reader.cpp:77
armarx::navigation::algorithms::Costmap::toPositionGlobal
Position toPositionGlobal(const Index &index) const
Definition: Costmap.cpp:71
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm::Result::reachable
Mask reachable
Definition: ShortestPathFasterAlgorithm.h:59
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: Component.cpp:58
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::drawCostmap
void drawCostmap(const armarx::navigation::algorithms::Costmap &costmap, const std::string &name, float heightOffset)
Definition: Component.cpp:251
armarx::navigation::algorithms::Costmap::getLocalSceneBounds
const SceneBounds & getLocalSceneBounds() const noexcept
Definition: Costmap.cpp:126
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm::Result
Definition: ShortestPathFasterAlgorithm.h:51
geometry.h
armarx::armem::client::util::SimpleWriterBase::registerPropertyDefinitions
void registerPropertyDefinitions(armarx::PropertyDefinitionsPtr &def)
Definition: SimpleWriterBase.cpp:13
Clock.h
armarx::navigation::memory::client::costmap::Reader::Query::providerName
std::string providerName
Definition: Reader.h:42
ShortestPathFasterAlgorithm.h
Costmap.h
armarx::armem::robot::RobotDescription
Definition: types.h:17
Color
uint32_t Color
RGBA color.
Definition: color.h:8
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::onExitComponent
void onExitComponent() override
Definition: Component.cpp:403
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::readStaticCostmap
bool readStaticCostmap()
Definition: Component.cpp:163
armarx::navigation::algorithms::Costmap::params
const Parameters & params() const noexcept
Definition: Costmap.cpp:230
armarx::armem::client::util::SimpleReaderBase::connect
virtual void connect(armarx::armem::client::MemoryNameSystem &mns)
Definition: SimpleReaderBase.cpp:30
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider
Definition: Component.cpp:52
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component
Definition: Component.h:42
armarx::armem::client::util::SimpleWriterBase::connect
void connect(armarx::armem::client::MemoryNameSystem &mns)
Definition: SimpleWriterBase.cpp:33
armarx::navigation::algorithms::Costmap::getGrid
const Grid & getGrid() const
Definition: Costmap.cpp:236
armarx::navigation::memory::client::laser_scanner_features::Reader::Query
Definition: Reader.h:56
max
T max(T t1, T t2)
Definition: gdiam.h:48
RobotReader.h
armarx::navigation::memory::client::costmap::Reader::Query
Definition: Reader.h:40
armarx::navigation::conv::to2D
std::vector< Eigen::Vector2f > to2D(const std::vector< Eigen::Vector3f > &v)
Definition: eigen.cpp:26
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:74
Decoupled.h
armarx::armem::robot::RobotDescription::name
std::string name
Definition: types.h:21
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:70
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
armarx::ArVizComponentPluginUser::arviz
armarx::viz::Client arviz
Definition: ArVizComponentPlugin.h:43
IceUtil::Handle< class PropertyDefinitionContainer >
types.h
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm::Result::distances
Eigen::MatrixXf distances
Definition: ShortestPathFasterAlgorithm.h:53
F
Definition: ExportDialogControllerTest.cpp:16
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::Component
Component()
Definition: Component.cpp:98
Component.h
armarx::navigation::conv::to3D
std::vector< Eigen::Vector3f > to3D(const std::vector< Eigen::Vector2f > &v)
Definition: eigen.cpp:11
armarx::core::time::Clock::Now
static DateTime Now()
Current time on the virtual clock.
Definition: Clock.cpp:97
armarx::Logging::deactivateSpam
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition: Logging.cpp:92
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::onInitComponent
void onInitComponent() override
Definition: Component.cpp:104
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:88
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::getDefaultName
std::string getDefaultName() const override
Definition: Component.cpp:408
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:107
armarx::PeriodicTask
Definition: ArmarXManager.h:70
eigen.h
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:42
armarx::navigation::algorithms::spfa::ShortestPathFasterAlgorithm
Definition: ShortestPathFasterAlgorithm.h:33
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::viz::Client::layer
Layer layer(std::string const &name) const
Definition: Client.cpp:73
armarx::navigation::algorithms::Costmap::isValid
bool isValid(const Index &index) const noexcept
checks whether the cell is masked out
Definition: Costmap.cpp:78
armarx::navigation::components::dynamic_distance_to_obstacle_costmap_provider::Component::computeNavigationCostmap
algorithms::Costmap computeNavigationCostmap(const algorithms::Costmap &obstacleDistancesCostmap)
Definition: Component.cpp:366
armarx::navigation::algorithms::Costmap::isInCollision
bool isInCollision(const Position &p) const
Definition: Costmap.cpp:242
armarx::navigation::algorithms::Costmap::getMutableGrid
Grid & getMutableGrid()
Definition: Costmap.h:69
armarx::navigation::algorithms::Costmap
Definition: Costmap.h:13