36 #include <VirtualRobot/XML/RobotIO.h>
37 #include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.h>
40 #include <Inventor/actions/SoGetMatrixAction.h>
41 #include <Inventor/actions/SoSearchAction.h>
42 #include <Inventor/SbViewportRegion.h>
49 #define ROBOT_UPDATE_TIMER_MS 33
50 #define TEXTFIELD_UPDATE_TIMER_MS 200
51 #define AUTO_FOLLOW_UPDATE 333
52 #define CARTESIAN_CONTROLLER_LOOP_AMOUNT 100
56 addWidget<RobotIKWidgetController>();
64 robotStateComponentName =
"";
65 robotIKComponentName =
"";
66 kinematicUnitComponentName =
"";
69 robotUpdateSensor = NULL;
70 textFieldUpdateSensor = NULL;
76 QMetaObject::invokeMethod(
this,
"initWidget");
78 usingProxy(robotStateComponentName);
79 usingProxy(robotIKComponentName);
80 usingProxy(kinematicUnitComponentName);
86 robotStateComponentPrx = getProxy<RobotStateComponentInterfacePrx>(robotStateComponentName);
87 kinematicUnitInterfacePrx = getProxy<KinematicUnitInterfacePrx>(kinematicUnitComponentName);
88 robotIKPrx = getProxy<RobotIKInterfacePrx>(robotIKComponentName);
91 robot = loadRobot(getIncludePaths());
96 getObjectScheduler()->terminate();
98 if (getWidget()->parentWidget())
100 getWidget()->parentWidget()->close();
103 ARMARX_ERROR <<
"RobotIKPlugin: Unable to load robot file! Terminating." << std::endl;
109 this->ui.robotViewer->getRobotViewer()->getRootNode()->addChild((SoNode*)visualization);
112 currentRobotVisualization = robot->getVisualization<VirtualRobot::CoinVisualization>();
113 this->ui.robotViewer->getRobotViewer()->getRootNode()->addChild(currentRobotVisualization->getCoinVisualization());
116 previewRobot = loadRobot(getIncludePaths());
117 previewRobotVisualization = previewRobot->getVisualization<VirtualRobot::CoinVisualization>();
120 cartesianControlRobot = previewRobot->clone();
123 SoSensorManager* sensor_mgr = SoDB::getSensorManager();
124 robotUpdateSensor =
new SoTimerSensor(robotUpdateTimerCB,
this);
126 sensor_mgr->insertTimerSensor(robotUpdateSensor);
129 textFieldUpdateSensor =
new SoTimerSensor(textFieldUpdateTimerCB,
this);
131 sensor_mgr->insertTimerSensor(textFieldUpdateSensor);
134 auto robotNodeSets = robot->getRobotNodeSets();
136 for (VirtualRobot::RobotNodeSetPtr
s : robotNodeSets)
138 this->ui.comboBox->addItem(QString::fromStdString(
s->getName()));
142 this->ui.comboBox->setEnabled(
true);
143 this->ui.cartesianselection->clear();
145 this->ui.cartesianselection->addItem(QString::fromStdString(
"Orientation and Position"));
146 this->ui.cartesianselection->addItem(QString::fromStdString(
"Position"));
147 this->ui.cartesianselection->addItem(QString::fromStdString(
"Orientation"));
148 this->ui.cartesianselection->addItem(QString::fromStdString(
"X position"));
149 this->ui.cartesianselection->addItem(QString::fromStdString(
"Y position"));
150 this->ui.cartesianselection->addItem(QString::fromStdString(
"Z position"));
153 this->ui.cartesianselection->setEnabled(
true);
154 this->ui.cartesianselection->setCurrentIndex(0);
157 enableMainWidgetAsync(
true);
160 void armarx::RobotIKWidgetController::onDisconnect()
163 SoSensorManager* sensor_mgr = SoDB::getSensorManager();
164 sensor_mgr->removeTimerSensor(textFieldUpdateSensor);
165 sensor_mgr->removeTimerSensor(robotUpdateSensor);
168 this->ui.comboBox->clear();
171 this->ui.comboBox->setEnabled(
false);
172 this->ui.moveTCP->setEnabled(
false);
173 this->ui.reachableLabel->setEnabled(
false);
174 this->ui.reachableLabel->setText(QString::fromStdString(
"No kinematic chain selected"));
175 this->ui.reachableLabel->setStyleSheet(
"QLabel { color : red; }");
176 this->ui.errorValue->setEnabled(
false);
177 this->ui.errorValue->setText(QString::fromStdString(
"Calculated error: 0"));
178 this->ui.errorValue->setEnabled(
false);
179 this->ui.pushButton->setEnabled(
false);
180 this->ui.checkBox->setChecked(
false);
181 this->ui.checkBox->setEnabled(
false);
182 this->ui.currentPose->setEnabled(
false);
183 this->ui.currentPoseMatrix->setEnabled(
false);
184 this->ui.desiredPose->setEnabled(
false);
185 this->ui.desiredPoseMatrix->setEnabled(
false);
186 this->ui.resetManip->setEnabled(
false);
187 this->ui.btnCopyCurrentPoseToClipboard->setEnabled(
false);
188 this->ui.pushButton_setDesiredPose->setEnabled(
false);
191 this->ui.robotViewer->getRobotViewer()->getRootNode()->removeAllChildren();
193 visualization = NULL;
194 robotUpdateSensor = NULL;
195 textFieldUpdateSensor = NULL;
200 QMetaObject::invokeMethod(
this,
"onDisconnect");
214 dialog->addProxyFinder<KinematicUnitInterfacePrx>({
"KinematicUnit",
"",
"*KinematicUnit|KinematicUnit*"});
215 dialog->addProxyFinder<RobotIKInterfacePrx>({
"RobotIK",
"",
"RobotIK*"});
217 return qobject_cast<SimpleConfigDialog*>(dialog);
222 robotStateComponentName = settings->value(
"robotStateComponentName").toString().toStdString();
223 robotIKComponentName = settings->value(
"robotIKComponentName").toString().toStdString();
224 kinematicUnitComponentName = settings->value(
"kinematicUnitComponentName").toString().toStdString();
229 settings->setValue(
"robotStateComponentName", robotStateComponentName.c_str());
230 settings->setValue(
"robotIKComponentName", robotIKComponentName.c_str());
231 settings->setValue(
"kinematicUnitComponentName", kinematicUnitComponentName.c_str());
236 robotStateComponentName = dialog->getProxyName(
"RobotStateComponent");
237 robotIKComponentName = dialog->getProxyName(
"RobotIK");
238 kinematicUnitComponentName = dialog->getProxyName(
"KinematicUnit");
243 ARMARX_INFO <<
"RobotIKWidgetController initWidget";
245 ui.setupUi(getWidget());
246 getWidget()->setEnabled(
false);
248 this->ui.gridLayout->setAlignment(Qt::AlignTop);
251 this->ui.reachableLabel->setStyleSheet(
"QLabel { color : red; }");
256 robotIKPrx->begin_computeExtendedIKGlobalPose(this->ui.comboBox->currentText().toStdString(),
new armarx::Pose(visualization->getUserDesiredPose()),
257 convertOption(this->ui.cartesianselection->currentText().toStdString()),
258 Ice::newCallback(
this, &RobotIKWidgetController::ikCallbackExecuteMotion));
261 void armarx::RobotIKWidgetController::ikCallbackExecuteMotion(
const Ice::AsyncResultPtr& r)
263 RobotIKInterfacePrx prx = RobotIKInterfacePrx::uncheckedCast(r->getProxy());
264 ExtendedIKResult solution = prx->end_computeExtendedIKGlobalPose(r);
267 currentSolution = improveCurrentSolution(solution);
269 QMetaObject::invokeMethod(
this,
"updateSolutionDisplay");
270 QMetaObject::invokeMethod(
this,
"executeMotion");
272 void armarx::RobotIKWidgetController::ikCallbackDisplaySolution(
const Ice::AsyncResultPtr& r)
275 RobotIKInterfacePrx prx = RobotIKInterfacePrx::uncheckedCast(r->getProxy());
276 ExtendedIKResult solution = prx->end_computeExtendedIKGlobalPose(r);
279 currentSolution = improveCurrentSolution(solution);
280 if (currentSolution.isReachable)
282 updatePreviewRobot();
285 QMetaObject::invokeMethod(
this,
"updateSolutionDisplay");
295 this->ui.moveTCP->setEnabled(
true);
296 this->ui.reachableLabel->setEnabled(
true);
297 this->ui.reachableLabel->setText(QString::fromStdString(
"Pose reachable!"));
298 this->ui.reachableLabel->setStyleSheet(
"QLabel { color : green; }");
299 this->ui.errorValue->setText(QString::fromStdString(
"Calculated error: 0"));
300 this->ui.errorValue->setEnabled(
true);
301 this->ui.pushButton->setEnabled(
true);
302 this->ui.currentPose->setEnabled(
true);
303 this->ui.currentPoseMatrix->setEnabled(
true);
304 this->ui.desiredPose->setEnabled(
true);
305 this->ui.desiredPoseMatrix->setEnabled(
true);
306 this->ui.resetManip->setEnabled(
true);
307 this->ui.checkBox->setEnabled(
true);
308 this->ui.btnCopyCurrentPoseToClipboard->setEnabled(
true);
309 this->ui.pushButton_setDesiredPose->setEnabled(
true);
312 if (visualization && robot->hasRobotNodeSet(arg1.toStdString()))
314 visualization->setVisualization(robot, robot->getRobotNodeSet(arg1.toStdString()));
316 visualization->addManipFinishCallback(manipFinishCallback,
this);
317 visualization->addManipMovedCallback(manipMovedCallback,
this);
326 if (visualization->getIsVisualizing())
328 manipFinishCallback(
this, NULL);
335 kinematicChainChanged(this->ui.comboBox->currentText());
340 if (getState() != eManagedIceObjectStarted)
348 if (currentSolution.isReachable)
351 ui.reachableLabel->setText(QString::fromStdString(
"Pose reachable!"));
352 ui.reachableLabel->setStyleSheet(
"QLabel { color : green; }");
353 visualization->setColor(0, 1, 0);
358 ui.reachableLabel->setText(QString::fromStdString(
"Pose unreachable!"));
359 ui.reachableLabel->setStyleSheet(
"QLabel { color : red; }");
360 visualization->setColor(1, 0, 0);
364 ui.errorValue->setText(
"Calculated error: " + QString::number(currentSolution.errorPosition,
'f', 1)
365 +
" mm " + QString::number(currentSolution.errorOrientation * 180 /
M_PI,
'f', 2) +
" deg");
371 auto visualizationRoot = this->ui.robotViewer->getRobotViewer()->getRootNode();
374 if (visualizationRoot->findChild(currentRobotVisualization->getCoinVisualization()) == -1)
376 visualizationRoot->addChild(currentRobotVisualization->getCoinVisualization());
381 if (visualizationRoot->findChild(currentRobotVisualization->getCoinVisualization()) != -1)
383 visualizationRoot->removeChild(currentRobotVisualization->getCoinVisualization());
390 auto visualizationRoot = this->ui.robotViewer->getRobotViewer()->getRootNode();
393 if (visualizationRoot->findChild(previewRobotVisualization->getCoinVisualization()) == -1)
395 visualizationRoot->addChild(previewRobotVisualization->getCoinVisualization());
400 if (visualizationRoot->findChild(previewRobotVisualization->getCoinVisualization()) != -1)
402 visualizationRoot->removeChild(previewRobotVisualization->getCoinVisualization());
407 void armarx::RobotIKWidgetController::connectSlots()
409 connect(ui.resetManip, SIGNAL(clicked()),
this, SLOT(resetManip()), Qt::UniqueConnection);
410 connect(ui.pushButton, SIGNAL(clicked()),
this, SLOT(executeMotion()), Qt::UniqueConnection);
411 connect(ui.comboBox, SIGNAL(currentIndexChanged(QString)),
this, SLOT(kinematicChainChanged(QString)), Qt::UniqueConnection);
412 connect(ui.cartesianselection, SIGNAL(currentIndexChanged(QString)),
this, SLOT(caertesianSelectionChanged(QString)), Qt::UniqueConnection);
413 connect(ui.checkBox, SIGNAL(toggled(
bool)),
this, SLOT(autoFollowChanged(
bool)), Qt::UniqueConnection);
414 connect(ui.btnCopyCurrentPoseToClipboard, SIGNAL(clicked()),
this, SLOT(on_btnCopyCurrentPoseToClipboard_clicked()), Qt::UniqueConnection);
415 connect(ui.checkBox_showCurrentRobot, SIGNAL(toggled(
bool)),
this, SLOT(showCurrentRobotChanged(
bool)), Qt::UniqueConnection);
416 connect(ui.checkBox_showPreviewRobot, SIGNAL(toggled(
bool)),
this, SLOT(showPreviewRobotChanged(
bool)), Qt::UniqueConnection);
417 connect(ui.pushButton_setDesiredPose, SIGNAL(clicked()),
this, SLOT(on_btnSetDesiredPose_clicked()), Qt::UniqueConnection);
420 Ice::StringSeq armarx::RobotIKWidgetController::getIncludePaths()
const
422 Ice::StringSeq includePaths;
426 Ice::StringSeq packages = robotStateComponentPrx->getArmarXPackages();
429 for (
const std::string& projectName : packages)
431 if (projectName.empty())
436 CMakePackageFinder
project(projectName);
437 auto pathsString =
project.getDataDir();
438 Ice::StringSeq projectIncludePaths =
armarx::Split(pathsString,
",;",
true,
true);
439 includePaths.insert(includePaths.end(), projectIncludePaths.begin(), projectIncludePaths.end());
444 ARMARX_ERROR <<
"Unable to retrieve robot filename." << std::endl;
454 std::string rfile = robotStateComponentPrx->getRobotFilename();
456 return VirtualRobot::RobotIO::loadRobot(rfile);
460 ARMARX_ERROR <<
"Unable to load robot from file" << std::endl;
465 void armarx::RobotIKWidgetController::manipFinishCallback(
void*
data, SoDragger* dragger)
467 RobotIKWidgetController*
controller =
static_cast<RobotIKWidgetController*
>(
data);
474 void armarx::RobotIKWidgetController::manipMovedCallback(
void*
data, SoDragger* dragger)
476 RobotIKWidgetController*
controller =
static_cast<RobotIKWidgetController*
>(
data);
481 QMetaObject::invokeMethod(
controller,
"showPreviewRobotChanged", Qt::QueuedConnection, Q_ARG(
bool,
false));
485 void armarx::RobotIKWidgetController::robotUpdateTimerCB(
void*
data, SoSensor* sensor)
487 RobotIKWidgetController*
controller =
static_cast<RobotIKWidgetController*
>(
data);
500 controller->ui.robotViewer->getRobotViewer()->cameraViewAll();
501 controller->startUpCameraPositioningFlag =
false;
507 void armarx::RobotIKWidgetController::textFieldUpdateTimerCB(
void*
data, SoSensor* sensor)
509 RobotIKWidgetController*
controller =
static_cast<RobotIKWidgetController*
>(
data);
516 if (
controller->visualization->getIsVisualizing())
523 controller->ui.currentPoseMatrix->setText(QString::fromStdString(actualPose.output()));
529 controller->ui.desiredPoseMatrix->setText(QString::fromStdString(desired.output()));
533 void armarx::RobotIKWidgetController::autoFollowSensorTimerCB(
void*
data, SoSensor* sensor)
535 RobotIKWidgetController*
controller =
static_cast<RobotIKWidgetController*
>(
data);
544 void armarx::RobotIKWidgetController::startIKSolving(RobotIKWidgetController*
controller)
548 controller->ui.reachableLabel->setText(QString::fromStdString(
"Calculating..."));
549 controller->ui.reachableLabel->setStyleSheet(
"QLabel { color : black; }");
550 controller->robotIKPrx->begin_computeExtendedIKGlobalPose(
controller->ui.comboBox->currentText().toStdString(),
553 Ice::newCallback(
controller, &RobotIKWidgetController::ikCallbackDisplaySolution));
557 armarx::ExtendedIKResult armarx::RobotIKWidgetController::improveCurrentSolution(armarx::ExtendedIKResult& solution)
559 if (!ui.checkBox_cartesianControl->isChecked())
564 if (!solution.isReachable)
573 vrmode = VirtualRobot::IKSolver::CartesianSelection::All;
589 cartesianControlRobot->setJointValues(solution.jointAngles);
590 VirtualRobot::RobotNodeSetPtr kc = cartesianControlRobot->getRobotNodeSet(ui.comboBox->currentText().toStdString());
591 VirtualRobot::RobotNodePtr tcp = kc->getTCP();
592 Eigen::Matrix4f globalTargetTCPPose = visualization->getUserDesiredPose();
593 Eigen::Matrix4f localTarget = cartesianControlRobot->getRootNode()->toLocalCoordinateSystem(globalTargetTCPPose);
596 cartesianPositionController.reset(
new CartesianPositionController(tcp));
599 cartesianVelocityController.reset(
new CartesianVelocityController(kc, tcp, VirtualRobot::JacobiProvider::eSVD));
602 float errorOriInitial = cartesianPositionController->getOrientationError(localTarget);
603 float errorPosInitial = cartesianPositionController->getPositionError(localTarget);
605 float stepLength = 0.05f;
610 Eigen::VectorXf tcpVelocities = cartesianPositionController->calculate(localTarget, vrmode);
611 Eigen::VectorXf nullspaceVel = cartesianVelocityController->calculateJointLimitAvoidance();
612 float nullspaceLen = nullspaceVel.norm();
613 if (nullspaceLen > stepLength)
615 nullspaceVel = nullspaceVel / nullspaceLen * stepLength;
617 Eigen::VectorXf
jointVelocities = cartesianVelocityController->calculate(tcpVelocities, nullspaceVel, vrmode);
621 if (len > stepLength)
626 for (
size_t n = 0; n < kc->getSize(); n++)
628 kc->getNode(n)->setJointValue(kc->getNode(n)->getJointValue() +
jointVelocities(n));
636 float errorOriAfter = cartesianPositionController->getOrientationError(localTarget);
637 float errorPosAfter = cartesianPositionController->getPositionError(localTarget);
638 if (errorOriAfter < errorOriInitial + 1.f / 180 *
M_PI && errorPosAfter < errorPosInitial + 1.f)
640 solution.jointAngles = kc->getJointValueMap();
641 solution.errorOrientation = errorOriAfter;
642 solution.errorPosition = errorPosAfter;
648 armarx::ExtendedIKResult armarx::RobotIKWidgetController::getIKSolution()
const
650 return ExtendedIKResult();
655 if (
option ==
"Orientation and Position")
659 else if (
option ==
"Position")
663 else if (
option ==
"Orientation")
667 else if (
option ==
"X position")
671 else if (
option ==
"Y position")
675 else if (
option ==
"Z position")
683 void armarx::RobotIKWidgetController::updatePreviewRobot()
686 previewRobot->setJointValues(currentSolution.jointAngles);
687 showPreviewRobotChanged(ui.checkBox_showPreviewRobot->isChecked());
690 void armarx::RobotIKWidgetController::on_btnSetDesiredPose_clicked()
694 if (d.exec() == QDialog::Accepted)
697 if (newDesiredPose->frame.empty())
701 else if (newDesiredPose->agent.empty())
710 visualization->setUserDesiredPose(newDesiredPose->toGlobalEigen(robot));
711 startIKSolving(
this);
721 void armarx::RobotIKWidgetController::executeMotion()
723 if (currentSolution.isReachable)
726 std::vector<VirtualRobot::RobotNodePtr> rn = robot->getRobotNodeSet(this->ui.comboBox->currentText().toStdString())->getAllRobotNodes();
727 NameControlModeMap jointModes;
730 for (
unsigned int i = 0; i < rn.size(); i++)
732 jointModes[rn[i]->getName()] = ePositionControl;
736 kinematicUnitInterfacePrx->switchControlMode(jointModes);
737 kinematicUnitInterfacePrx->setJointAngles(currentSolution.jointAngles);
746 SoSensorManager* sensor_mgr = SoDB::getSensorManager();
747 autoFollowSensor =
new SoTimerSensor(autoFollowSensorTimerCB,
this);
749 sensor_mgr->insertTimerSensor(autoFollowSensor);
753 SoSensorManager* sensor_mgr = SoDB::getSensorManager();
754 sensor_mgr->removeTimerSensor(autoFollowSensor);
758 void armarx::RobotIKWidgetController::on_btnCopyCurrentPoseToClipboard_clicked()
761 if (visualization->getIsVisualizing())
764 Eigen::Matrix4f tcpMatrix = robot->getRobotNodeSet(ui.comboBox->currentText().toStdString())->getTCP()->getPoseInRootFrame();
767 obj->serializeIceObject(pose);
770 QClipboard* clipboard = QApplication::clipboard();
771 clipboard->setText(QString::fromStdString(obj->asString(
true)));