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::costmap_example
17 * @author Fabian Reister ( fabian dot reister at kit dot edu )
18 * @date 2026
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 <cstdlib>
27#include <string>
28
29#include <Eigen/Core>
30
31#include <VirtualRobot/Random.h>
32
40
44
46{
47
48 const std::string Component::defaultName = "costmap_example";
49
51 {
52 addPlugin(costmapWriterPlugin);
53 }
54
57 {
60
61 // Publish to a topic (passing the TopicListenerPrx).
62 // def->topic(myTopicListener);
63
64 // Subscribe to a topic (passing the topic name).
65 // def->topic<PlatformUnitListener>("MyTopic");
66
67 // Use (and depend on) another component (passing the ComponentInterfacePrx).
68 // def->component(myComponentProxy)
69
70
71 // Add a required property. (The component won't start without a value being set.)
72 // def->required(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
73
74 // Add an optional property.
75 def->optional(properties.updateSize,
76 "p.updateSize",
77 "If enabled, the costmap size is updated randomly in each iteration.");
78 def->optional(properties.size,
79 "p.size",
80 "If updateSize is false, this is the size used for the costmap.");
81
82 return def;
83 }
84
85 void
87 {
88 // Topics and properties defined above are automagically registered.
89
90 // Keep debug observer data until calling `sendDebugObserverBatch()`.
91 // (Requires the armarx::DebugObserverComponentPluginUser.)
92 // setDebugObserverBatchModeEnabled(true);
93 }
94
95 void
97 {
98 // Do things after connecting to topics and components.
99
100 /* (Requires the armarx::DebugObserverComponentPluginUser.)
101 // Use the debug observer to log data over time.
102 // The data can be viewed in the ObserverView and the LivePlotter.
103 // (Before starting any threads, we don't need to lock mutexes.)
104 {
105 setDebugObserverDatafield("numBoxes", properties.numBoxes);
106 setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
107 sendDebugObserverBatch();
108 }
109 */
110
111 /* (Requires the armarx::ArVizComponentPluginUser.)
112 // Draw boxes in ArViz.
113 // (Before starting any threads, we don't need to lock mutexes.)
114 drawBoxes(properties, arviz);
115 */
116
117 // Setup the remote GUI.
118 {
121 }
122
123 costmapUpdateTask = new RunningTask<Component>(this, &Component::run, "CostmapUpdateTask");
124
125 costmapUpdateTask->start();
126 }
127
128 void
133
134 void
138
139 std::string
141 {
142 return Component::defaultName;
143 }
144
145 std::string
147 {
148 return Component::defaultName;
149 }
150
151 void
153 {
154 using namespace armarx::RemoteGui::Client;
155
156 // Setup the widgets.
157
158 tab.clearAll.setLabel("Clear all areas");
159
160 const auto setupSpinner = [](FloatSpinBox& spinner)
161 {
162 spinner.setValue(0);
163 spinner.setRange(0, 50000);
164 spinner.setDecimals(1);
165 };
166 setupSpinner(tab.minX);
167 setupSpinner(tab.minY);
168 setupSpinner(tab.maxX);
169 setupSpinner(tab.maxY);
170
171 tab.addArea.setLabel("Add blocked area");
172
173 // Setup the layout.
174
175 GridLayout grid;
176 int row = 0;
177 {
178 grid.add(Label("Min X"), {row, 0}).add(tab.minX, {row, 1});
179 ++row;
180
181 grid.add(Label("Min Y"), {row, 0}).add(tab.minY, {row, 1});
182 ++row;
183
184 grid.add(Label("Max X"), {row, 0}).add(tab.maxX, {row, 1});
185 ++row;
186
187 grid.add(Label("Max Y"), {row, 0}).add(tab.maxY, {row, 1});
188 ++row;
189
190 grid.add(tab.addArea, {row, 0});
191 ++row;
192 }
193
194 VBoxLayout root = {tab.clearAll, VSpacer(), grid};
195 RemoteGui_createTab(getName(), root, &tab);
196 }
197
198 void
200 {
201 if (tab.clearAll.wasClicked())
202 {
203 std::scoped_lock lock(areasMutex);
204 blockedAreas.clear();
205 ARMARX_INFO << "Cleared all blocked areas";
206 }
207
208 if (tab.addArea.wasClicked())
209 {
210 std::scoped_lock lock(areasMutex);
211 Eigen::AlignedBox2f area(Eigen::Vector2f(tab.minX.getValue(), tab.minY.getValue()),
212 Eigen::Vector2f(tab.maxX.getValue(), tab.maxY.getValue()));
213 ARMARX_INFO << "Add blocked area with min: " << area.min() << " and max " << area.max();
214 blockedAreas.emplace_back(area);
215 }
216 }
217
218 /* (Requires the armarx::ArVizComponentPluginUser.)
219 void
220 Component::drawBoxes(const Component::Properties& p, viz::Client& arviz)
221 {
222 // Draw something in ArViz (requires the armarx::ArVizComponentPluginUser.
223 // See the ArVizExample in RobotAPI for more examples.
224
225 viz::Layer layer = arviz.layer(p.boxLayerName);
226 for (int i = 0; i < p.numBoxes; ++i)
227 {
228 layer.add(viz::Box("box_" + std::to_string(i))
229 .position(Eigen::Vector3f(i * 100, 0, 0))
230 .size(20).color(simox::Color::blue()));
231 }
232 arviz.commit(layer);
233 }
234 */
235
236
238
239 void
241 {
243
244 while (not costmapUpdateTask->isStopped())
245 {
246
247 const int size = properties.updateSize
248 ? static_cast<int>(VirtualRobot::RandomFloat(500, 2000))
249 : properties.size;
250
251 const algorithms::Costmap::Parameters params{.cellSize = 100, .sceneBoundsMargin = 0};
252
253 const algorithms::SceneBounds sceneBounds{.min = Eigen::Vector2f::Zero(),
254 .max = Eigen::Vector2f(size, size)};
255
256 auto grid = algorithms::CostmapBuilder::createUniformGrid(sceneBounds, params);
257
258 // fill grid with some example data
259 {
260 // just a simple distance field example with varying center
261 const float centerX = VirtualRobot::RandomFloat(0, size - 1);
262 const float centerY = VirtualRobot::RandomFloat(0, size - 1);
263 const Eigen::Vector2f center(centerX, centerY);
264
265 for (int x = 0; x < grid.rows(); ++x)
266 {
267 for (int y = 0; y < grid.cols(); ++y)
268 {
269 const Eigen::Vector2f cellPos(x * params.cellSize, y * params.cellSize);
270
271 const float distance = (center - cellPos).norm();
272 grid(x, y) = distance;
273 }
274 }
275 }
276
277 const algorithms::Costmap::Mask mask = grid.array() > 0;
278
279 algorithms::Costmap costmap(grid, params, sceneBounds, mask);
280
281 // mask out any blocked areas
282 {
283 std::scoped_lock lock(areasMutex);
284 for (const auto& area : blockedAreas)
285 {
286 const auto minVertex = costmap.toVertex(area.min()).index;
287 const auto maxVertex = costmap.toVertex(area.max()).index;
288
289 for (int x = minVertex.x(); x <= maxVertex.x(); ++x)
290 {
291 for (int y = minVertex.y(); y <= maxVertex.y(); ++y)
292 {
293 costmap.getMutableGrid()(x, y) = 0;
294 }
295 }
296 }
297 }
298
299
300 ARMARX_INFO << "Storing costmap in memory";
301 ARMARX_CHECK(costmapWriterPlugin->get().store(
302 costmap, "example_costmap", getName(), Clock::Now()));
303
304
305 metronome.waitForNextTick();
306 }
307 }
308
309} // namespace armarx::navigation::components::costmap_example
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
Definition Bitmap.cpp:801
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
Default component property definition container.
Definition Component.h:70
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition Duration.cpp:48
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Definition Metronome.h:57
Duration waitForNextTick() const
Wait and block until the target period is met.
Definition Metronome.cpp:27
static Eigen::MatrixXf createUniformGrid(const SceneBounds &sceneBounds, const Costmap::Parameters &parameters)
Vertex toVertex(const Position &globalPosition) const
Definition Costmap.cpp:146
Eigen::Matrix< bool, Eigen::Dynamic, Eigen::Dynamic > Mask
Definition Costmap.h:60
void RemoteGui_update() override
After calling RemoteGui_startRunningTask, this function is called periodically in a separate thread.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition Component.cpp:56
RunningTask< Component >::pointer_type costmapUpdateTask
Definition Component.h:90
static std::string GetDefaultName()
Get the component's default name.
void createRemoteGuiTab()
This function should be called once in onConnect() or when you need to re-create the Remote GUI tab.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
double norm(const Point &a)
Definition point.hpp:102
double distance(const Point &a, const Point &b)
Definition point.hpp:95
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
Definition Widgets.cpp:438