30#include <VirtualRobot/MathTools.h>
31#include <VirtualRobot/Nodes/ForceTorqueSensor.h>
32#include <VirtualRobot/RobotNodeSet.h>
48 simulatorRobotListenerInterfaceTopic =
50 if (simulatorRobotListenerInterfaceTopic.empty())
52 simulatorRobotListenerInterfaceTopic =
"Simulator_Robot_" +
getRobotName();
54 simulatorForceTorqueListenerInterfaceTopic =
57 if (!controlIterationMsProp)
59 ARMARX_WARNING <<
"the controll iteration was set to 0ms. detting it to 1ms";
60 controlIterationMsProp = 1;
62 controlIterationMs = IceUtil::Time::milliSeconds(controlIterationMsProp);
63 usingTopic(simulatorRobotListenerInterfaceTopic);
64 usingTopic(simulatorForceTorqueListenerInterfaceTopic);
69 std::vector<std::string> entries;
72 bool trimEntries =
true;
73 entries =
Split(mappingStr,
",", trimEntries);
75 for (std::string entry : entries)
78 <<
"empty entry in ForceTorqueSensorMapping! entries:\n"
80 bool trimFields =
true;
81 std::vector<std::string> fields =
Split(entry,
":", trimFields);
83 <<
"invalid entry in ForceTorqueSensorMapping! invalid entry:\n"
84 << fields <<
"\nall entries:\n"
86 for (
auto& field : fields)
89 <<
"empty field in ForceTorqueSensorMapping entry! invalid entry:\n"
90 << fields <<
"\nall entries:\n"
93 const VirtualRobot::ForceTorqueSensorPtr ftsensor =
94 robot->getSensor<
typename VirtualRobot::ForceTorqueSensor>(fields.at(0));
97 ARMARX_WARNING <<
"the robot has not ft sensor of name '" << fields.at(0)
98 <<
"' this ForceTorqueSensorMapping entry has no effect: " << entry;
102 <<
VAROUT(fields.size()) <<
" "
103 << (fields.size() != 2 ?
VAROUT(fields.at(2)) : std::string{});
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)
112 mapping.reportFrame = fields.at(2);
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));
169 for (
const VirtualRobot::RobotNodePtr& node : *(
robot->getRobotNodeSet(
174 JointSimulationDevicePtr jdev = std::make_shared<JointSimulationDevice>(
175 node->getName(), anglesCtrl, velocitiesCtrl, torquesCtrl);
176 jointDevs.add(jdev->getDeviceName(), jdev);
192 <<
"No platform device will be created since platform name was given";
207 "' so no platform device will be created";
210 ARMARX_INFO <<
"adding devices for the platform done ("
216 ARMARX_INFO <<
"adding devices for force torque sensors:";
217 for (
const auto& ft :
robot->getSensors<VirtualRobot::ForceTorqueSensor>())
219 ForceTorqueSimulationSensorDevicePtr ftdev =
220 std::make_shared<ForceTorqueSimulationSensorDevice>(
221 getMappedFTName(ft->getName()),
222 getMappedFTReportingFrame(ft->getName(),
223 ft->getRobotNode()->getName()),
224 getMappedFTReportingTransformation(ft->getName()));
226 forceTorqueDevs.add(ftdev->getDeviceName(), ftdev);
228 ARMARX_INFO <<
"adding devices for force torque done ("
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);
269 gotSensorData =
false;
270 ARMARX_INFO <<
"fetching initial robot state" << std::flush;
271 rtUpdateSensors(
true);
272 ARMARX_INFO <<
"fetching initial robot done" << std::flush;
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);
280 platformDev->initAbsolutePositionX = absolutePositionX;
281 platformDev->initAbsolutePositionY = absolutePositionY;
282 platformDev->initAbsolutePositionRotation = absolutePositionRotation;
289 if (synchronizedSimulation)
294 ARMARX_INFO <<
"now transitioning to rt" << std::flush;
307 IceUtil::Time timeSinceLastIteration;
308 IceUtil::Time currentIterationStart;
316 timeSinceLastIteration = currentIterationStart - lastIterationStart;
317 lastIterationStart = currentIterationStart;
322 timeSinceLastIteration);
325 timeSinceLastIteration);
335 if (synchronizedSimulation)
337 gotSensorData =
false;
340 rtUpdateSensors(synchronizedSimulation);
343 sensorValuesTimestamp,
344 timeSinceLastIteration);
350 const IceUtil::Time sleepUntil = currentIterationStart + controlIterationMs;
352 while (currentTime < sleepUntil)
358 if (currentTime < currentIterationStart)
364 std::this_thread::sleep_for(
365 std::chrono::microseconds{100});
370 catch (Ice::Exception& e)
373 << e.what() <<
"\n\tname: " << e.ice_id() <<
"\n\tfile: " << e.ice_file()
374 <<
"\n\tline: " << e.ice_line() <<
"\n\tstack: " << e.ice_stackTrace()
378 catch (std::exception& e)
380 ARMARX_ERROR <<
"exception in rtTask!\nwhat:\n" << e.what() << std::flush;
393 IceUtil::Time
timestamp = IceUtil::Time::microSeconds(state.timestampInMicroSeconds);
404 fillTB(anglesTB, state.jointAngles,
"JointAngles");
405 fillTB(velocitiesTB, state.jointVelocities,
"JointVelocities");
406 fillTB(torquesTB, state.jointTorques,
"JointTorques");
408 for (ForceTorqueData
const& ftData : state.forceTorqueValues)
420 auto g = robPoseTB.guard();
422 <<
"Robot Pose is not allowed to be NULL. Maybe no state was reported from Simulator!";
423 robPoseTB.getWriteBuffer() = PosePtr::dynamicCast(state.pose)->toEigen();
435 auto& trans = state.linearVelocity;
436 auto& rotat = state.angularVelocity;
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;
453 gotSensorData =
true;
457RobotUnitSimulation::updateForceTorque(
const ForceTorqueData& ftData, IceUtil::Time
timestamp)
459 auto& sensorName = ftData.sensorName;
460 auto& nodeName = ftData.nodeName;
462 const std::string sensname =
463 ftMappings.count(sensorName) ? ftMappings.at(sensorName).sensorName : sensorName;
464 if (ftMappings.count(sensorName) && ftMappings.at(sensorName).originalReportFrame != nodeName)
467 << sensname <<
"') are reported in frame '" << nodeName <<
"' instead of '"
468 << ftMappings.at(sensorName).originalReportFrame
469 <<
"' as defined during setup! (this value is skipped!)";
475 <<
"Skipped all sensor values for force torque of sensor " << sensname
476 <<
" (node = " << nodeName <<
")";
479 auto g = forceTorqueTB.guard();
480 if (!forceTorqueDevs.has(sensname))
484 << forceTorqueDevs.keys();
487 auto i = forceTorqueDevs.index(sensname);
489 << forceTorqueTB.getWriteBuffer().size() <<
" > " << i;
490 auto& force = ftData.force;
491 auto& torque = ftData.torque;
492 ForceTorqueSimulationSensorDevice& ftdev = *forceTorqueDevs.at(i);
500 Eigen::Vector3f filteredTorque;
501 Eigen::Vector3f filteredForce;
511 forceTorqueTB.write();
512 forceTorqueTimes.at(i) =
timestamp.toMicroSeconds() * 1000;
514 <<
"Got new sensor values for force torque of sensor " << sensname
515 <<
" (node = " << nodeName <<
")";
520 const NameValueMap& nv,
521 const std::string name)
const
529 std::stringstream ignored;
530 bool someWereIgnored =
false;
531 for (
const auto& a : nv)
533 if (jointDevs.has(
a.first))
535 b.getWriteBuffer().at(jointDevs.index(
a.first)) =
a.second;
539 ignored <<
a.first <<
" -> " <<
a.second <<
"\n";
540 someWereIgnored =
true;
553RobotUnitSimulation::rtSendCommands()
559 if (!velocitiesCtrl.empty())
561 prx->actuateRobotJointsVel(
robotName, velocitiesCtrl);
563 if (!anglesCtrl.empty())
565 prx->actuateRobotJointsPos(
robotName, anglesCtrl);
567 if (!torquesCtrl.empty())
569 prx->actuateRobotJointsTorque(
robotName, torquesCtrl);
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;
584 Eigen::Vector3f rotationVel(0.f,
586 std::clamp(platformDev->target.velocityRotation,
590 prx->setRobotLinearVelocityRobotRootFrame(
592 prx->setRobotAngularVelocityRobotRootFrame(
595 <<
"setting platform vel ang: " << rotationVel.transpose();
597 <<
"setting platform vel lin: " << translationVel.transpose();
599 prx->ice_flushBatchRequests();
601 catch (Ice::ConnectionRefusedException&)
608 <<
"Ice::ConnectionRefusedException when sending commands to the simulator";
611 catch (Ice::NotRegisteredException&)
617 ARMARX_WARNING <<
"Ice::NotRegisteredException when sending commands to the simulator";
623RobotUnitSimulation::skipReport()
const
625 static const std::set<RobotUnitState> reportAcceptingStates{
631RobotUnitSimulation::rtPollRobotState()
633 if (!isPolling.exchange(
true))
640 auto rootname =
robot->getRootNode()->getName();
645 catch (Ice::Exception& e)
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;
654 catch (std::exception& e)
657 << e.what() << std::flush;
675 if (changedProperties.count(
"SynchronizedSimulation"))
681 if (synchronizedSimulation)
695RobotUnitSimulation::rtUpdateSensors(
bool wait)
701 std::unique_lock<std::mutex> dummlock{dummy};
702 std::size_t fails = 0;
703 while (!gotSensorData)
706 <<
"waiting for up to date sensor values (iteration " << iterationCount
708 cvGotSensorData.wait_for(dummlock, std::chrono::milliseconds{10});
724 const IceUtil::Time timeSinceLastIteration = now - sensorValuesTimestamp;
725 const float dt =
static_cast<float>(timeSinceLastIteration.toSecondsDouble());
726 sensorValuesTimestamp = now;
732 forceTorqueTB.read();
734 for (std::size_t i = 0; i < jointDevs.size(); ++i)
736 JointSimulationDevice& jdev = *jointDevs.at(i);
737 const float deltav = velocitiesTB.getReadBuffer().at(i) - jdev.
sensorValue.velocity;
739 jdev.
sensorValue.position = anglesTB.getReadBuffer().at(i);
740 jdev.
sensorValue.torque = torquesTB.getReadBuffer().at(i);
741 jdev.
sensorValue.velocity = velocitiesTB.getReadBuffer().at(i);
745 for (std::size_t i = 0; i < forceTorqueDevs.size(); ++i)
747 ForceTorqueSimulationSensorDevice& ft = *forceTorqueDevs.at(i);
754 auto&
s = platformDev->sensorValue;
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);
761 Eigen::Vector2f relativePositionGlobalFrame;
762 relativePositionGlobalFrame << absolutePositionX - platformDev->initAbsolutePositionX,
763 absolutePositionY - platformDev->initAbsolutePositionY;
764 s.relativePositionRotation =
765 absolutePositionRotation - platformDev->initAbsolutePositionRotation;
767 Eigen::Vector2f relativePosition =
768 Eigen::Rotation2Df(-platformDev->initAbsolutePositionRotation) *
769 relativePositionGlobalFrame;
770 s.relativePositionX = relativePosition(0);
771 s.relativePositionY = relativePosition(1);
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);
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
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.
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
VirtualRobot::RobotPtr robot
float maxAngularPlatformVelocity
std::atomic< long > simulationDataTimestampInMicroSeconds
SimulatorInterfacePrx simulatorPrx
void onConnectRobotUnit() override
called in onConnectComponent
static std::string GetDefaultName()
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)