diff --git a/source/RobotAPI/components/RobotNameService/RobotNameService.cpp b/source/RobotAPI/components/RobotNameService/RobotNameService.cpp index 9ab8e07d7ca5234e40e167ae73201cae04105db5..397a638912d93ef767bcd23795e7e2e709b0f18a 100644 --- a/source/RobotAPI/components/RobotNameService/RobotNameService.cpp +++ b/source/RobotAPI/components/RobotNameService/RobotNameService.cpp @@ -54,8 +54,8 @@ namespace armarx } bool - RobotNameService::registerRobot(const robot_name_service::dto::Robot& robot, - const Ice::Current& current) + RobotNameService::registerRobotInfo(const robot_name_service::dto::RobotInfo& robot, + const Ice::Current& current) { std::scoped_lock l(robotsMutex); ARMARX_INFO << "Register a new robot with name '" << robot.name << "' in RNS"; @@ -72,7 +72,7 @@ namespace armarx } void - RobotNameService::unregisterRobot(const std::string& name, const Ice::Current& current) + RobotNameService::unregisterRobotInfo(const std::string& name, const Ice::Current& current) { std::scoped_lock l(robotsMutex); @@ -82,8 +82,8 @@ namespace armarx } } - IceUtil::Optional<robot_name_service::dto::Robot> - RobotNameService::getRobot(const std::string& name, const Ice::Current& current) + IceUtil::Optional<robot_name_service::dto::RobotInfo> + RobotNameService::getRobotInfo(const std::string& name, const Ice::Current& current) { std::scoped_lock l(robotsMutex); diff --git a/source/RobotAPI/components/RobotNameService/RobotNameService.h b/source/RobotAPI/components/RobotNameService/RobotNameService.h index 7af787aef845a26c8ed47f7b9351c36cd6dce002..6cc056c194cdc73146551ae1da50e097b438c894 100644 --- a/source/RobotAPI/components/RobotNameService/RobotNameService.h +++ b/source/RobotAPI/components/RobotNameService/RobotNameService.h @@ -87,14 +87,14 @@ namespace armarx // RobotNameServiceInterface interface public: - bool registerRobot(const robot_name_service::dto::Robot& robot, - const Ice::Current& current) override; - void unregisterRobot(const std::string& name, const Ice::Current& current) override; - IceUtil::Optional<robot_name_service::dto::Robot> - getRobot(const std::string& name, const Ice::Current& current) override; + bool registerRobotInfo(const robot_name_service::dto::RobotInfo& robot, + const Ice::Current& current) override; + void unregisterRobotInfo(const std::string& name, const Ice::Current& current) override; + IceUtil::Optional<robot_name_service::dto::RobotInfo> + getRobotInfo(const std::string& name, const Ice::Current& current) override; private: mutable std::mutex robotsMutex; - std::map<std::string, robot_name_service::core::Robot> robots; + std::map<std::string, robot_name_service::core::RobotInfo> robots; }; } // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt index 113ccd8706d8f7c64cbd067f1002a5969b3f9507..5df70b65810beeead4599151d25b15960a26e615 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCES aronTreeWidget/modal/AronTreeWidgetModal.cpp ColorPalettes.cpp SkillManagerMonitorWidgetController.cpp + PeriodicUpdateWidget.cpp ) set(HEADERS @@ -53,6 +54,7 @@ set(HEADERS aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h ColorPalettes.h SkillManagerMonitorWidgetController.h + PeriodicUpdateWidget.h ) set(GUI_UIS diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e23920f1bb06788a1e6e4a8dc1d598349b4729a0 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.cpp @@ -0,0 +1,141 @@ +#include "PeriodicUpdateWidget.h" + +#include <cmath> + +#include <QCheckBox> +#include <QDoubleSpinBox> +#include <QHBoxLayout> +#include <QPushButton> +#include <QTimer> + +namespace armarx +{ + PeriodicUpdateWidget::PeriodicUpdateWidget(double frequency, double maxFrequency) + { + setSizePolicy(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Minimum); + + QLayout* vlayout = new QVBoxLayout(); + QLayout* hlayout = new QHBoxLayout(); + this->setLayout(vlayout); + + const int margin = 0; + hlayout->setContentsMargins(margin, margin, margin, margin); + + _updateButton = new QPushButton("Update", this); + _autoCheckBox = new QCheckBox("Auto Update", this); + _frequencySpinBox = new QDoubleSpinBox(this); + _frequencySpinBox->setValue(frequency); + _frequencySpinBox->setMinimum(0); + _frequencySpinBox->setMaximum(maxFrequency); + _frequencySpinBox->setSingleStep(0.5); + _frequencySpinBox->setSuffix(" Hz"); + + hlayout->addWidget(_updateButton); + hlayout->addWidget(_autoCheckBox); + hlayout->addWidget(_frequencySpinBox); + + vlayout->addItem(hlayout); + + + _timer = new QTimer(this); + _updateTimerFrequency(); + _frequencySpinBox->setEnabled(_autoCheckBox->isChecked()); + + + // Private connections. + connect(_autoCheckBox, &QCheckBox::toggled, this, &This::_toggleAutoUpdates); + connect(_frequencySpinBox, + &QDoubleSpinBox::editingFinished, + this, + &This::_updateTimerFrequency); + + // Public connections. + connect(_updateButton, &QPushButton::pressed, this, &This::updateSingle); + connect(_timer, &QTimer::timeout, this, &This::updatePeriodic); + + connect(this, &This::updateSingle, this, &This::update); + connect(this, &This::updatePeriodic, this, &This::update); + + // See `startTimerIfEnabled` for the signal reasoning. + // qOverload is required because `QTimer::start()` is overloaded. + connect(this, &This::startTimerSignal, _timer, qOverload<>(&QTimer::start)); + connect(this, &This::stopTimerSignal, _timer, &QTimer::stop); + } + + QPushButton* + PeriodicUpdateWidget::updateButton() + { + return _updateButton; + } + + int + PeriodicUpdateWidget::getUpdateIntervalMs() const + { + return static_cast<int>(std::round(1000 / _frequencySpinBox->value())); + } + + void + PeriodicUpdateWidget::startTimerIfEnabled() + { + /* A QTimer can only be started and stopped within its own thread (the thread for which + * it has the greatest affinity). Since this method can be called from any thread, we + * need to take a detour through these signals, which can be emitted from any thread and + * will always be caught in this object's (and thus the timer's) native thread. + */ + if (_autoCheckBox->isChecked()) + { + emit startTimerSignal(); + } + else + { + emit stopTimerSignal(); + } + } + + void + PeriodicUpdateWidget::stopTimer() + { + // See `startTimerIfEnabled` for the signal reasoning. + emit stopTimerSignal(); + } + + void + PeriodicUpdateWidget::_updateTimerFrequency() + { + _timer->setInterval(getUpdateIntervalMs()); + } + + void + PeriodicUpdateWidget::_toggleAutoUpdates(bool enabled) + { + // This method is already a slot, so it doesn't need to use the timer signals. + _frequencySpinBox->setEnabled(enabled); + if (enabled) + { + _timer->start(); + } + else + { + _timer->stop(); + } + } + + QCheckBox* + PeriodicUpdateWidget::autoCheckBox() + { + return _autoCheckBox; + } + + QDoubleSpinBox* + PeriodicUpdateWidget::frequencySpinBox() + { + return _frequencySpinBox; + } + + QTimer* + PeriodicUpdateWidget::timer() + { + return _timer; + } + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..9d199db39afc0a7042f5a5225b1f09c08d14bf46 --- /dev/null +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h @@ -0,0 +1,66 @@ +#pragma once + +#include <QWidget> + + +class QCheckBox; +class QDoubleSpinBox; +class QPushButton; +class QTimer; + +namespace armarx +{ + + class PeriodicUpdateWidget : public QWidget + { + Q_OBJECT + using This = PeriodicUpdateWidget; + + public: + PeriodicUpdateWidget(double frequency = 2.0, double maxFrequency = 60); + + + QTimer* timer(); + + QCheckBox* autoCheckBox(); + QDoubleSpinBox* frequencySpinBox(); + QPushButton* updateButton(); + + bool isAutoEnabled() const; + double getUpdateFrequency() const; + int getUpdateIntervalMs() const; + + void startTimerIfEnabled(); + void stopTimer(); + + + public slots: + + signals: + + void update(); + + void updateSingle(); + void updatePeriodic(); + + private slots: + + void _updateTimerFrequency(); + void _toggleAutoUpdates(bool enabled); + + signals: + + void startTimerSignal(); + void stopTimerSignal(); + + private: + QPushButton* _updateButton; + QCheckBox* _autoCheckBox; + QDoubleSpinBox* _frequencySpinBox; + + QPushButton* _collapseAllButton; + + QTimer* _timer; + }; + +} // namespace armarx diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui index 83e522b9d6f895b6f492ba63d13529712a3f194d..82569fa85833ef3eb89476da914b7ba02606864b 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui @@ -6,12 +6,12 @@ <rect> <x>0</x> <y>0</y> - <width>1060</width> - <height>657</height> + <width>1126</width> + <height>729</height> </rect> </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -19,41 +19,14 @@ <property name="windowTitle"> <string>SkillManagerMonitorWidget</string> </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="3" column="2"> - <widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/> - </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="checkBoxAutoUpdate"> - <property name="text"> - <string>Auto Update</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Update Frequency:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="3" column="3"> - <widget class="QPushButton" name="pushButtonRefreshNow"> - <property name="text"> - <string>Refresh Now</string> - </property> - </widget> - </item> - <item row="4" column="0" colspan="4"> + <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0"> + <item row="3" column="0" colspan="2"> <widget class="QSplitter" name="splitter_2"> <property name="enabled"> <bool>true</bool> </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -75,11 +48,14 @@ <string>Executions</string> </property> <layout class="QGridLayout" name="gridLayout_4"> - <item row="1" column="0" colspan="3"> + <item row="0" column="0" colspan="3"> <widget class="QTreeWidget" name="treeWidgetSkillExecutions"> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> <column> <property name="text"> - <string>ExecutionID</string> + <string>Timestamp</string> </property> </column> <column> @@ -94,27 +70,7 @@ </column> <column> <property name="text"> - <string>IsConstructing</string> - </property> - </column> - <column> - <property name="text"> - <string>IsInitializing</string> - </property> - </column> - <column> - <property name="text"> - <string>IsPreparing</string> - </property> - </column> - <column> - <property name="text"> - <string>IsRunning</string> - </property> - </column> - <column> - <property name="text"> - <string>Finished</string> + <string>Status</string> </property> </column> </widget> @@ -171,6 +127,9 @@ <item row="4" column="0"> <widget class="QLineEdit" name="lineEditSearch"> <property name="text"> + <string/> + </property> + <property name="placeholderText"> <string>Search...</string> </property> </widget> @@ -209,65 +168,65 @@ <bool>false</bool> </property> <widget class="QWidget" name="groupBoxSkillDetailsTop" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <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> - <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0"> - <widget class="QPushButton" name="pushButtonPaste"> - <property name="text"> - <string>Set args from clipboard</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QPushButton" name="pushButtonReset"> - <property name="text"> - <string>Reset args to profile</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="4"> - <widget class="QComboBox" name="comboBoxProfiles"> - <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <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> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QPushButton" name="pushButtonPaste"> <property name="text"> - <string><No Profile selected. Using root></string> + <string>Set args from clipboard</string> </property> - </item> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="pushButtonCopy"> - <property name="text"> - <string>Copy args to clipboard</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QWidget" name="skillDescription" native="true"/> - </item> - </layout> - </widget> + </widget> + </item> + <item row="0" column="3"> + <widget class="QPushButton" name="pushButtonReset"> + <property name="text"> + <string>Reset args to profile</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="4"> + <widget class="QComboBox" name="comboBoxProfiles"> + <item> + <property name="text"> + <string><No Profile selected. Using root></string> + </property> + </item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="pushButtonCopy"> + <property name="text"> + <string>Copy args to clipboard</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QWidget" name="skillDescription" native="true"/> + </item> + </layout> + </widget> <widget class="QWidget" name="groupBoxSkillDetailsBottom" native="true"> <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="leftMargin"> @@ -328,6 +287,50 @@ </widget> </widget> </item> + <item row="0" column="0" rowspan="3" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <layout class="QHBoxLayout" name="updateWidgetLayout"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="stopAllLayout"> + <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> + </layout> + </item> + </layout> + </item> </layout> </widget> <resources/> diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp index 8b88718f93dc71bae29b16094d9701c0ae7d896a..bbeaa5a4d9a889808db465419f732e5903031a31 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp @@ -22,11 +22,27 @@ #include "SkillManagerMonitorWidgetController.h" +#include <optional> +#include <regex> #include <string> +#include <SimoxUtility/algorithm/string.h> + +#include <RobotAPI/libraries/skills/core/Skill.h> + +#include "aronTreeWidget/visitors/AronTreeWidgetConverter.h" +#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h" +#include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h" + +// modals +#include "aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h" + +// debug +#include <QAction> #include <QClipboard> #include <QDoubleSpinBox> #include <QGridLayout> +#include <QMenu> #include <QTextBrowser> #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h> @@ -40,8 +56,12 @@ #include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h" #include "aronTreeWidget/widgets/SkillDescriptionWidget.h" +//configSk namespace armarx { + const skills::SkillID SkillManagerMonitorWidgetController::SelectedSkill::UNK_SKILL_ID = + skills::SkillID{.providerId = ::std::nullopt, .skillName = skills::SkillID::UNKNOWN}; + QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent) { @@ -76,6 +96,38 @@ namespace armarx // Others namespace armarx { + void + SkillManagerMonitorWidgetController::prepareAndRunMenu(const QPoint& pos) + { + QMenu* menu = new QMenu(); + + // Stop skill + QAction* stopSkillAction = new QAction("Stop execution", this); + skills::SkillStatus currentStatus = + skillStatusUpdates.at(selectedSkill.skillExecutionId).status; + stopSkillAction->setDisabled(currentStatus == skills::SkillStatus::Aborted || + currentStatus == skills::SkillStatus::Failed || + currentStatus == skills::SkillStatus::Succeeded); + + QAction* rerunSkillAction = new QAction("Re-run with similar params", this); + menu->addAction(stopSkillAction); + menu->addAction(rerunSkillAction); + connect(stopSkillAction, + &QAction::triggered, + this, + &SkillManagerMonitorWidgetController::stopSkill); + connect(rerunSkillAction, + &QAction::triggered, + this, + &SkillManagerMonitorWidgetController::rerunSkillWithSimilarParams); + + // Temporarily disable rerun-skill-Action + rerunSkillAction->setDisabled(true); + + // open menu + menu->popup(widget.treeWidgetSkillExecutions->viewport()->mapToGlobal(pos)); + } + SkillExecutionInfoTreeWidgetItem* SkillExecutionInfoTreeWidgetItem::SearchRecursiveForMatch( SkillExecutionInfoTreeWidgetItem* haystack, @@ -101,13 +153,12 @@ namespace armarx SkillManagerMonitorWidgetController::SkillManagerMonitorWidgetController() { widget.setupUi(getWidget()); + this->updateWidget = new PeriodicUpdateWidget(2.0, 60); + widget.updateWidgetLayout->insertWidget(0, updateWidget); + + this->stopAllButton = new QPushButton("Stop all executions"); + widget.stopAllLayout->addWidget(stopAllButton); - double default_hz = 2; - widget.doubleSpinBoxUpdateFreq->setValue(default_hz); - widget.doubleSpinBoxUpdateFreq->setMinimum(0.5); - widget.doubleSpinBoxUpdateFreq->setMaximum(20); - widget.doubleSpinBoxUpdateFreq->setSingleStep(0.5); - widget.doubleSpinBoxUpdateFreq->setSuffix(" Hz"); skillDescriptionWidget = new SkillDescriptionWidget(); widget.skillDescription->parentWidget()->layout()->replaceWidget(widget.skillDescription, @@ -115,16 +166,17 @@ namespace armarx widget.skillDescription = skillDescriptionWidget; - refreshSkillsResultTimer = new QTimer(this); - updateTimerFrequency(); - refreshSkillsResultTimer->start(); - - connect(widget.doubleSpinBoxUpdateFreq, - &QDoubleSpinBox::editingFinished, + connect(this->stopAllButton, + &QPushButton::clicked, this, - &SkillManagerMonitorWidgetController::updateTimerFrequency); - connect(refreshSkillsResultTimer, - &QTimer::timeout, + &SkillManagerMonitorWidgetController::stopAllExecutions); + connect(widget.treeWidgetSkillExecutions, + &QTreeWidget::customContextMenuRequested, + this, + &SkillManagerMonitorWidgetController::prepareAndRunMenu); + + connect(updateWidget, + &armarx::PeriodicUpdateWidget::update, this, &SkillManagerMonitorWidgetController::refreshSkillsAndExecutions); @@ -140,21 +192,31 @@ namespace armarx connect(widget.pushButtonExecuteSkill, &QPushButton::clicked, this, - &SkillManagerMonitorWidgetController::executeSkill); - // connect(widget.pushButtonStopSkill, - // &QPushButton::clicked, - // this, - // &SkillManagerMonitorWidgetController::stopSkill); + &SkillManagerMonitorWidgetController::executeSelectedSkill); connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged, this, &SkillManagerMonitorWidgetController::skillSelectionChanged); - connect(widget.pushButtonRefreshNow, + connect(widget.treeWidgetSkillExecutions, + &QTreeWidget::currentItemChanged, + this, + &SkillManagerMonitorWidgetController::skillExecutionSelectionChanged); + + /*connect(widget.pushButtonRefreshNow, &QPushButton::clicked, this, - &SkillManagerMonitorWidgetController::refreshSkills); + &SkillManagerMonitorWidgetController::refreshSkills);*/ + connect(widget.pushButtonSearch, + &QPushButton::clicked, + this, + &SkillManagerMonitorWidgetController::searchSkills); + // alternatively run search when pressing enter + connect(widget.lineEditSearch, + &QLineEdit::returnPressed, + this, + &SkillManagerMonitorWidgetController::searchSkills); } SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController() @@ -176,6 +238,7 @@ namespace armarx widget.treeWidgetSkillDetails->setColumnHidden(3, true); getProxy(memory, observerName, 1000); + this->updateWidget->startTimerIfEnabled(); connected = true; } @@ -192,23 +255,51 @@ namespace armarx skillsArgumentsTreeWidgetItem = nullptr; selectedSkill.skillId.providerId->providerName = ""; selectedSkill.skillId.skillName = ""; + this->updateWidget->stopTimer(); } void - SkillManagerMonitorWidgetController::updateTimerFrequency() + SkillManagerMonitorWidgetController::searchSkills() { - int f = static_cast<int>(std::round(1000 / widget.doubleSpinBoxUpdateFreq->value())); - refreshSkillsResultTimer->setInterval(f); + this->currentSkillSearch = widget.lineEditSearch->text(); } void SkillManagerMonitorWidgetController::refreshSkillsAndExecutions() { - if (widget.checkBoxAutoUpdate->isChecked()) + refreshSkills(); + refreshExecutions(); + } + + void + SkillManagerMonitorWidgetController::matchSkillUpdateToSearch( + std::map<skills::manager::dto::SkillID, skills::manager::dto::SkillDescription>& update) + { + /* + if (this->currentSkillSearch.isEmpty()) { - refreshSkills(); - refreshExecutions(); + return; } + + // TODO: whitespace to wildcard + + std::string search = this->currentSkillSearch.toLower().toStdString(); + std::transform(search.begin(), search.end(), search.begin(), + [](unsigned char c){ return std::tolower(c); }); + + for (auto it = update.begin(); it != update.end();) + { + if (simox::alg::to_lower(skills::SkillID::FromIce(it->first).skillName) + .find(this->currentSkillSearch.toLower().toStdString())) + { + it = update.erase(it); + } + else + { + ++it; + } + } +*/ } void @@ -227,6 +318,7 @@ namespace armarx std::scoped_lock l(updateMutex); auto managerSkills = memory->getSkillDescriptions(); + this->matchSkillUpdateToSearch(managerSkills); // completely recreate internal skills map skills.clear(); @@ -341,16 +433,16 @@ namespace armarx SkillManagerMonitorWidgetController::refreshExecutions() { static std::map<skills::SkillStatus, std::string> ExecutionStatus2String = { + // Main states + {skills::SkillStatus::Constructing, "Constructing"}, + {skills::SkillStatus::Initializing, "Initializing"}, + {skills::SkillStatus::Preparing, "Preparing"}, + {skills::SkillStatus::Running, "Running"}, + // Terminating {skills::SkillStatus::Aborted, "Aborted"}, {skills::SkillStatus::Failed, "Failed"}, - {skills::SkillStatus::Succeeded, "Succeeded"}, - - // Others - {skills::SkillStatus::Constructing, "Under construction"}, - {skills::SkillStatus::Running, "Running"}, - {skills::SkillStatus::Initializing, "Initializing"}, - {skills::SkillStatus::Preparing, "Preparing"}}; + {skills::SkillStatus::Succeeded, "Succeeded"}}; if (!memory) { @@ -362,15 +454,18 @@ namespace armarx { std::scoped_lock l(updateMutex); - auto currentManagerStatuses = - memory - ->getSkillExecutionStatuses(); // we assume that there are no more than 100 new skills.. + auto currentManagerStatuses = memory->getSkillExecutionStatuses(); for (const auto& [k, v] : currentManagerStatuses) { auto executionId = skills::SkillExecutionID::FromIce(k); auto statusUpdate = skills::SkillStatusUpdate::FromIce(v); + // update maps + skillStatusUpdates[executionId] = statusUpdate; + //skillExecutionParams.insert_or_assign(executionId, + // statusUpdate.usedParameterization); + SkillExecutionInfoTreeWidgetItem* found = nullptr; for (int i = 0; i < widget.treeWidgetSkillExecutions->topLevelItemCount(); ++i) { @@ -382,22 +477,14 @@ namespace armarx if (found) { - // update values - found->setText(3, - QString::fromStdString( - statusUpdate.hasBeenConstructed() ? " yes " : " no ")); - found->setText(4, - QString::fromStdString( - statusUpdate.hasBeenInitialized() ? " yes " : " no ")); - found->setText(5, - QString::fromStdString( - statusUpdate.hasBeenPrepared() ? " yes " : " no ")); - found->setText(6, - QString::fromStdString( - statusUpdate.hasBeenRunning() ? " yes " : " no ")); - found->setText(7, - QString::fromStdString( - statusUpdate.hasBeenTerminated() ? " yes " : " no ")); + for (std::pair<skills::SkillStatus, std::string> i : ExecutionStatus2String) + { + if (i.first == statusUpdate.status) + { + found->setText(3, QString::fromStdString(i.second)); + } + } + break; } } @@ -405,29 +492,22 @@ namespace armarx if (!found) { // TODO: Sort to executor! - auto item = new SkillExecutionInfoTreeWidgetItem( - executionId, widget.treeWidgetSkillExecutions); + auto item = new SkillExecutionInfoTreeWidgetItem(executionId); item->setText(0, QString::fromStdString( executionId.executionStartedTime.toDateTimeString())); item->setText(1, QString::fromStdString(executionId.executorName)); item->setText(2, QString::fromStdString(executionId.skillId.toString())); - item->setText(3, - QString::fromStdString( - statusUpdate.hasBeenConstructed() ? " yes " : " no ")); - item->setText(4, - QString::fromStdString( - statusUpdate.hasBeenInitialized() ? " yes " : " no ")); - item->setText( - 5, - QString::fromStdString(statusUpdate.hasBeenPrepared() ? " yes " : " no ")); - item->setText( - 6, - QString::fromStdString(statusUpdate.hasBeenRunning() ? " yes " : " no ")); - item->setText(7, - QString::fromStdString( - statusUpdate.hasBeenTerminated() ? " yes " : " no ")); + for (std::pair<skills::SkillStatus, std::string> i : ExecutionStatus2String) + { + if (i.first == statusUpdate.status) + { + item->setText(3, QString::fromStdString(i.second)); + } + } + + widget.treeWidgetSkillExecutions->insertTopLevelItem(0, item); } } } @@ -438,31 +518,48 @@ namespace armarx } void - SkillManagerMonitorWidgetController::executeSkill() + SkillManagerMonitorWidgetController::executeSelectedSkill() { - if (not selectedSkill.skillId.isFullySpecified()) - { - return; - } + auto data = getConfigAsAron(); + executeSkillWithParams(selectedSkill.skillId, data); + } + + void + SkillManagerMonitorWidgetController::rerunSkillWithSimilarParams() + { + // TODO: disabled until skillparameterization is replaced + //skills::SkillParameterization selectedExecutionParams = + //skillExecutionParams.at(selectedSkill.skillExecutionId); + //executeSkillWithParams(selectedSkill.skillExecutionId.skillId, + // selectedExecutionParams.parameterization); + executeSelectedSkill(); + } + + void + SkillManagerMonitorWidgetController::executeSkillWithParams(skills::SkillID skillId, + aron::data::DictPtr params) + { std::scoped_lock l(updateMutex); - auto providerId = *selectedSkill.skillId.providerId; - const auto& skillDescriptions = skills.at(providerId); - if (skillDescriptions.find(selectedSkill.skillId) == skillDescriptions.end()) + auto providerId = skillId.providerId; + if (!providerId.has_value()) + { + return; + } + const auto& skillDescriptions = skills.at(providerId.value()); + if (skillDescriptions.find(skillId) == skillDescriptions.end()) { return; } - - auto data = getConfigAsAron(); char hostname[HOST_NAME_MAX]; gethostname(hostname, HOST_NAME_MAX); - skills::SkillExecutionRequest req{selectedSkill.skillId, - "Skills.Manager GUI (hostname: " + std::string(hostname) + - ")", - data}; + skills::SkillExecutionRequest req{ + .skillId = selectedSkill.skillId, + .executorName = "Skills.Manager GUI (hostname: " + std::string(hostname) + ")", + .parameters = params}; ARMARX_CHECK(selectedSkill.skillId.isFullySpecified()); // sanity check ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.skillId << "."; @@ -470,24 +567,112 @@ namespace armarx memory->begin_executeSkill(req.toManagerIce()); } + void + SkillManagerMonitorWidgetController::stopAllExecutions() + { + QTreeWidget const* tree = widget.treeWidgetSkillExecutions; + + int const max_retries = 3; + int left_retries = max_retries; + bool retry = false; + + do + { + retry = false; + + for (ssize_t i = 0; i < tree->topLevelItemCount(); ++i) + { + SkillExecutionInfoTreeWidgetItem const* item = + dynamic_cast<SkillExecutionInfoTreeWidgetItem*>( + widget.treeWidgetSkillExecutions->topLevelItem(i)); + + if (not item) + { + // At this point, dynamic-casting failed and we don't know anything about the + // type. + ARMARX_ERROR << "Cannot stop unknown skill."; + retry = true; + continue; + } + + try + { + ARMARX_INFO << "Aborting skill '" << item->executionId.skillId.skillName + << "'..."; + memory->abortSkillAsync(item->executionId.toManagerIce()); + } + catch (Ice::Exception const& e) + { + retry = true; + ARMARX_ERROR << "Unhandeled Ice exception while aborting skill '" + << item->executionId.skillId.skillName << "'."; + } + catch (...) + { + retry = true; + ARMARX_ERROR << "Unhandled error while aborting skill '" + << item->executionId.skillId.skillName << "'."; + } + } + + if (retry) + { + left_retries -= 1; + + if (left_retries > 0) + { + ARMARX_WARNING << "There where errors aborting skills. Retrying..."; + } + else + { + ARMARX_ERROR << "Couldn't abort all skills after " << max_retries + << " tries. Giving up."; + retry = false; + } + } + } while (retry); + } + void SkillManagerMonitorWidgetController::stopSkill() { - // std::scoped_lock l(updateMutex); - // if (selectedSkill.skillId.isFullySpecified()) - // { - // return; - // } + std::scoped_lock l(updateMutex); + + /* + if (selectedSkill.skillExecutionId.skillId.fullySpecified()) + { + ARMARX_INFO << "The user requested to stop a skill, which was not fully specified!"; + return; + } + + const auto& skillDescriptions = skills.at(*selectedSkill.skillId.providerId); + if (!skillDescriptions.count(selectedSkill.skillId.skillName)) + { + return; + } +*/ + + ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.skillExecutionId.toString(); + + memory->abortSkillAsync(selectedSkill.skillExecutionId.toManagerIce()); + } - // const auto& skillDescriptions = skills.at(*selectedSkill.skillId.providerId); - // if (!skillDescriptions.count(selectedSkill.skillId.skillName)) - // { - // return; - // } + void + SkillManagerMonitorWidgetController::skillExecutionSelectionChanged(QTreeWidgetItem* current, + QTreeWidgetItem*) + { + std::scoped_lock l(updateMutex); + widget.groupBoxSkillExecutions->setEnabled(false); - // ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.skillId; + if (!current) + { + // gui has died? + return; + } - // manager->abortSkill(selectedSkill.skillId); + auto c = static_cast<SkillExecutionInfoTreeWidgetItem*>(current); + selectedSkill.skillExecutionId = c->executionId; + widget.groupBoxSkillExecutions->setEnabled(true); } void @@ -506,14 +691,14 @@ namespace armarx if (!current->parent()) { // no parent available. Perhaps provider clicked? Reset selected skill. - selectedSkill.skillId.providerId->providerName = ""; - selectedSkill.skillId.skillName = ""; + selectedSkill.skillId = SelectedSkill::UNK_SKILL_ID; return; } auto c = static_cast<SkillInfoTreeWidgetItem*>(current); auto skillDescription = c->skillDescription; + if (selectedSkill.skillId == skillDescription.skillId) { // no change @@ -537,7 +722,28 @@ namespace armarx ARMARX_CHECK(skills.at(*selectedSkill.skillId.providerId).count(selectedSkill.skillId) > 0); auto skillDesc = skills.at(*selectedSkill.skillId.providerId).at(selectedSkill.skillId); - skillDescriptionWidget->setSkillDescription(skillDesc); + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Name"), + QString::fromStdString(skillDesc.skillId.skillName)}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, + {QString::fromStdString("Description"), + QString::fromStdString(skillDesc.description)}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } + + { + auto it = new QTreeWidgetItem( + widget.treeWidgetSkillDetails, + {QString::fromStdString("Timeout"), + QString::fromStdString(std::to_string(skillDesc.timeout.toMilliSeconds())) + + " ms"}); + widget.treeWidgetSkillDetails->addTopLevelItem(it); + } // select root profile widget.comboBoxProfiles->setCurrentIndex(0); diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h index 9f251bf9e1e5890d9059836fa12017fca9264925..786f13d869aee2c6c80d7de9058e840ef0305db1 100644 --- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h +++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h @@ -33,6 +33,7 @@ #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h> #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> +#include "RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h" #include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h> #include <RobotAPI/interface/skills/SkillMemoryInterface.h> #include <RobotAPI/libraries/aron/core/data/variant/All.h> @@ -66,6 +67,7 @@ namespace armarx class SkillExecutionInfoTreeWidgetItem : public QTreeWidgetItem { + //Q_OBJECT public: SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id, QTreeWidgetItem* parent) : @@ -73,6 +75,12 @@ namespace armarx { } + // After constructing an item, it must be manually inserted into the tree! + SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id) : executionId(id) + { + } + + // When using this constructor, the new item will be appended to the bottom of the tree! SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id, QTreeWidget* parent) : QTreeWidgetItem(parent), executionId(id) { @@ -113,15 +121,16 @@ namespace armarx void onInitComponent() override; void onConnectComponent() override; - void onDisconnectComponent() override; + void onDisconnectComponent(); private slots: void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); + void skillExecutionSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); - void stopSkill(); - void executeSkill(); + void stopAllExecutions(); + void stopSkill(); // TODO: rename + void executeSelectedSkill(); - void updateTimerFrequency(); void refreshSkills(); void refreshExecutions(); void refreshSkillsAndExecutions(); @@ -130,6 +139,11 @@ namespace armarx void pasteCurrentConfig(); void resetCurrentConfig(); + void prepareAndRunMenu(const QPoint& pos); + void rerunSkillWithSimilarParams(); + + void searchSkills(); + private: aron::data::DictPtr getConfigAsAron() const; @@ -140,6 +154,7 @@ namespace armarx */ Ui::SkillManagerMonitorWidget widget; QPointer<SimpleConfigDialog> dialog; + QString currentSkillSearch; std::string observerName = "SkillManager"; skills::dti::SkillMemoryInterfacePrx memory = nullptr; @@ -150,24 +165,41 @@ namespace armarx {}; std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> skillStatusUpdates = {}; + // store copies (!) of skill descriptions + //std::map<skills::SkillExecutionID, skills::SkillParameterization> skillExecutionParams = {}; + // User Input struct SelectedSkill { + static const skills::SkillID UNK_SKILL_ID; + skills::SkillID skillId; + skills::SkillExecutionID skillExecutionId; // make default constructable SelectedSkill() : - skillId{.providerId = skills::ProviderID{.providerName = ""}, .skillName = ""} + skillId(UNK_SKILL_ID), + skillExecutionId{.skillId = UNK_SKILL_ID, + .executorName = skills::SkillExecutionID::UNKNOWN, + .executionStartedTime = armarx::core::time::DateTime::Invalid()} { } - } selectedSkill; + } + + selectedSkill; + + void executeSkillWithParams(skills::SkillID skillId, aron::data::DictPtr params); + void matchSkillUpdateToSearch(std::map<skills::manager::dto::SkillID, + skills::manager::dto::SkillDescription>& update); + + + PeriodicUpdateWidget* updateWidget = + nullptr; // TODO: this should not be held by the controller! + QPushButton* stopAllButton = nullptr; // also this. Oh well... // Helper to get the treeWidgetItem easily QTreeWidgetItem* skillsArgumentsTreeWidgetItem = nullptr; AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr; - - // others - QTimer* refreshSkillsResultTimer; SkillDescriptionWidget* skillDescriptionWidget = nullptr; // connected flag diff --git a/source/RobotAPI/interface/robot_name_service/RobotNameServiceInterface.ice b/source/RobotAPI/interface/robot_name_service/RobotNameServiceInterface.ice index 7891ed5dbfd4583eb592ebf8913d9c12ca3e9a4c..5fb248cd5f0824e78020c9279f72864b59688ead 100644 --- a/source/RobotAPI/interface/robot_name_service/RobotNameServiceInterface.ice +++ b/source/RobotAPI/interface/robot_name_service/RobotNameServiceInterface.ice @@ -27,10 +27,12 @@ #include <RobotAPI/interface/armem/mns.ice> #include <RobotAPI/interface/skills/SkillManagerInterface.ice> +#include <RobotAPI/interface/units/ForceTorqueUnit.ice> #include <RobotAPI/interface/units/HandUnitInterface.ice> #include <RobotAPI/interface/units/KinematicUnitInterface.ice> #include <RobotAPI/interface/units/LocalizationUnitInterface.ice> #include <RobotAPI/interface/units/PlatformUnitInterface.ice> +#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.ice> module armarx { @@ -39,24 +41,38 @@ module armarx module dto { - struct Hand + module location + { + enum Side + { + LEFT, + RIGHT, + UNKNOWN + }; + }; + + struct TCPInfo { string name; string ft_name; + location::Side side; HandUnitInterface* handUnitInterface; }; - dictionary<string, Hand> Hands; + // maps tcp name to tcp + dictionary<string, TCPInfo> TCPInfos; - struct Arm + struct ArmInfo { string kinematicChainName; - Hand hand; + location::Side side; + TCPInfo tcpInfo; }; - dictionary<string, Arm> Arms; + // maps kinematic chain name to arm + dictionary<string, ArmInfo> ArmInfos; - struct Robot + struct RobotInfo { string name; armarx::data::PackagePath xmlPackagePath; @@ -66,12 +82,10 @@ module armarx armarx::skills::manager::dti::SkillManagerInterface* skillManager; // kinematic stuff. MAY BE EMPTY - Arms arms; + ArmInfos armInfos; - // units. MAY BE NULL - armarx::KinematicUnitInterface* kinematicUnitInterface; - armarx::PlatformUnitInterface* platformUnitInterface; - armarx::LocalizationUnitInterface* localizationUnitInterface; + // RobotUnit + armarx::RobotUnitInterface* robotUnit; // TODO: Feel free to extend! }; @@ -81,9 +95,9 @@ module armarx { interface RobotNameServiceInterface { - bool registerRobot(dto::Robot robot); - void unregisterRobot(string name); - optional(1) dto::Robot getRobot(string name); + bool registerRobotInfo(dto::RobotInfo robot); + void unregisterRobotInfo(string name); + optional(1) dto::RobotInfo getRobotInfo(string name); }; }; }; diff --git a/source/RobotAPI/libraries/armem_robot/aron/Robot.xml b/source/RobotAPI/libraries/armem_robot/aron/Robot.xml index 7303d707d40e0f742a7faa2c9d1b8e4a9b561714..b7192c366e7ae685c176578b03a44d9f533f1e75 100644 --- a/source/RobotAPI/libraries/armem_robot/aron/Robot.xml +++ b/source/RobotAPI/libraries/armem_robot/aron/Robot.xml @@ -1,4 +1,3 @@ -<!--This class contains the data structure for ObjectPose --> <?xml version="1.0" encoding="UTF-8" ?> <AronTypeDefinition> <AronIncludes> diff --git a/source/RobotAPI/libraries/robot_name_service/client/Plugin.cpp b/source/RobotAPI/libraries/robot_name_service/client/Plugin.cpp index 89f973a6e3f4588096a977091cdcbbeb4742bc9a..0f944891c8bfa557ba7eeb72c6e4ca15b732466f 100644 --- a/source/RobotAPI/libraries/robot_name_service/client/Plugin.cpp +++ b/source/RobotAPI/libraries/robot_name_service/client/Plugin.cpp @@ -19,6 +19,8 @@ namespace armarx::plugins { using namespace armarx::robot_name_service::client::constants; + ARMARX_INFO << "Got as config: " << properties.configJson; + nlohmann::json config = nlohmann::json::parse(properties.configJson); if (config.contains(CONFIG_ROBOT_NAME)) @@ -53,7 +55,7 @@ namespace armarx::plugins { for (const auto& [k, config_arm] : config[CONFIG_ARMS].items()) { - auto& arm = robot.arms[k]; + auto& arm = robot.armInfos[k]; if (config_arm.contains(CONFIG_ARM_KINEMATIC_CHAIN_NAME)) { @@ -109,7 +111,7 @@ namespace armarx::plugins { for (const auto& [k, config_arm] : config[CONFIG_ARMS].items()) { - auto& arm = robot.arms[k]; + auto& arm = robot.armInfos[k]; if (config_arm.contains(CONFIG_ARM_HAND)) { @@ -126,7 +128,7 @@ namespace armarx::plugins } // finally commit robot - properties.rns->registerRobot(robot.toIce()); + properties.rns->registerRobotInfo(robot.toIce()); } void @@ -139,7 +141,7 @@ namespace armarx::plugins void RobotNameServiceComponentPlugin::preOnDisconnectComponent() { - properties.rns->unregisterRobot(robot.name); + properties.rns->unregisterRobotInfo(robot.name); } } // namespace armarx::plugins diff --git a/source/RobotAPI/libraries/robot_name_service/client/Plugin.h b/source/RobotAPI/libraries/robot_name_service/client/Plugin.h index 813003f98554196e32fa9cc2c27eb650cea5f914..5d59cd16f3755ab02d566b4bef1a5955cfe2be92 100644 --- a/source/RobotAPI/libraries/robot_name_service/client/Plugin.h +++ b/source/RobotAPI/libraries/robot_name_service/client/Plugin.h @@ -60,7 +60,7 @@ namespace armarx::plugins armarx::robot_name_service::dti::RobotNameServiceInterfacePrx rns; } properties; - armarx::robot_name_service::core::Robot robot; + armarx::robot_name_service::core::RobotInfo robot; friend class armarx::RobotNameServiceComponentPluginUser; }; diff --git a/source/RobotAPI/libraries/robot_name_service/core/CMakeLists.txt b/source/RobotAPI/libraries/robot_name_service/core/CMakeLists.txt index 6c702dd1e210e92e3e14c4d02a4e6d870a731c44..19ac42cfedb1959c36c25d6961ba589ebd91ad31 100644 --- a/source/RobotAPI/libraries/robot_name_service/core/CMakeLists.txt +++ b/source/RobotAPI/libraries/robot_name_service/core/CMakeLists.txt @@ -17,8 +17,18 @@ armarx_add_library( SOURCES Robot.cpp + aron_conversions.cpp HEADERS Robot.h + aron_conversions.h +) + +armarx_enable_aron_file_generation_for_target( + TARGET_NAME + "${LIB_NAME}" + ARON_FILES + aron/Robot.xml ) add_library(RobotAPI::robot_name_service_core ALIAS robot_name_service_core) + diff --git a/source/RobotAPI/libraries/robot_name_service/core/Robot.cpp b/source/RobotAPI/libraries/robot_name_service/core/Robot.cpp index bfa5fbfe5d529388f9b545d93adae68d5f853f57..11978184a40e334b4b3b29099debf83976df04e9 100644 --- a/source/RobotAPI/libraries/robot_name_service/core/Robot.cpp +++ b/source/RobotAPI/libraries/robot_name_service/core/Robot.cpp @@ -4,17 +4,17 @@ namespace armarx::robot_name_service::core { void - Hand::fromIce(const dto::Hand& r) + TCPInfo::fromIce(const dto::TCPInfo& r) { name = r.name; ft_name = r.ft_name; handUnitInterface = r.handUnitInterface; } - dto::Hand - Hand::toIce() const + dto::TCPInfo + TCPInfo::toIce() const { - dto::Hand r; + dto::TCPInfo r; r.name = name; r.ft_name = ft_name; r.handUnitInterface = handUnitInterface; @@ -22,57 +22,53 @@ namespace armarx::robot_name_service::core } void - Arm::fromIce(const dto::Arm& r) + ArmInfo::fromIce(const dto::ArmInfo& r) { kinematicChainName = r.kinematicChainName; - hand.fromIce(r.hand); + hand.fromIce(r.tcpInfo); } - dto::Arm - Arm::toIce() const + dto::ArmInfo + ArmInfo::toIce() const { - dto::Arm r; + dto::ArmInfo r; r.kinematicChainName = kinematicChainName; - r.hand = hand.toIce(); + r.tcpInfo = hand.toIce(); return r; } void - Robot::fromIce(const dto::Robot& r) + RobotInfo::fromIce(const dto::RobotInfo& r) { name = r.name; xmlPackagePath = r.xmlPackagePath; memoryNameSystem = armarx::armem::client::MemoryNameSystem(r.memoryNameSystem); skillManager = r.skillManager; - arms.clear(); - for (const auto& [k, a] : r.arms) + armInfos.clear(); + for (const auto& [k, a] : r.armInfos) { - arms[k].fromIce(a); + armInfos[k].fromIce(a); } - kinematicUnitInterface = r.kinematicUnitInterface; - platformUnitInterface = r.platformUnitInterface; - localizationUnitInterface = r.localizationUnitInterface; + robotUnit = r.robotUnit; } - dto::Robot - Robot::toIce() const + dto::RobotInfo + RobotInfo::toIce() const { - dto::Robot r; + dto::RobotInfo r; r.name = name; r.xmlPackagePath = xmlPackagePath; r.memoryNameSystem = memoryNameSystem.getMemoryNameSystem(); r.skillManager = skillManager; - for (const auto& [k, a] : arms) + for (const auto& [k, a] : armInfos) { - r.arms[k] = a.toIce(); + r.armInfos[k] = a.toIce(); } - r.kinematicUnitInterface = kinematicUnitInterface; - r.platformUnitInterface = platformUnitInterface; - r.localizationUnitInterface = localizationUnitInterface; + r.robotUnit = robotUnit; return r; } diff --git a/source/RobotAPI/libraries/robot_name_service/core/Robot.h b/source/RobotAPI/libraries/robot_name_service/core/Robot.h index 243d94c1b2a7f72d8f050ee770d06611da5a83cf..4dedb60a99ccb82519bf810363457fb5bb723e52 100644 --- a/source/RobotAPI/libraries/robot_name_service/core/Robot.h +++ b/source/RobotAPI/libraries/robot_name_service/core/Robot.h @@ -10,11 +10,11 @@ namespace armarx::robot_name_service::core { - class Hand + class TCPInfo { public: - void fromIce(const armarx::robot_name_service::dto::Hand& r); - armarx::robot_name_service::dto::Hand toIce() const; + void fromIce(const armarx::robot_name_service::dto::TCPInfo& r); + armarx::robot_name_service::dto::TCPInfo toIce() const; public: std::string name; @@ -22,22 +22,22 @@ namespace armarx::robot_name_service::core armarx::HandUnitInterfacePrx handUnitInterface; }; - class Arm + class ArmInfo { public: - void fromIce(const armarx::robot_name_service::dto::Arm& r); - armarx::robot_name_service::dto::Arm toIce() const; + void fromIce(const armarx::robot_name_service::dto::ArmInfo& r); + armarx::robot_name_service::dto::ArmInfo toIce() const; public: std::string kinematicChainName; - Hand hand; + TCPInfo hand; }; - class Robot + class RobotInfo { public: - void fromIce(const armarx::robot_name_service::dto::Robot& r); - armarx::robot_name_service::dto::Robot toIce() const; + void fromIce(const armarx::robot_name_service::dto::RobotInfo& r); + armarx::robot_name_service::dto::RobotInfo toIce() const; public: // header @@ -49,11 +49,9 @@ namespace armarx::robot_name_service::core armarx::skills::manager::dti::SkillManagerInterfacePrx skillManager; // kinematic stuff - std::map<std::string, Arm> arms; + std::map<std::string, ArmInfo> armInfos; // units - armarx::KinematicUnitInterfacePrx kinematicUnitInterface; - armarx::PlatformUnitInterfacePrx platformUnitInterface; - armarx::LocalizationUnitInterfacePrx localizationUnitInterface; + armarx::RobotUnitInterfacePrx robotUnit; }; } // namespace armarx::robot_name_service::core diff --git a/source/RobotAPI/libraries/robot_name_service/core/aron/Robot.xml b/source/RobotAPI/libraries/robot_name_service/core/aron/Robot.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b29a3d3c5bfb61b1ae6112a97972b2a4066aa58 --- /dev/null +++ b/source/RobotAPI/libraries/robot_name_service/core/aron/Robot.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<AronTypeDefinition> + <GenerateTypes> + + <Object name='armarx::robot_name_service::arondto::TCPInfo'> + <ObjectChild key='name'> + <string /> + </ObjectChild> + + </Object> + + <Object name='armarx::robot_name_service::arondto::TCPInfo'> + <ObjectChild key='name'> + <string /> + </ObjectChild> + + <ObjectChild key='ft_name'> + <string /> + </ObjectChild> + + </Object> + + <Object name='armarx::robot_name_service::arondto::ArmInfo'> + <ObjectChild key='kinematicChainName'> + <string /> + </ObjectChild> + + </Object> + + + <Object name='armarx::robot_name_service::arondto::RobotInfo'> + <ObjectChild key='name'> + <string /> + </ObjectChild> + + </Object> + + + </GenerateTypes> +</AronTypeDefinition> diff --git a/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.cpp b/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57d53663682f641335c663b5483e626388d01d12 --- /dev/null +++ b/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.cpp @@ -0,0 +1,6 @@ +#include "aron_conversions.h" + +namespace armarx::robot_name_service::core +{ + +} // namespace armarx::robot_name_service::core diff --git a/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.h b/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..4019e276eac94db6072c1338b74c3176d12734e8 --- /dev/null +++ b/source/RobotAPI/libraries/robot_name_service/core/aron_conversions.h @@ -0,0 +1,14 @@ +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <RobotAPI/interface/robot_name_service/RobotNameServiceInterface.h> +#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h> + +namespace armarx::robot_name_service::core +{ + +} // namespace armarx::robot_name_service::core diff --git a/source/RobotAPI/libraries/robot_name_service/server/CMakeLists.txt b/source/RobotAPI/libraries/robot_name_service/server/CMakeLists.txt index d0c268aa439c501d38505d3fab455bf6b4a9b876..862934ffff91b608fdf651a6b57c4371b4749238 100644 --- a/source/RobotAPI/libraries/robot_name_service/server/CMakeLists.txt +++ b/source/RobotAPI/libraries/robot_name_service/server/CMakeLists.txt @@ -18,8 +18,10 @@ armarx_add_library( SOURCES plugins.cpp + segments/RobotSegment.cpp HEADERS plugins.h + segments/RobotSegment.h ) add_library(RobotAPI::robot_name_service_server ALIAS robot_name_service_server) diff --git a/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.cpp b/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e67bbb2526b9876818b342c0d55991ad7e473b6 --- /dev/null +++ b/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.cpp @@ -0,0 +1,6 @@ +#include "RobotSegment.h" + +namespace armarx::robot_name_service::server::segment +{ + +} // namespace armarx::robot_name_service::server::segment diff --git a/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.h b/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.h new file mode 100644 index 0000000000000000000000000000000000000000..7e9d006f6b7ca1d736af0486ed09daa1fe98f3c4 --- /dev/null +++ b/source/RobotAPI/libraries/robot_name_service/server/segments/RobotSegment.h @@ -0,0 +1,17 @@ +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h> +#include <RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h> + +namespace armarx::robot_name_service::server::segment +{ + class RobotInfoCoreSegment : public armarx::armem::server::segment::SpecializedCoreSegment + { + public: + }; +} // namespace armarx::robot_name_service::server::segment diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp b/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp index d2f305c1a5e42b5dc28da3285ef46dcbe154b3e6..2bf5f3235ba19f60f4475e9fe3d126fbcfec1db9 100644 --- a/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.cpp @@ -4,6 +4,7 @@ namespace armarx { namespace skills { + skills::manager::dto::SkillExecutionID SkillExecutionID::toManagerIce() const { @@ -29,7 +30,9 @@ namespace armarx { armarx::core::time::DateTime t; armarx::core::time::fromIce(i.executionStartedTime, t); - return {skills::SkillID::FromIce(i.skillId), i.executorName, t}; + return {.skillId = skills::SkillID::FromIce(i.skillId), + .executorName = i.executorName, + .executionStartedTime = t}; } SkillExecutionID @@ -40,5 +43,13 @@ namespace armarx armarx::core::time::fromIce(i.executionStartedTime, t); return {skills::SkillID::FromIce(i.skillId, providerName), i.executorName, t}; } + + std::string + SkillExecutionID::toString() const + { + return skillId.toString() + ENTER_SEPARATOR + executorName + SEPARATOR + + executionStartedTime.toDateTimeString() + EXIT_SEPARATOR; + } + } // namespace skills } // namespace armarx diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h index 6c4975388e716c5b0491518a356add0b15cbbf5e..53fc20a1013f5924c77159580899ae824bd1ad86 100644 --- a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h +++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h @@ -18,6 +18,15 @@ namespace armarx { struct SkillExecutionID { + SkillID skillId; + std::string executorName; + armarx::core::time::DateTime executionStartedTime; + + static const constexpr char* UNKNOWN = "UNKNOWN"; + static const constexpr char* ENTER_SEPARATOR = "["; + static const constexpr char* EXIT_SEPARATOR = "]"; + static const constexpr char* SEPARATOR = "@"; + bool operator==(const SkillExecutionID& other) const { @@ -36,13 +45,6 @@ namespace armarx return this->toString() <= other.toString(); } - std::string - toString() const - { - return skillId.toString() + " requested by " + executorName + " at " + - executionStartedTime.toDateTimeString(); - } - skills::manager::dto::SkillExecutionID toManagerIce() const; skills::provider::dto::SkillExecutionID toProviderIce() const; @@ -52,10 +54,7 @@ namespace armarx static SkillExecutionID FromIce(const skills::provider::dto::SkillExecutionID&, const std::optional<skills::ProviderID>& providerName); - - SkillID skillId; - std::string executorName; - armarx::core::time::DateTime executionStartedTime; + std::string toString() const; }; } // namespace skills diff --git a/source/RobotAPI/libraries/skills/core/SkillID.h b/source/RobotAPI/libraries/skills/core/SkillID.h index e611a82828442ad378dde77d4d90edf477b5e5f1..91494c78c331272e85babe5052ccd2369e29833e 100644 --- a/source/RobotAPI/libraries/skills/core/SkillID.h +++ b/source/RobotAPI/libraries/skills/core/SkillID.h @@ -18,6 +18,7 @@ namespace armarx { public: static const constexpr char* NAME_SEPARATOR = "/"; + static const constexpr char* UNKNOWN = "UNKNOWN"; bool operator==(const SkillID& other) const; bool operator!=(const SkillID& other) const; diff --git a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp index 82908d85ac3b526848561cd94593291c15b40f67..55f9d80c01a78154aa95780e2cc6f549be94f843 100644 --- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp +++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp @@ -275,12 +275,18 @@ namespace armarx try { mainRet = skill->mainOfSkill(); - if (mainRet.status != TerminatedSkillStatus::Succeeded) + if (mainRet.status == TerminatedSkillStatus::Failed) { - std::string message = "SkillError 501: The main method of skill '" + skillName + - "' did not succeed."; + std::string message = + "SkillError 501: The main method of skill '" + skillName + "' did fail."; return exitAndMakeFailedResult(message); } + else if (mainRet.status == TerminatedSkillStatus::Aborted) + { + std::string message = + "SkillError 501: The main method of skill '" + skillName + "' got aborted."; + return exitAndMakeAbortedResult(message); + } } catch (const error::SkillAbortedException& ex) {