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::navigation_skill_provider
17 * @author Fabian Reister ( fabian dot reister at kit dot edu )
18 * @date 2023
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 <experimental/memory>
27#include <mutex>
28#include <string>
29
34
36
38
54
56{
58 {
59 addPlugin(virtualRobotReaderPlugin);
60 addPlugin(costmapReaderPlugin);
61 addPlugin(graphReaderPlugin);
62 addPlugin(roomsReaderPlugin);
63 addPlugin(objectClassReaderPlugin);
64 }
65
66 const std::string Component::defaultName = skills::constants::NavigationSkillProviderName;
67
68 namespace
69 {
70 void
71 defineProximityFieldParams(const armarx::PropertyDefinitionsPtr& def,
72 const std::string& prefix,
74 {
75 def->optional(params.mode, prefix + ".mode", "The mode of the proximity field.")
77 .map("DirectionDependent",
79 .map("DirectionIndependent",
81 def->optional(params.reduceVelocity,
82 prefix + ".reduceVelocity",
83 "Whether to first reduce the velocity when coming closer to an obstacle "
84 "before stopping.");
85 def->optional(params.safetyDistance,
86 prefix + ".minDistance",
87 "The minimum distance, below which the robot will stop.");
88 def->optional(
89 params.influenceDistance,
90 prefix + ".maxDistance",
91 "The maximum distance, above which the robot will move with the maximum velocity.");
92 def->optional(
93 params.k,
94 prefix + ".k",
95 "A parameter to adjust how the velocity is reduced when coming closer to "
96 "an obstacle. A higher value means the robot will reduce it's speed later.")
97 .setMin(1);
98 def->optional(
99 params.lambda,
100 prefix + ".lambda",
101 "A parameter to adjust how the velocity is reduced when coming closer to an "
102 "obstacle. A higher value means the robot will reduce it's speed earlier.")
103 .setMin(1);
104 }
105 } // namespace
106
109 {
112
113 def->component(navigatorPrx, "navigator");
114
115 def->required(properties.robotName, "RobotName", "Default robot name.");
116
117 auto optionalSubSkillID =
118 [&def](armarx::skills::SkillID& skillID, const std::string& nameBase)
119 {
120 ARMARX_CHECK(skillID.providerId.has_value());
121 def->optional(skillID.providerId->providerName, nameBase + ".providerName");
122 def->optional(skillID.skillName, nameBase + ".skillName");
123 };
124
125 def->required(properties.safetyGuardParams.robotRadius,
126 "p.navigateToLocation.safetyGuardParams.robotRadius",
127 "The robot radius used for distance calculation to the platform.");
128 def->optional(properties.safetyGuardParams.enableHumans,
129 "p.navigateToLocation.safetyGuardParams.enableHumans",
130 "Whether to consider humans for the safety guard.");
131 def->optional(properties.safetyGuardParams.enableLaserScanners,
132 "p.navigateToLocation.safetyGuardParams.enableLaserscanners",
133 "Whether to consider laser scanners for the safety guard.");
134 defineProximityFieldParams(def,
135 "p.navigateToLocation.safetyGuardParams.humanProximityField",
136 properties.safetyGuardParams.humanProximityField);
137 defineProximityFieldParams(
138 def,
139 "p.navigateToLocation.safetyGuardParams.laserScannerProximityField",
140 properties.safetyGuardParams.laserScannerProximityField);
141 def->optional(properties.safetyGuardParams.ignoreAttachedObjects,
142 "p.navigateToLocation.safetyGuardParams.ignoreAttachedObjects",
143 "Whether to ignore laser scanner features lying inside attached objects.");
144 def->optional(properties.safetyGuardParams.enableLaserScannerFiltering,
145 "p.navigateToLocation.safetyGuardParams.enableLaserScannerFiltering",
146 "Whether to filter out small laser scanner features close to the robot.");
147 def->optional(properties.safetyGuardParams.laserScannerFilteringThreshold,
148 "p.navigateToLocation.safetyGuardParams.laserScannerFilteringThreshold",
149 "Features with less or equal number of points are filtered out.");
150 def->optional(properties.safetyGuardParams.laserScannerMaxFilteringDistance,
151 "p.navigateToLocation.safetyGuardParams.laserScannerMaxFilteringDistance",
152 "Only features where all points are within this distance of the robot are "
153 "filtered out [mm].");
154
155
156 def->required(properties.generalConfig.maxVel.linear,
157 "p.default.generalConfig.maxVelocity.linear",
158 "The default maximum linear velocity.");
159 def->required(properties.generalConfig.maxVel.angular,
160 "p.default.generalConfig.maxVelocity.angular",
161 "The default maximum angular velocity.");
162
163 def->optional(
164 properties.generalConfig.enableRampingStart,
165 "p.default.generalConfig.enableRampingStart",
166 "The default value for whether ramping is enabled at the start of the trajectory.");
167 def->optional(
168 properties.generalConfig.enableRampingEnd,
169 "p.default.generalConfig.enableRampingEnd",
170 "The default value for whether ramping is enabled at the end of the trajectory.");
171 def->optional(
172 properties.generalConfig.enableRampingCorners,
173 "p.default.generalConfig.enableRampingCorners",
174 "The default value for whether ramping is enabled in corners of the trajectory.");
175 def->optional(properties.generalConfig.rampLength,
176 "p.default.generalConfig.rampLength",
177 "The default value for the distance over which ramping is applied [mm].");
178 def->optional(properties.generalConfig.cornerVelocity,
179 "p.default.generalConfig.cornerVelocity",
180 "The default value for the velocity in a corner [mm/s].");
181 def->optional(properties.generalConfig.boundaryVelocity,
182 "p.default.generalConfig.boundaryVelocity",
183 "The default value for the velocity at the ends [mm/s].");
184 def->optional(
185 properties.generalConfig.cornerLimit,
186 "p.default.generalConfig.cornerLimit",
187 "The default value for the angle above which a bend is considered a corner [deg].");
188
189
190 optionalSubSkillID(properties.navigateToNamedLocation.subSkillIDs.navigateToLocation,
191 "p.navigateToNamedLocation.subSkillIDs.navigateToLocation");
192 optionalSubSkillID(properties.navigateToChargingStation.subSkillIDs.navigateToNamedLocation,
193 "p.navigateToChargingStation.subSkillIDs.navigateToNamedLocation");
194
195 return def;
196 }
197
198 void
200 {
201 // Topics and properties defined above are automagically registered.
202
203 // Keep debug observer data until calling `sendDebugObserverBatch()`.
204 // (Requies the armarx::DebugObserverComponentPluginUser.)
205 // setDebugObserverBatchModeEnabled(true);
206 }
207
208 void
210 {
211 // Do things after connecting to topics and components.
212
213 iceNavigatorFactory.emplace(navigatorPrx);
214
215 skills::NavigatingSkillHelper::Services helperSrv{.iceNavigatorFactory =
216 iceNavigatorFactory.value(),
217 .memoryNameSystem = memoryNameSystem()};
219 .safetyGuardParamsMutex = std::experimental::make_observer(&safetyGuardParamsMutex),
220 .safetyGuardParams = std::experimental::make_observer(&properties.safetyGuardParams),
221 .defaultGeneralConfig = properties.generalConfig};
222
223 {
224 addSkillFactory<skills::NavigateTo>(helperProperties, helperSrv);
225 }
226
227 {
228 addSkillFactory<skills::NavigateToAlternatives>(helperProperties, helperSrv);
229 }
230
231 {
232 addSkillFactory<skills::NavigateToLocation>(helperProperties, helperSrv);
233 }
234
235 {
237 .locationReader = &graphReaderPlugin->get(),
238 .objectPoseClient = ObjectPoseClientPluginUser::getClient(),
239 .objectClassReader = &objectClassReaderPlugin->get(),
240 };
241 addSkillFactory<skills::NavigateToNamedLocation>(properties.navigateToNamedLocation,
242 services);
243 }
244
245 {
247 properties.navigateToChargingStation);
248 }
249
250 {
251 addSkillFactory<skills::MoveXMeters>(helperProperties, helperSrv);
252 }
253
254 {
255 addSkillFactory<skills::RotateXDegrees>(helperProperties, helperSrv);
256 }
257
258 {
260 .robotName = this->properties.robotName,
261 };
263 .robotReader = virtualRobotReaderPlugin->get(),
264 };
266 helperProperties, helperSrv, properties, srv);
267 }
268
269 {
270 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
271 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
272 ARMARX_CHECK_NOT_NULL(roomsReaderPlugin);
273
274 skills::GuideHumanToRoom::Services srv{.virtualRobotReader =
275 virtualRobotReaderPlugin->get(),
276 .costmapReader = costmapReaderPlugin->get(),
277 .roomsReader = roomsReaderPlugin->get(),
278 .arviz = arviz};
279
280 addSkillFactory<skills::GuideHumanToRoom>(helperProperties, helperSrv, srv);
281 }
282
283 {
284 skills::RotateTowards::Properties props{.robotName = properties.robotName};
285 skills::RotateTowards::Services srv{.robotReader = virtualRobotReaderPlugin->get()};
286 addSkillFactory<skills::RotateTowards>(helperProperties, helperSrv, props, srv);
287 }
288
289 {
291 skills::RotateTowardsLocation::Services srv{.locationReader = graphReaderPlugin->get()};
293 }
294
295
296 /* (Requies the armarx::DebugObserverComponentPluginUser.)
297 // Use the debug observer to log data over time.
298 // The data can be viewed in the ObserverView and the LivePlotter.
299 // (Before starting any threads, we don't need to lock mutexes.)
300 {
301 setDebugObserverDatafield("numBoxes", properties.numBoxes);
302 setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
303 sendDebugObserverBatch();
304 }
305 */
306
307 /* (Requires the armarx::ArVizComponentPluginUser.)
308 // Draw boxes in ArViz.
309 // (Before starting any threads, we don't need to lock mutexes.)
310 drawBoxes(properties, arviz);
311 */
312
313 // Setup the remote GUI.
314 {
317 }
318 }
319
320 void
324
325 void
329
330 std::string
332 {
333 return Component::defaultName;
334 }
335
336 std::string
338 {
339 return Component::defaultName;
340 }
341
342 void
344 {
345 using namespace armarx::RemoteGui::Client;
346
347 VBoxLayout root;
348
349 // thread-safe access to params
350 const auto safetyGuardParams = [this]()
351 {
352 std::lock_guard g{safetyGuardParamsMutex};
353 return properties.safetyGuardParams;
354 }();
355
356 const auto setSpinBox = [](armarx::RemoteGui::Client::FloatSpinBox& w,
357 float min,
358 float max,
359 int decimals,
360 float step)
361 {
362 w.setRange(min, max);
363 w.setDecimals(decimals);
364 w.setSteps(static_cast<int>((max - min) / step));
365 };
366
367 {
368 GridLayout grid;
369 int row = 0;
370 grid.add(Label("Enable Humans"), {.row = row, .column = 0})
371 .add(tab.enableHumans, {.row = row++, .column = 1});
372 grid.add(Label("Enable Laserscanner"), {.row = row, .column = 0})
373 .add(tab.enableLaserScanners, {.row = row++, .column = 1});
374 root.addChild(grid);
375
376 tab.enableHumans.setValue(safetyGuardParams.enableHumans);
377 tab.enableLaserScanners.setValue(safetyGuardParams.enableLaserScanners);
378 }
379 root.addChild(VSpacer());
380
381 const auto setupProximityFieldGui =
382 [&root, &setSpinBox](RemoteGuiTab::ProximityField& field,
384 const std::string& label)
385 {
386 GridLayout grid;
387 int row = 0;
388 grid.add(Label("Reduce speed"), {.row = row, .column = 0})
389 .add(field.reduceSpeed, {.row = row++, .column = 1});
390 grid.add(Label("Min distance"), {.row = row, .column = 0})
391 .add(field.minDistance, {.row = row++, .column = 1});
392 grid.add(armarx::RemoteGui::Client::VSpacer(), {.row = row++, .column = 0});
393 grid.add(Label("Max distance"), {.row = row, .column = 0})
394 .add(field.maxDistance, {.row = row++, .column = 1});
395 grid.add(Label("k"), {.row = row, .column = 0})
396 .add(field.k, {.row = row++, .column = 1});
397 grid.add(Label("lambda"), {.row = row, .column = 0})
398 .add(field.lambda, {.row = row++, .column = 1});
399
400 GroupBox box({grid});
401 box.setLabel(label);
402 root.addChild(box);
403
404 field.reduceSpeed.setValue(values.reduceVelocity);
405 field.minDistance.setValue(values.safetyDistance);
406 setSpinBox(field.minDistance, 0, 5000, 1, 1);
407 field.maxDistance.setValue(values.influenceDistance);
408 setSpinBox(field.maxDistance, 0, 10000, 1, 1);
409 field.k.setValue(values.k);
410 setSpinBox(field.k, 1, 20, 2, 0.1);
411 field.lambda.setValue(values.lambda);
412 setSpinBox(field.lambda, 1, 20, 2, 0.1);
413 };
414
415 setupProximityFieldGui(tab.humanProximityField,
416 safetyGuardParams.humanProximityField,
417 "Human proximity field");
418 root.addChild(VSpacer());
419 setupProximityFieldGui(tab.laserScannerProximityField,
420 safetyGuardParams.laserScannerProximityField,
421 "LaserScanner proximity field");
422
423 RemoteGui_createTab(getName(), root, &tab);
424 }
425
426 void
428 {
429 std::lock_guard g{safetyGuardParamsMutex};
430
431 auto& safetyGuardParams = properties.safetyGuardParams;
432
433 safetyGuardParams.enableHumans = tab.enableHumans.getValue();
434 safetyGuardParams.enableLaserScanners = tab.enableLaserScanners.getValue();
435
436 const auto readProximityField = [&](const RemoteGuiTab::ProximityField& field,
438 {
439 values.reduceVelocity = field.reduceSpeed.getValue();
440 values.safetyDistance = field.minDistance.getValue();
441 values.influenceDistance = field.maxDistance.getValue();
442 values.k = field.k.getValue();
443 values.lambda = field.lambda.getValue();
444 };
445
446 readProximityField(tab.humanProximityField, safetyGuardParams.humanProximityField);
447 readProximityField(tab.laserScannerProximityField,
448 safetyGuardParams.laserScannerProximityField);
449 }
450
451 /* (Requires the armarx::ArVizComponentPluginUser.)
452 void
453 Component::drawBoxes(const Component::Properties& p, viz::Client& arviz)
454 {
455 // Draw something in ArViz (requires the armarx::ArVizComponentPluginUser.
456 // See the ArVizExample in RobotAPI for more examples.
457
458 viz::Layer layer = arviz.layer(p.boxLayerName);
459 for (int i = 0; i < p.numBoxes; ++i)
460 {
461 layer.add(viz::Box("box_" + std::to_string(i))
462 .position(Eigen::Vector3f(i * 100, 0, 0))
463 .size(20).color(simox::Color::blue()));
464 }
465 arviz.commit(layer);
466 }
467 */
468
469
471
472} // namespace armarx::navigation::components::navigation_skill_provider
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
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
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
objpose::ObjectPoseClient getClient() const
skills::SkillBlueprint * addSkillFactory(const skills::SkillDescription &desc, const skills::LambdaSkill::FunctionType &f)
void RemoteGui_update() override
After calling RemoteGui_startRunningTask, this function is called periodically in a separate thread.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
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.
std::optional< ProviderID > providerId
Definition SkillID.h:40
std::string skillName
Definition SkillID.h:41
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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...
const std::string NavigationSkillProviderName
Definition constants.h:28
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
observer_ptr< _Tp > make_observer(_Tp *__p) noexcept
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
void addChild(Widget const &child)
Definition Widgets.cpp:95
void setRange(float min, float max)
Definition Widgets.cpp:330
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
Definition Widgets.cpp:438
void setLabel(std::string const &text)
Definition Widgets.cpp:420