From e1ab835b5abaedad74cbfb9442f0b289da350736 Mon Sep 17 00:00:00 2001 From: Raphael Grimm <raphael.grimm@kit.edu> Date: Mon, 2 Sep 2019 17:14:22 +0200 Subject: [PATCH] Added NJointCartesianWaypointController and a gui for it * Added NJointCartesianWaypointController * Added CartesianWaypointControlGuiGuiPlugin * changed CartesianWaypointControllerConfig to include the acc ramps --- etc/doxygen/pages/GuiPlugins.dox | 2 + .../components/units/RobotUnit/CMakeLists.txt | 2 + ...intCartesianVelocityControllerWithRamp.cpp | 6 + .../NJointCartesianWaypointController.cpp | 329 +++++++++++++++++ .../NJointCartesianWaypointController.h | 120 +++++++ source/RobotAPI/gui-plugins/CMakeLists.txt | 3 +- .../CMakeLists.txt | 30 ++ .../CartesianWaypointControlGuiGuiPlugin.cpp | 33 ++ .../CartesianWaypointControlGuiGuiPlugin.h | 50 +++ .../CartesianWaypointControlGuiWidget.ui | 335 ++++++++++++++++++ ...sianWaypointControlGuiWidgetController.cpp | 254 +++++++++++++ ...tesianWaypointControlGuiWidgetController.h | 124 +++++++ .../MatrixDatafieldDisplayWidget.cpp | 1 - source/RobotAPI/interface/CMakeLists.txt | 1 + .../CartesianWaypointControllerConfig.ice | 16 +- .../NJointCartesianWaypointController.ice | 67 ++++ .../CartesianVelocityControllerWithRamp.cpp | 3 + .../CartesianVelocityControllerWithRamp.h | 1 + .../core/CartesianWaypointController.cpp | 13 + .../core/CartesianWaypointController.h | 6 +- 20 files changed, 1384 insertions(+), 12 deletions(-) create mode 100644 source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp create mode 100644 source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CMakeLists.txt create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.cpp create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.h create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp create mode 100644 source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h create mode 100644 source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice diff --git a/etc/doxygen/pages/GuiPlugins.dox b/etc/doxygen/pages/GuiPlugins.dox index b8922c0ea..e090dfd48 100644 --- a/etc/doxygen/pages/GuiPlugins.dox +++ b/etc/doxygen/pages/GuiPlugins.dox @@ -26,4 +26,6 @@ The following Gui Plugins are available: \subpage ArmarXGui-GuiPlugins-RobotUnitPlugin \subpage ArmarXGui-GuiPlugins-GuiHealthClient + +\subpage RobotAPI-GuiPlugins-CartesianWaypointControlGui */ diff --git a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt index 60ce76b94..2fbf0d924 100755 --- a/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt +++ b/source/RobotAPI/components/units/RobotUnit/CMakeLists.txt @@ -49,6 +49,7 @@ set(LIB_FILES NJointControllers/NJointCartesianTorqueController.cpp NJointControllers/NJointTaskSpaceImpedanceController.cpp NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp + NJointControllers/NJointCartesianWaypointController.cpp #NJointControllers/NJointCartesianActiveImpedanceController.cpp Devices/SensorDevice.cpp @@ -117,6 +118,7 @@ set(LIB_HEADERS NJointControllers/NJointCartesianVelocityController.h NJointControllers/NJointCartesianTorqueController.h NJointControllers/NJointCartesianVelocityControllerWithRamp.h + NJointControllers/NJointCartesianWaypointController.h #NJointControllers/NJointCartesianActiveImpedanceController.h Devices/DeviceBase.h diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp index 0d3d1b5b4..6edb465ad 100644 --- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp +++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianVelocityControllerWithRamp.cpp @@ -85,12 +85,15 @@ namespace armarx void NJointCartesianVelocityControllerWithRamp::rtPreActivateController() { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" Eigen::VectorXf currentJointVelocities(velocitySensors.size()); for (size_t i = 0; i < velocitySensors.size(); i++) { currentJointVelocities(i) = *velocitySensors.at(i); } controller->setCurrentJointVelocity(currentJointVelocities); +#pragma GCC diagnostic pop ARMARX_IMPORTANT << "initial joint velocities: " << currentJointVelocities.transpose(); } @@ -159,7 +162,10 @@ namespace armarx void NJointCartesianVelocityControllerWithRamp::immediateHardStop(const Ice::Current&) { LockGuardType guard {controlDataMutex}; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" controller->setCurrentJointVelocity(Eigen::VectorXf::Zero(velocitySensors.size())); +#pragma GCC diagnostic pop getWriterControlStruct().xVel = 0; getWriterControlStruct().yVel = 0; getWriterControlStruct().zVel = 0; diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp new file mode 100644 index 000000000..c0f082947 --- /dev/null +++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp @@ -0,0 +1,329 @@ +#include <ArmarXCore/util/CPPUtility/Iterator.h> + +#include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h> +#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValue1DoFActuator.h> +#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h> + +#include "NJointCartesianWaypointController.h" + +namespace armarx +{ + + NJointControllerRegistration<NJointCartesianWaypointController> registrationControllerNJointCartesianWaypointController("NJointCartesianWaypointController"); + + std::string NJointCartesianWaypointController::getClassName(const Ice::Current&) const + { + return "NJointCartesianWaypointController"; + } + + NJointCartesianWaypointController::NJointCartesianWaypointController( + RobotUnitPtr, + const NJointCartesianWaypointControllerConfigPtr& config, + const VirtualRobot::RobotPtr& + ) + { + ARMARX_CHECK_NOT_NULL(config); + + //sensor + { + if (!config->ftName.empty()) + { + const auto svalFT = useSensorValue<SensorValueForceTorque>(config->ftName); + ARMARX_CHECK_NOT_NULL(svalFT); + _rtForceSensor = &(svalFT->force); + _rtTorqueSensor = &(svalFT->force); + } + } + //ctrl + { + auto rtRobot = useSynchronizedRtRobot(); + ARMARX_CHECK_NOT_NULL(rtRobot); + + auto rns = rtRobot->getRobotNodeSet(config->rns); + ARMARX_CHECK_NOT_NULL(rns); + ARMARX_CHECK_NOT_NULL(rns->getTCP()); + + _rtJointVelocityFeedbackBuffer = Eigen::VectorXf::Zero(static_cast<int>(rns->getSize())); + + _rtWpController = std::make_unique<CartesianWaypointController>( + rns, + _rtJointVelocityFeedbackBuffer, + config->runCfg.wpCfg.maxPositionAcceleration, + config->runCfg.wpCfg.maxOrientationAcceleration, + config->runCfg.wpCfg.maxNullspaceAcceleration + ); + + _rtWpController->setConfig({}); + + for (size_t i = 0; i < rns->getSize(); ++i) + { + std::string jointName = rns->getNode(i)->getName(); + auto ct = useControlTarget<ControlTarget1DoFActuatorVelocity>(jointName, ControlModes::Velocity1DoF); + auto sv = useSensorValue<SensorValue1DoFActuatorVelocity>(jointName); + ARMARX_CHECK_NOT_NULL(ct); + ARMARX_CHECK_NOT_NULL(sv); + + _rtVelTargets.emplace_back(&(ct->velocity)); + _rtVelSensors.emplace_back(&(sv->velocity)); + } + } + } + + void NJointCartesianWaypointController::rtPreActivateController() + { + _publishIsAtTarget = false; + _publishIsAtForceLimit = false; + _rtForceOffset = Eigen::Vector3f::Zero(); + + _publishErrorPos = 0; + _publishErrorOri = 0; + _publishErrorPosMax = 0; + _publishErrorOriMax = 0; + _publishForceThreshold = _rtForceThreshold; + + //feedback + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + for (const auto& [idx, ptr] : MakeIndexedContainer(_rtVelSensors)) + { + _rtJointVelocityFeedbackBuffer(idx) = *ptr; + } + _rtWpController->setCurrentJointVelocity(_rtJointVelocityFeedbackBuffer); +#pragma GCC diagnostic pop + } + } + + void NJointCartesianWaypointController::rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) + { + if (_tripBufWpCtrl.updateReadBuffer()) + { + ARMARX_RT_LOGF_IMPORTANT("updates in tripple buffer"); + auto& r = _tripBufWpCtrl._getNonConstReadBuffer(); + if (r.cfgUpdated) + { + r.cfgUpdated = false; + _rtWpController->setConfig(r.cfg.wpCfg); + _rtForceThreshold = r.cfg.forceThreshold; + _publishForceThreshold = _rtForceThreshold; + ARMARX_RT_LOGF_IMPORTANT("updated the controller config"); + } + if (r.wpsUpdated) + { + _rtStopConditionReached = false; + _publishIsAtTarget = false; + r.wpsUpdated = false; + ARMARX_RT_LOGF_IMPORTANT("updated waypoints (# = %u)", r.wps.size()); + _publishWpsNum = r.wps.size(); + _rtHasWps = !r.wps.empty(); + _rtWpController->swapWaypoints(r.wps); + _rtWpController->skipToClosestWaypoint(r.skipRad2mmFactor); + } + } + //run + bool reachedTarget = false; + bool reachedFtLimit = false; + + if (_rtForceSensor) + { + auto& ft = _tripBufFT.getWriteBuffer(); + ft.force = *_rtForceSensor; + ft.torque = *_rtTorqueSensor; + ft.timestampInUs = sensorValuesTimestamp.toMicroSeconds(); + _tripBufFT.commitWrite(); + + if (_setFTOffset) + { + _rtForceOffset = *_rtForceSensor; + _setFTOffset = false; + } + + const float currentForce = (*_rtForceSensor - _rtForceOffset).norm() ; + + reachedFtLimit = (_rtForceThreshold >= 0) && currentForce > _rtForceThreshold; + _publishForceCurrent = currentForce; + _publishIsAtForceLimit = reachedFtLimit; + } + + _publishWpsCur = _rtHasWps ? _rtWpController->currentWaypointIndex : 0; + + if (_rtHasWps) + { + const float errorPos = _rtWpController->getPositionError(); + const float errorOri = _rtWpController->getOrientationError(); + + _publishErrorPos = errorPos; + _publishErrorOri = errorOri; + if (!_rtWpController->isLastWaypoint()) + { + _publishErrorPosMax = _rtWpController->thresholdPositionNear; + _publishErrorOriMax = _rtWpController->thresholdOrientationNear; + } + else + { + _publishErrorPosMax = _rtWpController->thresholdPositionReached; + _publishErrorOriMax = _rtWpController->thresholdOrientationReached; + reachedTarget = (errorPos < _rtWpController->thresholdPositionReached) && + (errorOri < _rtWpController->thresholdOrientationReached); + } + } + _rtStopConditionReached = _rtStopConditionReached || reachedFtLimit || reachedTarget; + _publishIsAtTarget = reachedTarget; + if (!_rtHasWps || _rtStopConditionReached) + { + setNullVelocity(); + } + else + { + const Eigen::VectorXf& goal = _rtWpController->calculate(timeSinceLastIteration.toSecondsDouble()); + //write targets + ARMARX_CHECK_EQUAL(static_cast<std::size_t>(goal.size()), _rtVelTargets.size()); + for (const auto& [idx, ptr] : MakeIndexedContainer(_rtVelTargets)) + { + *ptr = goal(idx); + } + } + } + + void NJointCartesianWaypointController::rtPostDeactivateController() + { + + } + + bool NJointCartesianWaypointController::hasReachedTarget(const Ice::Current&) + { + return _publishIsAtTarget; + } + void NJointCartesianWaypointController::setConfig(const CartesianWaypointControllerConfigWithForceLimit& cfg, const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = false; + w.cfgUpdated = true; + w.cfg = cfg; + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "set new config"; + } + void NJointCartesianWaypointController::setWaypoints(const std::vector<Eigen::Matrix4f>& wps, const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = true; + w.cfgUpdated = false; + w.wps = wps; + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "set " << wps.size() << " new waypoints"; + } + void NJointCartesianWaypointController::setWaypoint(const Eigen::Matrix4f& wp, const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = true; + w.cfgUpdated = false; + w.wps.clear(); + w.wps.emplace_back(wp); + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "set new waypoint"; + } + void NJointCartesianWaypointController::setConfigAndWaypoints(const CartesianWaypointControllerConfigWithForceLimit& cfg, + const std::vector<Eigen::Matrix4f>& wps, + const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = true; + w.cfgUpdated = true; + w.cfg = cfg; + w.wps = wps; + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "set new config and" << wps.size() << " new waypoints"; + } + void NJointCartesianWaypointController::setConfigAndWaypoint(const CartesianWaypointControllerConfigWithForceLimit& cfg, + const Eigen::Matrix4f& wp, + const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = true; + w.cfgUpdated = true; + w.cfg = cfg; + w.wps.clear(); + w.wps.emplace_back(wp); + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "set new config and a new waypoint"; + } + void NJointCartesianWaypointController::setNullVelocity() + { + for (auto ptr : _rtVelTargets) + { + *ptr = 0; + } + } + + bool NJointCartesianWaypointController::hasReachedForceLimit(const Ice::Current&) + { + ARMARX_CHECK_NOT_NULL(_rtForceSensor); + return _publishIsAtForceLimit; + } + FTSensorValue NJointCartesianWaypointController::getFTSensorValue(const Ice::Current&) + { + ARMARX_CHECK_NOT_NULL(_rtForceSensor); + std::lock_guard g{_tripBufFTMut}; + return _tripBufFT.getUpToDateReadBuffer(); + } + void NJointCartesianWaypointController::setCurrentFTAsOffset(const Ice::Current&) + { + ARMARX_CHECK_NOT_NULL(_rtForceSensor); + _setFTOffset = true; + } + void NJointCartesianWaypointController::stopMovement(const Ice::Current&) + { + std::lock_guard g{_tripBufWpCtrlMut}; + auto& w = _tripBufWpCtrl.getWriteBuffer(); + w.wpsUpdated = true; + w.cfgUpdated = false; + w.wps.clear(); + _tripBufWpCtrl.commitWrite(); + ARMARX_IMPORTANT << "stop movement by setting 0 waypoints"; + } + + void NJointCartesianWaypointController::onPublish( + const SensorAndControl&, + const DebugDrawerInterfacePrx&, + const DebugObserverInterfacePrx& obs) + { + const std::size_t wpsNum = _publishWpsNum; + const std::size_t wpsCur = wpsNum ? _publishWpsCur + 1 : 0; + + const float errorPos = _publishErrorPos; + const float errorOri = _publishErrorOri; + const float errorPosMax = _publishErrorPosMax; + const float errorOriMax = _publishErrorOriMax; + const float forceThreshold = _publishForceThreshold; + const float forceCurrent = _publishForceCurrent; + + { + StringVariantBaseMap datafields; + datafields["WpNum"] = new Variant(static_cast<int>(wpsNum)); + datafields["WpCur"] = new Variant(static_cast<int>(wpsCur)); + + datafields["errorPos"] = new Variant(errorPos); + datafields["errorOri"] = new Variant(errorOri); + datafields["errorPosMax"] = new Variant(errorPosMax); + datafields["errorOriMax"] = new Variant(errorOriMax); + + datafields["forceThreshold"] = new Variant(forceThreshold); + datafields["forceCurrent"] = new Variant(forceCurrent); + + obs->setDebugChannel(getInstanceName(), datafields); + } + + ARMARX_INFO << deactivateSpam(1) << std::setprecision(4) + << "At waypoint " << wpsCur << " / " << wpsNum + << " (last " << _publishIsAtTarget + << ", ft limit " << _publishIsAtForceLimit + << ", perror " << errorPos << " / " << errorPosMax + << ", oerror " << errorOri << " / " << errorOriMax + << ')'; + } +} diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h new file mode 100644 index 000000000..50b76c243 --- /dev/null +++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h @@ -0,0 +1,120 @@ +#pragma once + +#include <VirtualRobot/Robot.h> +#include <VirtualRobot/RobotNodeSet.h> + +#include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointController.h> + +#include <RobotAPI/libraries/core/CartesianWaypointController.h> +#include <RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.h> + +namespace armarx +{ + + TYPEDEF_PTRS_HANDLE(NJointCartesianWaypointController); + + /** + * @brief The NJointCartesianWaypointController class + * @ingroup Library-RobotUnit-NJointControllers + */ + class NJointCartesianWaypointController : + public NJointController, + public NJointCartesianWaypointControllerInterface + { + public: + using ConfigPtrT = NJointCartesianWaypointControllerConfigPtr; + NJointCartesianWaypointController( + RobotUnitPtr robotUnit, + const NJointCartesianWaypointControllerConfigPtr& config, + const VirtualRobot::RobotPtr&); + + // NJointControllerInterface interface + std::string getClassName(const Ice::Current& = Ice::emptyCurrent) const override; + // WidgetDescription::StringWidgetDictionary getFunctionDescriptions(const Ice::Current& = Ice::emptyCurrent) const override; + // void callDescribedFunction(const std::string& name, const StringVariantBaseMap& valueMap, const Ice::Current& = Ice::emptyCurrent) override; + + // NJointController interface + void rtRun(const IceUtil::Time& sensorValuesTimestamp, const IceUtil::Time& timeSinceLastIteration) override; + // static WidgetDescription::WidgetPtr GenerateConfigDescription( + // const VirtualRobot::RobotPtr&, + // const std::map<std::string, ConstControlDevicePtr>&, + // const std::map<std::string, ConstSensorDevicePtr>&); + + // static NJointCartesianWaypointControllerConfigPtr GenerateConfigFromVariants(const StringVariantBaseMap& values); + // NJointCartesianWaypointController( + // RobotUnitPtr prov, + // NJointCartesianWaypointControllerConfigPtr config, + // const VirtualRobot::RobotPtr& r); + + void onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, const DebugObserverInterfacePrx&) override; + + public: + bool hasReachedTarget(const Ice::Current& = Ice::emptyCurrent) override; + bool hasReachedForceLimit(const Ice::Current& = Ice::emptyCurrent) override; + + void setConfig(const CartesianWaypointControllerConfigWithForceLimit& cfg, const Ice::Current& = Ice::emptyCurrent) override; + void setWaypoints(const std::vector<Eigen::Matrix4f>& wps, const Ice::Current& = Ice::emptyCurrent) override; + void setWaypoint(const Eigen::Matrix4f& wp, const Ice::Current& = Ice::emptyCurrent) override; + void setConfigAndWaypoints(const CartesianWaypointControllerConfigWithForceLimit& cfg, const std::vector<Eigen::Matrix4f>& wps, const Ice::Current& = Ice::emptyCurrent) override; + void setConfigAndWaypoint(const CartesianWaypointControllerConfigWithForceLimit& cfg, const Eigen::Matrix4f& wp, const Ice::Current& = Ice::emptyCurrent) override; + void stopMovement(const Ice::Current& = Ice::emptyCurrent) override; + + FTSensorValue getFTSensorValue(const Ice::Current& = Ice::emptyCurrent) override; + void setCurrentFTAsOffset(const Ice::Current& = Ice::emptyCurrent) override; + protected: + void rtPreActivateController() override; + void rtPostDeactivateController() override; + + //structs + private: + struct CtrlData + { + std::vector<Eigen::Matrix4f> wps; + CartesianWaypointControllerConfigWithForceLimit cfg; + float skipRad2mmFactor = 500; + bool wpsUpdated = false; + bool cfgUpdated = false; + }; + + //data + private: + void setNullVelocity(); + + //rt data + std::unique_ptr<CartesianWaypointController> _rtWpController; + Eigen::VectorXf _rtJointVelocityFeedbackBuffer; + + std::vector<const float*> _rtVelSensors; + std::vector<float*> _rtVelTargets; + + const Eigen::Vector3f* _rtForceSensor = nullptr; + const Eigen::Vector3f* _rtTorqueSensor = nullptr; + + Eigen::Vector3f _rtForceOffset; + + float _rtForceThreshold = -1; + bool _rtHasWps = false; + bool _rtStopConditionReached = false; + + //flags + std::atomic_bool _publishIsAtTarget{false}; + std::atomic_bool _publishIsAtForceLimit{false}; + std::atomic_bool _setFTOffset{false}; + + //buffers + mutable std::recursive_mutex _tripBufWpCtrlMut; + TripleBuffer<CtrlData> _tripBufWpCtrl; + mutable std::recursive_mutex _tripBufFTMut; + TripleBuffer<FTSensorValue> _tripBufFT; + + //publish data + std::atomic_size_t _publishWpsNum{0}; + std::atomic_size_t _publishWpsCur{0}; + std::atomic<float> _publishErrorPos{0}; + std::atomic<float> _publishErrorOri{0}; + std::atomic<float> _publishErrorPosMax{0}; + std::atomic<float> _publishErrorOriMax{0}; + std::atomic<float> _publishForceThreshold{0}; + std::atomic<float> _publishForceCurrent{0}; + }; +} diff --git a/source/RobotAPI/gui-plugins/CMakeLists.txt b/source/RobotAPI/gui-plugins/CMakeLists.txt index ee50015cb..a7264e2ef 100644 --- a/source/RobotAPI/gui-plugins/CMakeLists.txt +++ b/source/RobotAPI/gui-plugins/CMakeLists.txt @@ -10,4 +10,5 @@ add_subdirectory(LaserScannerPlugin) add_subdirectory(RobotUnitPlugin) add_subdirectory(HomogeneousMatrixCalculator) -add_subdirectory(GuiHealthClient) \ No newline at end of file +add_subdirectory(GuiHealthClient) +add_subdirectory(CartesianWaypointControlGui) \ No newline at end of file diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CMakeLists.txt b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CMakeLists.txt new file mode 100644 index 000000000..38578c06d --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CMakeLists.txt @@ -0,0 +1,30 @@ +armarx_set_target("CartesianWaypointControlGuiGuiPlugin") + +armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available") + +set(SOURCES + CartesianWaypointControlGuiGuiPlugin.cpp + CartesianWaypointControlGuiWidgetController.cpp +) + +set(HEADERS + CartesianWaypointControlGuiGuiPlugin.h + CartesianWaypointControlGuiWidgetController.h +) + +set(GUI_MOC_HDRS ${HEADERS}) + +set(GUI_UIS CartesianWaypointControlGuiWidget.ui) + +set(COMPONENT_LIBS + VirtualRobot + + SimpleConfigDialog + + RobotAPIInterfaces + RobotAPICore +) + +if(ArmarXGui_FOUND) + armarx_gui_library(CartesianWaypointControlGuiGuiPlugin "${SOURCES}" "${GUI_MOC_HDRS}" "${GUI_UIS}" "" "${COMPONENT_LIBS}") +endif() diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.cpp b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.cpp new file mode 100644 index 000000000..fea32168c --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.cpp @@ -0,0 +1,33 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * \package RobotAPI::gui-plugins::CartesianWaypointControlGuiGuiPlugin + * \author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * \date 2019 + * \copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include "CartesianWaypointControlGuiGuiPlugin.h" + +#include "CartesianWaypointControlGuiWidgetController.h" + +namespace armarx +{ + CartesianWaypointControlGuiGuiPlugin::CartesianWaypointControlGuiGuiPlugin() + { + addWidget < CartesianWaypointControlGuiWidgetController > (); + } +} diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.h b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.h new file mode 100644 index 000000000..b4b523dcc --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiGuiPlugin.h @@ -0,0 +1,50 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * \package RobotAPI::gui-plugins::CartesianWaypointControlGui + * \author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * \date 2019 + * \copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ +#pragma once + +#include <ArmarXCore/core/system/ImportExportComponent.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> + +namespace armarx +{ + /** + * \class CartesianWaypointControlGuiGuiPlugin + * \ingroup ArmarXGuiPlugins + * \brief CartesianWaypointControlGuiGuiPlugin brief description + * + * Detailed description + */ + class ARMARXCOMPONENT_IMPORT_EXPORT CartesianWaypointControlGuiGuiPlugin: + public armarx::ArmarXGuiPlugin + { + Q_OBJECT + Q_INTERFACES(ArmarXGuiInterface) + Q_PLUGIN_METADATA(IID "ArmarXGuiInterface/1.00") + public: + /** + * All widgets exposed by this plugin are added in the constructor + * via calls to addWidget() + */ + CartesianWaypointControlGuiGuiPlugin(); + }; +} diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui new file mode 100644 index 000000000..a4d546f47 --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidget.ui @@ -0,0 +1,335 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CartesianWaypointControlGuiWidget</class> + <widget class="QWidget" name="CartesianWaypointControlGuiWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>907</width> + <height>739</height> + </rect> + </property> + <property name="windowTitle"> + <string>CartesianWaypointControlGuiWidget</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Waypoints</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0" colspan="2"> + <widget class="QWidget" name="widgetWPs" native="true"> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="1" column="0" colspan="2"> + <widget class="QTextEdit" name="textEditWPs"/> + </item> + <item row="2" column="0"> + <widget class="QPushButton" name="pushButtonExecute"> + <property name="text"> + <string>Execute Waypoints</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Format</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButtonWPJson"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>json</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton4f"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Matrix4f</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="labelParsingSuccess"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="pushButtonStop"> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Settings</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="widgetSettings" native="true"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>FT limit</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="pushButtonZeroFT"> + <property name="text"> + <string>Zero FT</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonSendSettings"> + <property name="text"> + <string>Send</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxFTLimit"> + <property name="minimum"> + <double>-1.000000000000000</double> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + <property name="value"> + <double>-1.000000000000000</double> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Controller Creation</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Kinematic Chain</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEditFTName"/> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QPushButton" name="pushButtonCreateController"> + <property name="text"> + <string>Create</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>FT Sensor (optional)</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBoxChain"/> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="labelCurrentControllerChain"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="labelCurrentControllerFT"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Current</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>groupBox</sender> + <signal>clicked(bool)</signal> + <receiver>groupBox</receiver> + <slot>setVisible(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>24</x> + <y>16</y> + </hint> + <hint type="destinationlabel"> + <x>176</x> + <y>32</y> + </hint> + </hints> + </connection> + <connection> + <sender>groupBox_3</sender> + <signal>clicked(bool)</signal> + <receiver>groupBox_3</receiver> + <slot>setVisible(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>51</x> + <y>157</y> + </hint> + <hint type="destinationlabel"> + <x>105</x> + <y>159</y> + </hint> + </hints> + </connection> + <connection> + <sender>groupBox_2</sender> + <signal>clicked(bool)</signal> + <receiver>groupBox_2</receiver> + <slot>setVisible(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>154</x> + <y>268</y> + </hint> + <hint type="destinationlabel"> + <x>204</x> + <y>270</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp new file mode 100644 index 000000000..eb3e88376 --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.cpp @@ -0,0 +1,254 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * \package RobotAPI::gui-plugins::CartesianWaypointControlGuiWidgetController + * \author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * \date 2019 + * \copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include <random> +#include <string> + +#include <VirtualRobot/Util/json.h> + +#include <RobotAPI/libraries/core/remoterobot/RemoteRobot.h> + +#include "CartesianWaypointControlGuiWidgetController.h" + +namespace Eigen +{ + void from_json(const nlohmann::json& j, Eigen::Matrix4f& mx) + { + mx = VirtualRobot::json::posquat2eigen4f(j); + } +} + +namespace armarx +{ + CartesianWaypointControlGuiWidgetController::CartesianWaypointControlGuiWidgetController() + { + _ui.setupUi(getWidget()); + connect(_ui.radioButtonWPJson, SIGNAL(clicked()), this, SLOT(triggerParsing())); + connect(_ui.radioButton4f, SIGNAL(clicked()), this, SLOT(triggerParsing())); + connect(_ui.textEditWPs, SIGNAL(textChanged()), this, SLOT(triggerParsing())); + + connect(_ui.pushButtonStop, SIGNAL(clicked()), this, SLOT(on_pushButtonStop_clicked())); + connect(_ui.pushButtonExecute, SIGNAL(clicked()), this, SLOT(on_pushButtonExecute_clicked())); + connect(_ui.pushButtonZeroFT, SIGNAL(clicked()), this, SLOT(on_pushButtonZeroFT_clicked())); + connect(_ui.pushButtonSendSettings, SIGNAL(clicked()), this, SLOT(on_pushButtonSendSettings_clicked())); + connect(_ui.pushButtonCreateController, SIGNAL(clicked()), this, SLOT(on_pushButtonCreateController_clicked())); + } + + CartesianWaypointControlGuiWidgetController::~CartesianWaypointControlGuiWidgetController() = default; + + + void CartesianWaypointControlGuiWidgetController::loadSettings(QSettings* settings) + { + _robotStateComponentName = settings->value("rsc", "Armar6StateComponent").toString().toStdString(); + _robotUnitName = settings->value("ru", "Armar6Unit").toString().toStdString(); + } + + void CartesianWaypointControlGuiWidgetController::saveSettings(QSettings* settings) + { + settings->setValue("rsc", QString::fromStdString(_robotStateComponentName)); + settings->setValue("ru", QString::fromStdString(_robotUnitName)); + } + + + void CartesianWaypointControlGuiWidgetController::onInitComponent() + { + usingProxy(_robotStateComponentName); + usingProxy(_robotUnitName); + } + + + void CartesianWaypointControlGuiWidgetController::onConnectComponent() + { + //proxies + { + _robotStateComponent = getProxy<RobotStateComponentInterfacePrx>(_robotStateComponentName); + _robotUnit = getProxy<RobotUnitInterfacePrx>(_robotUnitName); + } + //robot + { + _robot = RemoteRobot::createLocalCloneFromFile(_robotStateComponent, VirtualRobot::RobotIO::eStructure); + } + //fill rns combo box + { + bool found = false; + for (const auto& rnsn : _robot->getRobotNodeSetNames()) + { + _ui.comboBoxChain->addItem(QString::fromStdString(rnsn)); + if (rnsn == "RightArm") + { + _ui.comboBoxChain->setCurrentIndex(_ui.comboBoxChain->count() - 1); + found = true; + } + } + if(found && _robot->hasRobotNode("FT R")) + { + _ui.lineEditFTName->setText("FT R"); + } + } + } + void CartesianWaypointControlGuiWidgetController::onDisconnectComponent() + { + deleteOldController(); + } + void CartesianWaypointControlGuiWidgetController::on_pushButtonCreateController_clicked() + { + deleteOldController(); + + static const std::string njointControllerClassName = "NJointCartesianWaypointController"; + + NJointCartesianWaypointControllerConfigPtr cfg = new NJointCartesianWaypointControllerConfig; + cfg->rns = _ui.comboBoxChain->currentText().toStdString(); + cfg->ftName = _ui.lineEditFTName->text().toStdString(); + cfg->runCfg = readRunCfg(); + _supportsFT = !cfg->ftName.empty(); + + _controllerName = getName() + "_" + njointControllerClassName + + std::to_string(std::random_device{}()); + + _ui.labelCurrentControllerChain->setText(QString::fromStdString(cfg->rns)); + _ui.labelCurrentControllerFT->setText(QString::fromStdString(cfg->ftName)); + + ARMARX_IMPORTANT << "Creating " << njointControllerClassName << " '" + << _controllerName << "'"; + _controller = NJointCartesianWaypointControllerInterfacePrx::checkedCast( + _robotUnit->createNJointController( + njointControllerClassName, + _controllerName, + cfg)); + ARMARX_CHECK_NOT_NULL(_controller); + } + + void CartesianWaypointControlGuiWidgetController::on_pushButtonSendSettings_clicked() + { + if (_controller) + { + ARMARX_IMPORTANT << "sending new config to " << _controllerName; + _controller->setConfig(readRunCfg()); + } + } + + void CartesianWaypointControlGuiWidgetController::on_pushButtonZeroFT_clicked() + { + if (_controller && _supportsFT) + { + ARMARX_IMPORTANT << "setting ft offset for " << _controllerName; + _controller->setCurrentFTAsOffset(); + } + } + + void CartesianWaypointControlGuiWidgetController::on_pushButtonExecute_clicked() + { + if (_controller) + { + _controller->activateController(); + ARMARX_IMPORTANT << "trigger execution of " << _lastParsedWPs.size() + << " waypoints on " << _controllerName; + _controller->setWaypoints(_lastParsedWPs); + } + } + + void CartesianWaypointControlGuiWidgetController::on_pushButtonStop_clicked() + { + if (_controller) + { + ARMARX_IMPORTANT << "sending stop command to controller " << _controllerName; + _controller->stopMovement(); + } + } + + QPointer<QDialog> CartesianWaypointControlGuiWidgetController::getConfigDialog(QWidget* parent) + { + if (!_dialog) + { + _dialog = new SimpleConfigDialog(parent); + _dialog->addProxyFinder<RobotUnitInterfacePrx>({"ru", "Robot Unit", "*Unit"}); + _dialog->addProxyFinder<RobotStateComponentInterfacePrx>({"rsc", "Robot State Component", "*Component"}); + } + return qobject_cast<SimpleConfigDialog*>(_dialog); + } + + void CartesianWaypointControlGuiWidgetController::configured() + { + _robotStateComponentName = _dialog->getProxyName("rsc"); + _robotUnitName = _dialog->getProxyName("ru"); + } + + void CartesianWaypointControlGuiWidgetController::triggerParsing() + { + _lastParsedWPs.clear(); + _ui.labelParsingSuccess->setText("<pre parsing>"); + ///TODO _lastParsedWPs labelParsingSuccess + if (_ui.radioButtonWPJson->isChecked()) + { + //parse json + try + { + auto json = ::nlohmann::json::parse(_ui.textEditWPs->toPlainText().toStdString()); + ARMARX_INFO << "parsed string as json"; + _lastParsedWPs = json.get<std::vector<Eigen::Matrix4f>>(); + } + catch (...) + { + _ui.labelParsingSuccess->setText("Failed to parse json array!"); + return; + } + } + else if (_ui.radioButton4f->isChecked()) + { + //parse lines + ///TODO parse Matrix4f style input + _ui.labelParsingSuccess->setText("NYI"); + return; + } + //test reachability + { + ///TODO test reachability and visualize + } + _ui.labelParsingSuccess->setText("Parsed " + QString::number(_lastParsedWPs.size()) + " waypoints."); + } + + CartesianWaypointControllerConfigWithForceLimit CartesianWaypointControlGuiWidgetController::readRunCfg() const + { + CartesianWaypointControllerConfigWithForceLimit cfg; + cfg.forceThreshold = static_cast<float>(_ui.doubleSpinBoxFTLimit->value()); + ///TODO add more gui elemetns to change the execution parameters + return cfg; + } + + void CartesianWaypointControlGuiWidgetController::deleteOldController() + { + if (_controller) + { + ARMARX_IMPORTANT << "deleting old controller '" << _controllerName << "'"; + try + { + _controller->deactivateAndDeleteController(); + } + catch (...) + { + _controller = nullptr; + } + } + } +} + + diff --git a/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h new file mode 100644 index 000000000..4816a63fe --- /dev/null +++ b/source/RobotAPI/gui-plugins/CartesianWaypointControlGui/CartesianWaypointControlGuiWidgetController.h @@ -0,0 +1,124 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::gui-plugins::CartesianWaypointControlGuiWidgetController + * @author Raphael Grimm ( raphael dot grimm at kit dot edu ) + * @date 2019 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ +#pragma once + +#include <VirtualRobot/Robot.h> + +#include <ArmarXCore/core/system/ImportExportComponent.h> + +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> +#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h> +#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> + +#include <RobotAPI/interface/core/RobotState.h> +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h> +#include <RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.h> + +#include <RobotAPI/gui-plugins/CartesianWaypointControlGui/ui_CartesianWaypointControlGuiWidget.h> + +namespace armarx +{ + /** + \page RobotAPI-GuiPlugins-CartesianWaypointControlGui CartesianWaypointControlGui + \brief The CartesianWaypointControlGui allows visualizing ... + + \image html CartesianWaypointControlGui.png + The user can + + API Documentation \ref CartesianWaypointControlGuiWidgetController + + \see CartesianWaypointControlGuiGuiPlugin + */ + + /** + * \class CartesianWaypointControlGuiWidgetController + * \brief CartesianWaypointControlGuiWidgetController brief one line description + * + * Detailed description + */ + class ARMARXCOMPONENT_IMPORT_EXPORT + CartesianWaypointControlGuiWidgetController: + public armarx::ArmarXComponentWidgetControllerTemplate < CartesianWaypointControlGuiWidgetController > + { + Q_OBJECT + + public: + /// Controller Constructor + explicit CartesianWaypointControlGuiWidgetController(); + + /// Controller destructor + virtual ~CartesianWaypointControlGuiWidgetController(); + + /// @see ArmarXWidgetController::loadSettings() + void loadSettings(QSettings* settings) override; + + /// @see ArmarXWidgetController::saveSettings() + void saveSettings(QSettings* settings) override; + + /** + * Returns the Widget name displayed in the ArmarXGui to create an + * instance of this class. + */ + static QString GetWidgetName() + { + return "RobotControl.CartesianWaypointControlGui"; + } + + void onInitComponent() override; + void onConnectComponent() override; + void onDisconnectComponent() override; + + QPointer<QDialog> getConfigDialog(QWidget* parent) override; + void configured() override; + + signals: + /* QT signal declarations */ + + private slots: + void on_pushButtonStop_clicked(); + void on_pushButtonExecute_clicked(); + void on_pushButtonZeroFT_clicked(); + void on_pushButtonSendSettings_clicked(); + void on_pushButtonCreateController_clicked(); + + void triggerParsing(); + + private: + CartesianWaypointControllerConfigWithForceLimit readRunCfg() const; + void deleteOldController(); + + private: + std::string _robotStateComponentName; + std::string _robotUnitName; + RobotStateComponentInterfacePrx _robotStateComponent; + RobotUnitInterfacePrx _robotUnit; + Ui::CartesianWaypointControlGuiWidget _ui; + QPointer<SimpleConfigDialog> _dialog; + NJointCartesianWaypointControllerInterfacePrx _controller; + std::string _controllerName; + VirtualRobot::RobotPtr _robot; + std::vector<Eigen::Matrix4f> _lastParsedWPs; + bool _supportsFT{false}; + }; +} + + diff --git a/source/RobotAPI/gui-plugins/HapticUnitPlugin/MatrixDatafieldDisplayWidget.cpp b/source/RobotAPI/gui-plugins/HapticUnitPlugin/MatrixDatafieldDisplayWidget.cpp index 294707b12..8a05e556a 100644 --- a/source/RobotAPI/gui-plugins/HapticUnitPlugin/MatrixDatafieldDisplayWidget.cpp +++ b/source/RobotAPI/gui-plugins/HapticUnitPlugin/MatrixDatafieldDisplayWidget.cpp @@ -22,7 +22,6 @@ * GNU General Public License */ #include "MatrixDatafieldDisplayWidget.h" -//#include "ui_MatrixDatafieldDisplayWidget.h" #include <QPainter> #include <pthread.h> diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt index a14744594..273194576 100644 --- a/source/RobotAPI/interface/CMakeLists.txt +++ b/source/RobotAPI/interface/CMakeLists.txt @@ -56,6 +56,7 @@ set(SLICE_FILES units/RobotUnit/NJointCartesianTorqueController.ice units/RobotUnit/NJointCartesianActiveImpedanceController.ice units/RobotUnit/NJointCartesianVelocityControllerWithRamp.ice + units/RobotUnit/NJointCartesianWaypointController.ice units/RobotUnit/RobotUnitInterface.ice units/RobotUnit/NJointJointSpaceDMPController.ice diff --git a/source/RobotAPI/interface/core/CartesianWaypointControllerConfig.ice b/source/RobotAPI/interface/core/CartesianWaypointControllerConfig.ice index 1e2a1a8e9..5a509ea7b 100644 --- a/source/RobotAPI/interface/core/CartesianWaypointControllerConfig.ice +++ b/source/RobotAPI/interface/core/CartesianWaypointControllerConfig.ice @@ -26,13 +26,17 @@ module armarx { struct CartesianWaypointControllerConfig { - float kpJointLimitAvoidance = 1; - float jointLimitAvoidanceScale = 2; + float maxPositionAcceleration = 500; + float maxOrientationAcceleration = 1; + float maxNullspaceAcceleration = 2; - float thresholdOrientationNear = 0.1; - float thresholdOrientationReached = 0.05; - float thresholdPositionNear = 50; - float thresholdPositionReached = 5; + float kpJointLimitAvoidance = 1; + float jointLimitAvoidanceScale = 2; + + float thresholdOrientationNear = 0.1; + float thresholdOrientationReached = 0.05; + float thresholdPositionNear = 50; + float thresholdPositionReached = 5; float maxOriVel = 1; float maxPosVel = 80; diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice new file mode 100644 index 000000000..4d722bb95 --- /dev/null +++ b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice @@ -0,0 +1,67 @@ +/* +* This file is part of ArmarX. +* +* ArmarX is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* ArmarX is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* @package ArmarX::RobotAPI +* @author Raphael Grimm +* @copyright 2019 Humanoids Group, H2T, KIT +* @license http://www.gnu.org/licenses/gpl-2.0.txt +* GNU General Public License +*/ + +#pragma once + +#include <ArmarXCore/interface/serialization/Eigen.ice> + +#include <RobotAPI/interface/units/RobotUnit/NJointController.ice> +#include <RobotAPI/interface/core/CartesianWaypointControllerConfig.ice> + +module armarx +{ + struct CartesianWaypointControllerConfigWithForceLimit + { + CartesianWaypointControllerConfig wpCfg; + float forceThreshold = -1; // < 0 -> no limit + }; + + struct FTSensorValue + { + long timestampInUs = 0; + Eigen::Vector3f force; + Eigen::Vector3f torque; + }; + + class NJointCartesianWaypointControllerConfig extends NJointControllerConfig + { + string rns; + CartesianWaypointControllerConfigWithForceLimit runCfg; + string ftName; //optional + }; + + interface NJointCartesianWaypointControllerInterface extends NJointControllerInterface + { + idempotent bool hasReachedTarget(); + idempotent bool hasReachedForceLimit(); + + void setConfig(CartesianWaypointControllerConfigWithForceLimit cfg); + void setWaypoints(Eigen::Matrix4fSeq wps); + void setWaypoint(Eigen::Matrix4f wp); + void setConfigAndWaypoints(CartesianWaypointControllerConfigWithForceLimit cfg, Eigen::Matrix4fSeq wps); + void setConfigAndWaypoint(CartesianWaypointControllerConfigWithForceLimit cfg, Eigen::Matrix4f wp); + + FTSensorValue getFTSensorValue(); + void setCurrentFTAsOffset(); + void stopMovement(); + }; +}; diff --git a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp index bd336320b..775d29544 100644 --- a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp +++ b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.cpp @@ -32,7 +32,10 @@ CartesianVelocityControllerWithRamp::CartesianVelocityControllerWithRamp(const V : controller(rns, tcp), mode(mode) { setMaxAccelerations(maxPositionAcceleration, maxOrientationAcceleration, maxNullspaceAcceleration); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" setCurrentJointVelocity(currentJointVelocity); +#pragma GCC diagnostic pop } void CartesianVelocityControllerWithRamp::setCurrentJointVelocity(const Eigen::Ref<const Eigen::VectorXf>& currentJointVelocity) diff --git a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h index 3f0932ab9..0c47ae498 100644 --- a/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h +++ b/source/RobotAPI/libraries/core/CartesianVelocityControllerWithRamp.h @@ -49,6 +49,7 @@ namespace armarx CartesianVelocityControllerWithRamp(CartesianVelocityControllerWithRamp&&) = default; CartesianVelocityControllerWithRamp& operator=(CartesianVelocityControllerWithRamp&&) = default; + [[deprecated("compued null space velocity does not match pseudo inverse svd method in simox. never use this function.")]] void setCurrentJointVelocity(const Eigen::Ref<const Eigen::VectorXf>& currentJointVelocity); Eigen::VectorXf calculate(const Eigen::VectorXf& cartesianVel, float jointLimitAvoidanceScale, float dt); diff --git a/source/RobotAPI/libraries/core/CartesianWaypointController.cpp b/source/RobotAPI/libraries/core/CartesianWaypointController.cpp index 975cc058a..675dc505f 100644 --- a/source/RobotAPI/libraries/core/CartesianWaypointController.cpp +++ b/source/RobotAPI/libraries/core/CartesianWaypointController.cpp @@ -223,5 +223,18 @@ namespace armarx ctrlCartesianPos2Vel.maxPosVel = cfg.maxPosVel; ctrlCartesianPos2Vel.KpOri = cfg.kpOri; ctrlCartesianPos2Vel.KpPos = cfg.kpPos; + + ctrlCartesianVelWithRamps.setMaxAccelerations( + cfg.maxPositionAcceleration, + cfg.maxOrientationAcceleration, + cfg.maxNullspaceAcceleration + ); + } + void CartesianWaypointController::setCurrentJointVelocity(const Eigen::Ref<const Eigen::VectorXf>& currentJointVelocity) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ctrlCartesianVelWithRamps.setCurrentJointVelocity(currentJointVelocity); +#pragma GCC diagnostic pop } } diff --git a/source/RobotAPI/libraries/core/CartesianWaypointController.h b/source/RobotAPI/libraries/core/CartesianWaypointController.h index e199af936..59932ae8d 100644 --- a/source/RobotAPI/libraries/core/CartesianWaypointController.h +++ b/source/RobotAPI/libraries/core/CartesianWaypointController.h @@ -58,10 +58,8 @@ namespace armarx ); - void setCurrentJointVelocity(const Eigen::Ref<const Eigen::VectorXf>& currentJointVelocity) - { - ctrlCartesianVelWithRamps.setCurrentJointVelocity(currentJointVelocity); - } + [[deprecated("compued null space velocity does not match pseudo inverse svd method in simox. never use this function.")]] + void setCurrentJointVelocity(const Eigen::Ref<const Eigen::VectorXf>& currentJointVelocity); const Eigen::VectorXf& calculate(float dt); -- GitLab