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 
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 "
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
118  {
119  }
120 
121  void
123  {
124  }
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;
191  info.proxy = getProxy<objpose::ObjectPoseProviderPrx>();
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 
313  objpose::ProvidedObjectPose
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
armarx::SimpleRunningTask
Usage:
Definition: TaskUtil.h:85
armarx::armem::attachment::ObjectID
armem::MemoryID ObjectID
Definition: types.h:79
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:51
armarx::SimulationObjectPoseProvider::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: SimulationObjectPoseProvider.cpp:46
DateTime.h
Pose.h
armarx::SimulationObjectPoseProvider::onExitComponent
void onExitComponent() override
Definition: SimulationObjectPoseProvider.cpp:122
armarx::GlobalFrame
const std::string GlobalFrame
Definition: FramedPose.h:65
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
erase_if
void erase_if(auto &c, Predicate pred)
Definition: pcl_filter.h:34
armarx::core::time::Duration::Seconds
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition: Duration.cpp:72
FramedPose.h
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::aron::input
ReaderT::InputType & input
Definition: rw.h:12
armarx::ObjectPoseProviderPluginUser::objectPoseTopic
objpose::ObjectPoseStorageInterfacePrx objectPoseTopic
Definition: ObjectPoseProviderPlugin.h:50
armarx::SimulationObjectPoseProvider::getDefaultName
std::string getDefaultName() const override
Definition: SimulationObjectPoseProvider.cpp:127
Metronome.h
armarx::SimulationObjectPoseProvider::GetDefaultName
static std::string GetDefaultName()
Get the component's default name.
Definition: SimulationObjectPoseProvider.cpp:133
armarx::fromIce
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
Definition: ice_conversions_boost_templates.h:27
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:351
armarx::SimulationObjectPoseProvider::onConnectComponent
void onConnectComponent() override
Definition: SimulationObjectPoseProvider.cpp:108
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:79
armarx::SimulationObjectPoseProvider::getProviderInfo
objpose::ProviderInfo getProviderInfo(const Ice::Current &) override
Definition: SimulationObjectPoseProvider.cpp:187
armarx::objpose::toIce
objpose::AABB toIce(const simox::AxisAlignedBoundingBox &aabb)
Definition: ice_conversions.cpp:103
ProvidedObjectPose.h
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:69
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
IceUtil::Handle
Definition: forward_declarations.h:30
armarx::core::time::Metronome
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Definition: Metronome.h:34
armarx::core::time::Duration
Represents a duration.
Definition: Duration.h:16
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:99
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
armarx::core::time::Frequency::Hertz
static Frequency Hertz(std::int64_t hertz)
Definition: Frequency.cpp:20
armarx::SimulationObjectPoseProvider::requestObjects
objpose::provider::RequestObjectsOutput requestObjects(const objpose::provider::RequestObjectsInput &input, const Ice::Current &) override
Definition: SimulationObjectPoseProvider.cpp:139
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::SimulationObjectPoseProvider::onDisconnectComponent
void onDisconnectComponent() override
Definition: SimulationObjectPoseProvider.cpp:117
armarx::armem::Duration
armarx::core::time::Duration Duration
Definition: forward_declarations.h:14
armarx::core::time::DateTime::Invalid
static DateTime Invalid()
Definition: DateTime.cpp:57
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::core::time::Duration::MilliSeconds
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition: Duration.cpp:48
armarx::SimulationObjectPoseProvider::onInitComponent
void onInitComponent() override
Definition: SimulationObjectPoseProvider.cpp:78
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:38
SimulationObjectPoseProvider.h