KinematicUnitGuiPlugin.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
25
26#include <RobotAPI/gui-plugins/KinematicUnitPlugin/ui_kinematicunitguiplugin.h>
27
28#include <SimoxUtility/algorithm/string.h>
29#include <SimoxUtility/json.h>
30#include <VirtualRobot/Nodes/RobotNode.h>
31#include <VirtualRobot/Robot.h>
32#include <VirtualRobot/RobotNodeSet.h>
33#include <VirtualRobot/Visualization/CoinVisualization/CoinVisualization.h>
34#include <VirtualRobot/Visualization/VisualizationFactory.h>
35#include <VirtualRobot/XML/RobotIO.h>
36
49
50#include <RobotAPI/gui-plugins/KinematicUnitPlugin/ui_KinematicUnitConfigDialog.h>
51#include <RobotAPI/interface/core/NameValueMap.h>
52#include <RobotAPI/interface/units/KinematicUnitInterface.h>
53
55
56// Qt headers
57#include <QCheckBox>
58#include <QClipboard>
59#include <QInputDialog>
60#include <QPushButton>
61#include <QSlider>
62#include <QSpinBox>
63#include <QStringList>
64#include <QTableView>
65#include <QTableWidget>
66#include <Qt>
67#include <QtGlobal>
68#include <qtimer.h>
69
71
72#include <Inventor/Qt/SoQt.h>
73#include <Inventor/SoDB.h>
74
75// System
76#include <cmath>
77#include <cstddef>
78#include <cstdio>
79#include <cstdlib>
80#include <filesystem>
81#include <iostream>
82#include <memory>
83#include <optional>
84#include <stdexcept>
85#include <string>
86
87
88//#define KINEMATIC_UNIT_FILE_DEFAULT std::string("RobotAPI/robots/Armar3/ArmarIII.xml")
89//#define KINEMATIC_UNIT_FILE_DEFAULT_PACKAGE std::string("RobotAPI")
90#define KINEMATIC_UNIT_NAME_DEFAULT "Robot"
91//#define TOPIC_NAME_DEFAULT "RobotState"
92
93constexpr float SLIDER_POS_DEG_MULTIPLIER = 5;
94constexpr float SLIDER_POS_RAD_MULTIPLIER = 100;
95constexpr float SLIDER_POS_HEMI_MULTIPLIER = 100;
96
97namespace armarx
98{
99
101 {
102
103 qRegisterMetaType<DebugInfo>("DebugInfo");
104
106 }
107
109 kinematicUnitNode(nullptr),
110 enableValueValidator(true),
111 historyTime(100000), // 1/10 s
112 currentValueMax(5.0f)
113 {
114 rootVisu = NULL;
115 debugLayerVisu = NULL;
116
117 // init gui
118 ui = std::make_unique<Ui::KinematicUnitGuiPlugin>();
119 ui->setupUi(getWidget());
120 getWidget()->setEnabled(false);
121
122 ui->tableJointList->setItemDelegateForColumn(eTabelColumnAngleProgressbar, &delegate);
123
124 ui->radioButtonUnknown->setHidden(true);
125 }
126
127 void
129 {
131 verbose = true;
132
133
134 rootVisu = new SoSeparator;
135 rootVisu->ref();
136 robotVisu = new SoSeparator;
137 robotVisu->ref();
138 rootVisu->addChild(robotVisu);
139
140 // create the debugdrawer component
141 std::string debugDrawerComponentName = "KinemticUnitGUIDebugDrawer_" + getName();
142 ARMARX_INFO << "Creating component " << debugDrawerComponentName;
145 showVisuLayers(false);
146
147 if (mutex3D)
148 {
149 //ARMARX_IMPORTANT << "mutex3d:" << mutex3D.get();
150 debugDrawer->setMutex(mutex3D);
151 }
152 else
153 {
154 ARMARX_ERROR << " No 3d mutex available...";
155 }
156
158 m->addObject(debugDrawer, false);
159
160
161 {
162 std::unique_lock lock(*mutex3D);
163 debugLayerVisu = new SoSeparator();
164 debugLayerVisu->ref();
165 debugLayerVisu->addChild(debugDrawer->getVisualization());
166 rootVisu->addChild(debugLayerVisu);
167 }
168
169 connectSlots();
170
172 }
173
174 void
176 {
177 // ARMARX_INFO << "Kinematic Unit Gui :: onConnectComponent()";
178 jointCurrentHistory.clear();
179 jointCurrentHistory.set_capacity(5);
180
181 // jointAnglesUpdateFrequency = new filters::MedianFilter(100);
183
184 lastJointAngleUpdateTimestamp = Clock::Now();
185 robotVisu->removeAllChildren();
186
187 robot.reset();
188
189 std::string rfile;
190 Ice::StringSeq includePaths;
191
192 // Get robot filename
193 try
194 {
195 Ice::StringSeq packages = kinematicUnitInterfacePrx->getArmarXPackages();
196 packages.push_back(Application::GetProjectName());
197 ARMARX_VERBOSE << "ArmarX packages " << packages;
198
199 for (const std::string& projectName : packages)
200 {
201 if (projectName.empty())
202 {
203 continue;
204 }
205
206 CMakePackageFinder project(projectName);
207 auto pathsString = project.getDataDir();
208 ARMARX_VERBOSE << "Data paths of ArmarX package " << projectName << ": "
209 << pathsString;
210 Ice::StringSeq projectIncludePaths = Split(pathsString, ";,", true, true);
211 ARMARX_VERBOSE << "Result: Data paths of ArmarX package " << projectName << ": "
212 << projectIncludePaths;
213 includePaths.insert(
214 includePaths.end(), projectIncludePaths.begin(), projectIncludePaths.end());
215 }
216
217 rfile = kinematicUnitInterfacePrx->getRobotFilename();
218 ARMARX_VERBOSE << "Relative robot file " << rfile;
219 ArmarXDataPath::getAbsolutePath(rfile, rfile, includePaths);
220 ARMARX_VERBOSE << "Absolute robot file " << rfile;
221
222 robotNodeSetName = kinematicUnitInterfacePrx->getRobotNodeSetName();
223 }
224 catch (...)
225 {
226 ARMARX_ERROR << "Unable to retrieve robot filename.";
227 }
228
229 try
230 {
231 ARMARX_INFO << "Loading robot from file " << rfile;
232 robot = loadRobotFile(rfile);
233 }
234 catch (const std::exception& e)
235 {
236 ARMARX_ERROR << "Failed to init robot: " << e.what();
237 }
238 catch (...)
239 {
240 ARMARX_ERROR << "Failed to init robot";
241 }
242
243 if (!robot || !robot->hasRobotNodeSet(robotNodeSetName))
244 {
245 getObjectScheduler()->terminate();
246 if (getWidget()->parentWidget())
247 {
248 getWidget()->parentWidget()->close();
249 }
250 return;
251 }
252
253 // Check robot name and disable setZero Button if necessary
254 if (not simox::alg::starts_with(robot->getName(), "Armar3"))
255 {
256 ARMARX_VERBOSE << "Disable the SetZero button because the robot name is '"
257 << robot->getName() << "'.";
258 ui->pushButtonKinematicUnitPos1->setDisabled(true);
259 }
260
261 kinematicUnitFile = rfile;
262 robotNodeSet = robot->getRobotNodeSet(robotNodeSetName);
263
264 kinematicUnitVisualization = getCoinVisualization(robot);
265 kinematicUnitNode = kinematicUnitVisualization->getCoinVisualization();
266 robotVisu->addChild(kinematicUnitNode);
267
268 // Fetch the current joint angles.
270
271 initGUIComboBox(robotNodeSet); // init the pull down menu (QT: ComboBox)
272 initGUIJointListTable(robotNodeSet);
273
274 const auto initialDebugInfo = kinematicUnitInterfacePrx->getDebugInfo();
275
276 initializeUi(initialDebugInfo);
277
278 QMetaObject::invokeMethod(this, "resetSlider");
280
283 updateTask->start();
284 }
285
286 void
288 {
289 Metronome metronome(Frequency::Hertz(10));
290
292 {
293 fetchData();
294 metronome.waitForNextTick();
295 }
296
297 ARMARX_INFO << "Connection to kinemetic unit lost. Update task terminates.";
298 }
299
300 void
302 {
304
305 if (updateTask)
306 {
307 updateTask->stop();
308 updateTask->join();
309 updateTask = nullptr;
310 }
311
312 // killTimer(updateTimerId);
314
315 {
316 std::unique_lock lock(mutexNodeSet);
317 robot.reset();
318 robotNodeSet.reset();
319 currentNode.reset();
320 }
321
322 {
323 std::unique_lock lock(*mutex3D);
324 robotVisu->removeAllChildren();
325 debugLayerVisu->removeAllChildren();
326 }
327 }
328
329 void
331 {
333
334 if (updateTask)
335 {
336 updateTask->stop();
337 updateTask->join();
338 updateTask = nullptr;
339 }
340
342
343 {
344 std::unique_lock lock(*mutex3D);
345
346 if (robotVisu)
347 {
348 robotVisu->removeAllChildren();
349 robotVisu->unref();
350 robotVisu = NULL;
351 }
352
353 if (debugLayerVisu)
354 {
355 debugLayerVisu->removeAllChildren();
356 debugLayerVisu->unref();
357 debugLayerVisu = NULL;
358 }
359
360 if (rootVisu)
361 {
362 rootVisu->removeAllChildren();
363 rootVisu->unref();
364 rootVisu = NULL;
365 }
366 }
367
368 /*
369 if (debugDrawer && debugDrawer->getObjectScheduler())
370 {
371 ARMARX_INFO << "Removing DebugDrawer component...";
372 debugDrawer->getObjectScheduler()->terminate();
373 ARMARX_INFO << "Removing DebugDrawer component...done";
374 }
375 */
376 }
377
378 QPointer<QDialog>
380 {
381 if (!dialog)
382 {
383 dialog = new KinematicUnitConfigDialog(parent);
384 dialog->setName(dialog->getDefaultName());
385 }
386
387 return qobject_cast<KinematicUnitConfigDialog*>(dialog);
388 }
389
390 void
392 {
393 ARMARX_VERBOSE << "KinematicUnitWidget::configured()";
394 kinematicUnitName = dialog->proxyFinder->getSelectedProxyName().toStdString();
395 enableValueValidator = dialog->ui->checkBox->isChecked();
396 viewerEnabled = dialog->ui->checkBox3DViewerEnabled->isChecked();
397 historyTime = dialog->ui->spinBoxHistory->value() * 1000;
398 currentValueMax = dialog->ui->doubleSpinBoxMaxMinCurrent->value();
399 }
400
401 void
403 {
404 kinematicUnitName = settings->value("kinematicUnitName", KINEMATIC_UNIT_NAME_DEFAULT)
405 .toString()
406 .toStdString();
407 enableValueValidator = settings->value("enableValueValidator", true).toBool();
408 viewerEnabled = settings->value("viewerEnabled", true).toBool();
409 historyTime = settings->value("historyTime", 100).toInt() * 1000;
410 currentValueMax = settings->value("currentValueMax", 5.0).toFloat();
411 }
412
413 void
415 {
416 settings->setValue("kinematicUnitName", QString::fromStdString(kinematicUnitName));
417 settings->setValue("enableValueValidator", enableValueValidator);
418 settings->setValue("viewerEnabled", viewerEnabled);
419 assert(historyTime % 1000 == 0);
420 settings->setValue("historyTime", static_cast<int>(historyTime / 1000));
421 settings->setValue("currentValueMax", currentValueMax);
422 }
423
424 void
426 {
427 if (debugDrawer)
428 {
429 if (show)
430 {
431 debugDrawer->enableAllLayers();
432 }
433 else
434 {
435 debugDrawer->disableAllLayers();
436 }
437 }
438 }
439
440 void
442 {
443 NameValueMap values;
444 {
445 std::unique_lock lock(mutexNodeSet);
446
448 const auto debugInfo = kinematicUnitInterfacePrx->getDebugInfo();
449
450 const auto selectedControlMode = getSelectedControlMode();
451
452 if (selectedControlMode == ePositionControl)
453 {
454 values = debugInfo.jointAngles;
455 }
456 else if (selectedControlMode == eVelocityControl)
457 {
458 values = debugInfo.jointVelocities;
459 }
460 }
461
462 JSONObjectPtr serializer = new JSONObject();
463 for (auto& kv : values)
464 {
465 serializer->setFloat(kv.first, kv.second);
466 }
467 const QString json = QString::fromStdString(serializer->asString(true));
468 QClipboard* clipboard = QApplication::clipboard();
469 clipboard->setText(json);
470 QApplication::processEvents();
471 }
472
473 void
475 {
476 // modelUpdateCB();
477 }
478
479 void
483
484 void
488
489 SoNode*
491 {
492 if (viewerEnabled)
493 {
494 ARMARX_INFO << "Returning scene ";
495 return rootVisu;
496 }
497 else
498 {
499 ARMARX_INFO << "viewer disabled - returning null scene";
500 return NULL;
501 }
502 }
503
504 void
506 {
507 connect(ui->pushButtonKinematicUnitPos1,
508 SIGNAL(clicked()),
509 this,
510 SLOT(kinematicUnitZeroPosition()));
511
512 connect(
513 ui->nodeListComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectJoint(int)));
514 connect(ui->horizontalSliderKinematicUnitPos,
515 SIGNAL(valueChanged(int)),
516 this,
517 SLOT(sliderValueChanged(int)));
518
519 connect(ui->horizontalSliderKinematicUnitPos,
520 SIGNAL(sliderReleased()),
521 this,
523
524 connect(ui->radioButtonPositionControl,
525 SIGNAL(clicked(bool)),
526 this,
527 SLOT(setControlModePosition()));
528 connect(ui->radioButtonVelocityControl,
529 SIGNAL(clicked(bool)),
530 this,
531 SLOT(setControlModeVelocity()));
532 connect(
533 ui->radioButtonTorqueControl, SIGNAL(clicked(bool)), this, SLOT(setControlModeTorque()));
534 connect(
535 ui->pushButtonFromJson, SIGNAL(clicked()), this, SLOT(on_pushButtonFromJson_clicked()));
536
537 connect(ui->copyToClipboard, SIGNAL(clicked()), this, SLOT(copyToClipboard()));
538 connect(ui->showDebugLayer,
539 SIGNAL(toggled(bool)),
540 this,
541 SLOT(showVisuLayers(bool)),
542 Qt::QueuedConnection);
543
544 connect(this,
545 SIGNAL(jointAnglesReported()),
546 this,
548 Qt::QueuedConnection);
549 connect(this,
550 SIGNAL(jointVelocitiesReported()),
551 this,
553 Qt::QueuedConnection);
554 connect(this,
555 SIGNAL(jointTorquesReported()),
556 this,
558 Qt::QueuedConnection);
559 connect(this,
560 SIGNAL(jointCurrentsReported()),
561 this,
563 Qt::QueuedConnection);
564 connect(this,
566 this,
568 Qt::QueuedConnection);
569 connect(this,
571 this,
573 Qt::QueuedConnection);
574 connect(this,
575 SIGNAL(jointStatusesReported()),
576 this,
578 Qt::QueuedConnection);
579
580 connect(ui->tableJointList,
581 SIGNAL(cellDoubleClicked(int, int)),
582 this,
583 SLOT(selectJointFromTableWidget(int, int)),
584 Qt::QueuedConnection);
585
586 connect(ui->checkBoxUseDegree,
587 SIGNAL(clicked()),
588 this,
589 SLOT(resetSlider()),
590 Qt::QueuedConnection);
591 connect(ui->checkBoxUseDegree, SIGNAL(clicked()), this, SLOT(setControlModePosition()));
592 connect(ui->checkBoxUseDegree, SIGNAL(clicked()), this, SLOT(setControlModeVelocity()));
593 connect(ui->checkBoxUseDegree, SIGNAL(clicked()), this, SLOT(setControlModeTorque()));
594
595 connect(this,
596 SIGNAL(onDebugInfoReceived(const DebugInfo&)),
597 this,
598 SLOT(debugInfoReceived(const DebugInfo&)));
599 }
600
601 void
603 {
604 //signal clicked is not emitted if you call setDown(), setChecked() or toggle().
605
606 // there is no default control mode
607 setControlModeRadioButtonGroup(ControlMode::eUnknown);
608
609 ui->widgetSliderFactor->setVisible(false);
610
611 fetchData();
612 }
613
614 void
616 {
617 if (!robotNodeSet)
618 {
619 return;
620 }
621
622 std::unique_lock lock(mutexNodeSet);
623 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
624 NameValueMap vels;
625 NameControlModeMap jointModes;
626
627 for (unsigned int i = 0; i < rn.size(); i++)
628 {
629 jointModes[rn[i]->getName()] = eVelocityControl;
630 vels[rn[i]->getName()] = 0.0f;
631 }
632
633 try
634 {
635 kinematicUnitInterfacePrx->switchControlMode(jointModes);
636 kinematicUnitInterfacePrx->setJointVelocities(vels);
637 }
638 catch (...)
639 {
640 }
641
642 const auto selectedControlMode = getSelectedControlMode();
643 if (selectedControlMode == eVelocityControl)
644 {
645 ui->horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
646 }
647 }
648
649 void
651 {
652 const auto selectedControlMode = getSelectedControlMode();
653
654 if (selectedControlMode == eVelocityControl || selectedControlMode == eTorqueControl)
655 {
657 }
658 else if (selectedControlMode == ePositionControl)
659 {
660 if (currentNode)
661 {
662 if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
663 currentNode->isFourBarJoint())
664 {
665 const bool isDeg = ui->checkBoxUseDegree->isChecked();
666 const auto factor =
668 const float conversionFactor = isDeg ? 180.0 / M_PI : 1.0f;
669 const float pos = currentNode->getJointValue() * conversionFactor;
670
671 ui->lcdNumberKinematicUnitJointValue->display((int)pos);
672 ui->horizontalSliderKinematicUnitPos->setSliderPosition((int)(pos * factor));
673 }
674
675 if (currentNode->isTranslationalJoint())
676 {
677 const auto factor = SLIDER_POS_DEG_MULTIPLIER;
678 const float pos = currentNode->getJointValue();
679
680 ui->lcdNumberKinematicUnitJointValue->display((int)pos);
681 ui->horizontalSliderKinematicUnitPos->setSliderPosition((int)(pos * factor));
682 }
683 }
684 }
685 }
686
687 void
689 {
690 const auto selectedControlMode = getSelectedControlMode();
691
692 if (selectedControlMode == eVelocityControl || selectedControlMode == eTorqueControl)
693 {
694 ui->horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
695 ui->lcdNumberKinematicUnitJointValue->display(SLIDER_ZERO_POSITION);
696 }
697 }
698
699 void
701 {
702 ARMARX_VERBOSE << "Setting control mode of radio button group to " << controlMode;
703
704 switch (controlMode)
705 {
706 case eDisabled:
707 case eUnknown:
708 case ePositionVelocityControl:
709 ui->radioButtonUnknown->setChecked(true);
710 break;
711 case ePositionControl:
712 ui->radioButtonPositionControl->setChecked(true);
713 break;
714 case eVelocityControl:
715 ui->radioButtonVelocityControl->setChecked(true);
716 break;
717 case eTorqueControl:
718 ui->radioButtonTorqueControl->setChecked(true);
719 break;
720 }
721 }
722
723 void
725 {
726 if (!ui->radioButtonPositionControl->isChecked())
727 {
728 return;
729 }
730 NameControlModeMap jointModes;
731 // selectedControlMode = ePositionControl;
732 ui->widgetSliderFactor->setVisible(false);
733
734 // FIXME currentNode should be passed to this function!
735
736 if (currentNode)
737 {
738 const QString unit = [&]() -> QString
739 {
740 if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
741 currentNode->isFourBarJoint())
742 {
743 if (ui->checkBoxUseDegree->isChecked())
744 {
745 return "deg";
746 }
747
748 return "rad";
749 }
750
751 if (currentNode->isTranslationalJoint())
752 {
753 return "mm";
754 }
755
756 throw std::invalid_argument("unknown/unsupported joint type");
757 }();
758
759 ui->labelUnit->setText(unit);
760
761
762 const auto [factor, conversionFactor] = [&]() -> std::pair<float, float>
763 {
764 if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
765 currentNode->isFourBarJoint())
766 {
767 const bool isDeg = ui->checkBoxUseDegree->isChecked();
768 if (isDeg)
769 {
770 return {SLIDER_POS_DEG_MULTIPLIER, 180.0 / M_PI};
771 }
772 return {SLIDER_POS_RAD_MULTIPLIER, 1};
773 }
774
775 if (currentNode->isTranslationalJoint())
776 {
777 return {SLIDER_POS_DEG_MULTIPLIER, 1};
778 }
779
780 throw std::invalid_argument("unknown/unsupported joint type");
781 }();
782
783 jointModes[currentNode->getName()] = ePositionControl;
784
786 {
787 kinematicUnitInterfacePrx->switchControlMode(jointModes);
788 }
789
790 const float lo = currentNode->getJointLimitLo() * conversionFactor;
791 const float hi = currentNode->getJointLimitHi() * conversionFactor;
792
793 if (hi - lo <= 0.0f)
794 {
795 return;
796 }
797
798 {
799 // currentNode->getJointValue() can we wrong after we re-connected to the robot unit.
800 // E.g., it can be 0 although the torso joint was at -365 before the unit disconnected.
801 // Therefore, we first have to fetch the actual joint values and use that one.
802 // However, this should actually not be necessary, as the robot model should be updated
803 // via the topics.
805 }
806
807 const float pos = currentNode->getJointValue() * conversionFactor;
808 ARMARX_INFO << "Setting position control for current node "
809 << "(name '" << currentNode->getName() << "' with current value " << pos
810 << ")";
811
812 // Setting the slider position to pos will set the position to the slider tick closest to pos
813 // This will initially send a position target with a small delta to the joint.
814 ui->horizontalSliderKinematicUnitPos->blockSignals(true);
815
816 const float sliderMax = hi * factor;
817 const float sliderMin = lo * factor;
818
819 ui->horizontalSliderKinematicUnitPos->setMaximum(sliderMax);
820 ui->horizontalSliderKinematicUnitPos->setMinimum(sliderMin);
821
822 const std::size_t desiredNumberOfTicks = 1'000;
823
824 const float tickInterval = (sliderMax - sliderMin) / desiredNumberOfTicks;
825 ARMARX_INFO << VAROUT(tickInterval);
826
827 ui->horizontalSliderKinematicUnitPos->setTickInterval(tickInterval);
828 ui->lcdNumberKinematicUnitJointValue->display(pos);
829
830 ui->horizontalSliderKinematicUnitPos->blockSignals(false);
831 resetSlider();
832 }
833 }
834
835 void
837 {
838 if (!ui->radioButtonVelocityControl->isChecked())
839 {
840 return;
841 }
842 NameControlModeMap jointModes;
843 NameValueMap jointVelocities;
844
845 if (currentNode)
846 {
847 jointModes[currentNode->getName()] = eVelocityControl;
848
849 // set the velocity to zero to stop any previous controller (e.g. torque controller)
850 jointVelocities[currentNode->getName()] = 0;
851
852
853 const QString unit = [&]() -> QString
854 {
855 if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
856 currentNode->isFourBarJoint())
857 {
858 if (ui->checkBoxUseDegree->isChecked())
859 {
860 return "deg/s";
861 }
862
863 return "rad/(100*s)";
864 }
865
866 if (currentNode->isTranslationalJoint())
867 {
868 return "mm/s";
869 }
870
871 throw std::invalid_argument("unknown/unsupported joint type");
872 }();
873
874
875 ui->labelUnit->setText(unit);
876 ARMARX_INFO << "setting velocity control for current Node Name: "
877 << currentNode->getName() << flush;
878
879 const bool isDeg = ui->checkBoxUseDegree->isChecked();
880 const bool isRot = currentNode->isRotationalJoint() or
881 currentNode->isHemisphereJoint() or currentNode->isFourBarJoint();
882
883 const float lo = isRot ? (isDeg ? -90 : -M_PI * 100) : -1000;
884 const float hi = isRot ? (isDeg ? +90 : +M_PI * 100) : 1000;
885
886 try
887 {
889 {
890 kinematicUnitInterfacePrx->switchControlMode(jointModes);
891 kinematicUnitInterfacePrx->setJointVelocities(jointVelocities);
892 }
893 }
894 catch (...)
895 {
896 }
897
898 ui->widgetSliderFactor->setVisible(true);
899
900 ui->horizontalSliderKinematicUnitPos->blockSignals(true);
901 ui->horizontalSliderKinematicUnitPos->setMaximum(hi);
902 ui->horizontalSliderKinematicUnitPos->setMinimum(lo);
903 ui->horizontalSliderKinematicUnitPos->blockSignals(false);
904 resetSlider();
905 }
906 }
907
908 ControlMode
910 {
911 if (ui->radioButtonPositionControl->isChecked())
912 {
913 return ControlMode::ePositionControl;
914 }
915
916 if (ui->radioButtonVelocityControl->isChecked())
917 {
918 return ControlMode::eVelocityControl;
919 }
920
921 if (ui->radioButtonTorqueControl->isChecked())
922 {
923 return ControlMode::eTorqueControl;
924 }
925
926 // if no button is checked, then the joint is likely initialized but no controller has been loaded yet
927 // (well, the no movement controller should be active)
928 return ControlMode::eUnknown;
929 }
930
931 void
933 {
934 if (!ui->radioButtonTorqueControl->isChecked())
935 {
936 return;
937 }
938 NameControlModeMap jointModes;
939
940 if (currentNode)
941 {
942 jointModes[currentNode->getName()] = eTorqueControl;
943 ui->labelUnit->setText("Ncm");
944 ARMARX_INFO << "setting torque control for current Node Name: "
945 << currentNode->getName() << flush;
946
948 {
949 try
950 {
951 kinematicUnitInterfacePrx->switchControlMode(jointModes);
952 }
953 catch (...)
954 {
955 }
956 }
957
958 ui->horizontalSliderKinematicUnitPos->blockSignals(true);
959 ui->horizontalSliderKinematicUnitPos->setMaximum(20000.0);
960 ui->horizontalSliderKinematicUnitPos->setMinimum(-20000.0);
961
962 ui->widgetSliderFactor->setVisible(true);
963
964 ui->horizontalSliderKinematicUnitPos->blockSignals(false);
965 resetSlider();
966 }
967 }
968
970 KinematicUnitWidgetController::loadRobotFile(std::string fileName)
971 {
973
974 if (verbose)
975 {
976 ARMARX_INFO << "Loading KinematicUnit " << kinematicUnitName << " from "
977 << kinematicUnitFile << " ..." << flush;
978 }
979
980 if (!ArmarXDataPath::getAbsolutePath(fileName, fileName))
981 {
982 ARMARX_INFO << "Could not find Robot XML file with name " << fileName << flush;
983 }
984
985 robot = VirtualRobot::RobotIO::loadRobot(fileName);
986
987 if (!robot)
988 {
989 ARMARX_INFO << "Could not find Robot XML file with name " << fileName << "("
990 << kinematicUnitName << ")" << flush;
991 }
992
993 return robot;
994 }
995
996 VirtualRobot::CoinVisualizationPtr
997 KinematicUnitWidgetController::getCoinVisualization(VirtualRobot::RobotPtr robot)
998 {
999 VirtualRobot::CoinVisualizationPtr coinVisualization;
1000
1001 if (robot != NULL)
1002 {
1003 ARMARX_VERBOSE << "getting coin visualization" << flush;
1004 coinVisualization = robot->getVisualization();
1005
1006 if (!coinVisualization || !coinVisualization->getCoinVisualization())
1007 {
1008 ARMARX_INFO << "could not get coin visualization" << flush;
1009 }
1010 }
1011
1012 return coinVisualization;
1013 }
1014
1015 VirtualRobot::RobotNodeSetPtr
1016 KinematicUnitWidgetController::getRobotNodeSet(VirtualRobot::RobotPtr robot,
1017 std::string nodeSetName)
1018 {
1019 VirtualRobot::RobotNodeSetPtr nodeSetPtr;
1020
1021 if (robot)
1022 {
1023 nodeSetPtr = robot->getRobotNodeSet(nodeSetName);
1024
1025 if (!nodeSetPtr)
1026 {
1027 ARMARX_INFO << "RobotNodeSet with name " << nodeSetName << " is not defined"
1028 << flush;
1029 }
1030 }
1031
1032 return nodeSetPtr;
1033 }
1034
1035 bool
1036 KinematicUnitWidgetController::initGUIComboBox(VirtualRobot::RobotNodeSetPtr robotNodeSet)
1037 {
1038 ui->nodeListComboBox->clear();
1039
1040 if (robotNodeSet)
1041 {
1042 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1043
1044 for (unsigned int i = 0; i < rn.size(); i++)
1045 {
1046 // ARMARX_INFO << "adding item to joint combo box" << rn[i]->getName() << flush;
1047 QString name(rn[i]->getName().c_str());
1048 ui->nodeListComboBox->addItem(name);
1049 }
1050 ui->nodeListComboBox->setCurrentIndex(-1);
1051 return true;
1052 }
1053 return false;
1054 }
1055
1056 bool
1057 KinematicUnitWidgetController::initGUIJointListTable(VirtualRobot::RobotNodeSetPtr robotNodeSet)
1058 {
1059 uint numberOfColumns = 10;
1060
1061 //dont use clear! It is not required here and somehow causes the tabel to have
1062 //numberOfColumns additional empty columns and rn.size() additional empty rows.
1063 //Somehow columncount (rowcount) stay at numberOfColumns (rn.size())
1064 //ui->tableJointList->clear();
1065
1066 if (robotNodeSet)
1067 {
1068 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1069
1070 //set dimension of table
1071 //ui->tableJointList->setColumnWidth(0,110);
1072
1073 //ui->tableJointList->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
1074 ui->tableJointList->setRowCount(rn.size());
1075 ui->tableJointList->setColumnCount(eTabelColumnCount);
1076
1077
1078 //ui->tableJointList->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
1079
1080 // set table header
1081 // if the order is changed dont forget to update the order in the enum JointTabelColumnIndex
1082 // in theheader file
1083 QStringList s;
1084 s << "Joint Name"
1085 << "Control Mode"
1086 << "Angle [deg]/Position [mm]"
1087 << "Velocity [deg/s]/[mm/s]"
1088 << "Torque [Nm] / PWM"
1089 << "Current [A]"
1090 << "Temperature [C]"
1091 << "Operation"
1092 << "Error"
1093 << "Enabled"
1094 << "Emergency Stop";
1095 ui->tableJointList->setHorizontalHeaderLabels(s);
1096 ARMARX_CHECK_EXPRESSION(ui->tableJointList->columnCount() == eTabelColumnCount)
1097 << "Current table size: " << ui->tableJointList->columnCount();
1098
1099
1100 // fill in joint names
1101 for (unsigned int i = 0; i < rn.size(); i++)
1102 {
1103 // ARMARX_INFO << "adding item to joint table" << rn[i]->getName() << flush;
1104 QString name(rn[i]->getName().c_str());
1105
1106 QTableWidgetItem* newItem = new QTableWidgetItem(name);
1107 ui->tableJointList->setItem(i, eTabelColumnName, newItem);
1108 }
1109
1110 // init missing table fields with default values
1111 for (unsigned int i = 0; i < rn.size(); i++)
1112 {
1113 for (unsigned int j = 1; j < numberOfColumns; j++)
1114 {
1115 QString state = "--";
1116 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1117 ui->tableJointList->setItem(i, j, newItem);
1118 }
1119 }
1120
1121 //hide columns Operation, Error, Enabled and Emergency Stop
1122 //they will be shown when changes occur
1123 ui->tableJointList->setColumnHidden(eTabelColumnTemperature, true);
1124 ui->tableJointList->setColumnHidden(eTabelColumnOperation, true);
1125 ui->tableJointList->setColumnHidden(eTabelColumnError, true);
1126 ui->tableJointList->setColumnHidden(eTabelColumnEnabled, true);
1127 ui->tableJointList->setColumnHidden(eTabelColumnEmergencyStop, true);
1128
1129 return true;
1130 }
1131
1132 return false;
1133 }
1134
1135 void
1137 {
1138 std::unique_lock lock(mutexNodeSet);
1139
1140 ARMARX_INFO << "Selected index: " << ui->nodeListComboBox->currentIndex();
1141
1142 if (!robotNodeSet || i < 0 || i >= static_cast<int>(robotNodeSet->getSize()))
1143 {
1144 return;
1145 }
1146
1147 currentNode = robotNodeSet->getAllRobotNodes()[i];
1148 ARMARX_IMPORTANT << "Selected joint is `" << currentNode->getName() << "`.";
1149
1150 const auto controlModes = kinematicUnitInterfacePrx->getControlModes();
1151 if (controlModes.count(currentNode->getName()) == 0)
1152 {
1153 ARMARX_ERROR << "Could not retrieve control mode for joint `" << currentNode->getName()
1154 << "` from kinematic unit!";
1155 return;
1156 }
1157
1158 const auto controlMode = controlModes.at(currentNode->getName());
1159 setControlModeRadioButtonGroup(controlMode);
1160
1161 if (controlMode == ePositionControl)
1162 {
1164 }
1165 else if (controlMode == eVelocityControl)
1166 {
1168 ui->horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
1169 }
1170 else if (controlMode == eTorqueControl)
1171 {
1173 ui->horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
1174 }
1175 }
1176
1177 void
1179 {
1180 if (column == eTabelColumnName)
1181 {
1182 ui->nodeListComboBox->setCurrentIndex(row);
1183 // selectJoint(row);
1184 }
1185 }
1186
1187 void
1189 {
1190 std::unique_lock lock(mutexNodeSet);
1191
1192 if (!currentNode)
1193 {
1194 return;
1195 }
1196
1197 const float value = static_cast<float>(ui->horizontalSliderKinematicUnitPos->value());
1198
1199 const ControlMode currentControlMode = getSelectedControlMode();
1200
1201 const bool isDeg = ui->checkBoxUseDegree->isChecked();
1202 const bool isRot = currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
1203 currentNode->isFourBarJoint();
1204
1205 if (currentControlMode == ePositionControl)
1206 {
1207 const auto factor =
1209 float conversionFactor = isRot && isDeg ? 180.0 / M_PI : 1.0f;
1210
1211 NameValueMap jointAngles;
1212
1213 jointAngles[currentNode->getName()] = value / conversionFactor / factor;
1214 ui->lcdNumberKinematicUnitJointValue->display(value / factor);
1216 {
1217 try
1218 {
1219 kinematicUnitInterfacePrx->setJointAngles(jointAngles);
1220 }
1221 catch (...)
1222 {
1223 }
1224 }
1225 }
1226 else if (currentControlMode == eVelocityControl)
1227 {
1228 float conversionFactor = isRot ? (isDeg ? 180.0 / M_PI : 100.f) : 1.0f;
1229 NameValueMap jointVelocities;
1230 jointVelocities[currentNode->getName()] =
1231 value / conversionFactor *
1232 static_cast<float>(ui->doubleSpinBoxKinematicUnitPosFactor->value());
1233 ui->lcdNumberKinematicUnitJointValue->display(value);
1234
1236 {
1237 try
1238 {
1239 kinematicUnitInterfacePrx->setJointVelocities(jointVelocities);
1240 }
1241 catch (...)
1242 {
1243 }
1244 }
1245 }
1246 else if (currentControlMode == eTorqueControl)
1247 {
1248 NameValueMap jointTorques;
1249 float torqueTargetValue =
1250 value / 100.0f *
1251 static_cast<float>(ui->doubleSpinBoxKinematicUnitPosFactor->value());
1252 jointTorques[currentNode->getName()] = torqueTargetValue;
1253 ui->lcdNumberKinematicUnitJointValue->display(torqueTargetValue);
1254
1256 {
1257 try
1258 {
1259 kinematicUnitInterfacePrx->setJointTorques(jointTorques);
1260 }
1261 catch (...)
1262 {
1263 }
1264 }
1265 }
1266 else
1267 {
1268 ARMARX_INFO << "current ControlModes unknown" << flush;
1269 }
1270 }
1271
1272 void
1274 const NameControlModeMap& reportedJointControlModes)
1275 {
1276 if (!getWidget() || !robotNodeSet)
1277 {
1278 return;
1279 }
1280
1281 std::unique_lock lock(mutexNodeSet);
1282 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1283
1284 for (unsigned int i = 0; i < rn.size(); i++)
1285 {
1286 NameControlModeMap::const_iterator it;
1287 it = reportedJointControlModes.find(rn[i]->getName());
1288 QString state;
1289
1290 if (it == reportedJointControlModes.end())
1291 {
1292 state = "unknown";
1293 }
1294 else
1295 {
1296 ControlMode currentMode = it->second;
1297
1298
1299 switch (currentMode)
1300 {
1301 /*case eNoMode:
1302 state = "None";
1303 break;
1304
1305 case eUnknownMode:
1306 state = "Unknown";
1307 break;
1308 */
1309 case eDisabled:
1310 state = "Disabled";
1311 break;
1312
1313 case eUnknown:
1314 state = "Unknown";
1315 break;
1316
1317 case ePositionControl:
1318 state = "Position";
1319 break;
1320
1321 case eVelocityControl:
1322 state = "Velocity";
1323 break;
1324
1325 case eTorqueControl:
1326 state = "Torque";
1327 break;
1328
1329
1330 case ePositionVelocityControl:
1331 state = "Position + Velocity";
1332 break;
1333
1334 default:
1335 //show the value of the mode so it can be implemented
1336 state = QString("<nyi Mode: %1>").arg(static_cast<int>(currentMode));
1337 break;
1338 }
1339 }
1340
1341 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1342 ui->tableJointList->setItem(i, eTabelColumnControlMode, newItem);
1343 }
1344 }
1345
1346 void
1348 const NameStatusMap& reportedJointStatuses)
1349 {
1350 if (!getWidget() || !robotNodeSet || reportedJointStatuses.empty())
1351 {
1352 return;
1353 }
1354
1355 std::unique_lock lock(mutexNodeSet);
1356 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1357
1358 for (unsigned int i = 0; i < rn.size(); i++)
1359 {
1360
1361 auto it = reportedJointStatuses.find(rn[i]->getName());
1362 if (it == reportedJointStatuses.end())
1363 {
1364 ARMARX_VERBOSE << deactivateSpam(5, rn[i]->getName()) << "Joint Status for "
1365 << rn[i]->getName() << " was not reported!";
1366 continue;
1367 }
1368 JointStatus currentStatus = it->second;
1369
1370 QString state = translateStatus(currentStatus.operation);
1371 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1372 ui->tableJointList->setItem(i, eTabelColumnOperation, newItem);
1373
1374 state = translateStatus(currentStatus.error);
1375 newItem = new QTableWidgetItem(state);
1376 ui->tableJointList->setItem(i, eTabelColumnError, newItem);
1377
1378 state = currentStatus.enabled ? "yes" : "no";
1379 newItem = new QTableWidgetItem(state);
1380 ui->tableJointList->setItem(i, eTabelColumnEnabled, newItem);
1381
1382 state = currentStatus.emergencyStop ? "yes" : "no";
1383 newItem = new QTableWidgetItem(state);
1384 ui->tableJointList->setItem(i, eTabelColumnEmergencyStop, newItem);
1385 }
1386
1387 //show columns
1388 ui->tableJointList->setColumnHidden(eTabelColumnOperation, false);
1389 ui->tableJointList->setColumnHidden(eTabelColumnError, false);
1390 ui->tableJointList->setColumnHidden(eTabelColumnEnabled, false);
1391 ui->tableJointList->setColumnHidden(eTabelColumnEmergencyStop, false);
1392 }
1393
1394 QString
1396 {
1397 switch (status)
1398 {
1399 case eOffline:
1400 return "Offline";
1401
1402 case eOnline:
1403 return "Online";
1404
1405 case eInitialized:
1406 return "Initialized";
1407
1408 default:
1409 return "?";
1410 }
1411 }
1412
1413 QString
1415 {
1416 switch (status)
1417 {
1418 case eOk:
1419 return "Ok";
1420
1421 case eWarning:
1422 return "Wr";
1423
1424 case eError:
1425 return "Er";
1426
1427 default:
1428 return "?";
1429 }
1430 }
1431
1432 void
1433 KinematicUnitWidgetController::updateJointAnglesTable(const NameValueMap& reportedJointAngles)
1434 {
1435 std::unique_lock lock(mutexNodeSet);
1436
1437 if (!robotNodeSet)
1438 {
1439 return;
1440 }
1441 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1442
1443
1444 for (unsigned int i = 0; i < rn.size(); i++)
1445 {
1446 NameValueMap::const_iterator it;
1447 VirtualRobot::RobotNodePtr node = rn[i];
1448 it = reportedJointAngles.find(node->getName());
1449
1450 if (it == reportedJointAngles.end())
1451 {
1452 continue;
1453 }
1454
1455 const float currentValue = it->second;
1456
1457 QModelIndex index = ui->tableJointList->model()->index(i, eTabelColumnAngleProgressbar);
1458 float conversionFactor = ui->checkBoxUseDegree->isChecked() &&
1459 (node->isRotationalJoint() or
1460 node->isHemisphereJoint() or node->isFourBarJoint())
1461 ? 180.0 / M_PI
1462 : 1;
1463 ui->tableJointList->model()->setData(
1464 index,
1465 (int)(cutJitter(currentValue * conversionFactor) * 100) / 100.0f,
1467 ui->tableJointList->model()->setData(
1468 index, node->getJointLimitHigh() * conversionFactor, eJointHiRole);
1469 ui->tableJointList->model()->setData(
1470 index, node->getJointLimitLow() * conversionFactor, eJointLoRole);
1471 }
1472 }
1473
1474 void
1476 const NameValueMap& reportedJointVelocities)
1477 {
1478 if (!getWidget())
1479 {
1480 return;
1481 }
1482
1483 std::unique_lock lock(mutexNodeSet);
1484 if (!robotNodeSet)
1485 {
1486 return;
1487 }
1488 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1489 QTableWidgetItem* newItem;
1490
1491 for (unsigned int i = 0; i < rn.size(); i++)
1492 {
1493 NameValueMap::const_iterator it;
1494 it = reportedJointVelocities.find(rn[i]->getName());
1495
1496 if (it == reportedJointVelocities.end())
1497 {
1498 continue;
1499 }
1500
1501 float currentValue = it->second;
1502 if (ui->checkBoxUseDegree->isChecked() &&
1503 (rn[i]->isRotationalJoint() or rn[i]->isHemisphereJoint() or
1504 rn[i]->isFourBarJoint()))
1505 {
1506 currentValue *= 180.0 / M_PI;
1507 }
1508 const QString Text = QString::number(cutJitter(currentValue), 'g', 2);
1509 newItem = new QTableWidgetItem(Text);
1510 ui->tableJointList->setItem(i, eTabelColumnVelocity, newItem);
1511 }
1512 }
1513
1514 void
1515 KinematicUnitWidgetController::updateJointTorquesTable(const NameValueMap& reportedJointTorques)
1516 {
1517
1518
1519 std::unique_lock lock(mutexNodeSet);
1520 if (!getWidget() || !robotNodeSet)
1521 {
1522 return;
1523 }
1524 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1525 QTableWidgetItem* newItem;
1526 NameValueMap::const_iterator it;
1527
1528 for (unsigned int i = 0; i < rn.size(); i++)
1529 {
1530 it = reportedJointTorques.find(rn[i]->getName());
1531
1532 if (it == reportedJointTorques.end())
1533 {
1534 continue;
1535 }
1536
1537 const float currentValue = it->second;
1538 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1539 ui->tableJointList->setItem(i, eTabelColumnTorque, newItem);
1540 }
1541 }
1542
1543 void
1545 const NameValueMap& reportedJointCurrents,
1546 const NameStatusMap& reportedJointStatuses)
1547 {
1548
1549
1550 std::unique_lock lock(mutexNodeSet);
1551 if (!getWidget() || !robotNodeSet || jointCurrentHistory.size() == 0)
1552 {
1553 return;
1554 }
1555 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1556 QTableWidgetItem* newItem;
1557
1558 // FIXME history!
1559 // NameValueMap reportedJointCurrents = jointCurrentHistory.back().second;
1560 NameValueMap::const_iterator it;
1561
1562 for (unsigned int i = 0; i < rn.size(); i++)
1563 {
1564 it = reportedJointCurrents.find(rn[i]->getName());
1565
1566 if (it == reportedJointCurrents.end())
1567 {
1568 continue;
1569 }
1570
1571 const float currentValue = it->second;
1572 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1573 ui->tableJointList->setItem(i, eTabelColumnCurrent, newItem);
1574 }
1575
1576 highlightCriticalValues(reportedJointStatuses);
1577 }
1578
1579 void
1581 const NameValueMap& reportedJointTemperatures)
1582 {
1583
1584
1585 std::unique_lock lock(mutexNodeSet);
1586 if (!getWidget() || !robotNodeSet || reportedJointTemperatures.empty())
1587 {
1588 return;
1589 }
1590 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1591 QTableWidgetItem* newItem;
1592 NameValueMap::const_iterator it;
1593
1594 for (unsigned int i = 0; i < rn.size(); i++)
1595 {
1596 it = reportedJointTemperatures.find(rn[i]->getName());
1597
1598 if (it == reportedJointTemperatures.end())
1599 {
1600 continue;
1601 }
1602
1603 const float currentValue = it->second;
1604 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1605 ui->tableJointList->setItem(i, eTabelColumnTemperature, newItem);
1606 }
1607 ui->tableJointList->setColumnHidden(eTabelColumnTemperature, false);
1608 }
1609
1610 void
1611 KinematicUnitWidgetController::updateModel(const NameValueMap& reportedJointAngles)
1612 {
1613 // ARMARX_INFO << "updateModel()" << flush;
1614 std::unique_lock lock(mutexNodeSet);
1615 if (!robotNodeSet)
1616 {
1617 return;
1618 }
1619 robot->setJointValues(reportedJointAngles);
1620 }
1621
1622 std::optional<float>
1623 mean(const boost::circular_buffer<NameValueMap>& buffer, const std::string& key)
1624 {
1625 float sum = 0;
1626 std::size_t count = 0;
1627
1628 for (const auto& element : buffer)
1629 {
1630 if (element.count(key) > 0)
1631 {
1632 sum += element.at(key);
1633 }
1634 }
1635
1636 if (count == 0)
1637 {
1638 return std::nullopt;
1639 }
1640
1641 return sum / static_cast<float>(count);
1642 }
1643
1644 void
1646 const NameStatusMap& reportedJointStatuses)
1647 {
1648 if (!enableValueValidator)
1649 {
1650 return;
1651 }
1652
1653 std::unique_lock lock(mutexNodeSet);
1654
1655 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1656
1657 // get standard line colors
1658 static std::vector<QBrush> standardColors;
1659 if (standardColors.size() == 0)
1660 {
1661 for (unsigned int i = 0; i < rn.size(); i++)
1662 {
1663 // all cells of a row have the same color
1664 standardColors.push_back(
1665 ui->tableJointList->item(i, eTabelColumnCurrent)->background());
1666 }
1667 }
1668
1669 // check robot current value of nodes
1670 for (unsigned int i = 0; i < rn.size(); i++)
1671 {
1672 const auto& jointName = rn[i]->getName();
1673
1674 const auto currentSmoothValOpt = mean(jointCurrentHistory, jointName);
1675 if (not currentSmoothValOpt.has_value())
1676 {
1677 continue;
1678 }
1679
1680 const float smoothValue = std::fabs(currentSmoothValOpt.value());
1681
1682 if (jointCurrentHistory.front().count(jointName) == 0)
1683 {
1684 continue;
1685 }
1686
1687 const float startValue = jointCurrentHistory.front().at(jointName);
1688 const bool isStatic = (smoothValue == startValue);
1689
1690 NameStatusMap::const_iterator it;
1691 it = reportedJointStatuses.find(rn[i]->getName());
1692 JointStatus currentStatus = it->second;
1693
1694 if (isStatic)
1695 {
1696 if (currentStatus.operation != eOffline)
1697 {
1698 // current value is zero, but joint is not offline
1699 ui->tableJointList->item(i, eTabelColumnCurrent)->setBackground(Qt::yellow);
1700 }
1701 }
1702 else if (std::abs(smoothValue) > currentValueMax)
1703 {
1704 // current value is too high
1705 ui->tableJointList->item(i, eTabelColumnCurrent)->setBackground(Qt::red);
1706 }
1707 else
1708 {
1709 // everything seems to work as expected
1710 ui->tableJointList->item(i, eTabelColumnCurrent)->setBackground(standardColors[i]);
1711 }
1712 }
1713 }
1714
1715 void
1717 {
1718 this->mutex3D = mutex3D;
1719
1720 if (debugDrawer)
1721 {
1722 debugDrawer->setMutex(mutex3D);
1723 }
1724 }
1725
1726 QPointer<QWidget>
1728 {
1729 if (customToolbar)
1730 {
1731 customToolbar->setParent(parent);
1732 }
1733 else
1734 {
1735 customToolbar = new QToolBar(parent);
1736 customToolbar->addAction("ZeroVelocity", this, SLOT(kinematicUnitZeroVelocity()));
1737 }
1738 return customToolbar.data();
1739 }
1740
1741 float
1742 KinematicUnitWidgetController::cutJitter(float value)
1743 {
1744 return (abs(value) < static_cast<float>(ui->jitterThresholdSpinBox->value())) ? 0 : value;
1745 }
1746
1747 void
1749 {
1750 ARMARX_DEBUG << "updateGui";
1751
1753 {
1754 ARMARX_WARNING << "KinematicUnit is not available!";
1755 return;
1756 }
1757
1758 const auto debugInfo = kinematicUnitInterfacePrx->getDebugInfo();
1759
1760 emit onDebugInfoReceived(debugInfo);
1761 }
1762
1763 void
1765 {
1766 ARMARX_DEBUG << "debug info received";
1767
1768 updateModel(debugInfo.jointAngles);
1769
1770 updateJointAnglesTable(debugInfo.jointAngles);
1771 updateJointVelocitiesTable(debugInfo.jointVelocities);
1772 updateJointTorquesTable(debugInfo.jointTorques);
1773 updateJointCurrentsTable(debugInfo.jointCurrents, debugInfo.jointStatus);
1774 updateControlModesTable(debugInfo.jointModes);
1775 updateJointStatusesTable(debugInfo.jointStatus);
1776 updateMotorTemperaturesTable(debugInfo.jointMotorTemperatures);
1777 }
1778
1779 void
1780 RangeValueDelegate::paint(QPainter* painter,
1781 const QStyleOptionViewItem& option,
1782 const QModelIndex& index) const
1783 {
1785 {
1786 float jointValue = index.data(KinematicUnitWidgetController::eJointAngleRole).toFloat();
1787 float loDeg = index.data(KinematicUnitWidgetController::eJointLoRole).toFloat();
1788 float hiDeg = index.data(KinematicUnitWidgetController::eJointHiRole).toFloat();
1789
1790 if (hiDeg - loDeg <= 0)
1791 {
1792 QStyledItemDelegate::paint(painter, option, index);
1793 return;
1794 }
1795
1796 QStyleOptionProgressBar progressBarOption;
1797 progressBarOption.rect = option.rect;
1798 progressBarOption.minimum = loDeg;
1799 progressBarOption.maximum = hiDeg;
1800 progressBarOption.progress = jointValue;
1801 progressBarOption.text = QString::number(jointValue);
1802 progressBarOption.textVisible = true;
1803 QPalette pal;
1804 pal.setColor(QPalette::Background, Qt::red);
1805 progressBarOption.palette = pal;
1806 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
1807 }
1808 else
1809 {
1810 QStyledItemDelegate::paint(painter, option, index);
1811 }
1812 }
1813
1815 {
1816 kinematicUnitInterfacePrx = nullptr;
1817
1818 if (updateTask)
1819 {
1820 updateTask->stop();
1821 updateTask->join();
1822 updateTask = nullptr;
1823 }
1824 }
1825
1826 void
1828 {
1829 bool ok;
1830 const auto text = QInputDialog::getMultiLineText(
1831 __widget, tr("JSON Joint values"), tr("Json:"), "{\n}", &ok)
1832 .toStdString();
1833
1834 if (!ok || text.empty())
1835 {
1836 return;
1837 }
1838
1839 NameValueMap jointAngles;
1840 try
1841 {
1842 jointAngles = simox::json::json2NameValueMap(text);
1843 }
1844 catch (...)
1845 {
1846 ARMARX_ERROR << "invalid json";
1847 }
1848
1849 NameControlModeMap jointModes;
1850 for (const auto& [key, _] : jointAngles)
1851 {
1852 jointModes[key] = ePositionControl;
1853 }
1854
1855 try
1856 {
1857 kinematicUnitInterfacePrx->switchControlMode(jointModes);
1858 kinematicUnitInterfacePrx->setJointAngles(jointAngles);
1859 }
1860 catch (...)
1861 {
1862 ARMARX_ERROR << "failed to switch mode or set angles";
1863 }
1864 }
1865
1866 void
1868 {
1869 const NameValueMap currentJointAngles = kinematicUnitInterfacePrx->getJointAngles();
1870 robot->setJointValues(currentJointAngles);
1871 }
1872
1873} // namespace armarx
#define lo(x)
#define hi(x)
uint8_t index
#define option(type, fn)
constexpr float SLIDER_POS_RAD_MULTIPLIER
#define KINEMATIC_UNIT_NAME_DEFAULT
constexpr float SLIDER_POS_DEG_MULTIPLIER
constexpr float SLIDER_POS_HEMI_MULTIPLIER
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define M_PI
Definition MathTools.h:17
#define VAROUT(x)
static const std::string & GetProjectName()
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
std::enable_if<!HasGetWidgetName< ArmarXWidgetType >::value >::type addWidget()
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
std::shared_ptr< RecursiveMutex > RecursiveMutexPtr
std::shared_ptr< std::recursive_mutex > mutex3D
void enableMainWidgetAsync(bool enable)
This function enables/disables the main widget asynchronously (if called from a non qt thread).
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
static TPtr create(Ice::PropertiesPtr properties=Ice::createProperties(), const std::string &configName="", const std::string &configDomain="ArmarX")
Factory method for a component.
Definition Component.h:116
static Frequency Hertz(std::int64_t hertz)
Definition Frequency.cpp:20
The JSONObject class is used to represent and (de)serialize JSON objects.
Definition JSONObject.h:44
void initializeUi(const DebugInfo &debugInfo)
void highlightCriticalValues(const NameStatusMap &reportedJointStatuses)
void onInitComponent() override
Pure virtual hook for the subclass.
void updateJointTorquesTable(const NameValueMap &reportedJointTorques)
armarx::RunningTask< KinematicUnitWidgetController >::pointer_type updateTask
void updateJointVelocitiesTable(const NameValueMap &reportedJointVelocities)
QPointer< QWidget > getCustomTitlebarWidget(QWidget *parent) override
getTitleToolbar returns a pointer to the a toolbar widget of this controller.
void onDisconnectComponent() override
Hook for subclass.
void loadSettings(QSettings *settings) override
Implement to load the settings that are part of the GUI configuration.
void updateModel(const NameValueMap &jointAngles)
void saveSettings(QSettings *settings) override
Implement to save the settings as part of the GUI configuration.
SoNode * getScene() override
Reimplementing this function and returning a SoNode* will show this SoNode in the 3DViewerWidget,...
void setMutex3D(RecursiveMutexPtr const &mutex3D) override
This mutex is used to protect 3d scene updates. Usually called by the ArmarXGui main window on creati...
armarx::DebugDrawerComponentPtr debugDrawer
void updateJointCurrentsTable(const NameValueMap &reportedJointCurrents, const NameStatusMap &reportedJointStatuses)
QString translateStatus(OperationStatus status)
void updateControlModesTable(const NameControlModeMap &reportedJointControlModes)
VirtualRobot::CoinVisualizationPtr kinematicUnitVisualization
QPointer< QDialog > getConfigDialog(QWidget *parent=0) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
void setControlModeRadioButtonGroup(const ControlMode &controlMode)
VirtualRobot::RobotNodeSetPtr robotNodeSet
void updateJointStatusesTable(const NameStatusMap &reportedJointStatuses)
void onConnectComponent() override
Pure virtual hook for the subclass.
void updateJointAnglesTable(const NameValueMap &reportedJointAngles)
void resetSlider()
Sets the Slider ui->horizontalSliderKinematicUnitPos to 0 if this->selectedControlMode is eVelocityCo...
void configured() override
This function must be implemented by the user, if he supplies a config dialog.
void onExitComponent() override
Hook for subclass.
void onDebugInfoReceived(const DebugInfo &debugInfo)
KinematicUnitInterfacePrx kinematicUnitInterfacePrx
std::unique_ptr< Ui::KinematicUnitGuiPlugin > ui
void debugInfoReceived(const DebugInfo &debugInfo)
void updateMotorTemperaturesTable(const NameValueMap &reportedMotorTemperatures)
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
ArmarXObjectSchedulerPtr getObjectScheduler() const
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
Ice::PropertiesPtr getIceProperties() const
Returns the set of Ice properties.
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Definition Metronome.h:57
Duration waitForNextTick() const
Wait and block until the target period is met.
Definition Metronome.cpp:27
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:188
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:194
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< ArmarXManager > ArmarXManagerPtr
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
std::vector< T > abs(const std::vector< T > &v)
IceInternal::Handle< JSONObject > JSONObjectPtr
Definition JSONObject.h:34
const LogSender::manipulator flush
Definition LogSender.h:251