33 ui->treeWidget->setColumnCount(11);
34 QTreeWidgetItem* head =
ui->treeWidget->headerItem();
49 "The controllers instance name (green: ok, red: active and requested "
50 "state missmatch or there is an error)");
51 head->setToolTip(
idxClass,
"The controllers class name");
53 "Whether the controller is active (green: ok, red: active and requested "
56 "Whether the controller is requested (green: ok, red: active and "
57 "requested state missmatch)");
59 "Whether the controller is deactivated due to an error (green: ok, red: "
60 "there is an error)");
62 "Whether the controller is internal (e.g. used by the kinematic unit)");
63 head->setToolTip(
idxCtrlDev,
"The control devices used by this controller");
65 "The controll mode for the control devices used by this controller");
66 head->setToolTip(
idxActivate,
"Button to activate the Controller");
67 head->setToolTip(
idxDeactivate,
"Button to deactivate the Controller");
68 head->setToolTip(
idxDelete,
"Button to delete the Controller");
70 ui->treeWidget->setColumnWidth(
idxName, 400);
82 ui->treeWidget->header()->setResizeMode(
idxActivate, QHeaderView::Fixed);
83 ui->treeWidget->header()->setResizeMode(
idxDeactivate, QHeaderView::Fixed);
84 ui->treeWidget->header()->setResizeMode(
idxDelete, QHeaderView::Fixed);
85 ui->treeWidget->header()->setResizeMode(
idxRequested, QHeaderView::Fixed);
86 ui->treeWidget->header()->setResizeMode(
idxActive, QHeaderView::Fixed);
87 ui->treeWidget->header()->setResizeMode(
idxError, QHeaderView::Fixed);
88 ui->treeWidget->header()->setResizeMode(
idxInternal, QHeaderView::Fixed);
90 ui->pushButtonStopAll->setIcon(QIcon{QString{
":/icons/media-playback-pause.ico"}});
91 ui->pushButtonRemoveAll->setIcon(QIcon{QString{
":/icons/Trash.svg"}});
93 ui->pushButtonStopAll, SIGNAL(clicked()),
this, SLOT(onPushButtonStopAll_clicked()));
94 connect(
ui->pushButtonRemoveAll,
97 SLOT(onPushButtonRemoveAll_clicked()));
107 const NJointControllerStatusSeq& allStatus)
109 std::unique_lock<std::recursive_timed_mutex> guard{
mutex, std::defer_lock};
110 if (!guard.try_lock_for(std::chrono::microseconds(100)))
114 for (
const auto&
status : allStatus)
116 if (statusUpdates[
status.instanceName].timestampUSec <
status.timestampUSec)
121 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
128 NJointControllersWidget::add(
const NJointControllerDescriptionWithStatus& ds)
130 if (!entries.count(ds.description.instanceName))
132 entries[ds.description.instanceName] =
135 entries.at(ds.description.instanceName)->update(ds.status);
139 NJointControllersWidget::onPushButtonStopAll_clicked()
143 robotUnit->switchNJointControllerSetup({});
148 NJointControllersWidget::onPushButtonRemoveAll_clicked()
150 for (
auto& pair : entries)
154 if (pair.second->deletable)
156 pair.second->deleteController();
169 std::unique_lock<std::recursive_timed_mutex> guard{
mutex};
176 auto data = ru->getNJointControllerDescriptionWithStatus(name);
178 if (!entries.count(name))
180 controllersCreated[name] = std::move(
data);
183 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
191 std::unique_lock<std::recursive_timed_mutex> guard{
mutex};
192 controllersDeleted.emplace(name);
195 QMetaObject::invokeMethod(
this,
"updateContent", Qt::QueuedConnection);
202 ui->treeWidget->setColumnWidth(
idxName, settings->value(
"ctrlColWName", 400).toInt());
203 ui->treeWidget->setColumnWidth(
idxClass, settings->value(
"ctrlColWClass", 200).toInt());
204 ui->treeWidget->setColumnWidth(
idxCtrlDev, settings->value(
"ctrlColWCDen", 130).toInt());
205 ui->treeWidget->setColumnWidth(
idxCtrlMode, settings->value(
"ctrlColWCMod", 150).toInt());
211 settings->setValue(
"ctrlColWName",
ui->treeWidget->columnWidth(
idxName));
212 settings->setValue(
"ctrlColWClass",
ui->treeWidget->columnWidth(
idxClass));
213 settings->setValue(
"ctrlColWCDen",
ui->treeWidget->columnWidth(
idxCtrlDev));
214 settings->setValue(
"ctrlColWCMod",
ui->treeWidget->columnWidth(
idxCtrlMode));
221 controllersCreated.clear();
222 statusUpdates.clear();
223 controllersDeleted.clear();
229 for (
const auto& pair : controllersCreated)
233 controllersCreated.clear();
234 for (
const auto& pair : statusUpdates)
236 const auto& name = pair.second.instanceName;
237 if (controllersDeleted.count(name))
241 auto it = entries.find(name);
242 if (it != entries.end())
244 it->second->update(pair.second);
248 NJointControllerDescriptionWithStatus stat;
249 stat.status = pair.second;
250 ARMARX_INFO <<
"loding description for the missing entry '" << name <<
"'";
251 stat.description =
robotUnit->getNJointControllerDescription(name);
255 statusUpdates.clear();
256 for (
const auto& name : controllersDeleted)
258 auto it = entries.find(name);
259 if (it != entries.end())
261 it->second->deleteContent();
262 it->second->deleteLater();
266 controllersDeleted.clear();
272 auto temp =
robotUnit->getNJointControllerDescriptionsWithStatuses();
274 std::unique_lock<std::recursive_timed_mutex> guard{
mutex};
275 for (NJointControllerDescriptionWithStatus& ds : temp)
277 controllersCreated[ds.description.instanceName] = std::move(ds);
285 if (controllersCreated.empty())
289 add(controllersCreated.begin()->second);
290 controllersCreated.erase(controllersCreated.begin());
296 QTreeWidget& treeWidget,
297 const NJointControllerDescription& desc) :
298 QObject(&parent), deletable{desc.deletable},
controller{desc.controller}
301 header =
new QTreeWidgetItem;
302 treeWidget.addTopLevelItem(header);
304 QString::fromStdString(desc.instanceName));
311 const std::size_t numDev = desc.controlModeAssignment.size();
312 const std::size_t numMod =
313 getMapValues<StringStringDictionary, std::set>(desc.controlModeAssignment).size();
317 QWidget* widgDev =
new QWidget{&parent};
318 QWidget* widgMod =
new QWidget{&parent};
321 QVBoxLayout* layDev =
new QVBoxLayout;
322 QVBoxLayout* layMod =
new QVBoxLayout;
323 layDev->setContentsMargins(0, 0, 0, 0);
324 layMod->setContentsMargins(0, 0, 0, 0);
325 widgDev->setLayout(layDev);
326 widgMod->setLayout(layMod);
327 boxDev =
new QCheckBox{QString::number(numDev) +
" Device" +
328 (numDev > 1 ? QString{
"s"} : QString{
""})};
329 boxMod =
new QCheckBox{QString::number(numMod) +
" Mode" +
330 (numMod > 1 ? QString{
"s"} : QString{
""})};
331 layDev->addWidget(boxDev);
332 layMod->addWidget(boxMod);
335 boxDev->setChecked(
false);
336 boxMod->setChecked(
false);
337 connect(boxDev, SIGNAL(clicked(
bool)),
this, SLOT(hideDeviceList()));
338 connect(boxMod, SIGNAL(clicked(
bool)),
this, SLOT(hideDeviceList()));
340 devsToModes.reserve(desc.controlModeAssignment.size());
341 for (
const auto& pair : desc.controlModeAssignment)
343 QTreeWidgetItem* child =
new QTreeWidgetItem;
344 header->addChild(child);
346 QString::fromStdString(pair.first));
348 QString::fromStdString(pair.second));
349 devsToModes.emplace_back(child);
350 child->setHidden(
true);
353 QPushButton* act =
new QPushButton;
354 QPushButton* dec =
new QPushButton;
355 act->setToolTip(
"Activate the Controller");
356 dec->setToolTip(
"Deactivate the Controller");
359 act->setIcon(QIcon{QString{
":/icons/media-playback-start.ico"}});
360 dec->setIcon(QIcon{QString{
":/icons/media-playback-pause.ico"}});
361 act->setFixedWidth(40);
362 dec->setFixedWidth(40);
363 act->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
364 dec->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
365 connect(act, SIGNAL(clicked(
bool)),
this, SLOT(activateController()));
366 connect(dec, SIGNAL(clicked(
bool)),
this, SLOT(deactivateController()));
369 QPushButton* del =
new QPushButton;
371 del->setToolTip(
"Delete the Controller");
372 del->setIcon(QIcon{QString{
":/icons/Trash.svg"}});
373 del->setFixedWidth(40);
374 del->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
375 connect(del, SIGNAL(clicked(
bool)),
this, SLOT(deleteController()));
380 for (
const auto& descr :
controller->getFunctionDescriptions())
382 new NJointControllersWidgetRemoteFunction{
423 .contains(state, Qt::CaseInsensitive);
430 .contains(state, Qt::CaseInsensitive);
442 for (
const auto& elem : devsToModes)
455 for (
const auto& elem : devsToModes)
458 .contains(mode, Qt::CaseInsensitive))
469 for (
auto item : devsToModes)
479 setDeviceListVisible(vis);
480 header->setHidden(!vis);
484 NJointControllersWidgetEntry::activateController()
491 NJointControllersWidgetEntry::deactivateController()
498 NJointControllersWidgetEntry::deleteController()
505 NJointControllersWidgetEntry::hideDeviceList()
507 QCheckBox* box =
dynamic_cast<QCheckBox*
>(sender());
510 bool checked = box->isChecked();
511 boxDev->setChecked(checked);
512 boxMod->setChecked(checked);
513 for (QTreeWidgetItem* dev : devsToModes)
515 dev->setHidden(!checked);
519 header->setExpanded(
true);
525 NJointControllersWidgetEntry::setDeviceListVisible(
bool vis)
527 boxDev->setChecked(vis);
528 boxMod->setChecked(vis);
529 for (QTreeWidgetItem* dev : devsToModes)
531 dev->setHidden(!vis);
536 QTreeWidget& treeWidget,
537 QTreeWidgetItem& header,
538 const std::string& name,
539 const NJointControllerInterfacePrx& ctrl,
541 functionName{name}, ctrl{ctrl}
545 setObjectName(QString::fromStdString(ctrl->getInstanceName() +
"_" + name));
546 functionHeader =
new QTreeWidgetItem;
547 header.addChild(functionHeader);
548 functionHeader->setFirstColumnSpanned(
true);
549 treeWidget.setItemWidget(functionHeader, 0,
this);
551 QHBoxLayout* l =
new QHBoxLayout;
553 l->setContentsMargins(0, 0, 0, 0);
556 QPushButton*
execute =
new QPushButton;
557 execute->setIcon(QIcon{QString{
":/icons/media-playback-start.ico"}});
558 execute->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
560 execute->setToolTip(
"Execute '" + QString::fromStdString(name) +
"' function");
561 connect(
execute, SIGNAL(clicked(
bool)),
this, SLOT(execFunction()));
565 execOnParamChange =
new QCheckBox{
"Call function on parameter changes"};
566 execOnParamChange->setToolTip(
"Execute '" + QString::fromStdString(name) +
567 "' function whenever a parameter changes");
568 l->addWidget(execOnParamChange);
572 execOnParamChange->setFixedHeight(0);
573 execOnParamChange->setSizePolicy(execOnParamChange->sizePolicy().horizontalPolicy(),
577 l->addWidget(
new QLabel{
"Remote function: " + QString::fromStdString(name)});
579 l->addSpacerItem(
new QSpacerItem{0, 0, QSizePolicy::Expanding});
584 QTreeWidgetItem* fnitem =
new QTreeWidgetItem;
585 functionHeader->addChild(fnitem);
586 fnitem->setFirstColumnSpanned(
true);
587 QWidget* container =
new QWidget;
588 treeWidget.setItemWidget(fnitem, 0, container);
589 QHBoxLayout* compress =
new QHBoxLayout;
590 compress->setContentsMargins(0, 0, 0, 0);
591 container->setLayout(compress);
594 paramValues = params->getVariants();
595 params->setContentsMargins(0, 0, 0, 0);
596 compress->addWidget(params);
598 compress->addItem(
new QSpacerItem{
599 0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding});
604 NJointControllersWidgetRemoteFunction::execFunction()
606 if (paramValues.empty())
609 <<
" with no parameters\n";
613 std::stringstream ss;
614 ss <<
"calling function " << functionName <<
" with parameters:\n";
615 for (
const auto& pair : paramValues)
620 if (pair.second->data)
622 ss <<
" '" << pair.first <<
"' of type " << pair.second->data->ice_id()
627 ss <<
" '" << pair.first <<
"' nullptr data \n";
632 ss <<
" '" << pair.first <<
"' nullptr\n";
637 ctrl->callDescribedFunction(functionName, paramValues);
643 paramValues[std::move(name)] = std::move(
value);
644 if (execOnParamChange->isChecked())