28#include <VirtualRobot/MathTools.h>
29#include <VirtualRobot/Nodes/ForceTorqueSensor.h>
30#include <VirtualRobot/RobotNodeSet.h>
46 simulatorRobotListenerInterfaceTopic =
48 if (simulatorRobotListenerInterfaceTopic.empty())
50 simulatorRobotListenerInterfaceTopic =
"Simulator_Robot_" +
getRobotName();
52 simulatorForceTorqueListenerInterfaceTopic =
55 if (!controlIterationMsProp)
57 ARMARX_WARNING <<
"the controll iteration was set to 0ms. detting it to 1ms";
58 controlIterationMsProp = 1;
60 controlIterationMs = IceUtil::Time::milliSeconds(controlIterationMsProp);
61 usingTopic(simulatorRobotListenerInterfaceTopic);
62 usingTopic(simulatorForceTorqueListenerInterfaceTopic);
67 std::vector<std::string> entries;
70 bool trimEntries =
true;
71 entries =
Split(mappingStr,
",", trimEntries);
73 for (std::string entry : entries)
76 <<
"empty entry in ForceTorqueSensorMapping! entries:\n"
78 bool trimFields =
true;
79 std::vector<std::string> fields =
Split(entry,
":", trimFields);
81 <<
"invalid entry in ForceTorqueSensorMapping! invalid entry:\n"
82 << fields <<
"\nall entries:\n"
84 for (
auto& field : fields)
87 <<
"empty field in ForceTorqueSensorMapping entry! invalid entry:\n"
88 << fields <<
"\nall entries:\n"
91 const VirtualRobot::ForceTorqueSensorPtr ftsensor =
92 robot->getSensor<
typename VirtualRobot::ForceTorqueSensor>(fields.at(0));
95 ARMARX_WARNING <<
"the robot has not ft sensor of name '" << fields.at(0)
96 <<
"' this ForceTorqueSensorMapping entry has no effect: " << entry;
100 <<
VAROUT(fields.size()) <<
" "
101 << (fields.size() != 2 ?
VAROUT(fields.at(2)) : std::string{});
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)
110 mapping.reportFrame = fields.at(2);
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));
167 for (
const VirtualRobot::RobotNodePtr& node : *(
robot->getRobotNodeSet(
172 JointSimulationDevicePtr jdev = std::make_shared<JointSimulationDevice>(
173 node->getName(), anglesCtrl, velocitiesCtrl, torquesCtrl);
174 jointDevs.add(jdev->getDeviceName(), jdev);
190 <<
"No platform device will be created since platform name was given";
205 "' so no platform device will be created";
208 ARMARX_INFO <<
"adding devices for the platform done ("
214 ARMARX_INFO <<
"adding devices for force torque sensors:";
215 for (
const auto& ft :
robot->getSensors<VirtualRobot::ForceTorqueSensor>())
217 ForceTorqueSimulationSensorDevicePtr ftdev =
218 std::make_shared<ForceTorqueSimulationSensorDevice>(
219 getMappedFTName(ft->getName()),
220 getMappedFTReportingFrame(ft->getName(),
221 ft->getRobotNode()->getName()),
222 getMappedFTReportingTransformation(ft->getName()));
224 forceTorqueDevs.add(ftdev->getDeviceName(), ftdev);
226 ARMARX_INFO <<
"adding devices for force torque done ("
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);
267 gotSensorData =
false;
268 ARMARX_INFO <<
"fetching initial robot state" << std::flush;
269 rtUpdateSensors(
true);
270 ARMARX_INFO <<
"fetching initial robot done" << std::flush;
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);
278 platformDev->initAbsolutePositionX = absolutePositionX;
279 platformDev->initAbsolutePositionY = absolutePositionY;
280 platformDev->initAbsolutePositionRotation = absolutePositionRotation;
287 if (synchronizedSimulation)
292 ARMARX_INFO <<
"now transitioning to rt" << std::flush;
305 IceUtil::Time timeSinceLastIteration;
306 IceUtil::Time currentIterationStart;
314 timeSinceLastIteration = currentIterationStart - lastIterationStart;
315 lastIterationStart = currentIterationStart;
320 timeSinceLastIteration);
323 timeSinceLastIteration);
333 if (synchronizedSimulation)
335 gotSensorData =
false;
338 rtUpdateSensors(synchronizedSimulation);
341 sensorValuesTimestamp,
342 timeSinceLastIteration);
348 const IceUtil::Time sleepUntil = currentIterationStart + controlIterationMs;
350 while (currentTime < sleepUntil)
356 if (currentTime < currentIterationStart)
362 std::this_thread::sleep_for(
363 std::chrono::microseconds{100});
368 catch (Ice::Exception& e)
371 << e.what() <<
"\n\tname: " << e.ice_id() <<
"\n\tfile: " << e.ice_file()
372 <<
"\n\tline: " << e.ice_line() <<
"\n\tstack: " << e.ice_stackTrace()
376 catch (std::exception& e)
378 ARMARX_ERROR <<
"exception in rtTask!\nwhat:\n" << e.what() << std::flush;
391 IceUtil::Time
timestamp = IceUtil::Time::microSeconds(state.timestampInMicroSeconds);
402 fillTB(anglesTB, state.jointAngles,
"JointAngles");
403 fillTB(velocitiesTB, state.jointVelocities,
"JointVelocities");
404 fillTB(torquesTB, state.jointTorques,
"JointTorques");
406 for (ForceTorqueData
const& ftData : state.forceTorqueValues)
418 auto g = robPoseTB.guard();
420 <<
"Robot Pose is not allowed to be NULL. Maybe no state was reported from Simulator!";
421 robPoseTB.getWriteBuffer() = PosePtr::dynamicCast(state.pose)->toEigen();
433 auto& trans = state.linearVelocity;
434 auto& rotat = state.angularVelocity;
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;
451 gotSensorData =
true;
455RobotUnitSimulation::updateForceTorque(
const ForceTorqueData& ftData, IceUtil::Time
timestamp)
457 auto& sensorName = ftData.sensorName;
458 auto& nodeName = ftData.nodeName;
460 const std::string sensname =
461 ftMappings.count(sensorName) ? ftMappings.at(sensorName).sensorName : sensorName;
462 if (ftMappings.count(sensorName) && ftMappings.at(sensorName).originalReportFrame != nodeName)
465 << sensname <<
"') are reported in frame '" << nodeName <<
"' instead of '"
466 << ftMappings.at(sensorName).originalReportFrame
467 <<
"' as defined during setup! (this value is skipped!)";
473 <<
"Skipped all sensor values for force torque of sensor " << sensname
474 <<
" (node = " << nodeName <<
")";
477 auto g = forceTorqueTB.guard();
478 if (!forceTorqueDevs.has(sensname))
482 << forceTorqueDevs.keys();
485 auto i = forceTorqueDevs.index(sensname);
487 << forceTorqueTB.getWriteBuffer().size() <<
" > " << i;
488 auto& force = ftData.force;
489 auto& torque = ftData.torque;
490 ForceTorqueSimulationSensorDevice& ftdev = *forceTorqueDevs.at(i);
498 Eigen::Vector3f filteredTorque;
499 Eigen::Vector3f filteredForce;
509 forceTorqueTB.write();
510 forceTorqueTimes.at(i) =
timestamp.toMicroSeconds() * 1000;
512 <<
"Got new sensor values for force torque of sensor " << sensname
513 <<
" (node = " << nodeName <<
")";
518 const NameValueMap& nv,
519 const std::string name)
const
527 std::stringstream ignored;
528 bool someWereIgnored =
false;
529 for (
const auto& a : nv)
531 if (jointDevs.has(
a.first))
533 b.getWriteBuffer().at(jointDevs.index(
a.first)) =
a.second;
537 ignored <<
a.first <<
" -> " <<
a.second <<
"\n";
538 someWereIgnored =
true;
551RobotUnitSimulation::rtSendCommands()
557 if (!velocitiesCtrl.empty())
559 prx->actuateRobotJointsVel(
robotName, velocitiesCtrl);
561 if (!anglesCtrl.empty())
563 prx->actuateRobotJointsPos(
robotName, anglesCtrl);
565 if (!torquesCtrl.empty())
567 prx->actuateRobotJointsTorque(
robotName, torquesCtrl);
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;
582 Eigen::Vector3f rotationVel(0.f,
584 std::clamp(platformDev->target.velocityRotation,
588 prx->setRobotLinearVelocityRobotRootFrame(
590 prx->setRobotAngularVelocityRobotRootFrame(
593 <<
"setting platform vel ang: " << rotationVel.transpose();
595 <<
"setting platform vel lin: " << translationVel.transpose();
597 prx->ice_flushBatchRequests();
599 catch (Ice::ConnectionRefusedException&)
606 <<
"Ice::ConnectionRefusedException when sending commands to the simulator";
609 catch (Ice::NotRegisteredException&)
615 ARMARX_WARNING <<
"Ice::NotRegisteredException when sending commands to the simulator";
621RobotUnitSimulation::skipReport()
const
623 static const std::set<RobotUnitState> reportAcceptingStates{
629RobotUnitSimulation::rtPollRobotState()
631 if (!isPolling.exchange(
true))
638 auto rootname =
robot->getRootNode()->getName();
643 catch (Ice::Exception& e)
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;
652 catch (std::exception& e)
655 << e.what() << std::flush;
673 if (changedProperties.count(
"SynchronizedSimulation"))
679 if (synchronizedSimulation)
693RobotUnitSimulation::rtUpdateSensors(
bool wait)
699 std::unique_lock<std::mutex> dummlock{dummy};
700 std::size_t fails = 0;
701 while (!gotSensorData)
704 <<
"waiting for up to date sensor values (iteration " << iterationCount
706 cvGotSensorData.wait_for(dummlock, std::chrono::milliseconds{10});
722 const IceUtil::Time timeSinceLastIteration = now - sensorValuesTimestamp;
723 const float dt =
static_cast<float>(timeSinceLastIteration.toSecondsDouble());
724 sensorValuesTimestamp = now;
730 forceTorqueTB.read();
732 for (std::size_t i = 0; i < jointDevs.size(); ++i)
734 JointSimulationDevice& jdev = *jointDevs.at(i);
735 const float deltav = velocitiesTB.getReadBuffer().at(i) - jdev.
sensorValue.velocity;
737 jdev.
sensorValue.position = anglesTB.getReadBuffer().at(i);
738 jdev.
sensorValue.torque = torquesTB.getReadBuffer().at(i);
739 jdev.
sensorValue.velocity = velocitiesTB.getReadBuffer().at(i);
743 for (std::size_t i = 0; i < forceTorqueDevs.size(); ++i)
745 ForceTorqueSimulationSensorDevice& ft = *forceTorqueDevs.at(i);
752 auto&
s = platformDev->sensorValue;
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);
759 Eigen::Vector2f relativePositionGlobalFrame;
760 relativePositionGlobalFrame << absolutePositionX - platformDev->initAbsolutePositionX,
761 absolutePositionY - platformDev->initAbsolutePositionY;
762 s.relativePositionRotation =
763 absolutePositionRotation - platformDev->initAbsolutePositionRotation;
765 Eigen::Vector2f relativePosition =
766 Eigen::Rotation2Df(-platformDev->initAbsolutePositionRotation) *
767 relativePositionGlobalFrame;
768 s.relativePositionX = relativePosition(0);
769 s.relativePositionY = relativePosition(1);
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);
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
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)
const Eigen::Matrix3f reportingTransformation
filters::ButterworthFilter tx
filters::ButterworthFilter fy
filters::ButterworthFilter fx
filters::ButterworthFilter ty
filters::ButterworthFilter fz
filters::ButterworthFilter tz
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
virtual void rtMarkRtLoopPreSleep()=0
virtual void rtMarkRtLoopStart()=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.
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
VirtualRobot::RobotPtr robot
float maxAngularPlatformVelocity
std::atomic< long > simulationDataTimestampInMicroSeconds
SimulatorInterfacePrx simulatorPrx
void onConnectRobotUnit() override
called in onConnectComponent
std::string simulatorPrxName
std::atomic_bool shutdownRtThread
void reportState(SimulatedRobotState const &state, const Ice::Current &=Ice::emptyCurrent) override
void onInitRobotUnit() override
called in onInitComponent
float maxLinearPlatformVelocity
SensorValueType sensorValue
DETAIL_SensorValueBase_DEFAULT_METHOD_IMPLEMENTATION Eigen::Vector3f torque
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
static bool HasTimeServer()
check if we have been initialized with a Timeserver
void update(Ice::Long, const VariantBasePtr &value, const Ice::Current &=Ice::emptyCurrent) override
double getRawValue() const
#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.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
#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)
double a(double t, double a0, double j)
double v(double t, double v0, double a0, double j)
This file offers overloads of toIce() and fromIce() functions for STL container types.
@ InitializingControlThread
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)