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 mobile_manipulation::ArmarXObjects::handover_visualization
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 <memory>
27#include <string>
28#include <vector>
29
30#include <Eigen/Geometry>
31
32#include <range/v3/algorithm/find.hpp>
33#include <range/v3/algorithm/find_if.hpp>
34#include <range/v3/range/conversion.hpp>
35#include <range/v3/view/transform.hpp>
36
37#include <VirtualRobot/SceneObjectSet.h>
38
49
53
60
64
66
68{
70 {
71 addPlugin(humanPoseReaderPlugin);
72 addPlugin(humanPersonInstanceReaderPlugin);
73 addPlugin(navigationHumanPoseReaderPlugin);
74 addPlugin(costmapWriterPlugin);
75 addPlugin(navigationRoomReaderPlugin);
76 }
77
78 const std::string Component::defaultName = "social_cost_map";
79
82 {
85
86 // Publish to a topic (passing the TopicListenerPrx).
87 // def->topic(myTopicListener);
88
89 // Subscribe to a topic (passing the topic name).
90 // def->topic<PlatformUnitListener>("MyTopic");
91
92 // Use (and depend on) another component (passing the ComponentInterfacePrx).
93 // def->component(myComponentProxy)
94
95
96 // Add a required property. (The component won't start without a value being set.)
97 // def->required(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
98
99 // Add an optionalproperty.
100 def->optional(properties.robotName, "p.robotName", "");
101 def->optional(properties.human.providerName, "p.human.providerName", "");
102 def->optional(properties.human.naviProviderName, "p.human.naviProviderName", "");
103
104 def->optional(
105 properties.taskPeriodMs, "p.taskPeriodMs", "Period in ms for updating the costmap.");
106 def->optional(properties.enableHumanPoseReader,
107 "p.enableHumanPoseReader",
108 "Enable human pose reader");
109 def->optional(properties.enableHumanPersonInstanceReader,
110 "p.enableHumanPersonInstanceReader",
111 "Enable human person instance reader");
112 def->optional(properties.enableNavigationHumanPoseReader,
113 "p.enableNavigationHumanPoseReader",
114 "Enable navigation human pose reader");
115 def->optional(properties.restrictToRooms,
116 "p.restrictToRooms",
117 "Restrict considered objects to those inside the given rooms.");
118 def->optional(properties.roomNames,
119 "p.roomNames",
120 "Comma separated list of room names to restrict considered objects to.");
121
122 return def;
123 }
124
125 void
127 {
128 // Topics and properties defined above are automagically registered.
129
130 // Keep debug observer data until calling `sendDebugObserverBatch()`.
131 // (Requies the armarx::DebugObserverComponentPluginUser.)
132 // setDebugObserverBatchModeEnabled(true);
133 }
134
135 void
137 {
139
140 const auto timestamp = armarx::Clock::Now();
141
143
144 const auto objectPoseClient = ObjectPoseClientPluginUser::getClient();
145 const armarx::objpose::ObjectPoseSeq objectPoses = objectPoseClient.fetchObjectPoses();
146
147 std::vector<armarx::navigation::algorithms::Room> rooms;
148 if (properties.restrictToRooms)
149 {
150 const std::vector<std::string> roomNames =
151 simox::alg::split(properties.roomNames, ",", true);
152
153 {
155 .providerName = std::nullopt, .timestamp = timestamp};
156
157 const auto result = navigationRoomReaderPlugin->get().query(query);
158
159 if (not result)
160 {
161 ARMARX_INFO << "Failed to obtain rooms from navigation memory. Reason: "
162 << result.errorMessage;
163 }
164 else
165 {
166 for (const auto& roomName : roomNames)
167 {
168 auto it = ranges::find(
169 result.rooms, roomName, &armarx::navigation::algorithms::Room::name);
170
171 if (it != result.rooms.end())
172 {
173 rooms.push_back(*it);
174 }
175 else
176 {
177 ARMARX_WARNING << "Room " << QUOTED(roomName)
178 << " not found in navigation memory.";
179 }
180 }
181 ARMARX_INFO << "Found " << rooms.size() << " rooms in navigation memory.";
182 }
183 }
184 }
185
186
188 objectPoses, VirtualRobot::ObjectIO::ObjectDescription::eCollisionModel);
189
190 // reset
191 objects = std::make_shared<VirtualRobot::SceneObjectSet>();
192
193 for (const auto& object : objectsAll->getSceneObjects())
194 {
195 const Eigen::Vector3f global_P_obj = object->getGlobalPosition();
196
197 if (not object->getCollisionModel())
198 {
199 ARMARX_DEBUG << "Object " << QUOTED(object->getName())
200 << " has no collision model. Skipping.";
201 continue;
202 }
203
204 if (not properties.restrictToRooms)
205 {
206 objects->addSceneObject(object);
207 continue;
208 }
209
210 for (const auto& room : rooms)
211 {
212 if (room.isInside(global_P_obj, true))
213 {
214 objects->addSceneObject(object);
215 break;
216 }
217 }
218 }
219 ARMARX_INFO << "Number of objects considered for costmap: "
220 << objects->getSceneObjects().size();
221
222 ARMARX_INFO << "Creating task";
223 periodicTask = new armarx::PeriodicTask<Component>(
224 this, &Component::visualizeOnce, properties.taskPeriodMs, "runningTask");
225
227
228 ARMARX_INFO << "Starting control thread";
229 periodicTask->start();
230 }
231
232 void
236
237 void
241
242 void
243 Component::visualizeOnce()
244 {
245 const auto debugObserverLogCb =
246 [this](const std::string& name, const armarx::Duration& duration)
247 {
248 ARMARX_DEBUG << name << " " << duration;
249 setDebugObserverDatafield("timing." + name + " [ms]", duration.toMilliSeconds());
250 };
251 {};
252
253 const auto makeSwCb = [&](const std::string& name)
254 { return [=](const armarx::Duration& duration) { debugObserverLogCb(name, duration); }; };
255
256
257 // will be populated with human positions from multiple sources
258 std::vector<Eigen::Vector3f> humanPositions;
259
260 const auto timestamp = armarx::Clock::Now();
261
262 if (properties.enableHumanPoseReader)
263 {
265 .providerName = properties.human.providerName,
266 .timestamp = timestamp,
267 .maxAge = armarx::Duration::MilliSeconds(2000)};
268
269 const auto humanPoseResult = humanPoseReaderPlugin->get().query(query);
270
271 if (not humanPoseResult)
272 {
273 ARMARX_VERBOSE << "Failed to obtain humans from memory. Reason: "
274 << humanPoseResult.errorMessage;
275 }
276 else
277 {
278
279 for (const auto& humanPose : humanPoseResult.humanPoses)
280 {
281 if (const auto meanPos = armarx::armem::human::computeMeanPosition(
283 {
284 humanPositions.push_back(meanPos.value());
285 }
286 }
287
288 ARMARX_INFO << "Found " << humanPoseResult.humanPoses.size()
289 << " humans in human pose memory.";
290 }
291 }
292
293 // get humans from human person instance memory
294 if(properties.enableHumanPersonInstanceReader)
295 {
296 const armarx::armem::human::client::PersonInstanceReader::Query query{
297 .providerName = "", // all providers
298 .timestamp = timestamp,
299 .maxAge = armarx::Duration::MilliSeconds(2000)};
300
301 const auto result = humanPersonInstanceReaderPlugin->get().query(query);
302
303 if (not result)
304 {
305 ARMARX_INFO << "Failed to obtain human person instances from memory. Reason: "
306 << result.errorMessage;
307 }
308 else
309 {
310
311 ARMARX_INFO << "Found " << result.personInstances.size()
312 << " human persons in human person instance memory.";
313
314 for (const auto& person : result.personInstances)
315 {
316 humanPositions.emplace_back(person.globalPose.translation());
317 }
318 }
319 }
320
321 if (properties.enableNavigationHumanPoseReader)
322 {
323
324 const armarx::navigation::memory::client::human::Reader::Query queryNavigationHumans{
325 .providerName = properties.human.naviProviderName,
326 .timestamp = timestamp,
327 .maxAge = armarx::Duration::MilliSeconds(2000)};
328
329 const auto resultNavi =
330 navigationHumanPoseReaderPlugin->get().queryHumans(queryNavigationHumans);
331
332 if (not resultNavi)
333 {
334 ARMARX_INFO << "Failed to obtain humans from navigation memory. Reason: "
335 << resultNavi.errorMessage;
336 }
337
338
339 if (resultNavi.humans.empty())
340 {
341 ARMARX_DEBUG << "No humans in navigation memory.";
342 }
343
344 ARMARX_INFO << "Found " << resultNavi.humans.size() << " humans in navigation memory.";
345
346 for (const auto& human : resultNavi.humans)
347 {
348 humanPositions.emplace_back(conv::to3D(human.pose.translation()));
349 }
350 }
351
352 ARMARX_INFO << "Total number of humans considered: " << humanPositions.size();
353
354
355 /*if (result.humanPoses.empty())
356 {
357 ARMARX_VERBOSE << "No humans";
358 return;
359 }*/
360
361
362 SocialCostmapBuilder socialCostmapBuilder(
364 armarx::navigation::algorithms::Costmap::Parameters{.binaryGrid = false,
365 .cellSize = 100});
366
367
368 // prepare humans for costmap building
369 const std::vector<navigation::core::Pose2D> humanPoses =
370 humanPositions |
371 ranges::views::transform(
372 [](const Eigen::Vector3f& humanPosition)
373 {
374 return Eigen::Isometry2f{
375 Eigen::Translation2f(humanPosition.x(), humanPosition.y())};
376 }) |
377 ranges::to_vector;
378
379
380 {
381 armarx::core::time::ScopedStopWatch sw(makeSwCb("platform"));
382
383 auto costmapPlatform =
384 socialCostmapBuilder.create(humanPoses, SocialCostmapBuilder::Mode::Mode1);
385 //ARMARX_INFO << "platform: vmin=" << costmapPlatform.getGrid().minCoeff() << " vmax=" << costmapPlatform.getGrid().maxCoeff();
386
387 const float intimateZoneCostTh = 0.6f;
388
389 // cut out the high values
390 const Eigen::Matrix<bool, -1, -1> mask =
391 (costmapPlatform.getMutableGrid().array() < intimateZoneCostTh);
392 costmapPlatform.getMutableMask().emplace(mask);
393
394 armarx::core::time::ScopedStopWatch sw2(makeSwCb("platform_storing"));
395
396 costmapWriterPlugin->get().store(
397 costmapPlatform, "social_costmap_platform", getName(), timestamp);
398
399 //const auto x = costmapPlatform.getGrid().array().max();
400 }
401
403 }
404
405 std::string
407 {
408 return Component::defaultName;
409 }
410
411 std::string
413 {
414 return Component::defaultName;
415 }
416
418
419} // namespace armarx::navigation::components::social_cost_map
std::string timestamp()
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
#define QUOTED(x)
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.
objpose::ObjectPoseClient getClient() const
The periodic task executes one thread method repeatedly using the time period specified in the constr...
Represents a duration.
Definition Duration.h:17
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition Component.cpp:81
static std::string GetDefaultName()
Get the component's default name.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
std::optional< Eigen::Vector3f > computeMeanPosition(const HumanPose &humanPose, KeyPointCoordinateSystem coordSystem)
Definition util.cpp:31
SceneBounds computeSceneBounds(const VirtualRobot::SceneObjectSetPtr &obstacles, const std::vector< VirtualRobot::RobotPtr > &articulatedObjects, const SceneBounds &init, const std::vector< Room > &rooms, const float margin, const bool restrictToRooms)
Definition util.cpp:62
std::vector< Eigen::Vector3f > to3D(const std::vector< Eigen::Vector2f > &v)
Definition eigen.cpp:14
VirtualRobot::SceneObjectSetPtr asSceneObjects(const objpose::ObjectPoseSeq &objectPoses, const VirtualRobot::ObjectIO::ObjectDescription loadMode)
Definition util.cpp:147
std::vector< ObjectPose > ObjectPoseSeq
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
#define ARMARX_TRACE
Definition trace.h:77