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