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 
27 #include <SimoxUtility/algorithm/string.h>
28 
31 
35 
36 #include <experimental/map>
37 #include <range/v3/range/conversion.hpp>
38 #include <range/v3/view/filter.hpp>
39 #include <range/v3/view/transform.hpp>
40 
41 namespace 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 (e.g. 'Kitchen/multivitamin-juice/0'). "
70  "If you want an entity to be localized for n seconds append ':n'. If you want to see all active entities, set the component to DEBUG.");
71 
72  return def;
73  }
74 
75  void
77  {
78  // Topics and properties defined above are automagically registered.
79 
80  // Keep debug observer data until calling `sendDebugObserverBatch()`.
81  // (Requies the armarx::DebugObserverComponentPluginUser.)
82  // setDebugObserverBatchModeEnabled(true);
83 
84  // setup the active requests
85  for (const auto& entity : simox::alg::split(properties.initiallyRequestedEntities, ","))
86  {
87  const auto tokens = simox::alg::split(entity, ":");
88 
89  ARMARX_CHECK(not tokens.empty());
90  ARMARX_CHECK(tokens.size() <= 2)
91  << "Could not use multiple durations for localization request '" << entity << "'";
92 
93  const auto& objectName = tokens[0];
94 
97  const auto until = tokens.size() == 1
99  : DateTime::Now() + Duration::Seconds(std::stoi(tokens.at(1)));
100 
101  activeRequests.insert({objectName, until});
102  }
103  }
104 
105  void
107  {
108  // Do things after connecting to topics and components.
109 
110  poseProviderTask = new SimpleRunningTask<>([this]() { this->poseProviderTaskRun(); });
111  poseProviderTask->start();
112  }
113 
114  void
116  {
117  }
118 
119  void
121  {
122  }
123 
124  std::string
126  {
127  return SimulationObjectPoseProvider::defaultName;
128  }
129 
130 
131  std::string
133  {
134  return SimulationObjectPoseProvider::defaultName;
135  }
136 
137  objpose::provider::RequestObjectsOutput
139  const objpose::provider::RequestObjectsInput& input,
140  const Ice::Current& /*unused*/)
141  {
142  if (properties.requestAllEntities)
143  {
144  ARMARX_WARNING << "All entities are requested by default. "
145  "Requesting an object does not have an effect.";
146  // The method will still finish to generate a return object.
147  }
148 
149  const std::lock_guard l(knownObjectsMutex);
150  const std::lock_guard l2(activeRequestsMutex);
151 
153 
154  objpose::provider::RequestObjectsOutput output;
155  for (const auto& id : input.objectIDs)
156  {
157  const std::string entityId = id.dataset + "/" + id.className + "/" + id.instanceName;
158  if (knownObjects.find(entityId) != knownObjects.end())
159  {
160  if (activeRequests.find(entityId) != activeRequests.end())
161  {
162  ARMARX_INFO << "Object '" << entityId
163  << "' is already requested. Updating the request time.";
164  }
165  activeRequests[entityId] =
166  now + armarx::core::time::Duration::MilliSeconds(input.relativeTimeoutMS);
167  output.results[id].success = true;
168  }
169  else
170  {
171  std::vector<std::string> allNames;
172  allNames.reserve(knownObjects.size());
173  for (const auto& [name, _] : knownObjects)
174  {
175  allNames.push_back(name);
176  }
177  ARMARX_WARNING << "Could not query unknown object '" << entityId
178  << "'. All known objects are: " << allNames;
179  output.results[id].success = false;
180  }
181  }
182  return output;
183  }
184 
185  objpose::ProviderInfo
186  SimulationObjectPoseProvider::getProviderInfo(const Ice::Current& /*unused*/)
187  {
188  objpose::ProviderInfo info;
189  info.objectType = objpose::KnownObject;
190  info.proxy = getProxy<objpose::ObjectPoseProviderPrx>();
191  info.supportedObjects = {};
192  return info;
193  }
194 
195  void
196  SimulationObjectPoseProvider::poseProviderTaskRun()
197  {
198  Metronome metronome(Frequency::Hertz(properties.updateFrequency));
199 
200  while (poseProviderTask and not poseProviderTask->isStopped())
201  {
202  metronome.waitForNextTick();
203  const DateTime now = DateTime::Now();
204 
205  // update scene objects
206  armarx::SceneVisuData sceneData;
207  try
208  {
209  sceneData = simulatorPrx->getScene();
210  for (const auto& object : sceneData.objects)
211  {
212  ARMARX_DEBUG << "Found object in scene: " << object.name;
213  }
214  }
215  catch (const Ice::LocalException& e)
216  {
217  ARMARX_INFO << "Could not get object poses from simulator: " << e.what();
218  continue;
219  }
220 
221  ARMARX_DEBUG << deactivateSpam(10) << "Received " << sceneData.objects.size()
222  << " objects and " << sceneData.robots.size() << " robots.";
223 
224  std::vector<objpose::ProvidedObjectPose> providedObjects;
225 
226  if (properties.requestAllEntities)
227  {
228  // Convert all poses directly
229  providedObjects = getAllPoses(sceneData, now);
230  }
231  else
232  {
233  // Update known objects
234  updateKnownObjects(sceneData);
235  removeExpiredRequests(now);
236  providedObjects = getRequestedPoses(now);
237  }
238 
239  // Report the poses
240  try
241  {
242  ARMARX_DEBUG << deactivateSpam(10) << "Reporting " << providedObjects.size()
243  << " object poses";
244  objectPoseTopic->reportObjectPoses(getName(), objpose::toIce(providedObjects));
245  }
246  catch (const Ice::LocalException& e)
247  {
248  ARMARX_INFO << "Could not report object poses to object memory: " << e.what();
249  continue;
250  }
251  }
252  }
253 
254  std::vector<objpose::ProvidedObjectPose>
255  SimulationObjectPoseProvider::getAllPoses(const armarx::SceneVisuData& sceneData,
256  const DateTime& time) const
257  {
258  auto convertPoses = [this, time](const auto& simObject)
259  { return objectPoseFromVisuData(simObject, time); };
260 
261  return sceneData.objects | ranges::views::transform(convertPoses) | ranges::to_vector;
262  }
263 
264  void
265  SimulationObjectPoseProvider::updateKnownObjects(const armarx::SceneVisuData& sceneData)
266  {
267  const std::scoped_lock l(knownObjectsMutex);
268 
269  knownObjects.clear();
270  for (const auto& object : sceneData.objects)
271  {
272  knownObjects.insert({object.name, object});
273  }
274  }
275 
276  void
277  SimulationObjectPoseProvider::removeExpiredRequests(const DateTime& time)
278  {
279  const std::scoped_lock l2(activeRequestsMutex);
280 
281  auto isTimeout = [time](const auto& request)
282  {
283  const auto& provideUntilTime = request.second;
284  return (not provideUntilTime.isInvalid()) and time > provideUntilTime;
285  };
286 
287  std::experimental::erase_if(activeRequests, isTimeout);
288  }
289 
290  std::vector<objpose::ProvidedObjectPose>
291  SimulationObjectPoseProvider::getRequestedPoses(const DateTime& time) const
292  {
293  const std::scoped_lock l(knownObjectsMutex);
294  const std::scoped_lock l2(activeRequestsMutex);
295 
296  auto isRequestedObjectKnown = [this](const auto& request)
297  {
298  const auto& objectName = request.first;
299  return this->knownObjects.find(objectName) != this->knownObjects.end();
300  };
301 
302  auto getPoseFromRequest = [this, time](const auto& request)
303  {
304  const auto& object = this->knownObjects.at(request.first);
305  return objectPoseFromVisuData(object, time);
306  };
307 
308  return activeRequests | ranges::views::filter(isRequestedObjectKnown) |
309  ranges::views::transform(getPoseFromRequest) | ranges::to_vector;
310  }
311 
312  objpose::ProvidedObjectPose
313  SimulationObjectPoseProvider::objectPoseFromVisuData(const armarx::ObjectVisuData& visuData,
314  const DateTime& time) const
315  {
316  objpose::ProvidedObjectPose pose;
317 
318  pose.providerName = getName();
319  pose.objectType = objpose::ObjectType::KnownObject;
320  pose.isStatic = visuData.staticObject;
321 
322  pose.objectID = armarx::ObjectID(visuData.name);
323 
324  pose.objectPose = armarx::fromIce(visuData.objectPoses.at(visuData.name));
325  pose.objectPoseFrame = armarx::GlobalFrame;
326 
327  pose.confidence = 1;
328  pose.timestamp = time;
329 
330  return pose;
331  }
332 } // namespace armarx
armarx::SimpleRunningTask
Usage:
Definition: TaskUtil.h:70
armarx::armem::attachment::ObjectID
armem::MemoryID ObjectID
Definition: types.h:79
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:55
armarx::SimulationObjectPoseProvider::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: SimulationObjectPoseProvider.cpp:46
DateTime.h
Pose.h
armarx::SimulationObjectPoseProvider::onExitComponent
void onExitComponent() override
Definition: SimulationObjectPoseProvider.cpp:120
armarx::GlobalFrame
const std::string GlobalFrame
Definition: FramedPose.h:62
armarx::ObjectPoseProviderPluginUser::objectPoseTopic
objpose::ObjectPoseTopicPrx objectPoseTopic
Definition: ObjectPoseProviderPlugin.h:56
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::core::time::Duration::Seconds
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition: Duration.cpp:83
FramedPose.h
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
armarx::aron::input
ReaderT::InputType & input
Definition: rw.h:19
armarx::SimulationObjectPoseProvider::getDefaultName
std::string getDefaultName() const override
Definition: SimulationObjectPoseProvider.cpp:125
Metronome.h
armarx::SimulationObjectPoseProvider::GetDefaultName
static std::string GetDefaultName()
Get the component's default name.
Definition: SimulationObjectPoseProvider.cpp:132
armarx::fromIce
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
Definition: ice_conversions_boost_templates.h:26
armarx::SimulationObjectPoseProvider::onConnectComponent
void onConnectComponent() override
Definition: SimulationObjectPoseProvider.cpp:106
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:74
armarx::SimulationObjectPoseProvider::getProviderInfo
objpose::ProviderInfo getProviderInfo(const Ice::Current &) override
Definition: SimulationObjectPoseProvider.cpp:186
armarx::objpose::toIce
objpose::AABB toIce(const simox::AxisAlignedBoundingBox &aabb)
Definition: ice_conversions.cpp:94
ProvidedObjectPose.h
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:70
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
IceUtil::Handle
Definition: forward_declarations.h:29
armarx::core::time::Metronome
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Definition: Metronome.h:35
armarx::transform
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT > >
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition: algorithm.h:315
armarx::core::time::Duration
Represents a duration.
Definition: Duration.h:17
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::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:107
armarx::core::time::Frequency::Hertz
static Frequency Hertz(std::int64_t hertz)
Definition: Frequency.cpp:23
armarx::SimulationObjectPoseProvider::requestObjects
objpose::provider::RequestObjectsOutput requestObjects(const objpose::provider::RequestObjectsInput &input, const Ice::Current &) override
Definition: SimulationObjectPoseProvider.cpp:138
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::SimulationObjectPoseProvider::onDisconnectComponent
void onDisconnectComponent() override
Definition: SimulationObjectPoseProvider.cpp:115
armarx::armem::Duration
armarx::core::time::Duration Duration
Definition: forward_declarations.h:14
armarx::core::time::DateTime::Invalid
static DateTime Invalid()
Definition: DateTime.cpp:60
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::core::time::Duration::MilliSeconds
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition: Duration.cpp:55
armarx::SimulationObjectPoseProvider::onInitComponent
void onInitComponent() override
Definition: SimulationObjectPoseProvider.cpp:76
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:36
SimulationObjectPoseProvider.h