diff --git a/source/RobotAPI/libraries/BasicRTControllers/PassThroughController.h b/source/RobotAPI/libraries/BasicRTControllers/PassThroughController.h index 05c70890cbb232fe8911e2ac73c7f120c1a5b825..38e8ccac55917f9eef81a3c27c601f089ce444c0 100644 --- a/source/RobotAPI/libraries/BasicRTControllers/PassThroughController.h +++ b/source/RobotAPI/libraries/BasicRTControllers/PassThroughController.h @@ -40,18 +40,18 @@ namespace armarx template <typename T> struct AtomicWrapper { - std::atomic<T> val; - - AtomicWrapper( ):val{ }{} - AtomicWrapper(const T& v ):val{v }{} - AtomicWrapper(const std::atomic<T> &val ):val{val.load() }{} - AtomicWrapper(const AtomicWrapper &other):val{other.val.load()}{} - - AtomicWrapper &operator=(const AtomicWrapper &other) - { - val.store(other.val.load()); - return *this; - } + std::atomic<T> val; + + AtomicWrapper(): val { } {} + AtomicWrapper(const T& v): val {v } {} + AtomicWrapper(const std::atomic<T>& val): val {val.load() } {} + AtomicWrapper(const AtomicWrapper& other): val {other.val.load()} {} + + AtomicWrapper& operator=(const AtomicWrapper& other) + { + val.store(other.val.load()); + return *this; + } }; template <typename TargetType> @@ -65,7 +65,7 @@ namespace armarx public: using Traits = PassThroughControllerTargetTypeTraits<TargetType>; - inline PassThroughController(IceInternal::Handle<RobotUnit> robotUnit, LVL1ControllerConfigPtr config); + inline PassThroughController(LVL1ControllerDataProviderInterfacePtr prov, LVL1ControllerConfigPtr config); inline virtual void rtRun(const IceUtil::Time&, const IceUtil::Time&) override; inline virtual void rtSwapBufferAndRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) override; @@ -73,8 +73,8 @@ namespace armarx //ice interface inline virtual std::string getClassName(const Ice::Current& = GlobalIceCurrent) const override; - inline virtual void setJoint(const std::string& name, Ice::Float value, const Ice::Current & = GlobalIceCurrent) override; - inline virtual void setJoints(const StringFloatDictionary& values, const Ice::Current & = GlobalIceCurrent) override; + inline virtual void setJoint(const std::string& name, Ice::Float value, const Ice::Current& = GlobalIceCurrent) override; + inline virtual void setJoints(const StringFloatDictionary& values, const Ice::Current& = GlobalIceCurrent) override; protected: std::vector<float*> lvl0Targets; std::vector<const float*> jointStates; @@ -136,7 +136,7 @@ namespace armarx LVL1ControllerRegistration<PassThroughController<JointPositionTarget>> registrationSomeControllerPositionPassThroughController("PositionPassThroughController"); LVL1ControllerRegistration<PassThroughController<JointVelocityTarget>> registrationSomeControllerVelocityPassThroughController("VelocityPassThroughController"); - LVL1ControllerRegistration<PassThroughController<JointTorqueTarget >> registrationSomeControllerJointPassThroughController ("JointPassThroughController"); + LVL1ControllerRegistration<PassThroughController<JointTorqueTarget >> registrationSomeControllerJointPassThroughController("JointPassThroughController"); template <typename TargetType> std::string PassThroughController<TargetType>::getClassName(const Ice::Current&) const @@ -145,7 +145,7 @@ namespace armarx } template <typename TargetType> - PassThroughController<TargetType>::PassThroughController(IceInternal::Handle<RobotUnit> robotUnit, LVL1ControllerConfigPtr config) + PassThroughController<TargetType>::PassThroughController(LVL1ControllerDataProviderInterfacePtr prov, LVL1ControllerConfigPtr config) { PassThroughControllerConfigPtr cfg = PassThroughControllerConfigPtr::dynamicCast(config); ARMARX_CHECK_EXPRESSION_W_HINT(cfg, @@ -153,19 +153,19 @@ namespace armarx << " instead of " << PassThroughControllerConfig::ice_staticId()); //make sure the used units are supported - auto kinunit = robotUnit->getRTKinematicDataUnit(); - ARMARX_CHECK_EXPRESSION_W_HINT(kinunit, "The RobotUnit " << robotUnit->getName() << " has no kinematic data unit"); + auto kinunit = prov->getRTKinematicDataUnit(); + ARMARX_CHECK_EXPRESSION_W_HINT(kinunit, "The DataProvider " << prov->getName() << " has no kinematic data unit"); //get pointers to sensor values from units jointStates = Traits::getSensorValues(kinunit, cfg->jointNames) ; //not initialized, this is done in rtPreActivateController - iceTargets.resize(cfg->jointNames.size(),0); + iceTargets.resize(cfg->jointNames.size(), 0); //get pointers for the results of this controller lvl0Targets.reserve(cfg->jointNames.size()); - for (const auto & j : cfg->jointNames) + for (const auto& j : cfg->jointNames) { - auto target = dynamic_cast<TargetType*>(robotUnit->getJointTarget(j, Traits::getControlMode())); + auto target = dynamic_cast<TargetType*>(prov->getJointTarget(j, Traits::getControlMode())); ARMARX_CHECK_EXPRESSION_W_HINT(target, "The joint " << j << " has no controll mode " << Traits::getControlMode()); lvl0Targets.emplace_back(Traits::getTargetDatamember(*target)); } @@ -197,20 +197,20 @@ namespace armarx } template <typename TargetType> - void PassThroughController<TargetType>::setJoint(const std::string& name, Ice::Float value, const Ice::Current &) + void PassThroughController<TargetType>::setJoint(const std::string& name, Ice::Float value, const Ice::Current&) { auto targetIt = indices.find(name); - if(targetIt == indices.end()) + if (targetIt == indices.end()) { - throw InvalidArgumentException{"The joint " + name + " is not controlled by this (" + getName() + ") controller"}; + throw InvalidArgumentException {"The joint " + name + " is not controlled by this (" + getName() + ") controller"}; } iceTargets.at(targetIt->second).val.store(value); } template <typename TargetType> - void PassThroughController<TargetType>::setJoints(const StringFloatDictionary& values, const Ice::Current &) + void PassThroughController<TargetType>::setJoints(const StringFloatDictionary& values, const Ice::Current&) { - for(const auto& value:values) + for (const auto& value : values) { setJoint(value.first, value.second); } diff --git a/source/RobotAPI/libraries/RobotRTControllers/Constants.h b/source/RobotAPI/libraries/RobotRTControllers/Constants.h index 74e538838dd8f045ed93982ec0a894d7de3f894d..a56fce762581992a0e915d79f2a5a47efd29c3a7 100644 --- a/source/RobotAPI/libraries/RobotRTControllers/Constants.h +++ b/source/RobotAPI/libraries/RobotRTControllers/Constants.h @@ -30,7 +30,10 @@ namespace armarx { namespace ControllerConstants { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" static const float ValueNotSetNaN = std::nanf(std::to_string((1 << 16) - 1).c_str()); +#pragma GCC diagnostic pop } } diff --git a/source/RobotAPI/libraries/RobotRTControllers/LVL1Controller.h b/source/RobotAPI/libraries/RobotRTControllers/LVL1Controller.h index 8dbd97b1ef17102767bd325e95cbe05ccb430e59..aa19370a1e71bc7cdd6c218ea264bebcc482b3eb 100644 --- a/source/RobotAPI/libraries/RobotRTControllers/LVL1Controller.h +++ b/source/RobotAPI/libraries/RobotRTControllers/LVL1Controller.h @@ -31,13 +31,36 @@ #include <ArmarXCore/core/Component.h> #include <ArmarXCore/core/util/Registrar.h> #include <ArmarXCore/core/util/TripleBuffer.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include <RobotAPI/interface/libraries/RTControllers/LVL1Controller.h> #include "Targets/JointTargetBase.h" +//units +#include "DataUnits/ForceTorqueDataUnit.h" +#include "DataUnits/HapticDataUnit.h" +#include "DataUnits/IMUDataUnit.h" +#include "DataUnits/KinematicDataUnit.h" +#include "DataUnits/PlatformDataUnit.h" + namespace armarx { + class LVL1ControllerDataProviderInterface: virtual public Ice::Object + { + public: + virtual const ForceTorqueDataUnitInterface* getRTForceTorqueDataUnit() const = 0; + virtual const HapticDataUnitInterface* getRTHapticDataUnit() const = 0; + virtual const IMUDataUnitInterface* getRTIMUDataUnit() const = 0; + virtual const KinematicDataUnitInterface* getRTKinematicDataUnit() const = 0; + virtual const PlatformDataUnitInterface* getRTPlatformDataUnit() const = 0; + + virtual JointTargetBase* getJointTarget(const std::string& jointName, const std::string& controlMode) = 0; + + virtual std::string getName() const = 0; + }; + using LVL1ControllerDataProviderInterfacePtr = IceInternal::Handle<LVL1ControllerDataProviderInterface>; + /** * @defgroup Library-RobotRTControllers RobotRTControllers * @ingroup RobotAPI @@ -82,7 +105,7 @@ namespace armarx * * \section rtnrtcomm Communication between RT and NonRT * All communication between RT and NonRT has to be lockfree. - * So you have to use constructs like atomics or TripleBuffers (See armarx::LVL1ControllerTemplate). + * So you have to use constructs like atomics or TripleBuffers (See armarx::LVL1ControllerWithTripleBuffer). * * \image html LVL1ControllerGeneralDataFlow.svg "General Dataflow in a LVL1Controller" * @@ -172,17 +195,16 @@ namespace armarx }; using LVL1ControllerPtr = IceInternal::Handle<LVL1Controller>; - class RobotUnit; - - using LVL1ControllerRegistry = Registrar<std::function<LVL1ControllerPtr(IceInternal::Handle<RobotUnit> robotUnit, LVL1ControllerConfigPtr config)>>; + using LVL1ControllerRegistry = Registrar<std::function<LVL1ControllerPtr(LVL1ControllerDataProviderInterfacePtr robotUnit, LVL1ControllerConfigPtr config)>>; template<class ControllerType> struct LVL1ControllerRegistration { LVL1ControllerRegistration(const std::string& name) { - LVL1ControllerRegistry::registerElement(name, [](IceInternal::Handle<RobotUnit> robotUnit, LVL1ControllerConfigPtr config) + LVL1ControllerRegistry::registerElement(name, [](LVL1ControllerDataProviderInterfacePtr prov, LVL1ControllerConfigPtr config) { - return new ControllerType(robotUnit, config); + ARMARX_CHECK_EXPRESSION_W_HINT(prov, "DataProvider is NULL!"); + return new ControllerType(prov, config); }); } }; @@ -273,10 +295,10 @@ namespace armarx * \endcode */ template <typename ControlDataStruct> - class LVL1ControllerTemplate: virtual public LVL1Controller + class LVL1ControllerWithTripleBuffer: virtual public LVL1Controller { public: - LVL1ControllerTemplate(const ControlDataStruct& initialCommands = ControlDataStruct()): + LVL1ControllerWithTripleBuffer(const ControlDataStruct& initialCommands = ControlDataStruct()): controlDataTripleBuffer {initialCommands} { } @@ -313,6 +335,6 @@ namespace armarx WriteBufferedTripleBuffer<ControlDataStruct> controlDataTripleBuffer; }; template <typename ControlDataStruct> - using LVL1ControllerTemplatePtr = IceInternal::Handle<LVL1ControllerTemplate<ControlDataStruct>>; + using LVL1ControllerTemplatePtr = IceInternal::Handle<LVL1ControllerWithTripleBuffer<ControlDataStruct>>; } #endif diff --git a/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.cpp b/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.cpp index 095e2ef7e464918f755b1c584a8a0dcc73c49785..97ab989622bd3089e6960d7d69291a745b0811ff 100644 --- a/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.cpp +++ b/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.cpp @@ -35,6 +35,7 @@ void armarx::RobotUnit::addLVL0Controller(const std::string& jointName, armarx:: { std::string controlMode = lvl0Controller.getControlMode(); GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); if (hasLVL0Controller(jointName, controlMode)) { ARMARX_ERROR << "A LVL0Controller for " + jointName + "(" + controlMode + ") does already exist!"; @@ -47,26 +48,20 @@ void armarx::RobotUnit::addLVL0Controller(const std::string& jointName, armarx:: } } -const armarx::LVL0ControllerBase& armarx::RobotUnit::getLVL0Controller(const std::string& jointName, const std::string& controlMode) const +const armarx::LVL0ControllerBase* armarx::RobotUnit::getLVL0Controller(const std::string& jointName, const std::string& controlMode) const { GuardType guard {dataMutex}; - return *lvl0Controllers.at(jointName).at(controlMode); + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); + return lvl0Controllers.at(jointName).at(controlMode); } -armarx::LVL0ControllerBase& armarx::RobotUnit::getLVL0Controller(const std::string& jointName, const std::string& controlMode) +armarx::LVL0ControllerBase* armarx::RobotUnit::getLVL0Controller(const std::string& jointName, const std::string& controlMode) { GuardType guard {dataMutex}; - return *lvl0Controllers.at(jointName).at(controlMode); + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); + return lvl0Controllers.at(jointName).at(controlMode); } -armarx::RobotUnit::RobotUnit(const std::vector<std::string>& jointNames): - jointNames {jointNames}, - jointNameIndices {toIndexMap(jointNames)}, - controllersRequested {jointNames.size()}, - controllersActivated {jointNames.size()}, - lvl0ControllersEmergencyStop {jointNames.size()} -{} - Ice::StringSeq armarx::RobotUnit::getControllersKnown(const Ice::Current&) const { return LVL1ControllerRegistry::getKeys(); @@ -201,6 +196,7 @@ armarx::JointNameToControlModesDictionary armarx::RobotUnit::getJointControlMode void armarx::RobotUnit::switchSetup(const Ice::StringSeq& controllerRequestedNames, const Ice::Current&) { GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); //check if all of these controllers exist for (const auto& lvl1 : controllerRequestedNames) { @@ -272,12 +268,12 @@ void armarx::RobotUnit::switchSetup(const Ice::StringSeq& controllerRequestedNam const auto& joint = jointNames.at(i); if (lvl1ControllerAssignement[joint].empty()) { - getRequestedLVL0Controllers().at(i) = &getLVL0Controller(joint, ControlModes::EmergencyStopMode); + getRequestedLVL0Controllers().at(i) = getLVL0Controller(joint, ControlModes::EmergencyStopMode); ARMARX_WARNING << "Joint '" << joint << "' has no lvl1 controller assigned!"; continue; } const auto& lvl0Mode = lvl1Controllers.at(lvl1ControllerAssignement[joint])->jointControlModeMap.at(joint); - getRequestedLVL0Controllers().at(i) = &getLVL0Controller(joint, lvl0Mode); + getRequestedLVL0Controllers().at(i) = getLVL0Controller(joint, lvl0Mode); } //populate controllersRequested.lvl1Controllers getRequestedLVL1Controllers().clear(); @@ -320,7 +316,9 @@ armarx::LVL1ControllerInterfacePrx armarx::RobotUnit::loadController(const std:: } //create the controller jointsUsedByLVL1Controler.clear(); - LVL1ControllerPtr lvl1 = factory(this, config); + RobotUnitInterfacePtr::dynamicCast(RobotUnitPtr {this}); + LVL1ControllerDataProviderInterfacePtr::dynamicCast(RobotUnitPtr {this}); + LVL1ControllerPtr lvl1 = factory(LVL1ControllerDataProviderInterfacePtr::dynamicCast(RobotUnitPtr {this}), config); lvl1->jointControlModeMap = jointsUsedByLVL1Controler; lvl1->jointIndices.clear(); lvl1->jointIndices.reserve(jointsUsedByLVL1Controler.size()); @@ -342,19 +340,31 @@ armarx::JointTargetBase* armarx::RobotUnit::getJointTarget(const std::string& jo { return nullptr; } - const auto& lvl0 = getLVL0Controller(jointName, controlMode); - ARMARX_CHECK_EXPRESSION(lvl0.getControlMode() == controlMode); + const auto lvl0 = getLVL0Controller(jointName, controlMode); + ARMARX_CHECK_EXPRESSION(lvl0->getControlMode() == controlMode); jointsUsedByLVL1Controler[jointName] = controlMode; - return lvl0.getTarget(); + return lvl0->getTarget(); +} + +void armarx::RobotUnit::setJointNames(const std::vector<std::string>& names) +{ + GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(!areJointNamesSet(), "JointNames were already set!"); + jointNames = names; + jointNameIndices = toIndexMap(jointNames); + lvl0ControllersEmergencyStop.resize(jointNames.size()); + controllersRequested.reinitAllBuffers(LVL0AndLVL1ControllerList(jointNames.size())); + controllersActivated.reinitAllBuffers(LVL0AndLVL1ControllerList(jointNames.size())); } bool armarx::RobotUnit::hasLVL1Controller(const std::string& name) const { GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); return lvl1Controllers.end() != lvl1Controllers.find(name); } -void armarx::RobotUnit::setLVL1ControllerActive(const armarx::LVL1ControllerPtr& lvl1, bool isActive) +void armarx::RobotUnit::rtSetLVL1ControllerActive(const armarx::LVL1ControllerPtr& lvl1, bool isActive) { if (isActive) { @@ -366,9 +376,16 @@ void armarx::RobotUnit::setLVL1ControllerActive(const armarx::LVL1ControllerPtr& } } +bool armarx::RobotUnit::areJointNamesSet() const +{ + GuardType guard {dataMutex}; + return !jointNames.empty(); +} + bool armarx::RobotUnit::hasLVL0Controller(const std::string& jointName, const std::string& controlMode) const { GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); return lvl0Controllers.end() != lvl0Controllers.find(jointName) && lvl0Controllers.at(jointName).end() != lvl0Controllers.at(jointName).find(controlMode) && lvl0Controllers.at(jointName).at(controlMode); @@ -452,76 +469,6 @@ bool armarx::RobotUnit::loadLibFromPackage(const std::string& package, const std return false; } -bool armarx::RobotUnit::rtControllersWereSwitched() const -{ - return controllersRequested.updateReadBuffer(); -} - -std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::getRequestedLVL0Controllers() -{ - return controllersRequested.getWriteBuffer().lvl0Controllers; -} - -std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::getRequestedLVL1Controllers() -{ - return controllersRequested.getWriteBuffer().lvl1Controllers; -} - -const std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::getRequestedLVL0Controllers() const -{ - return controllersRequested.getWriteBuffer().lvl0Controllers; -} - -const std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::getRequestedLVL1Controllers() const -{ - return controllersRequested.getWriteBuffer().lvl1Controllers; -} - -const std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::getActivatedLVL0Controllers() const -{ - return controllersActivated.getUpToDateReadBuffer().lvl0Controllers; -} - -const std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::getActivatedLVL1Controllers() const -{ - return controllersActivated.getUpToDateReadBuffer().lvl1Controllers; -} - -const std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::rtGetRequestedLVL0Controllers() const -{ - return controllersRequested.getReadBuffer().lvl0Controllers; -} - -const std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::rtGetRequestedLVL1Controllers() const -{ - return controllersRequested.getReadBuffer().lvl1Controllers; -} - -std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::rtGetActivatedLVL0Controllers() -{ - return controllersActivated.getWriteBuffer().lvl0Controllers; -} - -std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::rtGetActivatedLVL1Controllers() -{ - return controllersActivated.getWriteBuffer().lvl1Controllers; -} - -const std::vector<armarx::LVL0ControllerBase*>& armarx::RobotUnit::rtGetActivatedLVL0Controllers() const -{ - return controllersActivated.getWriteBuffer().lvl0Controllers; -} - -const std::vector<armarx::LVL1ControllerPtr>& armarx::RobotUnit::rtGetActivatedLVL1Controllers() const -{ - return controllersActivated.getWriteBuffer().lvl1Controllers; -} - -void armarx::RobotUnit::rtCommitActivatedLVL1Controllers() -{ - controllersActivated.commitWrite(); -} - bool armarx::RobotUnit::rtSwitchSetup() { if (!rtControllersWereSwitched()) @@ -532,25 +479,31 @@ bool armarx::RobotUnit::rtSwitchSetup() for (std::size_t i = 0; i < rtGetRequestedLVL1Controllers().size(); ++i) { //deactivate old - if (rtGetActivatedLVL1Controllers().at(i)) + if (rtGetActivatedLVL1Controller(i)) { - rtGetActivatedLVL1Controllers().at(i)->rtDeactivateController(); + rtGetActivatedLVL1Controller(i)->rtDeactivateController(); } //activate new - if (rtGetRequestedLVL1Controllers().at(i)) + if (rtGetRequestedLVL1Controller(i)) { - rtGetRequestedLVL1Controllers().at(i)->rtActivateController(); + rtGetRequestedLVL1Controller(i)->rtActivateController(); } //update activated - rtGetActivatedLVL1Controllers().at(i) = rtGetRequestedLVL1Controllers().at(i); + rtGetActivatedLVL1Controller(i) = rtGetRequestedLVL1Controller(i); } //handle lvl0 for (std::size_t i = 0; i < rtGetRequestedLVL0Controllers().size(); ++i) { - if (rtGetRequestedLVL0Controllers().at(i) != rtGetActivatedLVL0Controllers().at(i)) + if (rtGetRequestedLVL0Controller(i) != rtGetActivatedLVL0Controller(i)) { - rtSwitchLVL0Controller(i, rtGetActivatedLVL0Controllers().at(i), rtGetRequestedLVL0Controllers().at(i)); - rtGetActivatedLVL0Controllers().at(i) = rtGetRequestedLVL0Controllers().at(i); + rtSwitchLVL0Controller(i, rtGetActivatedLVL0Controller(i), rtGetRequestedLVL0Controller(i)); + rtGetActivatedLVL0Controller(i) = rtGetRequestedLVL0Controller(i); + } + if (!rtGetRequestedLVL0Controller(i)) + { + //no lvl0 controller is set! + rtSwitchLVL0Controller(i, rtGetActivatedLVL0Controller(i), rtGetEmergencyStopLVL0Controller(i)); + rtGetActivatedLVL0Controller(i) = rtGetActivatedLVL0Controller(i); } } return true; @@ -572,19 +525,19 @@ void armarx::RobotUnit::rtDeactivateAssignedLVL1Controller(std::size_t index) { for (std::size_t i = 0; i < rtGetRequestedLVL1Controllers().size(); ++i) { - if (!rtGetRequestedLVL1Controllers().at(i)) + if (!rtGetRequestedLVL1Controller(i)) { continue; } - if (rtGetRequestedLVL1Controllers().at(i)->rtUsesJoint(index)) + if (rtGetRequestedLVL1Controller(i)->rtUsesJoint(index)) { - rtGetRequestedLVL1Controllers().at(i)->rtDeactivateController(); - for (auto used : rtGetRequestedLVL1Controllers().at(i)->rtGetJointIndices()) + rtGetRequestedLVL1Controller(i)->rtDeactivateController(); + for (auto used : rtGetRequestedLVL1Controller(i)->rtGetJointIndices()) { - rtSwitchLVL0Controller(used, rtGetActivatedLVL0Controllers().at(i), lvl0ControllersEmergencyStop.at(i)); - rtGetActivatedLVL0Controllers().at(i) = lvl0ControllersEmergencyStop.at(i); + rtSwitchLVL0Controller(used, rtGetActivatedLVL0Controller(i), rtGetEmergencyStopLVL0Controller(i)); + rtGetActivatedLVL0Controller(i) = rtGetEmergencyStopLVL0Controller(i); } - rtGetActivatedLVL1Controllers().at(i) = nullptr; + rtGetActivatedLVL1Controller(i) = nullptr; return; } } @@ -598,8 +551,10 @@ void armarx::RobotUnit::rtRunLVL0Controllers() } } -bool armarx::RobotUnit::rtValidateLVL0ControllerSetup() const +bool armarx::RobotUnit::validateAddedLVL0Controllers() const { + GuardType guard {dataMutex}; + ARMARX_CHECK_EXPRESSION_W_HINT(areJointNamesSet(), "Joint names a were not set!"); for (const auto& lvl0 : lvl0ControllersEmergencyStop) { if (!lvl0) diff --git a/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.h b/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.h index f98dbc8e5d3400df4b15a0c812a7016b28777bdd..734be3dfb30840bd9cc51a0937e5549aa7c799d2 100644 --- a/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.h +++ b/source/RobotAPI/libraries/RobotRTControllers/RobotUnit.h @@ -40,12 +40,6 @@ #include "LVL0Controller.h" #include "LVL1Controller.h" -#include "DataUnits/ForceTorqueDataUnit.h" -#include "DataUnits/HapticDataUnit.h" -#include "DataUnits/IMUDataUnit.h" -#include "DataUnits/KinematicDataUnit.h" -#include "DataUnits/PlatformDataUnit.h" - namespace armarx { class DynamicLibrary; @@ -104,11 +98,13 @@ namespace armarx * { * initYourCommunication();//implement this * passYourLVL0ControllersToTheRobotUnit();//implement this - * if(!rtValidateLVL0ControllerSetup()) + * if(!validateAddedLVL0Controllers()) * { * //report errors * throw std::logic_error{"lvl0 controller setup invalid"}; * } + * + * //at this point the RT thread becomes RT (calls before this may not be rt) * IceUtil::Time currentStateTimestamp = TimeUtil::GetTime(); * IceUtil::Time lastStateTimestamp = TimeUtil::GetTime(); * getTheCurrentRobotState();//implement this @@ -124,19 +120,19 @@ namespace armarx * throw std::logic_error{"switching the controller setup failed"}; * } * //validate the setup if you need to - * //if you had to change something, call rtCommitActivatedLVL1Controllers(); + * //if you had to change something, call rtCommitActivatedControllers(); * } * //run the lvl1 controllers * rtRunLVL1Controllers(currentStateTimestamp, currentStateTimestamp - lastStateTimestamp); * //validate targets * for(std::size_t i = 0; i<rtGetActivatedLVL0Controllers().size(); ++i) * { - * if(!rtGetActivatedLVL0Controllers().at(i)->isTargetVaild()) + * if(!rtGetActivatedLVL0Controller(i)->isTargetVaild()) * { * //handle this error! * //you probably should log this error to some error struct * rtDeactivateAssignedLVL1Controller(i); - * rtCommitActivatedLVL1Controllers(); + * rtCommitActivatedControllers(); * } * } * //run lvl0 @@ -182,15 +178,24 @@ namespace armarx * This controller should activate the motor brakes. */ class RobotUnit : - virtual public armarx::Component, - virtual public armarx::RobotUnitInterface + virtual public Component, + virtual public RobotUnitInterface, + virtual public LVL1ControllerDataProviderInterface { public: using MutexType = std::recursive_mutex; using GuardType = std::lock_guard<MutexType>; - RobotUnit(const std::vector<std::string>& jointNames); - + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + //ice LVL1ControllerDataProviderInterface + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + virtual std::string getName() const override + { + return Component::getName(); + } + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + //ice interface + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // //controllers virtual Ice::StringSeq getControllersKnown(const Ice::Current& = GlobalIceCurrent) const override; virtual Ice::StringSeq getControllerNamesLoaded(const Ice::Current& = GlobalIceCurrent) const override; @@ -205,73 +210,74 @@ namespace armarx virtual JointNameToControlModeDictionary getJointControlModesRequested(const Ice::Current& = GlobalIceCurrent) const override; virtual JointNameToControlModeDictionary getJointControlModesActivated(const Ice::Current& = GlobalIceCurrent) const override; virtual JointNameToControlModesDictionary getJointControlModesSupported(const Ice::Current& = GlobalIceCurrent) const override; - //loading and switching (ice) + //loading and switching virtual void switchSetup(const Ice::StringSeq& controllerRequestedNames, const Ice::Current& = GlobalIceCurrent) override; virtual LVL1ControllerInterfacePrx loadController(const std::string& className, const std::string& instanceName, const LVL1ControllerConfigPtr& config, const Ice::Current& = GlobalIceCurrent) override; virtual bool loadLibFromPath(const std::string& path, const Ice::Current& = GlobalIceCurrent) override; virtual bool loadLibFromPackage(const std::string& package, const std::string& lib, const Ice::Current& = GlobalIceCurrent) override; - //get buffers (ice)ELMO_MODE_OF_OPERATION_CURRENT_CONTROL - /// @return The requested lvl0 controllers (none is null) - std::vector<LVL0ControllerBase*>& getRequestedLVL0Controllers(); - /// @return The requested lvl1 controllers (some may be null) - std::vector<LVL1ControllerPtr >& getRequestedLVL1Controllers(); - /// @return The requested lvl0 controllers (none is null) - const std::vector<LVL0ControllerBase*>& getRequestedLVL0Controllers() const; - /// @return The requested lvl1 controllers (some may be null) - const std::vector<LVL1ControllerPtr >& getRequestedLVL1Controllers() const; - /// @return The activated lvl0 controllers (none is null) - const std::vector<LVL0ControllerBase*>& getActivatedLVL0Controllers() const; - /// @return The activated lvl1 controllers (some may be null) - const std::vector<LVL1ControllerPtr >& getActivatedLVL1Controllers() const; - //buffers (rt) - bool rtControllersWereSwitched() const; - /// @return The requested lvl0 controllers (none is null) - const std::vector<LVL0ControllerBase*>& rtGetRequestedLVL0Controllers() const; - /// @return The requested lvl1 controllers (some may be null) - const std::vector<LVL1ControllerPtr >& rtGetRequestedLVL1Controllers() const; - /// @return The activated lvl0 controllers (none is null) - std::vector<LVL0ControllerBase*>& rtGetActivatedLVL0Controllers(); - /// @return The activated lvl1 controllers (some may be null) - std::vector<LVL1ControllerPtr >& rtGetActivatedLVL1Controllers(); - /// @return The activated lvl0 controllers (none is null) - const std::vector<LVL0ControllerBase*>& rtGetActivatedLVL0Controllers() const; - /// @return The activated lvl1 controllers (some may be null) - const std::vector<LVL1ControllerPtr >& rtGetActivatedLVL1Controllers() const; - void rtCommitActivatedLVL1Controllers(); - //switching (rt) - bool rtSwitchSetup(); - void rtRunLVL1Controllers(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration); - void rtDeactivateAssignedLVL1Controller(std::size_t index); - void rtRunLVL0Controllers(); - - /** - * @brief Hook for switching the lvl0 controller (this changes the controll mode) - * @param index The index of the lvl0 controller - * @param oldLVL0 The old lvl0 controller (will be deactivated) - * @param newLVL0 The new lvl0 controller (will be activated) - */ - virtual void rtSwitchLVL0Controller(std::size_t index, LVL0ControllerBase* oldLVL0, LVL0ControllerBase* newLVL0) = 0; - //checks (rt) - virtual bool rtValidateLVL0ControllerSetup() const; - - //units (ice) + //units virtual KinematicUnitInterfacePrx getKinematicUnit(const Ice::Current& = GlobalIceCurrent) const = 0; virtual ForceTorqueUnitInterfacePrx getForceTorqueUnit(const Ice::Current& = GlobalIceCurrent) const = 0; virtual InertialMeasurementUnitInterfacePrx getInertialMeasurementUnit(const Ice::Current& = GlobalIceCurrent) const = 0; virtual PlatformUnitInterfacePrx getPlatformUnitInterface(const Ice::Current& = GlobalIceCurrent) const = 0; - //units (ice but results are used in rt) + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // used by lvl1 controllers + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + //units (nonrt but results are used in rt) virtual const ForceTorqueDataUnitInterface* getRTForceTorqueDataUnit() const = 0; virtual const HapticDataUnitInterface* getRTHapticDataUnit() const = 0; virtual const IMUDataUnitInterface* getRTIMUDataUnit() const = 0; virtual const KinematicDataUnitInterface* getRTKinematicDataUnit() const = 0; virtual const PlatformDataUnitInterface* getRTPlatformDataUnit() const = 0; - //targets (ice) - JointTargetBase* getJointTarget(const std::string& jointName, const std::string& controlMode); + //targets (nonrt but results are used in rt) + virtual JointTargetBase* getJointTarget(const std::string& jointName, const std::string& controlMode) override; protected: + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // NonRT + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // setup the data structures + void setJointNames(const std::vector<std::string>& names); + + // Component /// @see PropertyUser::createPropertyDefinitions() virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; + //get buffers + /// @return The requested lvl0 controllers (none is null) + std::vector<LVL0ControllerBase*>& getRequestedLVL0Controllers() + { + return controllersRequested.getWriteBuffer().lvl0Controllers; + } + /// @return The requested lvl1 controllers (some may be null) + std::vector<LVL1ControllerPtr >& getRequestedLVL1Controllers() + { + return controllersRequested.getWriteBuffer().lvl1Controllers; + } + /// @return The requested lvl0 controllers (none is null) + const std::vector<LVL0ControllerBase*>& getRequestedLVL0Controllers() const + { + return controllersRequested.getWriteBuffer().lvl0Controllers; + } + /// @return The requested lvl1 controllers (some may be null) + const std::vector<LVL1ControllerPtr >& getRequestedLVL1Controllers() const + { + return controllersRequested.getWriteBuffer().lvl1Controllers; + } + /// @return The activated lvl0 controllers (none is null) + const std::vector<LVL0ControllerBase*>& getActivatedLVL0Controllers() const + { + return controllersActivated.getUpToDateReadBuffer().lvl0Controllers; + } + /// @return The activated lvl1 controllers (some may be null) + const std::vector<LVL1ControllerPtr >& getActivatedLVL1Controllers() const + { + return controllersActivated.getUpToDateReadBuffer().lvl1Controllers; + } + + //checks + /// @return Return whether the set of added LVL0Controllers is ok (e.g. if each joint has one EmergencyStop controller) + virtual bool validateAddedLVL0Controllers() const; /** * @brief Add a LVL0Controller for a specified joint. @@ -282,10 +288,15 @@ namespace armarx void addLVL0Controller(const std::string& jointName, LVL0ControllerBase& lvl0Controller); /// @return The LVL0Controller for given joint and control mode. - const LVL0ControllerBase& getLVL0Controller(const std::string& jointName, const std::string& controlMode) const; + const LVL0ControllerBase* getLVL0Controller(const std::string& jointName, const std::string& controlMode) const; /// @return The LVL0Controller for given joint and control mode. - LVL0ControllerBase& getLVL0Controller(const std::string& jointName, const std::string& controlMode); + LVL0ControllerBase* getLVL0Controller(const std::string& jointName, const std::string& controlMode); + + LVL0ControllerBase* rtGetEmergencyStopLVL0Controller(std::size_t index) + { + return lvl0ControllersEmergencyStop.at(index); + } /// @return Whether a LVL0Controller for given joint and control mode exists. bool hasLVL0Controller(const std::string& jointName, const std::string& controlMode) const; @@ -293,13 +304,118 @@ namespace armarx /// @return Whether a LVL1Controller for this name is loaded. bool hasLVL1Controller(const std::string& name) const; - static void setLVL1ControllerActive(const LVL1ControllerPtr& lvl1, bool isActive = 1); + static void rtSetLVL1ControllerActive(const LVL1ControllerPtr& lvl1, bool isActive = 1); + + //other + private: + bool areJointNamesSet() const; + bool loadLibFromAbsolutePath(const std::string& path); + + protected: + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // RT + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // get buffers (rt) + bool rtControllersWereSwitched() const + { + return controllersRequested.updateReadBuffer(); + } + /// @return The requested lvl0 controllers (none is null) + const std::vector<LVL0ControllerBase*>& rtGetRequestedLVL0Controllers() const + { + return controllersRequested.getReadBuffer().lvl0Controllers; + } + /// @return The requested lvl1 controllers (some may be null) + const std::vector<LVL1ControllerPtr >& rtGetRequestedLVL1Controllers() const + { + return controllersRequested.getReadBuffer().lvl1Controllers; + } + /// @return The activated lvl0 controllers (none is null) + std::vector<LVL0ControllerBase*>& rtGetActivatedLVL0Controllers() + { + return controllersActivated.getWriteBuffer().lvl0Controllers; + } + /// @return The activated lvl1 controllers (some may be null) + std::vector<LVL1ControllerPtr >& rtGetActivatedLVL1Controllers() + { + return controllersActivated.getWriteBuffer().lvl1Controllers; + } + /// @return The activated lvl0 controllers (none is null) + const std::vector<LVL0ControllerBase*>& rtGetActivatedLVL0Controllers() const + { + return controllersActivated.getWriteBuffer().lvl0Controllers; + } + /// @return The activated lvl1 controllers (some may be null) + const std::vector<LVL1ControllerPtr >& rtGetActivatedLVL1Controllers() const + { + return controllersActivated.getWriteBuffer().lvl1Controllers; + } + //get controllers (rt) + LVL0ControllerBase* const& rtGetActivatedLVL0Controller(std::size_t index) const + { + return rtGetActivatedLVL0Controllers().at(index); + } + const LVL1ControllerPtr& rtGetActivatedLVL1Controller(std::size_t index) const + { + return rtGetActivatedLVL1Controllers().at(index); + } + LVL0ControllerBase*& rtGetActivatedLVL0Controller(std::size_t index) + { + return rtGetActivatedLVL0Controllers().at(index); + } + LVL1ControllerPtr& rtGetActivatedLVL1Controller(std::size_t index) + { + return rtGetActivatedLVL1Controllers().at(index); + } + + + LVL0ControllerBase* rtGetRequestedLVL0Controller(std::size_t index) const + { + return rtGetRequestedLVL0Controllers().at(index); + } + const LVL1ControllerPtr& rtGetRequestedLVL1Controller(std::size_t index) const + { + return getRequestedLVL1Controllers().at(index); + } + + void rtCommitActivatedControllers() + { + controllersActivated.commitWrite(); + } + + //switching (rt) + bool rtSwitchSetup(); + void rtRunLVL1Controllers(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration); + void rtDeactivateAssignedLVL1Controller(std::size_t index); + void rtRunLVL0Controllers(); + + /** + * @brief Hook for switching the lvl0 controller (this changes the controll mode) + * @param index The index of the lvl0 controller + * @param oldLVL0 The old lvl0 controller (will be deactivated) + * @param newLVL0 The new lvl0 controller (will be activated) + */ + virtual void rtSwitchLVL0Controller(std::size_t index, LVL0ControllerBase* oldLVL0, LVL0ControllerBase* newLVL0) = 0; + + protected: + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + // data + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // + mutable MutexType dataMutex; + //data accessible in RT and nonRT + std::vector<std::string> jointNames; + std::unordered_map<std::string, std::size_t> jointNameIndices; + /// @brief True if some error occured in switch LVL1Controllers + std::atomic_bool switchSetupError {false}; + + private: + //controllers struct LVL0AndLVL1ControllerList { LVL0AndLVL1ControllerList(std::size_t size): - lvl0Controllers{size,nullptr}, - lvl1Controllers{size,nullptr} + lvl0Controllers {size, nullptr}, + lvl1Controllers {size, nullptr} {} LVL0AndLVL1ControllerList() = default; @@ -308,14 +424,6 @@ namespace armarx std::vector<LVL0ControllerBase*> lvl0Controllers; std::vector<LVL1ControllerPtr > lvl1Controllers; }; - mutable MutexType dataMutex; - //data accessible in RT and nonRT - const std::vector<std::string> jointNames; - const std::unordered_map<std::string, std::size_t> jointNameIndices; - /// @brief - std::atomic_bool switchSetupError {false}; - //used to communicate with rt - //non rt data /** * @brief Holds pointer to all lvl0 controllers. (index: [jointname][controlmode]) * Is initialized by derived classes. @@ -327,18 +435,19 @@ namespace armarx * May not be accessed in rt. */ std::map<std::string, LVL1ControllerPtr> lvl1Controllers; - std::map<std::string, DynamicLibraryPtr> loadedLibs; - private: - bool loadLibFromAbsolutePath(const std::string& path); + /// @brief LVL0Controllers for Emergency stop + std::vector<LVL0ControllerBase*> lvl0ControllersEmergencyStop; - /// @brief Stores joints accessed via getJointTarget - JointNameToControlModeDictionary jointsUsedByLVL1Controler; + //used to communicate with rt /// @brief Controllers the RT thread is supposed to activate (direction nonRT -> RT) (some lvl1 controllers may be null) TripleBuffer<LVL0AndLVL1ControllerList> controllersRequested; /// @brief Controllers the RT thread is currently running (direction RT -> nonRT) (some lvl1 controllers may be null) TripleBuffer<LVL0AndLVL1ControllerList> controllersActivated; - /// @brief LVL0Controllers for Emergency stop - std::vector<LVL0ControllerBase*> lvl0ControllersEmergencyStop; + + //other + /// @brief Stores joints accessed via getJointTarget + JointNameToControlModeDictionary jointsUsedByLVL1Controler; + std::map<std::string, DynamicLibraryPtr> loadedLibs; }; using RobotUnitPtr = IceInternal::Handle<RobotUnit>;