Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • sw/armarx/robot-api
  • uwkce_singer/robot-api
  • untcg_hofmann/robot-api
  • ulqba_korosakov/RobotAPI
4 results
Show changes
Showing
with 1216 additions and 638 deletions
......@@ -78,6 +78,7 @@ set(LIB_HEADERS
util/introspection/ClassMemberInfo.h
util/RtLogging.h
util/RtTiming.h
util/NonRtTiming.h
util/CtrlUtil.h
#robot unit modules need to be added to the list below (but not here)
......
# RobotUnit
# RobotUnit {#RobotUnit}
The RobotUnit can be used for real-time control.
The central principle is that all controllers are executed synchronously.
The controllers are arranged in a 2-layer architecture.
......
......@@ -853,7 +853,7 @@ namespace armarx::RobotUnitModule
}
SensorAndControl& sc = _module<ControlThreadDataBuffer>().rtGetSensorAndControlBuffer();
sc.writeTimestamp = IceUtil::Time::now(); // this has to be in real time
sc.writeTimestamp = armarx::rtNow(); // this has to be in real time
sc.sensorValuesTimestamp = sensorValuesTimestamp;
sc.timeSinceLastIteration = timeSinceLastIteration;
ARMARX_CHECK_EQUAL(rtGetSensorDevices().size(), sc.sensors.size());
......
......@@ -95,8 +95,11 @@ namespace armarx::RobotUnitModule
std::stringstream ss;
ss << "Requested controller class '" << className
<< "' unknown! Known classes:" << NJointControllerRegistry::getKeys()
<< " (If this class exists in a different lib then load it via "
"loadLibFromPath(path) or loadLibFromPackage(package, lib))";
<< " (If this class exists in a different lib then load it in the property "
"definitions of the RT-unit. DO NOT load it via "
"loadLibFromPath(path) or loadLibFromPackage(package, lib)) (see "
"https://git.h2t.iar.kit.edu/sw/armarx-integration/robots/armar7/documentation/-/"
"issues/85)";
ARMARX_ERROR << ss.str();
throw InvalidArgumentException{ss.str()};
}
......@@ -303,6 +306,9 @@ namespace armarx::RobotUnitModule
ControllerManagement::loadLibFromPath(const std::string& path, const Ice::Current&)
{
throwIfInControlThread(BOOST_CURRENT_FUNCTION);
ARMARX_WARNING << "Do not use this function as it has implications on the RT thread (see "
"https://git.h2t.iar.kit.edu/sw/armarx-integration/robots/armar7/"
"documentation/-/issues/85)";
const bool result = getArmarXManager()->loadLibFromPath(path);
ARMARX_INFO << "loadLibFromPath('" << path << "') -> " << result;
return result;
......@@ -314,6 +320,9 @@ namespace armarx::RobotUnitModule
const Ice::Current&)
{
throwIfInControlThread(BOOST_CURRENT_FUNCTION);
ARMARX_WARNING << "Do not use this function as it has implications on the RT thread (see "
"https://git.h2t.iar.kit.edu/sw/armarx-integration/robots/armar7/"
"documentation/-/issues/85)";
const bool result = getArmarXManager()->loadLibFromPackage(package, lib);
ARMARX_INFO << "loadLibFromPackage('" << package << "', '" << lib << "') -> " << result;
return result;
......
......@@ -35,6 +35,7 @@
#include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleDevices.h>
#include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleUnits.h>
#include <RobotAPI/components/units/RobotUnit/Units/RobotUnitSubUnit.h>
#include <RobotAPI/components/units/RobotUnit/util/NonRtTiming.h>
namespace armarx::RobotUnitModule
{
......@@ -255,7 +256,7 @@ namespace armarx::RobotUnitModule
{
ARMARX_TRACE;
throwIfInControlThread(BOOST_CURRENT_FUNCTION);
const auto beg = TimeUtil::GetTime(true);
const auto beg = armarx::rtNow();
StringVariantBaseMap ctrlDevMap;
......@@ -314,7 +315,7 @@ namespace armarx::RobotUnitModule
}
}
const auto end = TimeUtil::GetTime(true);
const auto end = armarx::rtNow();
return new TimedVariant{TimestampVariant{end - beg}, lastControlThreadTimestamp};
}
......@@ -476,6 +477,7 @@ namespace armarx::RobotUnitModule
getProperty<std::string>("DebugDrawerUpdatesTopicName").getValue();
debugObserverTopicName = getProperty<std::string>("DebugObserverTopicName").getValue();
observerEnablePublishing = getProperty<bool>("ObserverEnablePublishing").getValue();
observerPublishSensorValues = getProperty<bool>("ObserverPublishSensorValues").getValue();
observerPublishControlTargets =
getProperty<bool>("ObserverPublishControlTargets").getValue();
......@@ -575,7 +577,10 @@ namespace armarx::RobotUnitModule
[&] { publish({}); }, publishPeriodMs, false, getName() + "_PublisherTask");
ARMARX_INFO << "starting publisher with timestep " << publishPeriodMs;
publisherTask->setDelayWarningTolerance(10 * publishPeriodMs);
publisherTask->start();
if (observerEnablePublishing)
{
publisherTask->start();
}
}
void
......@@ -628,7 +633,10 @@ namespace armarx::RobotUnitModule
const auto requestedJointControllers =
_module<ControlThreadDataBuffer>().copyRequestedJointControllers();
lastControlThreadTimestamp = controlThreadOutputBuffer.sensorValuesTimestamp;
// controlThreadOutputBuffer.sensorValuesTimestamp is in MONOTONIC_RAW (not relative to epoch).
// We have to map it to be relative to epoch (REAL_TIME).
lastControlThreadTimestamp =
armarx::mapRtTimestampToNonRtTimestamp(controlThreadOutputBuffer.sensorValuesTimestamp);
const bool publishToObserver = !(publishIterationCount % debugObserverSkipIterations);
//publish publishing meta state
......
......@@ -58,6 +58,10 @@ namespace armarx::RobotUnitModule
defineOptionalProperty<std::size_t>(
"PublishPeriodMs", 10, "Milliseconds between each publish");
defineOptionalProperty<bool>("ObserverEnablePublishing",
true,
"Whether the publishing thread is started or not",
PropertyDefinitionBase::eModifiable);
defineOptionalProperty<bool>("ObserverPublishSensorValues",
true,
"Whether sensor values are send to the observer",
......@@ -271,6 +275,8 @@ namespace armarx::RobotUnitModule
/// @brief Whether \ref SensorValueBase "SensorValues" should be published to the observers
std::atomic_bool observerPublishSensorValues;
/// @brief Whether the publishing thread should be started or not
std::atomic_bool observerEnablePublishing;
/// @brief Whether \ref ControlTargetBase "ControlTargets" should be published to the observers
std::atomic_bool observerPublishControlTargets;
/// @brief Whether \ref Timing information should be published to the observers
......
......@@ -362,7 +362,7 @@ namespace armarx
const auto numExcessEntries =
std::max(requiredAdditionalEntries, numEntries - entries.size());
const auto requiredSize = entries.size() + numExcessEntries;
ARMARX_WARNING << "Iteration " << iterationCount << " required "
ARMARX_VERBOSE << "Iteration " << iterationCount << " required "
<< requiredAdditionalEntries << " | " << numExcessEntries
<< " additional message entries. \n"
<< "The requested total number of entries is " << requiredSize << ". \n"
......@@ -371,7 +371,7 @@ namespace armarx
<< getMaximalNumberOfBufferEntries();
if (requiredSize > getMaximalNumberOfBufferEntries())
{
ARMARX_WARNING << deactivateSpam(1, to_string(requiredSize)) << "Iteration "
ARMARX_VERBOSE << deactivateSpam(1, to_string(requiredSize)) << "Iteration "
<< iterationCount << " would require " << requiredSize
<< " message entries, but the maximal number of entries is "
<< getMaximalNumberOfBufferEntries();
......
......@@ -34,6 +34,7 @@
#include "../Devices/SensorDevice.h"
#include "../SensorValues/SensorValueBase.h"
#include "HeterogenousContinuousContainer.h"
#include "RtTiming.h"
namespace armarx
{
......@@ -50,7 +51,7 @@ namespace armarx::detail
{
struct RtMessageLogEntryBase
{
RtMessageLogEntryBase() : time{IceUtil::Time::now()}
RtMessageLogEntryBase() : time{armarx::rtNow()}
{
}
......
/*
* This file is part of ArmarX.
*
* Copyright (C) 2011-2017, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
*
* 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
* @author Mirko Waechter( mirko.waechter at kit dot edu)
* @date 2018
* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
* GNU General Public License
*/
#pragma once
#include <time.h>
#include <IceUtil/Time.h>
#include "RtTiming.h"
namespace armarx
{
inline IceUtil::Time
nonRtNow()
{
using namespace rt_timing::constants;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return IceUtil::Time::microSeconds(ts.tv_sec * seconds2MicroSeconds +
ts.tv_nsec / nanoSeconds2MicroSeconds);
}
inline IceUtil::Time
mapRtTimestampToNonRtTimestamp(const IceUtil::Time& time_monotic_raw)
{
// This is the "real time" clock, i.e. NTP-synchronized and relative to epoch.
IceUtil::Time now_real_time = armarx::nonRtNow();
// This is not relative to epoch and not NTP-synchronized.
IceUtil::Time now_monotonic_raw = armarx::rtNow();
/*
* Assumption for small very small time deltas (i.e. "time" is close to "now"):
*
* time_real_time - now_real_time == time_monotic_raw - now_monotonic_raw
* =>
* time_real_time = time_monotic_raw - now_monotonic_raw + now_real_time
*/
//
IceUtil::Time time_real_time = time_monotic_raw - now_monotonic_raw + now_real_time;
ARMARX_DEBUG << VAROUT(time_monotic_raw) << " vs. " << VAROUT(time_real_time);
return time_real_time;
}
} // namespace armarx
......@@ -23,19 +23,27 @@
*/
#pragma once
#include <chrono>
//#include <ArmarXCore/core/time/TimeUtil.h>
#include "ControlThreadOutputBuffer.h"
#include <time.h>
#include <IceUtil/Time.h>
namespace armarx
{
namespace rt_timing::constants
{
inline constexpr const std::int64_t seconds2MicroSeconds = 1e6;
static constexpr const std::int64_t nanoSeconds2MicroSeconds = 1000;
} // namespace rt_timing::constants
inline IceUtil::Time
rtNow()
{
using namespace rt_timing::constants;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return IceUtil::Time::microSeconds(ts.tv_sec * 1e6 + ts.tv_nsec / 1000);
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
return IceUtil::Time::microSeconds(ts.tv_sec * seconds2MicroSeconds +
ts.tv_nsec / nanoSeconds2MicroSeconds);
}
} // namespace armarx
......@@ -43,16 +51,14 @@ namespace armarx
//! \ingroup VirtualTime
//! Prints duration with comment in front of it, yet only once per second.
#define RT_TIMING_END_COMMENT(name, comment) \
ARMARX_RT_LOGF_INFO( \
"%s - duration: %.3f ms", comment, (armarx::rtNow() - name).toMilliSecondsDouble()) \
.deactivateSpam(1);
printf("%s - duration: %.3f ms \n", comment, (armarx::rtNow() - name).toMilliSecondsDouble());
//! \ingroup VirtualTime
//! Prints duration
#define RT_TIMING_END(name) RT_TIMING_END_COMMENT(name, #name)
//! \ingroup VirtualTime
//! Prints duration with comment in front of it if it took longer than threshold
#define RT_TIMING_CEND_COMMENT(name, comment, thresholdMs) \
if ((armarx::rtNow() - name).toMilliSeconds() >= thresholdMs) \
if ((armarx::rtNow() - name).toMilliSecondsDouble() >= thresholdMs) \
RT_TIMING_END_COMMENT(name, comment)
//! \ingroup VirtualTime
//! Prints duration if it took longer than thresholdMs
......
# GamepadUnit
# GamepadUnit {#GamepadUnit}
This component is used to control the robot with a gamepad.
......
......@@ -651,7 +651,8 @@ namespace armarx
{
if (currentNode)
{
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint())
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
currentNode->isFourBarJoint())
{
const bool isDeg = ui.checkBoxUseDegree->isChecked();
const auto factor =
......@@ -728,7 +729,8 @@ namespace armarx
{
const QString unit = [&]() -> QString
{
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint())
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
currentNode->isFourBarJoint())
{
if (ui.checkBoxUseDegree->isChecked())
{
......@@ -751,7 +753,8 @@ namespace armarx
const auto [factor, conversionFactor] = [&]() -> std::pair<float, float>
{
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint())
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
currentNode->isFourBarJoint())
{
const bool isDeg = ui.checkBoxUseDegree->isChecked();
if (isDeg)
......@@ -841,7 +844,8 @@ namespace armarx
const QString unit = [&]() -> QString
{
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint())
if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
currentNode->isFourBarJoint())
{
if (ui.checkBoxUseDegree->isChecked())
{
......@@ -865,7 +869,8 @@ namespace armarx
<< currentNode->getName() << flush;
const bool isDeg = ui.checkBoxUseDegree->isChecked();
const bool isRot = currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint();
const bool isRot = currentNode->isRotationalJoint() or
currentNode->isHemisphereJoint() or currentNode->isFourBarJoint();
const float lo = isRot ? (isDeg ? -90 : -M_PI * 100) : -1000;
const float hi = isRot ? (isDeg ? +90 : +M_PI * 100) : 1000;
......@@ -1186,7 +1191,8 @@ namespace armarx
const ControlMode currentControlMode = getSelectedControlMode();
const bool isDeg = ui.checkBoxUseDegree->isChecked();
const bool isRot = currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or currentNode->isFourBarJoint();
const bool isRot = currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
currentNode->isFourBarJoint();
if (currentControlMode == ePositionControl)
{
......@@ -1347,8 +1353,8 @@ namespace armarx
auto it = reportedJointStatuses.find(rn[i]->getName());
if (it == reportedJointStatuses.end())
{
ARMARX_WARNING << deactivateSpam(5) << "Joint Status for " << rn[i]->getName()
<< " was not reported!";
ARMARX_VERBOSE << deactivateSpam(5, rn[i]->getName()) << "Joint Status for "
<< rn[i]->getName() << " was not reported!";
continue;
}
JointStatus currentStatus = it->second;
......@@ -1441,11 +1447,11 @@ namespace armarx
const float currentValue = it->second;
QModelIndex index = ui.tableJointList->model()->index(i, eTabelColumnAngleProgressbar);
float conversionFactor =
ui.checkBoxUseDegree->isChecked() &&
(node->isRotationalJoint() or node->isHemisphereJoint() or node->isFourBarJoint())
? 180.0 / M_PI
: 1;
float conversionFactor = ui.checkBoxUseDegree->isChecked() &&
(node->isRotationalJoint() or
node->isHemisphereJoint() or node->isFourBarJoint())
? 180.0 / M_PI
: 1;
ui.tableJointList->model()->setData(
index,
(int)(cutJitter(currentValue * conversionFactor) * 100) / 100.0f,
......@@ -1486,7 +1492,8 @@ namespace armarx
float currentValue = it->second;
if (ui.checkBoxUseDegree->isChecked() &&
(rn[i]->isRotationalJoint() or rn[i]->isHemisphereJoint() or rn[i]->isFourBarJoint()))
(rn[i]->isRotationalJoint() or rn[i]->isHemisphereJoint() or
rn[i]->isFourBarJoint()))
{
currentValue *= 180.0 / M_PI;
}
......
......@@ -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
......
#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
#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
......@@ -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>&lt;No Profile selected. Using root&gt;</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>&lt;No Profile selected. Using root&gt;</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/>
......
......@@ -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
......
......@@ -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);
};
};
};
......