SimulationObjectPoseProvider.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 armarx
17 * @author Philip Scherer ( ulila@student.kit.edu )
18 * @date 2022
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <algorithm>
26#include <experimental/map>
27
28#include <SimoxUtility/algorithm/string.h>
29
32
36
37#include <range/v3/range/conversion.hpp>
38#include <range/v3/view/filter.hpp>
39#include <range/v3/view/transform.hpp>
40
41namespace armarx
42{
43 const std::string SimulationObjectPoseProvider::defaultName = "SimulationObjectPoseProvider";
44
47 {
50
51 // Publish to a topic (passing the TopicListenerPrx).
52 // def->topic(myTopicListener);
53
54 // Subscribe to a topic (passing the topic name).
55 // def->topic<PlatformUnitListener>("MyTopic");
56
57 def->component(simulatorPrx, "Simulator");
58
59 def->optional(properties.updateFrequency,
60 "UpdateFrequency",
61 "Frequency at which to update the objects in the ObjectMemory.");
62
63 def->optional(properties.requestAllEntities,
64 "p.requestAllEntities",
65 "True if all entities should be requested all the time.");
66
67 def->optional(properties.initiallyRequestedEntities,
68 "p.initiallyRequestedEntities",
69 "All entities (comma separated) that should be requested from the beginning "
70 "(e.g. 'Kitchen/multivitamin-juice/0'). "
71 "If you want an entity to be localized for n seconds append ':n'. If you "
72 "want to see all active entities, set the component to DEBUG.");
73
74 return def;
75 }
76
77 void
79 {
80 // Topics and properties defined above are automagically registered.
81
82 // Keep debug observer data until calling `sendDebugObserverBatch()`.
83 // (Requies the armarx::DebugObserverComponentPluginUser.)
84 // setDebugObserverBatchModeEnabled(true);
85
86 // setup the active requests
87 for (const auto& entity : simox::alg::split(properties.initiallyRequestedEntities, ","))
88 {
89 const auto tokens = simox::alg::split(entity, ":");
90
91 ARMARX_CHECK(not tokens.empty());
92 ARMARX_CHECK(tokens.size() <= 2)
93 << "Could not use multiple durations for localization request '" << entity << "'";
94
95 const auto& objectName = tokens[0];
96
99 const auto until = tokens.size() == 1
101 : DateTime::Now() + Duration::Seconds(std::stoi(tokens.at(1)));
102
103 activeRequests.insert({objectName, until});
104 }
105 }
106
107 void
109 {
110 // Do things after connecting to topics and components.
111
112 poseProviderTask = new SimpleRunningTask<>([this]() { this->poseProviderTaskRun(); });
113 poseProviderTask->start();
114 }
115
116 void
120
121 void
125
126 std::string
128 {
129 return SimulationObjectPoseProvider::defaultName;
130 }
131
132 std::string
134 {
135 return SimulationObjectPoseProvider::defaultName;
136 }
137
138 objpose::provider::RequestObjectsOutput
140 const objpose::provider::RequestObjectsInput& input,
141 const Ice::Current& /*unused*/)
142 {
143 if (properties.requestAllEntities)
144 {
145 ARMARX_WARNING << "All entities are requested by default. "
146 "Requesting an object does not have an effect.";
147 // The method will still finish to generate a return object.
148 }
149
150 const std::lock_guard l(knownObjectsMutex);
151 const std::lock_guard l2(activeRequestsMutex);
152
154
155 objpose::provider::RequestObjectsOutput output;
156 for (const auto& id : input.objectIDs)
157 {
158 const std::string entityId = id.dataset + "/" + id.className + "/" + id.instanceName;
159 if (knownObjects.find(entityId) != knownObjects.end())
160 {
161 if (activeRequests.find(entityId) != activeRequests.end())
162 {
163 ARMARX_INFO << "Object '" << entityId
164 << "' is already requested. Updating the request time.";
165 }
166 activeRequests[entityId] =
167 now + armarx::core::time::Duration::MilliSeconds(input.relativeTimeoutMS);
168 output.results[id].success = true;
169 }
170 else
171 {
172 std::vector<std::string> allNames;
173 allNames.reserve(knownObjects.size());
174 for (const auto& [name, _] : knownObjects)
175 {
176 allNames.push_back(name);
177 }
178 ARMARX_WARNING << "Could not query unknown object '" << entityId
179 << "'. All known objects are: " << allNames;
180 output.results[id].success = false;
181 }
182 }
183 return output;
184 }
185
186 objpose::ProviderInfo
187 SimulationObjectPoseProvider::getProviderInfo(const Ice::Current& /*unused*/)
188 {
189 objpose::ProviderInfo info;
190 info.objectType = objpose::KnownObject;
192 info.supportedObjects = {};
193 return info;
194 }
195
196 void
197 SimulationObjectPoseProvider::poseProviderTaskRun()
198 {
199 Metronome metronome(Frequency::Hertz(properties.updateFrequency));
200
201 while (poseProviderTask and not poseProviderTask->isStopped())
202 {
203 metronome.waitForNextTick();
204 const DateTime now = DateTime::Now();
205
206 // update scene objects
207 armarx::SceneVisuData sceneData;
208 try
209 {
210 sceneData = simulatorPrx->getScene();
211 for (const auto& object : sceneData.objects)
212 {
213 ARMARX_DEBUG << "Found object in scene: " << object.name;
214 }
215 }
216 catch (const Ice::LocalException& e)
217 {
218 ARMARX_INFO << "Could not get object poses from simulator: " << e.what();
219 continue;
220 }
221
222 ARMARX_DEBUG << deactivateSpam(10) << "Received " << sceneData.objects.size()
223 << " objects and " << sceneData.robots.size() << " robots.";
224
225 std::vector<objpose::ProvidedObjectPose> providedObjects;
226
227 if (properties.requestAllEntities)
228 {
229 // Convert all poses directly
230 providedObjects = getAllPoses(sceneData, now);
231 }
232 else
233 {
234 // Update known objects
235 updateKnownObjects(sceneData);
236 removeExpiredRequests(now);
237 providedObjects = getRequestedPoses(now);
238 }
239
240 // Report the poses
241 try
242 {
243 ARMARX_DEBUG << deactivateSpam(10) << "Reporting " << providedObjects.size()
244 << " object poses";
245 objectPoseTopic->reportObjectPoses(getName(), objpose::toIce(providedObjects));
246 }
247 catch (const Ice::LocalException& e)
248 {
249 ARMARX_INFO << "Could not report object poses to object memory: " << e.what();
250 continue;
251 }
252 }
253 }
254
255 std::vector<objpose::ProvidedObjectPose>
256 SimulationObjectPoseProvider::getAllPoses(const armarx::SceneVisuData& sceneData,
257 const DateTime& time) const
258 {
259 auto convertPoses = [this, time](const auto& simObject)
260 { return objectPoseFromVisuData(simObject, time); };
261
262 return sceneData.objects | ranges::views::transform(convertPoses) | ranges::to_vector;
263 }
264
265 void
266 SimulationObjectPoseProvider::updateKnownObjects(const armarx::SceneVisuData& sceneData)
267 {
268 const std::scoped_lock l(knownObjectsMutex);
269
270 knownObjects.clear();
271 for (const auto& object : sceneData.objects)
272 {
273 knownObjects.insert({object.name, object});
274 }
275 }
276
277 void
278 SimulationObjectPoseProvider::removeExpiredRequests(const DateTime& time)
279 {
280 const std::scoped_lock l2(activeRequestsMutex);
281
282 auto isTimeout = [time](const auto& request)
283 {
284 const auto& provideUntilTime = request.second;
285 return (not provideUntilTime.isInvalid()) and time > provideUntilTime;
286 };
287
288 std::experimental::erase_if(activeRequests, isTimeout);
289 }
290
291 std::vector<objpose::ProvidedObjectPose>
292 SimulationObjectPoseProvider::getRequestedPoses(const DateTime& time) const
293 {
294 const std::scoped_lock l(knownObjectsMutex);
295 const std::scoped_lock l2(activeRequestsMutex);
296
297 auto isRequestedObjectKnown = [this](const auto& request)
298 {
299 const auto& objectName = request.first;
300 return this->knownObjects.find(objectName) != this->knownObjects.end();
301 };
302
303 auto getPoseFromRequest = [this, time](const auto& request)
304 {
305 const auto& object = this->knownObjects.at(request.first);
306 return objectPoseFromVisuData(object, time);
307 };
308
309 return activeRequests | ranges::views::filter(isRequestedObjectKnown) |
310 ranges::views::transform(getPoseFromRequest) | ranges::to_vector;
311 }
312
314 SimulationObjectPoseProvider::objectPoseFromVisuData(const armarx::ObjectVisuData& visuData,
315 const DateTime& time) const
316 {
317 objpose::ProvidedObjectPose pose;
318
319 pose.providerName = getName();
320 pose.objectType = objpose::ObjectType::KnownObject;
321 pose.isStatic = visuData.staticObject;
322
323 pose.objectID = armarx::ObjectID(visuData.name);
324
325 pose.objectPose = armarx::fromIce(visuData.objectPoses.at(visuData.name));
326 pose.objectPoseFrame = armarx::GlobalFrame;
327
328 pose.confidence = 1;
329 pose.timestamp = time;
330
331 return pose;
332 }
333} // namespace armarx
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 DateTime Now()
Definition DateTime.cpp:51
static DateTime Invalid()
Definition DateTime.cpp:57
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition Duration.cpp:72
static Frequency Hertz(std::int64_t hertz)
Definition Frequency.cpp:20
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:99
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
objpose::ObjectPoseStorageInterfacePrx objectPoseTopic
bool isStopped()
Retrieve whether stop() has been called.
objpose::ProviderInfo getProviderInfo(const Ice::Current &) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
static std::string GetDefaultName()
Get the component's default name.
objpose::provider::RequestObjectsOutput requestObjects(const objpose::provider::RequestObjectsInput &input, const Ice::Current &) override
Represents a point in time.
Definition DateTime.h:25
static DateTime Now()
Definition DateTime.cpp:51
Represents a duration.
Definition Duration.h:17
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition Duration.cpp:48
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Definition Metronome.h:57
An object pose provided by an ObjectPoseProvider.
std::string providerName
Name of the providing component.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
objpose::AABB toIce(const simox::AxisAlignedBoundingBox &aabb)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
SimpleRunningTask(Ts...) -> SimpleRunningTask< std::function< void(void)> >