KinematicSubUnit.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 RobotAPI::ArmarXObjects::KinematicSubUnit
17  * @author Raphael ( raphael dot grimm at kit dot edu )
18  * @date 2017
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 #include "KinematicSubUnit.h"
23 
24 #include <VirtualRobot/RobotNodeSet.h>
25 
27 
29 #include <RobotAPI/interface/units/KinematicUnitInterface.h>
31 
33 {
34 }
35 
36 void
38  std::string relRobFile,
40  std::map<std::string, ActuatorData>&& newDevs,
41  std::vector<std::set<std::string>> controlDeviceHardwareControlModeGrps,
42  std::set<std::string> controlDeviceHardwareControlModeGrpsMerged,
43  RobotUnit* newRobotUnit)
44 {
45  std::lock_guard<std::mutex> guard{dataMutex};
46  ARMARX_CHECK_EXPRESSION(getState() == eManagedIceObjectCreated);
47 
50  robot = rob;
51  robot->setUpdateCollisionModel(false);
52  robot->setUpdateVisualization(false);
53  robot->setThreadsafe(false);
54 
55  ARMARX_CHECK_EXPRESSION(!robotUnit);
56  ARMARX_CHECK_EXPRESSION(newRobotUnit);
57  robotUnit = newRobotUnit;
58 
59  ARMARX_CHECK_EXPRESSION(relativeRobotFile.empty());
60  ARMARX_CHECK_EXPRESSION(!relRobFile.empty());
61  relativeRobotFile = relRobFile;
62 
63  devs = std::move(newDevs);
64  controlDeviceHardwareControlModeGroups = controlDeviceHardwareControlModeGrps;
65  controlDeviceHardwareControlModeGroupsMerged = controlDeviceHardwareControlModeGrpsMerged;
66 
67  auto nodes = robot->getRobotNodes();
68  for (auto& node : nodes)
69  {
70  if (node->isJoint() && !devs.count(node->getName()))
71  {
72  sensorLessJoints.push_back(node);
73  }
74  }
75 }
76 
77 void
80 {
81  if (!getProxy())
82  {
83  //this unit is not initialized yet
84  ARMARX_IMPORTANT << deactivateSpam(1) << "not initialized yet";
85  return;
86  }
87  if (!listenerPrx)
88  {
89  ARMARX_IMPORTANT << deactivateSpam(1) << "listener is not set";
90  return;
91  }
92  std::lock_guard<std::mutex> guard{dataMutex};
93  bool ctrlModesAValueChanged = false;
94  bool angAValueChanged = false;
95  bool velAValueChanged = false;
96  bool accAValueChanged = false;
97  bool torAValueChanged = false;
98  bool motorCurrentAValueChanged = false;
99  bool motorTemperaturesAValueChanged = false;
100  bool statusesAvalueChanged = false;
101 
102  long timestamp = sc.sensorValuesTimestamp.toMicroSeconds();
103  std::set<NJointControllerBase*> nJointCtrls{c.nJointControllers.begin(),
104  c.nJointControllers.end()};
105  std::vector<std::string> actuatorsWithoutSensor;
106  actuatorsWithoutSensor.reserve(devs.size());
107  for (const auto& name2actuatorData : devs)
108  {
109  const ActuatorData& actuatorData = name2actuatorData.second;
110  const auto& name = actuatorData.name;
111  //mode
112  {
113  ControlMode c = eUnknown;
114  if (actuatorData.ctrlPos && nJointCtrls.count(actuatorData.ctrlPos.get()))
115  {
116  c = ePositionControl;
117  }
118  if (actuatorData.ctrlVel && nJointCtrls.count(actuatorData.ctrlVel.get()))
119  {
120  ARMARX_CHECK_EXPRESSION(eUnknown == c);
121  c = eVelocityControl;
122  }
123  if (actuatorData.ctrlTor && nJointCtrls.count(actuatorData.ctrlTor.get()))
124  {
125  ARMARX_CHECK_EXPRESSION(eUnknown == c);
126  c = eTorqueControl;
127  }
128  ctrlModesAValueChanged =
129  ctrlModesAValueChanged || !ctrlModes.count(name) || (ctrlModes.at(name) != c);
130  ctrlModes[name] = c;
131  }
132  if (actuatorData.sensorDeviceIndex < sc.sensors.size())
133  {
134  const SensorValueBase* s = sc.sensors.at(actuatorData.sensorDeviceIndex).get();
135  UpdateNameValueMap<float,
136  SensorValue1DoFActuatorPosition,
137  &SensorValue1DoFActuatorPosition::position>(
138  ang, name, s, angAValueChanged);
139  UpdateNameValueMap<float,
140  SensorValue1DoFActuatorVelocity,
141  &SensorValue1DoFActuatorVelocity::velocity>(
142  vel, name, s, velAValueChanged);
143  UpdateNameValueMap<float,
144  SensorValue1DoFActuatorAcceleration,
145  &SensorValue1DoFActuatorAcceleration::acceleration>(
146  acc, name, s, accAValueChanged);
147  UpdateNameValueMap<float,
148  SensorValue1DoFActuatorTorque,
149  &SensorValue1DoFActuatorTorque::torque>(
150  tor, name, s, torAValueChanged);
151  UpdateNameValueMap<float,
152  SensorValue1DoFActuatorCurrent,
153  &SensorValue1DoFActuatorCurrent::motorCurrent>(
154  motorCurrents, name, s, motorCurrentAValueChanged);
155  UpdateNameValueMap<float,
156  SensorValue1DoFActuatorMotorTemperature,
157  &SensorValue1DoFActuatorMotorTemperature::motorTemperature>(
158  motorTemperatures, name, s, motorTemperaturesAValueChanged);
159  UpdateNameValueMap<JointStatus,
162  statuses, name, s, statusesAvalueChanged);
163  }
164  else
165  {
166  actuatorsWithoutSensor.emplace_back(name);
167  }
168  }
169  if (!actuatorsWithoutSensor.empty())
170  {
171  ARMARX_WARNING << deactivateSpam(5) << "these actuators have no sensor!:\n"
172  << actuatorsWithoutSensor;
173  }
174 
175  // update the joint values of linked joints
176  robot->setJointValues(ang);
177  auto nodes = robot->getRobotNodes();
178  for (auto& node : nodes)
179  {
180  node->updatePose(false);
181  }
182  for (auto& node : sensorLessJoints)
183  {
184  ang[node->getName()] = node->getJointValue();
185  }
186 
187 
188  ARMARX_DEBUG << deactivateSpam(30) << "reporting updated data:\n"
189  << ctrlModes.size()
190  << " \tcontrol modes (updated = " << ctrlModesAValueChanged << ")\n"
191  << ang.size() << " \tjoint angles (updated = " << angAValueChanged << ")\n"
192  << vel.size() << " \tjoint velocities (updated = " << velAValueChanged << ")\n"
193  << acc.size() << " \tjoint accelerations (updated = " << accAValueChanged << ")\n"
194  << tor.size() << " \tjoint torques (updated = " << torAValueChanged << ")\n"
195  << motorCurrents.size()
196  << " \tmotor currents (updated = " << motorCurrentAValueChanged << ")\n"
197  << motorTemperatures.size()
198  << " \tmotor temperatures (updated = " << motorTemperaturesAValueChanged << ")\n";
199  auto prx = listenerPrx->ice_batchOneway();
200  prx->reportJointAngles(ang, timestamp, angAValueChanged);
201  prx->reportJointVelocities(vel, timestamp, velAValueChanged);
202  prx->reportJointTorques(tor, timestamp, torAValueChanged);
203  if (reportSkipper.checkFrequency("Meta")) // only report the following data with low frequency
204  {
205  prx->reportJointAccelerations(acc, timestamp, accAValueChanged);
206  if (!motorCurrents.empty())
207  {
208  prx->reportJointCurrents(motorCurrents, timestamp, motorCurrentAValueChanged);
209  }
210  if (!motorTemperatures.empty())
211  {
212  prx->reportJointMotorTemperatures(
213  motorTemperatures, timestamp, motorTemperaturesAValueChanged);
214  }
215  if (!statuses.empty())
216  {
217  prx->reportJointStatuses(statuses, timestamp, statusesAvalueChanged);
218  }
219  prx->reportControlModeChanged(ctrlModes, timestamp, ctrlModesAValueChanged);
220  }
221  prx->ice_flushBatchRequests();
222 }
223 
224 void
225 armarx::KinematicSubUnit::requestJoints(const Ice::StringSeq&, const Ice::Current&)
226 {
227  ARMARX_WARNING << "NYI";
228 }
229 
230 void
231 armarx::KinematicSubUnit::releaseJoints(const Ice::StringSeq&, const Ice::Current&)
232 {
233  ARMARX_WARNING << "NYI";
234 }
235 
236 void
238 {
239  std::lock_guard<std::mutex> guard{dataMutex};
240  for (const auto& n2v : angles)
241  {
242  if (devs.count(n2v.first))
243  {
244  if (devs.at(n2v.first).ctrlPos)
245  {
246  devs.at(n2v.first).ctrlPos->set(n2v.second);
247  }
248  }
249  }
250 }
251 
252 void
254  const Ice::Current&)
255 {
256  std::lock_guard<std::mutex> guard{dataMutex};
257  for (const auto& n2v : velocities)
258  {
259  if (devs.count(n2v.first))
260  {
261  if (devs.at(n2v.first).ctrlVel)
262  {
263  devs.at(n2v.first).ctrlVel->set(n2v.second);
264  }
265  }
266  }
267 }
268 
269 void
271 {
272  std::lock_guard<std::mutex> guard{dataMutex};
273  for (const auto& n2v : torques)
274  {
275  if (devs.count(n2v.first))
276  {
277  if (devs.at(n2v.first).ctrlTor)
278  {
279  devs.at(n2v.first).ctrlTor->set(n2v.second);
280  }
281  }
282  }
283 }
284 
285 void
286 armarx::KinematicSubUnit::switchControlMode(const armarx::NameControlModeMap& ncm,
287  const Ice::Current&)
288 {
289  std::map<std::string, NJointControllerBasePtr> toActivate;
290  {
291  std::lock_guard<std::mutex> guard{dataMutex};
292  for (const auto& n2c : ncm)
293  {
294  const std::string& name = n2c.first;
295  ControlMode mode = n2c.second;
296  if (!devs.count(name))
297  {
298  ARMARX_WARNING << "requested mode '"
300  << "' for nonexistent device '" << name
301  << "'. (ignoring this device)";
302  continue;
303  }
304  NJointKinematicUnitPassThroughControllerPtr ctrl =
305  NJointKinematicUnitPassThroughControllerPtr::dynamicCast(
306  devs.at(name).getController(mode));
307  if (!ctrl)
308  {
309  ARMARX_WARNING << "requested unsupported mode '"
310  << KinematicUnitHelper::ControlModeToString(mode) << "' for device '"
311  << name << "'. (ignoring this device)";
312  continue;
313  }
314  if (ctrl->isControllerActive())
315  {
316  continue;
317  }
318  ctrl->reset(); // reset immediately instead of preActivate() to avoid race condition
319  toActivate[name] = std::move(ctrl);
320  }
321  const auto printToActivate = ARMARX_STREAM_PRINTER
322  {
323  for (const auto& elem : toActivate)
324  {
325  out << " '" << elem.first << "' -> '" << elem.second->getInstanceName() << "'\n";
326  }
327  };
328  ARMARX_DEBUG << "switching control modes requests these NJointControllers (without "
329  "consideration of ControlDeviceHardwareControlModeGroups):\n"
330  << printToActivate;
331  for (const auto& n2NJointCtrl : toActivate)
332  {
333  const auto& name = n2NJointCtrl.first;
334  ARMARX_DEBUG << "checking group of '" << name << "'";
335  const NJointControllerBasePtr& nJointCtrl = n2NJointCtrl.second;
336  if (!controlDeviceHardwareControlModeGroupsMerged.count(name))
337  {
338  continue;
339  }
340  //is in a group! (find the correct group)
341  const std::set<std::string>* group = nullptr;
342  for (const auto& grp : controlDeviceHardwareControlModeGroups)
343  {
344  if (grp.count(name))
345  {
346  group = &grp;
347  break;
348  }
349  }
351  const auto jointCtrl = nJointCtrl->getControlDevicesUsedJointController().at(name);
352  const auto hwMode = jointCtrl->getHardwareControlMode();
353  //check against all other elems of the group
354  for (const auto& other : *group)
355  {
356  if (name == other)
357  {
358  continue;
359  }
360  if (!devs.count(other))
361  {
362  continue;
363  }
364  //this device may have a controller switch
365  if (toActivate.count(other))
366  {
367  const auto otherJointCtrl =
368  toActivate.at(other)->getControlDevicesUsedJointController().at(other);
369  const auto otherHwMode = otherJointCtrl->getHardwareControlMode();
370  if (otherHwMode != hwMode)
371  {
372  std::stringstream strstr;
373  strstr << "The hardware control mode for two control devices with "
374  "requested control mode changein the same group does not match!\n"
375  << "Device 1: '" << name << "' mode "
376  << "'" << jointCtrl->getControlMode() << "' hw mode '" << hwMode
377  << "'\n"
378  << "Device 2: '" << other << "' mode "
379  << "'" << otherJointCtrl->getControlMode() << "' hw mode '"
380  << otherHwMode << "'\n";
381  ARMARX_ERROR << strstr.str();
382  throw InvalidArgumentException{strstr.str()};
383  }
384  }
385  else
386  {
387  //get the current active
388  const auto otherNJointCtrl = devs.at(other).getActiveController();
389  const auto otherJointCtrl =
390  otherNJointCtrl
391  ? otherNJointCtrl->getControlDevicesUsedJointController().at(other)
392  : nullptr;
393  const auto otherHwMode =
394  otherJointCtrl ? otherJointCtrl->getHardwareControlMode() : "";
395  if (hwMode != otherHwMode)
396  {
397  toActivate[other] = std::move(devs.at(other).getController(ncm.at(name)));
398  ARMARX_CHECK_EXPRESSION(toActivate.at(other));
399  ARMARX_CHECK_EXPRESSION(toActivate.at(other)
400  ->getControlDevicesUsedJointController()
401  .at(other)
402  ->getHardwareControlMode() == hwMode);
403  ARMARX_VERBOSE << "activating '" << nJointCtrl->getInstanceName()
404  << "' caused activation of '"
405  << toActivate.at(name)->getInstanceName() << "'";
406  }
407  }
408  }
409  ARMARX_DEBUG << "checking group of '" << name << "'...done!";
410  }
411  ARMARX_DEBUG << "switching control modes requests these NJointControllers (with "
412  "consideration of ControlDeviceHardwareControlModeGroups):\n"
413  << printToActivate;
414  //now check if groups are satisfied
415  ARMARX_CHECK_EXPRESSION(robotUnit);
416  }
417  if (!toActivate.empty())
418  {
419  robotUnit->activateNJointControllers(getMapValues(toActivate));
420  }
421 }
422 
423 void
425 {
426  ARMARX_WARNING << "NYI";
427 }
428 
429 void
431 {
432  ARMARX_WARNING << "NYI";
433 }
434 
435 armarx::NameControlModeMap
437 {
438  std::lock_guard<std::mutex> guard{dataMutex};
439  return ctrlModes;
440 }
441 
443 armarx::KinematicSubUnit::getJointAngles(const Ice::Current& c) const
444 {
445  std::lock_guard<std::mutex> guard{dataMutex};
446  return ang;
447 }
448 
451 {
452  std::lock_guard<std::mutex> guard{dataMutex};
453  return vel;
454 }
455 
456 Ice::StringSeq
457 armarx::KinematicSubUnit::getJoints(const Ice::Current& c) const
458 {
459  std::lock_guard<std::mutex> guard{dataMutex};
460  return getMapKeys(ang);
461 }
462 
463 armarx::DebugInfo
464 armarx::KinematicSubUnit::getDebugInfo(const Ice::Current& c) const
465 {
466  std::lock_guard<std::mutex> guard{dataMutex};
467 
468  armarx::DebugInfo debugInfo{.jointModes = ctrlModes,
469  .jointAngles = ang,
470  .jointVelocities = vel,
471  .jointAccelerations = acc,
472  .jointTorques = tor,
473  .jointCurrents = motorCurrents,
474  .jointMotorTemperatures = motorTemperatures,
475  .jointStatus = statuses};
476 
477  return debugInfo;
478 }
479 
482 {
483  switch (c)
484  {
485  case ePositionVelocityControl:
486  return ctrlPos;
487  case ePositionControl:
488  return ctrlPos;
489  case eVelocityControl:
490  return ctrlVel;
491  case eTorqueControl:
492  return ctrlTor;
493  default:
494  return nullptr;
495  }
496 }
497 
500 {
501  if (ctrlPos->isControllerActive())
502  {
503  return ctrlPos;
504  }
505  if (ctrlVel->isControllerActive())
506  {
507  return ctrlVel;
508  }
509  if (ctrlTor->isControllerActive())
510  {
511  return ctrlTor;
512  }
513  return nullptr;
514 }
armarx::KinematicSubUnit::setupData
void setupData(std::string relRobFile, VirtualRobot::RobotPtr rob, std::map< std::string, ActuatorData > &&newDevs, std::vector< std::set< std::string >> controlDeviceHardwareControlModeGrps, std::set< std::string > controlDeviceHardwareControlModeGrpsMerged, RobotUnit *newRobotUnit)
Definition: KinematicSubUnit.cpp:37
armarx::KinematicSubUnit::getJoints
Ice::StringSeq getJoints(const Ice::Current &c) const override
Definition: KinematicSubUnit.cpp:457
armarx::KinematicSubUnit::setJointVelocities
void setJointVelocities(const NameValueMap &velocities, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:253
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:180
algorithm.h
armarx::KinematicSubUnit::setJointAngles
void setJointAngles(const NameValueMap &angles, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:237
armarx::KinematicSubUnit::getJointVelocities
NameValueMap getJointVelocities(const Ice::Current &) const override
Definition: KinematicSubUnit.cpp:450
armarx::JointAndNJointControllers
Structure used by the RobotUnit to swap lists of Joint and NJoint controllers.
Definition: JointAndNJointControllers.h:32
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:183
armarx::KinematicSubUnit::ActuatorData::getActiveController
NJointControllerPtr getActiveController() const
Definition: KinematicSubUnit.cpp:499
armarx::SensorValueBase
The SensorValueBase class.
Definition: SensorValueBase.h:40
armarx::KinematicSubUnit::setJointTorques
void setJointTorques(const NameValueMap &torques, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:270
armarx::getMapValues
void getMapValues(const MapType &map, OutputIteratorType it)
Definition: algorithm.h:176
armarx::KinematicSubUnit::update
void update(const SensorAndControl &sc, const JointAndNJointControllers &c) override
Definition: KinematicSubUnit.cpp:78
RobotUnit.h
armarx::detail::ControlThreadOutputBufferEntry::sensors
std::vector< PropagateConst< SensorValueBase * > > sensors
Definition: ControlThreadOutputBuffer.h:203
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
armarx::SensorValue1DoFActuatorStatus::status
DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION armarx::JointStatus status
Definition: SensorValue1DoFActuator.h:101
armarx::navigation::platform_controller::platform_global_trajectory::NameValueMap
std::map< std::string, float > NameValueMap
Definition: PlatformGlobalTrajectoryController.h:93
armarx::KinematicSubUnit::releaseJoints
void releaseJoints(const Ice::StringSeq &, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:231
armarx::KinematicSubUnit::requestJoints
void requestJoints(const Ice::StringSeq &, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:225
armarx::KinematicSubUnit::KinematicSubUnit
KinematicSubUnit()
Definition: KinematicSubUnit.cpp:32
armarx::KinematicSubUnit::ActuatorData::getController
NJointControllerPtr getController(ControlMode c) const
Definition: KinematicSubUnit.cpp:481
armarx::KinematicSubUnit::ActuatorData::sensorDeviceIndex
std::size_t sensorDeviceIndex
Definition: KinematicSubUnit.h:49
armarx::detail::ControlThreadOutputBufferEntry
Definition: ControlThreadOutputBuffer.h:177
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:72
armarx::KinematicSubUnit::getJointAngles
NameValueMap getJointAngles(const Ice::Current &) const override
Definition: KinematicSubUnit.cpp:443
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:189
armarx::KinematicSubUnit::setJointDecelerations
void setJointDecelerations(const NameValueMap &, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:430
armarx::KinematicSubUnit::setJointAccelerations
void setJointAccelerations(const NameValueMap &, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:424
armarx::detail::ControlThreadOutputBufferEntry::sensorValuesTimestamp
IceUtil::Time sensorValuesTimestamp
Definition: ControlThreadOutputBuffer.h:201
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
KinematicUnitHelper.h
armarx::KinematicSubUnit::getControlModes
NameControlModeMap getControlModes(const Ice::Current &) override
Definition: KinematicSubUnit.cpp:436
armarx::NJointControllerPtr
SynchronousNJointControllerPtr NJointControllerPtr
Definition: NJointControllerBase.h:1169
float
#define float
Definition: 16_Level.h:22
KinematicSubUnit.h
armarx::SensorValue1DoFActuatorStatus
Definition: SensorValue1DoFActuator.h:98
armarx::RobotUnit
The RobotUnit class manages a robot and its controllers.
Definition: RobotUnit.h:180
armarx::KinematicSubUnit::ActuatorData
Definition: KinematicSubUnit.h:46
armarx::KinematicSubUnit::ActuatorData::name
std::string name
Definition: KinematicSubUnit.h:48
armarx::KinematicSubUnit::getDebugInfo
DebugInfo getDebugInfo(const Ice::Current &c=Ice::emptyCurrent) const override
Definition: KinematicSubUnit.cpp:464
armarx::KinematicSubUnit::ActuatorData::ctrlPos
NJointKinematicUnitPassThroughControllerPtr ctrlPos
Definition: KinematicSubUnit.h:50
armarx::KinematicUnitHelper::ControlModeToString
static std::string ControlModeToString(ControlMode controlMode)
Definition: KinematicUnitHelper.h:43
armarx::KinematicSubUnit::ActuatorData::ctrlTor
NJointKinematicUnitPassThroughControllerPtr ctrlTor
Definition: KinematicSubUnit.h:52
armarx::KinematicSubUnit::ActuatorData::ctrlVel
NJointKinematicUnitPassThroughControllerPtr ctrlVel
Definition: KinematicSubUnit.h:51
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::KinematicSubUnit::switchControlMode
void switchControlMode(const NameControlModeMap &ncm, const Ice::Current &) override
Definition: KinematicSubUnit.cpp:286
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::getMapKeys
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition: algorithm.h:157
VirtualRobot::RobotPtr
std::shared_ptr< class Robot > RobotPtr
Definition: Bus.h:18
ARMARX_STREAM_PRINTER
#define ARMARX_STREAM_PRINTER
use this macro to write output code that is executed when printed and thus not executed if the debug ...
Definition: Logging.h:304