26 #include <SimoxUtility/algorithm/string.h>
27 #include <SimoxUtility/json.h>
28 #include <VirtualRobot/XML/RobotIO.h>
43 #include <RobotAPI/gui-plugins/KinematicUnitPlugin/ui_KinematicUnitConfigDialog.h>
44 #include <RobotAPI/interface/core/NameValueMap.h>
45 #include <RobotAPI/interface/units/KinematicUnitInterface.h>
52 #include <QInputDialog>
53 #include <QPushButton>
56 #include <QStringList>
58 #include <QTableWidget>
65 #include <Inventor/Qt/SoQt.h>
66 #include <Inventor/SoDB.h>
83 #define KINEMATIC_UNIT_NAME_DEFAULT "Robot"
96 qRegisterMetaType<DebugInfo>(
"DebugInfo");
98 addWidget<KinematicUnitWidgetController>();
102 kinematicUnitNode(nullptr),
103 enableValueValidator(true),
105 currentValueMax(5.0f)
116 ui.radioButtonUnknown->setHidden(
true);
133 std::string debugDrawerComponentName =
"KinemticUnitGUIDebugDrawer_" +
getName();
134 ARMARX_INFO <<
"Creating component " << debugDrawerComponentName;
136 Component::create<DebugDrawerComponent>(
getIceProperties(), debugDrawerComponentName);
154 std::unique_lock lock(*
mutex3D);
170 jointCurrentHistory.clear();
171 jointCurrentHistory.set_capacity(5);
182 Ice::StringSeq includePaths;
191 for (
const std::string& projectName : packages)
193 if (projectName.empty())
199 auto pathsString =
project.getDataDir();
200 ARMARX_VERBOSE <<
"Data paths of ArmarX package " << projectName <<
": "
202 Ice::StringSeq projectIncludePaths =
Split(pathsString,
";,",
true,
true);
203 ARMARX_VERBOSE <<
"Result: Data paths of ArmarX package " << projectName <<
": "
204 << projectIncludePaths;
206 includePaths.end(), projectIncludePaths.begin(), projectIncludePaths.end());
223 ARMARX_INFO <<
"Loading robot from file " << rfile;
224 robot = loadRobotFile(rfile);
226 catch (
const std::exception& e)
248 ARMARX_VERBOSE <<
"Disable the SetZero button because the robot name is '"
249 <<
robot->getName() <<
"'.";
250 ui.pushButtonKinematicUnitPos1->setDisabled(
true);
270 QMetaObject::invokeMethod(
this,
"resetSlider");
289 ARMARX_INFO <<
"Connection to kinemetic unit lost. Update task terminates.";
308 std::unique_lock lock(mutexNodeSet);
315 std::unique_lock lock(*
mutex3D);
336 std::unique_lock lock(*
mutex3D);
376 dialog->setName(dialog->getDefaultName());
379 return qobject_cast<KinematicUnitConfigDialog*>(dialog);
387 enableValueValidator = dialog->ui->checkBox->isChecked();
388 viewerEnabled = dialog->ui->checkBox3DViewerEnabled->isChecked();
389 historyTime = dialog->ui->spinBoxHistory->value() * 1000;
390 currentValueMax = dialog->ui->doubleSpinBoxMaxMinCurrent->value();
399 enableValueValidator = settings->value(
"enableValueValidator",
true).toBool();
400 viewerEnabled = settings->value(
"viewerEnabled",
true).toBool();
401 historyTime = settings->value(
"historyTime", 100).toInt() * 1000;
402 currentValueMax = settings->value(
"currentValueMax", 5.0).toFloat();
408 settings->setValue(
"kinematicUnitName", QString::fromStdString(
kinematicUnitName));
409 settings->setValue(
"enableValueValidator", enableValueValidator);
410 settings->setValue(
"viewerEnabled", viewerEnabled);
411 assert(historyTime % 1000 == 0);
412 settings->setValue(
"historyTime",
static_cast<int>(historyTime / 1000));
413 settings->setValue(
"currentValueMax", currentValueMax);
437 std::unique_lock lock(mutexNodeSet);
444 if (selectedControlMode == ePositionControl)
446 values = debugInfo.jointAngles;
448 else if (selectedControlMode == eVelocityControl)
450 values = debugInfo.jointVelocities;
457 serializer->setFloat(kv.first, kv.second);
459 const QString json = QString::fromStdString(serializer->asString(
true));
460 QClipboard* clipboard = QApplication::clipboard();
461 clipboard->setText(json);
462 QApplication::processEvents();
491 ARMARX_INFO <<
"viewer disabled - returning null scene";
499 connect(
ui.pushButtonKinematicUnitPos1,
502 SLOT(kinematicUnitZeroPosition()));
505 ui.nodeListComboBox, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
selectJoint(
int)));
506 connect(
ui.horizontalSliderKinematicUnitPos,
507 SIGNAL(valueChanged(
int)),
511 connect(
ui.horizontalSliderKinematicUnitPos,
512 SIGNAL(sliderReleased()),
516 connect(
ui.radioButtonPositionControl,
517 SIGNAL(clicked(
bool)),
520 connect(
ui.radioButtonVelocityControl,
521 SIGNAL(clicked(
bool)),
530 connect(
ui.showDebugLayer,
531 SIGNAL(toggled(
bool)),
534 Qt::QueuedConnection);
540 Qt::QueuedConnection);
545 Qt::QueuedConnection);
550 Qt::QueuedConnection);
555 Qt::QueuedConnection);
560 Qt::QueuedConnection);
565 Qt::QueuedConnection);
570 Qt::QueuedConnection);
572 connect(
ui.tableJointList,
573 SIGNAL(cellDoubleClicked(
int,
int)),
576 Qt::QueuedConnection);
578 connect(
ui.checkBoxUseDegree,
582 Qt::QueuedConnection);
601 ui.widgetSliderFactor->setVisible(
false);
614 std::unique_lock lock(mutexNodeSet);
615 std::vector<VirtualRobot::RobotNodePtr> rn =
robotNodeSet->getAllRobotNodes();
617 NameControlModeMap jointModes;
619 for (
unsigned int i = 0; i < rn.size(); i++)
621 jointModes[rn[i]->getName()] = eVelocityControl;
622 vels[rn[i]->getName()] = 0.0f;
635 if (selectedControlMode == eVelocityControl)
637 ui.horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
646 if (selectedControlMode == eVelocityControl || selectedControlMode == eTorqueControl)
650 else if (selectedControlMode == ePositionControl)
657 const bool isDeg =
ui.checkBoxUseDegree->isChecked();
660 const float conversionFactor = isDeg ? 180.0 /
M_PI : 1.0f;
661 const float pos =
currentNode->getJointValue() * conversionFactor;
663 ui.lcdNumberKinematicUnitJointValue->display((
int)pos);
664 ui.horizontalSliderKinematicUnitPos->setSliderPosition((
int)(pos * factor));
672 ui.lcdNumberKinematicUnitJointValue->display((
int)pos);
673 ui.horizontalSliderKinematicUnitPos->setSliderPosition((
int)(pos * factor));
684 if (selectedControlMode == eVelocityControl || selectedControlMode == eTorqueControl)
686 ui.horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
687 ui.lcdNumberKinematicUnitJointValue->display(SLIDER_ZERO_POSITION);
694 ARMARX_VERBOSE <<
"Setting control mode of radio button group to " << controlMode;
700 case ePositionVelocityControl:
701 ui.radioButtonUnknown->setChecked(
true);
703 case ePositionControl:
704 ui.radioButtonPositionControl->setChecked(
true);
706 case eVelocityControl:
707 ui.radioButtonVelocityControl->setChecked(
true);
710 ui.radioButtonTorqueControl->setChecked(
true);
718 if (!
ui.radioButtonPositionControl->isChecked())
722 NameControlModeMap jointModes;
724 ui.widgetSliderFactor->setVisible(
false);
730 const QString unit = [&]() -> QString
735 if (
ui.checkBoxUseDegree->isChecked())
748 throw std::invalid_argument(
"unknown/unsupported joint type");
751 ui.labelUnit->setText(unit);
754 const auto [factor, conversionFactor] = [&]() -> std::pair<float, float>
759 const bool isDeg =
ui.checkBoxUseDegree->isChecked();
772 throw std::invalid_argument(
"unknown/unsupported joint type");
775 jointModes[
currentNode->getName()] = ePositionControl;
782 const float lo =
currentNode->getJointLimitLo() * conversionFactor;
783 const float hi =
currentNode->getJointLimitHi() * conversionFactor;
799 const float pos =
currentNode->getJointValue() * conversionFactor;
800 ARMARX_INFO <<
"Setting position control for current node "
801 <<
"(name '" <<
currentNode->getName() <<
"' with current value " << pos
806 ui.horizontalSliderKinematicUnitPos->blockSignals(
true);
808 const float sliderMax =
hi * factor;
809 const float sliderMin =
lo * factor;
811 ui.horizontalSliderKinematicUnitPos->setMaximum(sliderMax);
812 ui.horizontalSliderKinematicUnitPos->setMinimum(sliderMin);
814 const std::size_t desiredNumberOfTicks = 1
'000;
816 const float tickInterval = (sliderMax - sliderMin) / desiredNumberOfTicks;
817 ARMARX_INFO << VAROUT(tickInterval);
819 ui.horizontalSliderKinematicUnitPos->setTickInterval(tickInterval);
820 ui.lcdNumberKinematicUnitJointValue->display(pos);
822 ui.horizontalSliderKinematicUnitPos->blockSignals(false);
828 KinematicUnitWidgetController::setControlModeVelocity()
830 if (!ui.radioButtonVelocityControl->isChecked())
834 NameControlModeMap jointModes;
835 NameValueMap jointVelocities;
839 jointModes[currentNode->getName()] = eVelocityControl;
841 // set the velocity to zero to stop any previous controller (e.g. torque controller)
842 jointVelocities[currentNode->getName()] = 0;
845 const QString unit = [&]() -> QString
847 if (currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
848 currentNode->isFourBarJoint())
850 if (ui.checkBoxUseDegree->isChecked())
855 return "rad/(100*s)";
858 if (currentNode->isTranslationalJoint())
863 throw std::invalid_argument("unknown/unsupported joint type");
867 ui.labelUnit->setText(unit);
868 ARMARX_INFO << "setting velocity control for current Node Name: "
869 << currentNode->getName() << flush;
871 const bool isDeg = ui.checkBoxUseDegree->isChecked();
872 const bool isRot = currentNode->isRotationalJoint() or
873 currentNode->isHemisphereJoint() or currentNode->isFourBarJoint();
875 const float lo = isRot ? (isDeg ? -90 : -M_PI * 100) : -1000;
876 const float hi = isRot ? (isDeg ? +90 : +M_PI * 100) : 1000;
880 if (kinematicUnitInterfacePrx)
882 kinematicUnitInterfacePrx->switchControlMode(jointModes);
883 kinematicUnitInterfacePrx->setJointVelocities(jointVelocities);
890 ui.widgetSliderFactor->setVisible(true);
892 ui.horizontalSliderKinematicUnitPos->blockSignals(true);
893 ui.horizontalSliderKinematicUnitPos->setMaximum(hi);
894 ui.horizontalSliderKinematicUnitPos->setMinimum(lo);
895 ui.horizontalSliderKinematicUnitPos->blockSignals(false);
901 KinematicUnitWidgetController::getSelectedControlMode() const
903 if (ui.radioButtonPositionControl->isChecked())
905 return ControlMode::ePositionControl;
908 if (ui.radioButtonVelocityControl->isChecked())
910 return ControlMode::eVelocityControl;
913 if (ui.radioButtonTorqueControl->isChecked())
915 return ControlMode::eTorqueControl;
918 // if no button is checked, then the joint is likely initialized but no controller has been loaded yet
919 // (well, the no movement controller should be active)
920 return ControlMode::eUnknown;
924 KinematicUnitWidgetController::setControlModeTorque()
926 if (!ui.radioButtonTorqueControl->isChecked())
930 NameControlModeMap jointModes;
934 jointModes[currentNode->getName()] = eTorqueControl;
935 ui.labelUnit->setText("Ncm");
936 ARMARX_INFO << "setting torque control for current Node Name: "
937 << currentNode->getName() << flush;
939 if (kinematicUnitInterfacePrx)
943 kinematicUnitInterfacePrx->switchControlMode(jointModes);
950 ui.horizontalSliderKinematicUnitPos->blockSignals(true);
951 ui.horizontalSliderKinematicUnitPos->setMaximum(20000.0);
952 ui.horizontalSliderKinematicUnitPos->setMinimum(-20000.0);
954 ui.widgetSliderFactor->setVisible(true);
956 ui.horizontalSliderKinematicUnitPos->blockSignals(false);
961 VirtualRobot::RobotPtr
962 KinematicUnitWidgetController::loadRobotFile(std::string fileName)
964 VirtualRobot::RobotPtr robot;
968 ARMARX_INFO << "Loading KinematicUnit " << kinematicUnitName << " from "
969 << kinematicUnitFile << " ..." << flush;
972 if (!ArmarXDataPath::getAbsolutePath(fileName, fileName))
974 ARMARX_INFO << "Could not find Robot XML file with name " << fileName << flush;
977 robot = VirtualRobot::RobotIO::loadRobot(fileName);
981 ARMARX_INFO << "Could not find Robot XML file with name " << fileName << "("
982 << kinematicUnitName << ")" << flush;
988 VirtualRobot::CoinVisualizationPtr
989 KinematicUnitWidgetController::getCoinVisualization(VirtualRobot::RobotPtr robot)
991 VirtualRobot::CoinVisualizationPtr coinVisualization;
995 ARMARX_VERBOSE << "getting coin visualization" << flush;
996 coinVisualization = robot->getVisualization<VirtualRobot::CoinVisualization>();
998 if (!coinVisualization || !coinVisualization->getCoinVisualization())
1000 ARMARX_INFO << "could not get coin visualization" << flush;
1004 return coinVisualization;
1007 VirtualRobot::RobotNodeSetPtr
1008 KinematicUnitWidgetController::getRobotNodeSet(VirtualRobot::RobotPtr robot,
1009 std::string nodeSetName)
1011 VirtualRobot::RobotNodeSetPtr nodeSetPtr;
1015 nodeSetPtr = robot->getRobotNodeSet(nodeSetName);
1019 ARMARX_INFO << "RobotNodeSet with name " << nodeSetName << " is not defined"
1028 KinematicUnitWidgetController::initGUIComboBox(VirtualRobot::RobotNodeSetPtr robotNodeSet)
1030 ui.nodeListComboBox->clear();
1034 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1036 for (unsigned int i = 0; i < rn.size(); i++)
1038 // ARMARX_INFO << "adding item to joint combo box" << rn[i]->getName() << flush;
1039 QString name(rn[i]->getName().c_str());
1040 ui.nodeListComboBox->addItem(name);
1042 ui.nodeListComboBox->setCurrentIndex(-1);
1049 KinematicUnitWidgetController::initGUIJointListTable(VirtualRobot::RobotNodeSetPtr robotNodeSet)
1051 uint numberOfColumns = 10;
1053 //dont use clear! It is not required here and somehow causes the tabel to have
1054 //numberOfColumns additional empty columns and rn.size() additional empty rows.
1055 //Somehow columncount (rowcount) stay at numberOfColumns (rn.size())
1056 //ui.tableJointList->clear();
1060 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1062 //set dimension of table
1063 //ui.tableJointList->setColumnWidth(0,110);
1065 //ui.tableJointList->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
1066 ui.tableJointList->setRowCount(rn.size());
1067 ui.tableJointList->setColumnCount(eTabelColumnCount);
1070 //ui.tableJointList->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
1073 // if the order is changed dont forget to update the order in the enum JointTabelColumnIndex
1074 // in theheader file
1078 << "Angle [deg]/Position [mm]"
1079 << "Velocity [deg/s]/[mm/s]"
1080 << "Torque [Nm] / PWM"
1082 << "Temperature [C]"
1086 << "Emergency Stop";
1087 ui.tableJointList->setHorizontalHeaderLabels(s);
1088 ARMARX_CHECK_EXPRESSION(ui.tableJointList->columnCount() == eTabelColumnCount)
1089 << "Current table size: " << ui.tableJointList->columnCount();
1092 // fill in joint names
1093 for (unsigned int i = 0; i < rn.size(); i++)
1095 // ARMARX_INFO << "adding item to joint table" << rn[i]->getName() << flush;
1096 QString name(rn[i]->getName().c_str());
1098 QTableWidgetItem* newItem = new QTableWidgetItem(name);
1099 ui.tableJointList->setItem(i, eTabelColumnName, newItem);
1102 // init missing table fields with default values
1103 for (unsigned int i = 0; i < rn.size(); i++)
1105 for (unsigned int j = 1; j < numberOfColumns; j++)
1107 QString state = "--";
1108 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1109 ui.tableJointList->setItem(i, j, newItem);
1113 //hide columns Operation, Error, Enabled and Emergency Stop
1114 //they will be shown when changes occur
1115 ui.tableJointList->setColumnHidden(eTabelColumnTemperature, true);
1116 ui.tableJointList->setColumnHidden(eTabelColumnOperation, true);
1117 ui.tableJointList->setColumnHidden(eTabelColumnError, true);
1118 ui.tableJointList->setColumnHidden(eTabelColumnEnabled, true);
1119 ui.tableJointList->setColumnHidden(eTabelColumnEmergencyStop, true);
1128 KinematicUnitWidgetController::selectJoint(int i)
1130 std::unique_lock lock(mutexNodeSet);
1132 ARMARX_INFO << "Selected index: " << ui.nodeListComboBox->currentIndex();
1134 if (!robotNodeSet || i < 0 || i >= static_cast<int>(robotNodeSet->getSize()))
1139 currentNode = robotNodeSet->getAllRobotNodes()[i];
1140 ARMARX_IMPORTANT << "Selected joint is `" << currentNode->getName() << "`.";
1142 const auto controlModes = kinematicUnitInterfacePrx->getControlModes();
1143 if (controlModes.count(currentNode->getName()) == 0)
1145 ARMARX_ERROR << "Could not retrieve control mode for joint `" << currentNode->getName()
1146 << "` from kinematic unit!";
1150 const auto controlMode = controlModes.at(currentNode->getName());
1151 setControlModeRadioButtonGroup(controlMode);
1153 if (controlMode == ePositionControl)
1155 setControlModePosition();
1157 else if (controlMode == eVelocityControl)
1159 setControlModeVelocity();
1160 ui.horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
1162 else if (controlMode == eTorqueControl)
1164 setControlModeTorque();
1165 ui.horizontalSliderKinematicUnitPos->setSliderPosition(SLIDER_ZERO_POSITION);
1170 KinematicUnitWidgetController::selectJointFromTableWidget(int row, int column)
1172 if (column == eTabelColumnName)
1174 ui.nodeListComboBox->setCurrentIndex(row);
1175 // selectJoint(row);
1180 KinematicUnitWidgetController::sliderValueChanged(int pos)
1182 std::unique_lock lock(mutexNodeSet);
1189 const float value = static_cast<float>(ui.horizontalSliderKinematicUnitPos->value());
1191 const ControlMode currentControlMode = getSelectedControlMode();
1193 const bool isDeg = ui.checkBoxUseDegree->isChecked();
1194 const bool isRot = currentNode->isRotationalJoint() or currentNode->isHemisphereJoint() or
1195 currentNode->isFourBarJoint();
1197 if (currentControlMode == ePositionControl)
1200 isRot && !isDeg ? SLIDER_POS_RAD_MULTIPLIER : SLIDER_POS_DEG_MULTIPLIER;
1201 float conversionFactor = isRot && isDeg ? 180.0 / M_PI : 1.0f;
1203 NameValueMap jointAngles;
1205 jointAngles[currentNode->getName()] = value / conversionFactor / factor;
1206 ui.lcdNumberKinematicUnitJointValue->display(value / factor);
1207 if (kinematicUnitInterfacePrx)
1211 kinematicUnitInterfacePrx->setJointAngles(jointAngles);
1218 else if (currentControlMode == eVelocityControl)
1220 float conversionFactor = isRot ? (isDeg ? 180.0 / M_PI : 100.f) : 1.0f;
1221 NameValueMap jointVelocities;
1222 jointVelocities[currentNode->getName()] =
1223 value / conversionFactor *
1224 static_cast<float>(ui.doubleSpinBoxKinematicUnitPosFactor->value());
1225 ui.lcdNumberKinematicUnitJointValue->display(value);
1227 if (kinematicUnitInterfacePrx)
1231 kinematicUnitInterfacePrx->setJointVelocities(jointVelocities);
1238 else if (currentControlMode == eTorqueControl)
1240 NameValueMap jointTorques;
1241 float torqueTargetValue =
1243 static_cast<float>(ui.doubleSpinBoxKinematicUnitPosFactor->value());
1244 jointTorques[currentNode->getName()] = torqueTargetValue;
1245 ui.lcdNumberKinematicUnitJointValue->display(torqueTargetValue);
1247 if (kinematicUnitInterfacePrx)
1251 kinematicUnitInterfacePrx->setJointTorques(jointTorques);
1260 ARMARX_INFO << "current ControlModes unknown" << flush;
1265 KinematicUnitWidgetController::updateControlModesTable(
1266 const NameControlModeMap& reportedJointControlModes)
1268 if (!getWidget() || !robotNodeSet)
1273 std::unique_lock lock(mutexNodeSet);
1274 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1276 for (unsigned int i = 0; i < rn.size(); i++)
1278 NameControlModeMap::const_iterator it;
1279 it = reportedJointControlModes.find(rn[i]->getName());
1282 if (it == reportedJointControlModes.end())
1288 ControlMode currentMode = it->second;
1291 switch (currentMode)
1309 case ePositionControl:
1313 case eVelocityControl:
1317 case eTorqueControl:
1322 case ePositionVelocityControl:
1323 state = "Position + Velocity";
1327 //show the value of the mode so it can be implemented
1328 state = QString("<nyi Mode: %1>").arg(static_cast<int>(currentMode));
1333 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1334 ui.tableJointList->setItem(i, eTabelColumnControlMode, newItem);
1339 KinematicUnitWidgetController::updateJointStatusesTable(
1340 const NameStatusMap& reportedJointStatuses)
1342 if (!getWidget() || !robotNodeSet || reportedJointStatuses.empty())
1347 std::unique_lock lock(mutexNodeSet);
1348 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1350 for (unsigned int i = 0; i < rn.size(); i++)
1353 auto it = reportedJointStatuses.find(rn[i]->getName());
1354 if (it == reportedJointStatuses.end())
1356 ARMARX_VERBOSE << deactivateSpam(5, rn[i]->getName()) << "Joint Status for "
1357 << rn[i]->getName() << " was not reported!";
1360 JointStatus currentStatus = it->second;
1362 QString state = translateStatus(currentStatus.operation);
1363 QTableWidgetItem* newItem = new QTableWidgetItem(state);
1364 ui.tableJointList->setItem(i, eTabelColumnOperation, newItem);
1366 state = translateStatus(currentStatus.error);
1367 newItem = new QTableWidgetItem(state);
1368 ui.tableJointList->setItem(i, eTabelColumnError, newItem);
1370 state = currentStatus.enabled ? "yes" : "no";
1371 newItem = new QTableWidgetItem(state);
1372 ui.tableJointList->setItem(i, eTabelColumnEnabled, newItem);
1374 state = currentStatus.emergencyStop ? "yes" : "no";
1375 newItem = new QTableWidgetItem(state);
1376 ui.tableJointList->setItem(i, eTabelColumnEmergencyStop, newItem);
1380 ui.tableJointList->setColumnHidden(eTabelColumnOperation, false);
1381 ui.tableJointList->setColumnHidden(eTabelColumnError, false);
1382 ui.tableJointList->setColumnHidden(eTabelColumnEnabled, false);
1383 ui.tableJointList->setColumnHidden(eTabelColumnEmergencyStop, false);
1387 KinematicUnitWidgetController::translateStatus(OperationStatus status)
1398 return "Initialized";
1406 KinematicUnitWidgetController::translateStatus(ErrorStatus status)
1425 KinematicUnitWidgetController::updateJointAnglesTable(const NameValueMap& reportedJointAngles)
1427 std::unique_lock lock(mutexNodeSet);
1433 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1436 for (unsigned int i = 0; i < rn.size(); i++)
1438 NameValueMap::const_iterator it;
1439 VirtualRobot::RobotNodePtr node = rn[i];
1440 it = reportedJointAngles.find(node->getName());
1442 if (it == reportedJointAngles.end())
1447 const float currentValue = it->second;
1449 QModelIndex index = ui.tableJointList->model()->index(i, eTabelColumnAngleProgressbar);
1450 float conversionFactor = ui.checkBoxUseDegree->isChecked() &&
1451 (node->isRotationalJoint() or
1452 node->isHemisphereJoint() or node->isFourBarJoint())
1455 ui.tableJointList->model()->setData(
1457 (int)(cutJitter(currentValue * conversionFactor) * 100) / 100.0f,
1459 ui.tableJointList->model()->setData(
1460 index, node->getJointLimitHigh() * conversionFactor, eJointHiRole);
1461 ui.tableJointList->model()->setData(
1462 index, node->getJointLimitLow() * conversionFactor, eJointLoRole);
1467 KinematicUnitWidgetController::updateJointVelocitiesTable(
1468 const NameValueMap& reportedJointVelocities)
1475 std::unique_lock lock(mutexNodeSet);
1480 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1481 QTableWidgetItem* newItem;
1483 for (unsigned int i = 0; i < rn.size(); i++)
1485 NameValueMap::const_iterator it;
1486 it = reportedJointVelocities.find(rn[i]->getName());
1488 if (it == reportedJointVelocities.end())
1493 float currentValue = it->second;
1494 if (ui.checkBoxUseDegree->isChecked() &&
1495 (rn[i]->isRotationalJoint() or rn[i]->isHemisphereJoint() or
1496 rn[i]->isFourBarJoint()))
1498 currentValue *= 180.0 / M_PI;
1500 const QString Text = QString::number(cutJitter(currentValue), 'g
', 2);
1501 newItem = new QTableWidgetItem(Text);
1502 ui.tableJointList->setItem(i, eTabelColumnVelocity, newItem);
1507 KinematicUnitWidgetController::updateJointTorquesTable(const NameValueMap& reportedJointTorques)
1511 std::unique_lock lock(mutexNodeSet);
1512 if (!getWidget() || !robotNodeSet)
1516 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1517 QTableWidgetItem* newItem;
1518 NameValueMap::const_iterator it;
1520 for (unsigned int i = 0; i < rn.size(); i++)
1522 it = reportedJointTorques.find(rn[i]->getName());
1524 if (it == reportedJointTorques.end())
1529 const float currentValue = it->second;
1530 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1531 ui.tableJointList->setItem(i, eTabelColumnTorque, newItem);
1536 KinematicUnitWidgetController::updateJointCurrentsTable(
1537 const NameValueMap& reportedJointCurrents,
1538 const NameStatusMap& reportedJointStatuses)
1542 std::unique_lock lock(mutexNodeSet);
1543 if (!getWidget() || !robotNodeSet || jointCurrentHistory.size() == 0)
1547 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1548 QTableWidgetItem* newItem;
1551 // NameValueMap reportedJointCurrents = jointCurrentHistory.back().second;
1552 NameValueMap::const_iterator it;
1554 for (unsigned int i = 0; i < rn.size(); i++)
1556 it = reportedJointCurrents.find(rn[i]->getName());
1558 if (it == reportedJointCurrents.end())
1563 const float currentValue = it->second;
1564 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1565 ui.tableJointList->setItem(i, eTabelColumnCurrent, newItem);
1568 highlightCriticalValues(reportedJointStatuses);
1572 KinematicUnitWidgetController::updateMotorTemperaturesTable(
1573 const NameValueMap& reportedJointTemperatures)
1577 std::unique_lock lock(mutexNodeSet);
1578 if (!getWidget() || !robotNodeSet || reportedJointTemperatures.empty())
1582 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1583 QTableWidgetItem* newItem;
1584 NameValueMap::const_iterator it;
1586 for (unsigned int i = 0; i < rn.size(); i++)
1588 it = reportedJointTemperatures.find(rn[i]->getName());
1590 if (it == reportedJointTemperatures.end())
1595 const float currentValue = it->second;
1596 newItem = new QTableWidgetItem(QString::number(cutJitter(currentValue)));
1597 ui.tableJointList->setItem(i, eTabelColumnTemperature, newItem);
1599 ui.tableJointList->setColumnHidden(eTabelColumnTemperature, false);
1603 KinematicUnitWidgetController::updateModel(const NameValueMap& reportedJointAngles)
1605 // ARMARX_INFO << "updateModel()" << flush;
1606 std::unique_lock lock(mutexNodeSet);
1611 robot->setJointValues(reportedJointAngles);
1614 std::optional<float>
1615 mean(const boost::circular_buffer<NameValueMap>& buffer, const std::string& key)
1618 std::size_t count = 0;
1620 for (const auto& element : buffer)
1622 if (element.count(key) > 0)
1624 sum += element.at(key);
1630 return std::nullopt;
1633 return sum / static_cast<float>(count);
1637 KinematicUnitWidgetController::highlightCriticalValues(
1638 const NameStatusMap& reportedJointStatuses)
1640 if (!enableValueValidator)
1645 std::unique_lock lock(mutexNodeSet);
1647 std::vector<VirtualRobot::RobotNodePtr> rn = robotNodeSet->getAllRobotNodes();
1649 // get standard line colors
1650 static std::vector<QBrush> standardColors;
1651 if (standardColors.size() == 0)
1653 for (unsigned int i = 0; i < rn.size(); i++)
1655 // all cells of a row have the same color
1656 standardColors.push_back(
1657 ui.tableJointList->item(i, eTabelColumnCurrent)->background());
1661 // check robot current value of nodes
1662 for (unsigned int i = 0; i < rn.size(); i++)
1664 const auto& jointName = rn[i]->getName();
1666 const auto currentSmoothValOpt = mean(jointCurrentHistory, jointName);
1667 if (not currentSmoothValOpt.has_value())
1672 const float smoothValue = std::fabs(currentSmoothValOpt.value());
1674 if (jointCurrentHistory.front().count(jointName) == 0)
1679 const float startValue = jointCurrentHistory.front().at(jointName);
1680 const bool isStatic = (smoothValue == startValue);
1682 NameStatusMap::const_iterator it;
1683 it = reportedJointStatuses.find(rn[i]->getName());
1684 JointStatus currentStatus = it->second;
1688 if (currentStatus.operation != eOffline)
1690 // current value is zero, but joint is not offline
1691 ui.tableJointList->item(i, eTabelColumnCurrent)->setBackground(Qt::yellow);
1694 else if (std::abs(smoothValue) > currentValueMax)
1696 // current value is too high
1697 ui.tableJointList->item(i, eTabelColumnCurrent)->setBackground(Qt::red);
1701 // everything seems to work as expected
1702 ui.tableJointList->item(i, eTabelColumnCurrent)->setBackground(standardColors[i]);
1708 KinematicUnitWidgetController::setMutex3D(RecursiveMutexPtr const& mutex3D)
1710 this->mutex3D = mutex3D;
1714 debugDrawer->setMutex(mutex3D);
1719 KinematicUnitWidgetController::getCustomTitlebarWidget(QWidget* parent)
1723 customToolbar->setParent(parent);
1727 customToolbar = new QToolBar(parent);
1728 customToolbar->addAction("ZeroVelocity", this, SLOT(kinematicUnitZeroVelocity()));
1730 return customToolbar.data();
1734 KinematicUnitWidgetController::cutJitter(float value)
1736 return (abs(value) < static_cast<float>(ui.jitterThresholdSpinBox->value())) ? 0 : value;
1740 KinematicUnitWidgetController::fetchData()
1742 ARMARX_DEBUG << "updateGui";
1744 if (not kinematicUnitInterfacePrx)
1746 ARMARX_WARNING << "KinematicUnit is not available!";
1750 const auto debugInfo = kinematicUnitInterfacePrx->getDebugInfo();
1752 emit onDebugInfoReceived(debugInfo);
1756 KinematicUnitWidgetController::debugInfoReceived(const DebugInfo& debugInfo)
1758 ARMARX_DEBUG << "debug info received";
1760 updateModel(debugInfo.jointAngles);
1762 updateJointAnglesTable(debugInfo.jointAngles);
1763 updateJointVelocitiesTable(debugInfo.jointVelocities);
1764 updateJointTorquesTable(debugInfo.jointTorques);
1765 updateJointCurrentsTable(debugInfo.jointCurrents, debugInfo.jointStatus);
1766 updateControlModesTable(debugInfo.jointModes);
1767 updateJointStatusesTable(debugInfo.jointStatus);
1768 updateMotorTemperaturesTable(debugInfo.jointMotorTemperatures);
1772 RangeValueDelegate::paint(QPainter* painter,
1773 const QStyleOptionViewItem& option,
1774 const QModelIndex& index) const
1776 if (index.column() == KinematicUnitWidgetController::eTabelColumnAngleProgressbar)
1778 float jointValue = index.data(KinematicUnitWidgetController::eJointAngleRole).toFloat();
1779 float loDeg = index.data(KinematicUnitWidgetController::eJointLoRole).toFloat();
1780 float hiDeg = index.data(KinematicUnitWidgetController::eJointHiRole).toFloat();
1782 if (hiDeg - loDeg <= 0)
1784 QStyledItemDelegate::paint(painter, option, index);
1788 QStyleOptionProgressBar progressBarOption;
1789 progressBarOption.rect = option.rect;
1790 progressBarOption.minimum = loDeg;
1791 progressBarOption.maximum = hiDeg;
1792 progressBarOption.progress = jointValue;
1793 progressBarOption.text = QString::number(jointValue);
1794 progressBarOption.textVisible = true;
1796 pal.setColor(QPalette::Background, Qt::red);
1797 progressBarOption.palette = pal;
1798 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
1802 QStyledItemDelegate::paint(painter, option, index);
1806 KinematicUnitWidgetController::~KinematicUnitWidgetController()
1808 kinematicUnitInterfacePrx = nullptr;
1814 updateTask = nullptr;
1819 KinematicUnitWidgetController::on_pushButtonFromJson_clicked()
1822 const auto text = QInputDialog::getMultiLineText(
1823 __widget, tr("JSON Joint values"), tr("Json:"), "{\n}", &ok)
1826 if (!ok || text.empty())
1831 NameValueMap jointAngles;
1834 jointAngles = simox::json::json2NameValueMap(text);
1838 ARMARX_ERROR << "invalid json";
1841 NameControlModeMap jointModes;
1842 for (const auto& [key, _] : jointAngles)
1844 jointModes[key] = ePositionControl;
1849 kinematicUnitInterfacePrx->switchControlMode(jointModes);
1850 kinematicUnitInterfacePrx->setJointAngles(jointAngles);
1854 ARMARX_ERROR << "failed to switch mode or set angles";
1859 KinematicUnitWidgetController::synchronizeRobotJointAngles()
1861 const NameValueMap currentJointAngles = kinematicUnitInterfacePrx->getJointAngles();
1862 robot->setJointValues(currentJointAngles);
1865 } // namespace armarx