RobotUnitSimulation.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 ArmarXSimulation::ArmarXObjects::RobotUnitSimulation
17  * @author Raphael Grimm ( 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 
23 #include "RobotUnitSimulation.h"
24 
25 #include <chrono>
26 #include <set>
27 
28 #include <VirtualRobot/MathTools.h>
29 #include <VirtualRobot/Nodes/ForceTorqueSensor.h>
30 #include <VirtualRobot/RobotNodeSet.h>
31 
34 
35 
36 using namespace armarx;
37 
38 void
40 {
41  robot = cloneRobot();
42  simulatorPrxName = getProperty<std::string>("SimulatorName").getValue();
44 
45  synchronizedSimulation = getProperty<bool>("SynchronizedSimulation").getValue();
46  simulatorRobotListenerInterfaceTopic =
47  getProperty<std::string>("SimulatorRobotListenerInterfaceTopic").getValue();
48  if (simulatorRobotListenerInterfaceTopic.empty())
49  {
50  simulatorRobotListenerInterfaceTopic = "Simulator_Robot_" + getRobotName();
51  }
52  simulatorForceTorqueListenerInterfaceTopic =
53  getProperty<std::string>("SimulatorForceTorqueListenerInterfaceTopic").getValue();
54  std::size_t controlIterationMsProp = getProperty<std::size_t>("ControlIterationMs").getValue();
55  if (!controlIterationMsProp)
56  {
57  ARMARX_WARNING << "the controll iteration was set to 0ms. detting it to 1ms";
58  controlIterationMsProp = 1;
59  }
60  controlIterationMs = IceUtil::Time::milliSeconds(controlIterationMsProp);
61  usingTopic(simulatorRobotListenerInterfaceTopic);
62  usingTopic(simulatorForceTorqueListenerInterfaceTopic);
63 
64  //ft mapping
65  {
66  const std::string mappingStr = getProperty<std::string>("ForceTorqueSensorMapping");
67  std::vector<std::string> entries;
68  if (mappingStr != "")
69  {
70  bool trimEntries = true;
71  entries = Split(mappingStr, ",", trimEntries);
72  }
73  for (std::string entry : entries)
74  {
75  ARMARX_CHECK_EXPRESSION(!entry.empty())
76  << "empty entry in ForceTorqueSensorMapping! entries:\n"
77  << entries;
78  bool trimFields = true;
79  std::vector<std::string> fields = Split(entry, ":", trimFields);
80  ARMARX_CHECK_EXPRESSION(fields.size() == 2 || fields.size() == 3)
81  << "invalid entry in ForceTorqueSensorMapping! invalid entry:\n"
82  << fields << "\nall entries:\n"
83  << entries;
84  for (auto& field : fields)
85  {
86  ARMARX_CHECK_EXPRESSION(!field.empty())
87  << "empty field in ForceTorqueSensorMapping entry! invalid entry:\n"
88  << fields << "\nall entries:\n"
89  << entries;
90  }
91  const VirtualRobot::ForceTorqueSensorPtr ftsensor =
92  robot->getSensor<typename VirtualRobot::ForceTorqueSensor>(fields.at(0));
93  if (!ftsensor)
94  {
95  ARMARX_WARNING << "the robot has not ft sensor of name '" << fields.at(0)
96  << "' this ForceTorqueSensorMapping entry has no effect: " << entry;
97  continue;
98  }
99  ARMARX_CHECK_EXPRESSION(fields.size() == 2 || robot->hasRobotNode(fields.at(2)))
100  << VAROUT(fields.size()) << " "
101  << (fields.size() != 2 ? VAROUT(fields.at(2)) : std::string{});
102  ARMARX_CHECK_EXPRESSION(!ftMappings.count(fields.at(0)));
103  FTMappingData& mapping = ftMappings[fields.at(0)];
104  mapping.originalReportFrame = ftsensor->getRobotNode()->getName();
105  mapping.reportFrame = mapping.originalReportFrame;
106  mapping.reportTransformation = Eigen::Matrix3f::Identity();
107  mapping.sensorName = fields.at(1);
108  if (fields.size() == 3)
109  {
110  mapping.reportFrame = fields.at(2);
111  //get rotation from original to target
112  const auto orig = robot->getRobotNode(mapping.originalReportFrame)->getGlobalPose();
113  const auto targ = robot->getRobotNode(mapping.reportFrame)->getGlobalPose();
114  mapping.reportTransformation =
115  (targ.block<3, 3>(0, 0).inverse() * orig.block<3, 3>(0, 0));
116  }
117  }
118  }
119 
120  maxLinearPlatformVelocity = getProperty<float>("maxLinearPlatformVelocity").getValue();
122 
123  maxAngularPlatformVelocity = getProperty<float>("maxAngularPlatformVelocity").getValue();
125 
126  ARMARX_INFO << "using " << VAROUT(simulatorRobotListenerInterfaceTopic);
127  ARMARX_INFO << "using " << VAROUT(simulatorForceTorqueListenerInterfaceTopic);
128  ARMARX_INFO << "using " << VAROUT(controlIterationMs);
129 }
130 
131 void
133 {
134  simulatorPrx = getProxy<SimulatorInterfacePrx>(simulatorPrxName);
135  if (!rtThread.joinable())
136  {
137  rtThread = std::thread{[&] { rtTask(); }};
138  }
139 }
140 
141 void
143 {
144  shutdownRtThread = true;
145  rtThread.join();
146 }
147 
148 void
150 {
152  {
153  ARMARX_IMPORTANT << "exiting rt thread";
154  };
155  try
156  {
157  {
158  const auto timing = -TimeUtil::GetTime(true);
160  //device init
161  {
162  const auto timing = -TimeUtil::GetTime(true);
163  //joints
164  {
165  const auto timing = -TimeUtil::GetTime(true);
166  ARMARX_INFO << "adding devices for joints:";
167  for (const VirtualRobot::RobotNodePtr& node : *(robot->getRobotNodeSet(
168  getProperty<std::string>("RobotNodeSetName").getValue())))
169  {
170  if (node->isJoint())
171  {
172  JointSimulationDevicePtr jdev = std::make_shared<JointSimulationDevice>(
173  node->getName(), anglesCtrl, velocitiesCtrl, torquesCtrl);
174  jointDevs.add(jdev->getDeviceName(), jdev);
175  addSensorDevice(jdev);
176  addControlDevice(jdev);
177  }
178  }
179  ARMARX_INFO << "adding devices for joints done ("
180  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
181  }
182  //platform
183  {
184  const auto timing = -TimeUtil::GetTime(true);
185  ARMARX_INFO << "adding devices for the platform:";
186 
187  if (getRobotPlatformName().empty())
188  {
190  << "No platform device will be created since platform name was given";
191  }
192  else
193  {
194  if (robot->hasRobotNode(getRobotPlatformName()))
195  {
196  platformDev =
197  std::make_shared<PlatformSimulationDevice>(getRobotPlatformName());
198  addSensorDevice(platformDev);
199  addControlDevice(platformDev);
200  }
201  else
202  {
203  ARMARX_WARNING << "No robot node with the name '" +
205  "' so no platform device will be created";
206  }
207  }
208  ARMARX_INFO << "adding devices for the platform done ("
209  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
210  }
211  //force torque
212  {
213  const auto timing = -TimeUtil::GetTime(true);
214  ARMARX_INFO << "adding devices for force torque sensors:";
215  for (const auto& ft : robot->getSensors<VirtualRobot::ForceTorqueSensor>())
216  {
217  ForceTorqueSimulationSensorDevicePtr ftdev =
218  std::make_shared<ForceTorqueSimulationSensorDevice>(
219  getMappedFTName(ft->getName()),
220  getMappedFTReportingFrame(ft->getName(),
221  ft->getRobotNode()->getName()),
222  getMappedFTReportingTransformation(ft->getName()));
223  addSensorDevice(ftdev);
224  forceTorqueDevs.add(ftdev->getDeviceName(), ftdev);
225  }
226  ARMARX_INFO << "adding devices for force torque done ("
227  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
228  }
229  //global pose device
230  {
231  // globalPoseDevice = std::make_shared<GlobalRobotPoseSimulationSensorDevice>();
232  // addSensorDevice(globalPoseDevice);
233  }
234  ARMARX_INFO << "transitioning to " << RobotUnitState::InitializingUnits
235  << std::flush;
237  ARMARX_INFO << "device init done ("
238  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
239  ARMARX_INFO << "transitioned to " << getRobotUnitState() << std::flush;
240  }
241  //unit init
242  {
243  const auto timing = -TimeUtil::GetTime(true);
244  //resize my tripple buffers
245  {
246  const auto timing = -TimeUtil::GetTime(true);
247  torquesTB.reinit(std::vector<float>(jointDevs.size(), 0));
248  anglesTB.reinit(std::vector<float>(jointDevs.size(), 0));
249  velocitiesTB.reinit(std::vector<float>(jointDevs.size(), 0));
250  forceTorqueTB.reinit(std::vector<FT>(forceTorqueDevs.size(), FT{}));
251  forceTorqueTimes.clear();
252  forceTorqueTimes.resize(forceTorqueDevs.size(), 0);
254  ARMARX_INFO << "resize buffers done ("
255  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
256  }
258  << std::flush;
260  ARMARX_INFO << "transitioned to " << getRobotUnitState() << std::flush;
261  ARMARX_INFO << "unit init done ("
262  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
263  }
264  //get initial sensor values
265  {
266  const auto timing = -TimeUtil::GetTime(true);
267  gotSensorData = false;
268  ARMARX_INFO << "fetching initial robot state" << std::flush;
269  rtUpdateSensors(true);
270  ARMARX_INFO << "fetching initial robot done" << std::flush;
271  if (platformDev)
272  {
273  const float absolutePositionX = robPoseTB.getReadBuffer()(0, 3);
274  const float absolutePositionY = robPoseTB.getReadBuffer()(1, 3);
275  const float absolutePositionRotation =
276  VirtualRobot::MathTools::eigen4f2rpy(robPoseTB.getReadBuffer())(2);
277 
278  platformDev->initAbsolutePositionX = absolutePositionX;
279  platformDev->initAbsolutePositionY = absolutePositionY;
280  platformDev->initAbsolutePositionRotation = absolutePositionRotation;
281  }
282  ARMARX_INFO << "get init sensor values done ("
283  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
284  }
285  //enter RT
286  {
287  if (synchronizedSimulation)
288  {
289  simulatorPrx->stop();
290  ARMARX_IMPORTANT << "using synchronized simulator execution" << std::flush;
291  }
292  ARMARX_INFO << "now transitioning to rt" << std::flush;
293  {
294  const auto timing = -TimeUtil::GetTime(true);
296  ARMARX_INFO << "init rt thread done ("
297  << (timing + TimeUtil::GetTime(true)).toMicroSeconds() << " us)";
298  }
299  ARMARX_INFO << "transitioned to " << getRobotUnitState() << std::flush;
300  }
301  ARMARX_INFO << "pre loop done (" << (timing + TimeUtil::GetTime(true)).toMicroSeconds()
302  << " us)";
303  }
304  //meassure time
305  IceUtil::Time timeSinceLastIteration;
306  IceUtil::Time currentIterationStart;
307  IceUtil::Time lastIterationStart = TimeUtil::GetTime();
308  //loop
309  while (!shutdownRtThread)
310  {
312  //time
313  currentIterationStart = TimeUtil::GetTime();
314  timeSinceLastIteration = currentIterationStart - lastIterationStart;
315  lastIterationStart = currentIterationStart;
316  //call functions
317  rtSwitchControllerSetup(); // << switch controllers
319  rtRunNJointControllers(sensorValuesTimestamp,
320  timeSinceLastIteration); // << run NJointControllers
321  rtHandleInvalidTargets(); // << deactivate broken NJointControllers
322  rtRunJointControllers(sensorValuesTimestamp,
323  timeSinceLastIteration); // << run JointControllers
324  //communicate with the simulator
325  {
328  {
330  };
331  rtSendCommands();
332  //run sim
333  if (synchronizedSimulation)
334  {
335  gotSensorData = false;
336  simulatorPrx->step();
337  }
338  rtUpdateSensors(synchronizedSimulation);
339  }
341  sensorValuesTimestamp,
342  timeSinceLastIteration); // << swap out ControllerTargets / SensorValues
343  ++iterationCount;
345  //sleep remainder
346  //since the timeserver does not end the sleep on shutdown (and this would block shutdown),
347  //we do busy waiting and poll the time
348  const IceUtil::Time sleepUntil = currentIterationStart + controlIterationMs;
349  IceUtil::Time currentTime = TimeUtil::GetTime();
350  while (currentTime < sleepUntil)
351  {
352  if (shutdownRtThread)
353  {
354  return;
355  }
356  if (currentTime < currentIterationStart)
357  {
358  //this fixes sleeping for a long time
359  //in case the time server is reset
360  break;
361  }
362  std::this_thread::sleep_for(
363  std::chrono::microseconds{100}); //polling is done with 10kHz
364  currentTime = TimeUtil::GetTime();
365  }
366  }
367  }
368  catch (Ice::Exception& e)
369  {
370  ARMARX_ERROR << "exception in rtTask!\nwhat:\n"
371  << e.what() << "\n\tname: " << e.ice_id() << "\n\tfile: " << e.ice_file()
372  << "\n\tline: " << e.ice_line() << "\n\tstack: " << e.ice_stackTrace()
373  << std::flush;
374  throw;
375  }
376  catch (std::exception& e)
377  {
378  ARMARX_ERROR << "exception in rtTask!\nwhat:\n" << e.what() << std::flush;
379  throw;
380  }
381  catch (...)
382  {
383  ARMARX_ERROR << "exception in rtTask!" << std::flush;
384  throw;
385  }
386 }
387 
388 void
389 RobotUnitSimulation::reportState(const SimulatedRobotState& state, const Ice::Current&)
390 {
391  IceUtil::Time timestamp = IceUtil::Time::microSeconds(state.timestampInMicroSeconds);
392 
394  {
395  simulationDataTimestampInMicroSeconds = state.timestampInMicroSeconds;
396  }
397  else
398  {
400  }
401 
402  fillTB(anglesTB, state.jointAngles, "JointAngles");
403  fillTB(velocitiesTB, state.jointVelocities, "JointVelocities");
404  fillTB(torquesTB, state.jointTorques, "JointTorques");
405 
406  for (ForceTorqueData const& ftData : state.forceTorqueValues)
407  {
408  updateForceTorque(ftData, timestamp);
409  }
410 
411  // Pose
412  if (skipReport())
413  {
414  ARMARX_DEBUG << deactivateSpam() << "Skipped all sensor values for robot pose";
415  }
416  else
417  {
418  auto g = robPoseTB.guard();
419  ARMARX_CHECK_NOT_NULL(state.pose)
420  << "Robot Pose is not allowed to be NULL. Maybe no state was reported from Simulator!";
421  robPoseTB.getWriteBuffer() = PosePtr::dynamicCast(state.pose)->toEigen();
422  robPoseTB.write();
423  ARMARX_DEBUG << deactivateSpam() << "Got sensor values for robot pose";
424  }
425 
426  if (skipReport())
427  {
428  ARMARX_DEBUG << deactivateSpam() << "Skipped all sensor values for robot vel";
429  return;
430  }
431  else
432  {
433  auto& trans = state.linearVelocity;
434  auto& rotat = state.angularVelocity;
435 
436  auto g = robVelTB.guard();
437  robVelTB.getWriteBuffer().lin(0) = trans->x;
438  robVelTB.getWriteBuffer().lin(1) = trans->y;
439  robVelTB.getWriteBuffer().lin(2) = trans->z;
440  robVelTB.getWriteBuffer().lin =
441  robPoseTB.getReadBuffer().block<3, 3>(0, 0).transpose() * robVelTB.getWriteBuffer().lin;
442  robVelTB.getWriteBuffer().ang(0) = rotat->x;
443  robVelTB.getWriteBuffer().ang(1) = rotat->y;
444  robVelTB.getWriteBuffer().ang(2) = rotat->z;
445  robVelTB.getWriteBuffer().ang =
446  robPoseTB.getReadBuffer().block<3, 3>(0, 0).transpose() * robVelTB.getWriteBuffer().ang;
447  robVelTB.write();
448  ARMARX_DEBUG << deactivateSpam() << "Got sensor values for robot vel";
449  }
450 
451  gotSensorData = true;
452 }
453 
454 void
455 RobotUnitSimulation::updateForceTorque(const ForceTorqueData& ftData, IceUtil::Time timestamp)
456 {
457  auto& sensorName = ftData.sensorName;
458  auto& nodeName = ftData.nodeName;
459 
460  const std::string sensname =
461  ftMappings.count(sensorName) ? ftMappings.at(sensorName).sensorName : sensorName;
462  if (ftMappings.count(sensorName) && ftMappings.at(sensorName).originalReportFrame != nodeName)
463  {
464  ARMARX_ERROR << deactivateSpam(0.25) << "Sensor values for sensor '" << sensorName << "' ('"
465  << sensname << "') are reported in frame '" << nodeName << "' instead of '"
466  << ftMappings.at(sensorName).originalReportFrame
467  << "' as defined during setup! (this value is skipped!)";
468  return;
469  }
470  if (skipReport())
471  {
472  ARMARX_DEBUG << deactivateSpam(10, sensname)
473  << "Skipped all sensor values for force torque of sensor " << sensname
474  << " (node = " << nodeName << ")";
475  return;
476  }
477  auto g = forceTorqueTB.guard();
478  if (!forceTorqueDevs.has(sensname))
479  {
480  ARMARX_WARNING << deactivateSpam(10, sensname) << "no ftsensor with name " << sensname
481  << "\nftsensors:\n"
482  << forceTorqueDevs.keys();
483  return;
484  }
485  auto i = forceTorqueDevs.index(sensname);
486  ARMARX_CHECK_EXPRESSION(forceTorqueTB.getWriteBuffer().size() > i)
487  << forceTorqueTB.getWriteBuffer().size() << " > " << i;
488  auto& force = ftData.force;
489  auto& torque = ftData.torque;
490  ForceTorqueSimulationSensorDevice& ftdev = *forceTorqueDevs.at(i);
491  ftdev.fx.update(force->x);
492  ftdev.fy.update(force->y);
493  ftdev.fz.update(force->z);
494  ftdev.tx.update(torque->x);
495  ftdev.ty.update(torque->y);
496  ftdev.tz.update(torque->z);
497 
498  Eigen::Vector3f filteredTorque;
499  Eigen::Vector3f filteredForce;
500  filteredForce(0) = ftdev.fx.getRawValue();
501  filteredForce(1) = ftdev.fy.getRawValue();
502  filteredForce(2) = ftdev.fz.getRawValue();
503  filteredTorque(0) = ftdev.tx.getRawValue();
504  filteredTorque(1) = ftdev.ty.getRawValue();
505  filteredTorque(2) = ftdev.tz.getRawValue();
506 
507  forceTorqueTB.getWriteBuffer().at(i).force = ftdev.reportingTransformation * filteredForce;
508  forceTorqueTB.getWriteBuffer().at(i).torque = ftdev.reportingTransformation * filteredTorque;
509  forceTorqueTB.write();
510  forceTorqueTimes.at(i) = timestamp.toMicroSeconds() * 1000; // Nanoseconds
511  ARMARX_DEBUG << deactivateSpam(10, sensname)
512  << "Got new sensor values for force torque of sensor " << sensname
513  << " (node = " << nodeName << ")";
514 }
515 
516 void
517 RobotUnitSimulation::fillTB(TripleBufferWithGuardAndTime<std::vector<float>>& b,
518  const NameValueMap& nv,
519  const std::string name) const
520 {
521  if (skipReport())
522  {
523  ARMARX_DEBUG << deactivateSpam(10, name) << "Skipped all sensor values for " << name;
524  return;
525  }
526  auto g = b.guard();
527  std::stringstream ignored;
528  bool someWereIgnored = false;
529  for (const auto& a : nv)
530  {
531  if (jointDevs.has(a.first))
532  {
533  b.getWriteBuffer().at(jointDevs.index(a.first)) = a.second;
534  }
535  else
536  {
537  ignored << a.first << " -> " << a.second << "\n";
538  someWereIgnored = true;
539  }
540  }
541  b.write();
542  ARMARX_DEBUG << deactivateSpam(10, name) << "Got new sensor values for " << name;
543  if (someWereIgnored)
544  {
545  ARMARX_VERBOSE << deactivateSpam(10, name) << "Ignored sensor values for " << name << ":\n"
546  << ignored.str();
547  }
548 }
549 
550 void
551 RobotUnitSimulation::rtSendCommands()
552 {
553  try
554  {
555  auto prx = simulatorPrx->ice_batchOneway();
556  //send commands
557  if (!velocitiesCtrl.empty())
558  {
559  prx->actuateRobotJointsVel(robotName, velocitiesCtrl);
560  }
561  if (!anglesCtrl.empty())
562  {
563  prx->actuateRobotJointsPos(robotName, anglesCtrl);
564  }
565  if (!torquesCtrl.empty())
566  {
567  prx->actuateRobotJointsTorque(robotName, torquesCtrl);
568  }
569 
570  if (platformDev)
571  {
572  Eigen::Vector3f translationVel;
573  translationVel(0) = std::clamp(platformDev->target.velocityX,
576  translationVel(1) = std::clamp(platformDev->target.velocityY,
579  translationVel(2) = 0;
580  translationVel /= 1000;
581 
582  Eigen::Vector3f rotationVel(0.f,
583  0.f,
584  std::clamp(platformDev->target.velocityRotation,
587 
588  prx->setRobotLinearVelocityRobotRootFrame(
589  robotName, platformDev->getDeviceName(), new Vector3(translationVel));
590  prx->setRobotAngularVelocityRobotRootFrame(
591  robotName, platformDev->getDeviceName(), new Vector3(rotationVel));
593  << "setting platform vel ang: " << rotationVel.transpose();
595  << "setting platform vel lin: " << translationVel.transpose();
596  }
597  prx->ice_flushBatchRequests();
598  }
599  catch (Ice::ConnectionRefusedException&)
600  {
601  if (!shutdownRtThread)
602  {
603  //ignore this when shutting down. this probably happened when the simulator
604  //was shut down while the RobotUnitSimulation was still running
606  << "Ice::ConnectionRefusedException when sending commands to the simulator";
607  }
608  }
609  catch (Ice::NotRegisteredException&)
610  {
611  if (!shutdownRtThread)
612  {
613  //ignore this when shutting down. this probably happened when the simulator
614  //was shut down while the RobotUnitSimulation was still running
615  ARMARX_WARNING << "Ice::NotRegisteredException when sending commands to the simulator";
616  }
617  }
618 }
619 
620 bool
621 RobotUnitSimulation::skipReport() const
622 {
623  static const std::set<RobotUnitState> reportAcceptingStates{
625  return !reportAcceptingStates.count(getRobotUnitState());
626 }
627 
628 void
629 RobotUnitSimulation::rtPollRobotState()
630 {
631  if (!isPolling.exchange(true))
632  {
633  std::thread{[&]
634  {
635  try
636  {
637  const auto name = getRobotName();
638  auto rootname = robot->getRootNode()->getName();
639  SimulatedRobotState state = simulatorPrx->getRobotState(robotName);
640 
641  reportState(state);
642  }
643  catch (Ice::Exception& e)
644  {
645  ARMARX_ERROR << "exception in polling!\nwhat:\n"
646  << e.what() << "\n\tname: " << e.ice_id()
647  << "\n\tfile: " << e.ice_file()
648  << "\n\tline: " << e.ice_line()
649  << "\n\tstack: " << e.ice_stackTrace() << std::flush;
650  throw;
651  }
652  catch (std::exception& e)
653  {
654  ARMARX_ERROR << "exception in polling!\nwhat:\n"
655  << e.what() << std::flush;
656  throw;
657  }
658  catch (...)
659  {
660  ARMARX_ERROR << "exception in polling!" << std::flush;
661  throw;
662  }
663  isPolling = false;
664  }}
665  .detach();
666  }
667 }
668 
669 void
670 RobotUnitSimulation::componentPropertiesUpdated(const std::set<std::string>& changedProperties)
671 {
672  RobotUnit::componentPropertiesUpdated(changedProperties);
673  if (changedProperties.count("SynchronizedSimulation"))
674  {
675  synchronizedSimulation = getProperty<bool>("SynchronizedSimulation").getValue();
676  }
677  if (areDevicesReady())
678  {
679  if (synchronizedSimulation)
680  {
681  simulatorPrx->stop();
682  ARMARX_IMPORTANT << "using synchronized simulator execution" << std::flush;
683  }
684  else
685  {
686  simulatorPrx->start();
687  ARMARX_IMPORTANT << "using synchronized simulator execution" << std::flush;
688  }
689  }
690 }
691 
692 void
693 RobotUnitSimulation::rtUpdateSensors(bool wait)
694 {
695  //wait for all new data
696  if (wait)
697  {
698  std::mutex dummy;
699  std::unique_lock<std::mutex> dummlock{dummy};
700  std::size_t fails = 0;
701  while (!gotSensorData)
702  {
704  << "waiting for up to date sensor values (iteration " << iterationCount
705  << ") ";
706  cvGotSensorData.wait_for(dummlock, std::chrono::milliseconds{10});
707  ++fails;
708  if (!(fails % 10))
709  {
710  rtPollRobotState();
711  }
712  }
713  }
714 
715  // This should be the timestamp from the time where the data was queried
716  // We have to use armarx::rtNow() now because of changes in the framework to assess the timestamp in
717  // a realtime-conform way (using MONOTONIC_RAW clock, which is the time difference since last boot).
718  // This probably breaks simulation speeds faster than realtime, but this feature probably was broken
719  // before anyways. See https://git.h2t.iar.kit.edu/sw/armarx/armarx-simulation/-/issues/26.
720  const IceUtil::Time now = armarx::rtNow();
721  //const IceUtil::Time now = IceUtil::Time::microSeconds(simulationDataTimestampInMicroSeconds);
722  const IceUtil::Time timeSinceLastIteration = now - sensorValuesTimestamp;
723  const float dt = static_cast<float>(timeSinceLastIteration.toSecondsDouble());
724  sensorValuesTimestamp = now;
725  torquesTB.read();
726  anglesTB.read();
727  velocitiesTB.read();
728  robPoseTB.read();
729  robVelTB.read();
730  forceTorqueTB.read();
731  //update joint sensors
732  for (std::size_t i = 0; i < jointDevs.size(); ++i)
733  {
734  JointSimulationDevice& jdev = *jointDevs.at(i);
735  const float deltav = velocitiesTB.getReadBuffer().at(i) - jdev.sensorValue.velocity;
736  jdev.sensorValue.acceleration = deltav / dt;
737  jdev.sensorValue.position = anglesTB.getReadBuffer().at(i);
738  jdev.sensorValue.torque = torquesTB.getReadBuffer().at(i);
739  jdev.sensorValue.velocity = velocitiesTB.getReadBuffer().at(i);
740  }
741 
742  //ft
743  for (std::size_t i = 0; i < forceTorqueDevs.size(); ++i)
744  {
745  ForceTorqueSimulationSensorDevice& ft = *forceTorqueDevs.at(i);
746  ft.sensorValue.force = forceTorqueTB.getReadBuffer().at(i).force;
747  ft.sensorValue.torque = forceTorqueTB.getReadBuffer().at(i).torque;
748  }
749  //platform
750  if (platformDev)
751  {
752  auto& s = platformDev->sensorValue;
753 
754  const float absolutePositionX = robPoseTB.getReadBuffer()(0, 3);
755  const float absolutePositionY = robPoseTB.getReadBuffer()(1, 3);
756  const float absolutePositionRotation =
757  VirtualRobot::MathTools::eigen4f2rpy(robPoseTB.getReadBuffer())(2);
758 
759  Eigen::Vector2f relativePositionGlobalFrame;
760  relativePositionGlobalFrame << absolutePositionX - platformDev->initAbsolutePositionX,
761  absolutePositionY - platformDev->initAbsolutePositionY;
762  s.relativePositionRotation =
763  absolutePositionRotation - platformDev->initAbsolutePositionRotation;
764  // Revert the rotation by rotating by the negative angle
765  Eigen::Vector2f relativePosition =
766  Eigen::Rotation2Df(-platformDev->initAbsolutePositionRotation) *
767  relativePositionGlobalFrame;
768  s.relativePositionX = relativePosition(0);
769  s.relativePositionY = relativePosition(1);
770 
771  const RobVel& v = robVelTB.getReadBuffer();
772  s.setVelocitiesAndDeriveAcceleration(v.lin(0) / 3.f, v.lin(1) / 3.f, v.ang(2) / 5.0f, dt);
773  }
774  //globalpose
775  // globalPoseDevice->sensor.pose = robPoseTB.getReadBuffer();
776 
777  rtSetRobotGlobalPose(robPoseTB.getReadBuffer(), false);
778  //this call should not do anything in this case, since sensors are updated above
779  rtReadSensorDeviceValues(sensorValuesTimestamp, timeSinceLastIteration);
780 }
armarx::TripleBufferWithGuardAndTime::getReadBuffer
const T & getReadBuffer() const
Definition: RobotUnitSimulation.h:96
armarx::RobotUnitModule::Units::initializeDefaultUnits
virtual void initializeDefaultUnits()
Calls all init hooks for all managed Units.
Definition: RobotUnitModuleUnits.cpp:201
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::KeyValueVector::keys
KeyContT const & keys() const
Definition: KeyValueVector.h:179
armarx::ForceTorqueSimulationSensorDevice::fx
filters::ButterworthFilter fx
Definition: ForceTorqueSimulationSensorDevice.h:58
armarx::RobotUnitSimulation::rtThread
std::thread rtThread
Definition: RobotUnitSimulation.h:231
armarx::RobotUnitModule::ControlThread::rtRunNJointControllers
void rtRunNJointControllers(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
Runs NJoint controllers.
Definition: RobotUnitModuleControlThread.cpp:580
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
armarx::RTThreadTimingsSensorDevice::rtMarkRtBusSendReceiveStart
virtual void rtMarkRtBusSendReceiveStart()=0
OnScopeExit.h
armarx::KeyValueVector::at
ValT & at(IdxT i)
Definition: KeyValueVector.h:115
armarx::RobotUnitSimulation::simulatorPrxName
std::string simulatorPrxName
Definition: RobotUnitSimulation.h:234
armarx::TripleBufferWithGuardAndTime::write
void write()
Definition: RobotUnitSimulation.h:102
armarx::filters::ButterworthFilter::update
void update(Ice::Long, const VariantBasePtr &value, const Ice::Current &=Ice::emptyCurrent) override
Definition: ButterworthFilter.cpp:104
armarx::RobotUnitSimulation::reportState
void reportState(SimulatedRobotState const &state, const Ice::Current &=Ice::emptyCurrent) override
Definition: RobotUnitSimulation.cpp:389
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
armarx::KeyValueVector::size
IdxT size() const
Definition: KeyValueVector.h:158
armarx::ForceTorqueSimulationSensorDevice::ty
filters::ButterworthFilter ty
Definition: ForceTorqueSimulationSensorDevice.h:56
armarx::KeyValueVector::has
bool has(const KeyT &k) const
Definition: KeyValueVector.h:193
armarx::Split
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelperTemplates.h:36
armarx::TripleBufferWithGuardAndTime::guard
std::unique_lock< std::recursive_mutex > guard()
Definition: RobotUnitSimulation.h:66
armarx::RTThreadTimingsSensorDevice::rtMarkRtLoopPreSleep
virtual void rtMarkRtLoopPreSleep()=0
armarx::RobotUnitSimulation::maxAngularPlatformVelocity
float maxAngularPlatformVelocity
Definition: RobotUnitSimulation.h:238
armarx::ForceTorqueSimulationSensorDevice::reportingTransformation
const Eigen::Matrix3f reportingTransformation
Definition: ForceTorqueSimulationSensorDevice.h:63
armarx::RobotUnitModule::Devices::rtGetRTThreadTimingsSensorDevice
RTThreadTimingsSensorDevice & rtGetRTThreadTimingsSensorDevice()
Returns the SensorDevice used to log timings in the ControlThread.
Definition: RobotUnitModuleDevices.h:411
armarx::KeyValueVector::index
IdxT index(const KeyT &k) const
Definition: KeyValueVector.h:108
ARMARX_ON_SCOPE_EXIT
#define ARMARX_ON_SCOPE_EXIT
Executes given code when the enclosing scope is left.
Definition: OnScopeExit.h:120
armarx::RobotUnitModule::ControlThread::rtReadSensorDeviceValues
void rtReadSensorDeviceValues(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
Calls SensorDevice::rtReadSensorValues for all SensorDevices.
Definition: RobotUnitModuleControlThread.cpp:534
armarx::JointSimulationDevice
Definition: JointSimulationDevice.h:36
armarx::RobotUnitModule::ControlThread::rtSetRobotGlobalPose
void rtSetRobotGlobalPose(const Eigen::Matrix4f &gp, bool updateRobot=true)
Definition: RobotUnitModuleControlThread.cpp:1231
armarx::RobotUnitModule::ModuleBase::getRobotUnitState
RobotUnitState getRobotUnitState() const
Returns the RobotUnit's State.
Definition: RobotUnitModuleBase.ipp:29
armarx::SensorValueForceTorque::force
Eigen::Vector3f force
Definition: SensorValueForceTorque.h:36
clamp
double clamp(double x, double a, double b)
Definition: point.hpp:136
cxxopts::empty
bool empty(const std::string &s)
Definition: cxxopts.hpp:234
armarx::RTThreadTimingsSensorDevice::rtMarkRtLoopStart
virtual void rtMarkRtLoopStart()=0
armarx::RobotUnitModule::ModuleBase::finishUnitInitialization
virtual void finishUnitInitialization()
Transition RobotUnitState::InitializingUnits -> RobotUnitState::WaitingForRTThreadInitialization.
Definition: RobotUnitModuleBase.cpp:270
armarx::ForceTorqueSimulationSensorDevice::fz
filters::ButterworthFilter fz
Definition: ForceTorqueSimulationSensorDevice.h:60
armarx::RobotUnitState::InitializingUnits
@ InitializingUnits
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::RobotUnitModule::ControlThread::rtRunJointControllers
void rtRunJointControllers(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
Runs Joint controllers and writes target values to ControlDevices.
Definition: RobotUnitModuleControlThread.cpp:568
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
armarx::RobotUnitState::Running
@ Running
armarx::RobotUnitSimulation::robot
VirtualRobot::RobotPtr robot
Definition: RobotUnitSimulation.h:240
armarx::RobotUnitModule::ModuleBase::componentPropertiesUpdated
void componentPropertiesUpdated(const std::set< std::string > &changedProperties) override
Definition: RobotUnitModuleBase.cpp:207
armarx::KeyValueVector::add
void add(KeyT key, ValT value)
Definition: KeyValueVector.h:95
armarx::TimeUtil::HasTimeServer
static bool HasTimeServer()
check if we have been initialized with a Timeserver
Definition: TimeUtil.cpp:124
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::TripleBufferWithGuardAndTime::reinit
void reinit(const T &i)
Definition: RobotUnitSimulation.h:84
magic_enum::detail::entries
constexpr auto entries(std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:810
armarx::Vector3
The Vector3 class.
Definition: Pose.h:112
armarx::RobotUnitModule::ModuleBase::finishControlThreadInitialization
virtual void finishControlThreadInitialization()
Transition RobotUnitState::InitializingControlThread -> RobotUnitState::Running.
Definition: RobotUnitModuleBase.cpp:291
armarx::RobotUnitModule::ControlThread::rtSwitchControllerSetup
bool rtSwitchControllerSetup(SwitchControllerMode mode=SwitchControllerMode::IceRequests)
Changes the set of active controllers.
Definition: RobotUnitModuleControlThread.cpp:293
armarx::RobotUnitSimulation::onConnectRobotUnit
void onConnectRobotUnit() override
called in onConnectComponent
Definition: RobotUnitSimulation.cpp:132
timestamp
std::string timestamp()
Definition: CartographerAdapter.cpp:85
armarx::SensorValueForceTorque::torque
DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION Eigen::Vector3f torque
Definition: SensorValueForceTorque.h:35
armarx::RobotUnitModule::Devices::addSensorDevice
void addSensorDevice(const SensorDevicePtr &sd)
Adds a SensorDevice to the robot.
Definition: RobotUnitModuleDevices.cpp:377
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::RobotUnitSimulation::robotName
std::string robotName
Definition: RobotUnitSimulation.h:235
ARMARX_CHECK_POSITIVE
#define ARMARX_CHECK_POSITIVE(number)
This macro evaluates whether number is positive (> 0) and if it turns out to be false it will throw a...
Definition: ExpressionException.h:145
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::RobotUnitState::InitializingControlThread
@ InitializingControlThread
armarx::TripleBufferWithGuardAndTime
Definition: RobotUnitSimulation.h:59
armarx::RobotUnitModule::ControlThread::rtHandleInvalidTargets
void rtHandleInvalidTargets()
Deactivates all NJointControllers generating invalid targets.
Definition: RobotUnitModuleControlThread.cpp:511
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
armarx::ForceTorqueSimulationSensorDevice::tx
filters::ButterworthFilter tx
Definition: ForceTorqueSimulationSensorDevice.h:55
armarx::TripleBufferWithGuardAndTime::getWriteBuffer
T & getWriteBuffer()
Definition: RobotUnitSimulation.h:90
armarx::RobotUnitModule::RobotData::getRobotPlatformName
const std::string & getRobotPlatformName() const
Returns the name of the robot's platform.
Definition: RobotUnitModuleRobotData.cpp:77
ExpressionException.h
armarx::control::njoint_controller::platform::platform_follower_controller::NameValueMap
std::map< std::string, float > NameValueMap
Definition: PlatformFollowerController.h:88
armarx::ManagedIceObject::usingTopic
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
Definition: ManagedIceObject.cpp:254
armarx::RobotUnitModule::Devices::addControlDevice
void addControlDevice(const ControlDevicePtr &cd)
Adds a ControlDevice to the robot.
Definition: RobotUnitModuleDevices.cpp:335
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
armarx::RobotUnitModule::ControlThread::rtResetAllTargets
void rtResetAllTargets()
Calls JointController::rtResetTarget for all active Joint controllers.
Definition: RobotUnitModuleControlThread.cpp:500
armarx::SensorDeviceTemplate::sensorValue
SensorValueType sensorValue
Definition: SensorDevice.h:123
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
armarx::ForceTorqueSimulationSensorDevice
Definition: ForceTorqueSimulationSensorDevice.h:34
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::RobotUnitSimulation::joinControlThread
void joinControlThread() override
Implementations have to join their ControlThread in this hook. (used by RobotUnit::finishRunning())
Definition: RobotUnitSimulation.cpp:142
armarx::RobotUnitModule::ModuleBase::areDevicesReady
bool areDevicesReady() const
Returns whether Devices are ready.
Definition: RobotUnitModuleBase.cpp:405
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
armarx::ForceTorqueSimulationSensorDevice::tz
filters::ButterworthFilter tz
Definition: ForceTorqueSimulationSensorDevice.h:57
armarx::RTThreadTimingsSensorDevice::rtMarkRtBusSendReceiveEnd
virtual void rtMarkRtBusSendReceiveEnd()=0
armarx::RobotUnitSimulation::rtTask
void rtTask()
Definition: RobotUnitSimulation.cpp:149
armarx::ForceTorqueSimulationSensorDevice::fy
filters::ButterworthFilter fy
Definition: ForceTorqueSimulationSensorDevice.h:59
armarx::RobotUnitModule::ControlThread::rtUpdateSensorAndControlBuffer
void rtUpdateSensorAndControlBuffer(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
Updates the current SensorValues and ControlTargets for code running outside of the ControlThread.
Definition: RobotUnitModuleControlThread.cpp:855
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::RobotUnitSimulation::simulatorPrx
SimulatorInterfacePrx simulatorPrx
Definition: RobotUnitSimulation.h:232
armarx::TripleBufferWithGuardAndTime::read
void read()
Definition: RobotUnitSimulation.h:111
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::transpose
std::vector< std::vector< T > > transpose(const std::vector< std::vector< T >> &src, Thrower thrower)
Definition: SimoxCSpace.cpp:772
armarx::RobotUnitSimulation::simulationDataTimestampInMicroSeconds
std::atomic< long > simulationDataTimestampInMicroSeconds
Definition: RobotUnitSimulation.h:233
armarx::RobotUnitSimulation::maxLinearPlatformVelocity
float maxLinearPlatformVelocity
Definition: RobotUnitSimulation.h:237
armarx::filters::ButterworthFilter::getRawValue
double getRawValue() const
Definition: ButterworthFilter.cpp:161
armarx::RobotUnitModule::RobotData::cloneRobot
VirtualRobot::RobotPtr cloneRobot(bool updateCollisionModel=false) const
Returns a clone of the robot's model.
Definition: RobotUnitModuleRobotData.cpp:129
armarx::RobotUnitSimulation::onInitRobotUnit
void onInitRobotUnit() override
called in onInitComponent
Definition: RobotUnitSimulation.cpp:39
RobotUnitSimulation.h
armarx::RobotUnitModule::RobotData::getRobotName
std::string getRobotName() const
Returns the robot's name.
Definition: RobotUnitModuleRobotData.cpp:119
armarx::RobotUnitModule::ModuleBase::finishDeviceInitialization
virtual void finishDeviceInitialization()
Transition RobotUnitState::InitializingDevices -> RobotUnitState::InitializingUnits.
Definition: RobotUnitModuleBase.cpp:249
armarx::ManagedIceObject::usingProxy
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Definition: ManagedIceObject.cpp:154
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::RobotUnitSimulation::shutdownRtThread
std::atomic_bool shutdownRtThread
Definition: RobotUnitSimulation.h:230
dt
constexpr T dt
Definition: UnscentedKalmanFilterTest.cpp:45
armarx::RobotUnitSimulation::componentPropertiesUpdated
void componentPropertiesUpdated(const std::set< std::string > &changedProperties) override
Definition: RobotUnitSimulation.cpp:670
armarx::rtNow
IceUtil::Time rtNow()
Definition: RtTiming.h:40