HandEyeCalibrationWidgetController.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * \package RobotComponents::gui-plugins::HandEyeCalibrationWidgetController
17 * \author Stefan Reither ( stef dot reither at web dot de )
18 * \date 2018
19 * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <cctype>
26#include <iomanip>
27
28#include <QClipboard>
29#include <QFileDialog>
30#include <QFileInfo>
31#include <QMessageBox>
32
33#include <pcl/common/transforms.h>
34#include <pcl/filters/filter.h>
35#include <pcl/filters/passthrough.h>
36#include <VirtualRobot/MathTools.h>
37
42
47
48#include <VisionX/interface/components/Calibration.h>
49
50const QString defaultFileName("HandEyeCalib_Data.json");
51
52using namespace armarx;
53
55
56
58
59void
63
64void
68
69QPointer<QDialog>
71{
72 if (!dialog)
73 {
74 dialog = new SimpleConfigDialog(parent);
75 dialog->addProxyFinder<visionx::PointCloudProviderInterfacePrx>(
76 {"PointCloudProvider", "PointCloudProvider", "*"});
77 dialog->addProxyFinder<RobotStateComponentInterfacePrx>(
78 {"RobotStateComponent", "RobotStateComponent", "RobotState*"});
79 }
80 return qobject_cast<SimpleConfigDialog*>(dialog);
81}
82
83void
85{
86 providerName = dialog->getProxyName("PointCloudProvider");
87 robotStateComponentName = dialog->getProxyName("RobotStateComponent");
88}
89
90void
92{
93 ARMARX_INFO << "onInitPointCloudProcessor";
94
95 QMetaObject::invokeMethod(this, "initUI");
96
97 usingProxy(robotStateComponentName);
98}
99
100void
101HandEyeCalibrationWidgetController::initUI()
102{
103 widget.setupUi(getWidget());
104 widget.lineEdit_file->setText(QDir::currentPath() + "/" + defaultFileName);
105 getWidget()->setEnabled(false);
106}
107
108void
109HandEyeCalibrationWidgetController::saveDatapoint()
110{
111 if (activeEndEffector)
112 {
114 entry.Add("EndEffector", activeEndEffector->getName());
115
116 std::map<std::string, float> config = localRobot->getConfig()->getRobotNodeJointValueMap();
117 entry.Add("RobotConfig", config);
118
119 Eigen::Matrix4f offset = getOffsetMatrixForEEF(activeEndEffector);
120 entry.AddMatrix("Offset", offset);
121
122 std::string fileName = widget.lineEdit_file->text().toStdString();
123 SimpleJsonLogger logger(fileName, true);
124 logger.log(entry);
125 logger.close();
126
127 QMessageBox::information(
128 getWidget(), tr("HandEyeCalibration"), tr("Datapoint successful written to file."));
129 }
130}
131
132void
133HandEyeCalibrationWidgetController::selectFile()
134{
135 QString fileName = QFileDialog::getOpenFileName(getWidget(),
136 tr("Select file for saving data points"),
137 QDir::currentPath(),
138 tr("JSON-File (*.json);; All Files (*)"));
139 if (!fileName.isEmpty())
140 {
141 widget.lineEdit_file->setText(fileName);
142 }
143}
144
146HandEyeCalibrationWidgetController::getEEFRobot(VirtualRobot::EndEffectorPtr eef) const
147{
148 if (eef && robotEEFMap.count(eef->getName()) == 1)
149 {
150 return robotEEFMap.at(eef->getName()).first;
151 }
152 return VirtualRobot::RobotPtr();
153}
154
155Eigen::Matrix4f
156HandEyeCalibrationWidgetController::getOffsetMatrixForEEF(
157 const VirtualRobot::EndEffectorPtr eef) const
158{
159 if (eef && robotEEFMap.count(eef->getName()) == 1)
160 {
161 return robotEEFMap.at(eef->getName()).second;
162 }
163 return Eigen::Matrix4f::Identity();
164}
165
166void
167HandEyeCalibrationWidgetController::setOffsetMatrixForEEF(const VirtualRobot::EndEffectorPtr eef,
168 const Eigen::Matrix4f& offset)
169{
170 if (eef && robotEEFMap.count(eef->getName()) == 1)
171 {
172 robotEEFMap.at(eef->getName()).second = offset;
173 }
174}
175
176void
178{
179 ARMARX_INFO << "onConnectPointCloudProcessor";
180
181 robotStateComponentPrx =
182 getProxy<RobotStateComponentInterfacePrx>(robotStateComponentName, true);
183
184 usingPointCloudProvider(providerName);
185 providerInfo = getPointCloudProvider(providerName, true);
186 referenceFrame = getProviderFrame();
187 providerBuffer.reset(new pcl::PointCloud<PointT>());
188
189 localRobot = loadRobotFromFile();
190 try
191 {
192 pointcloudRobot = RemoteRobot::createLocalClone(robotStateComponentPrx);
193 }
194 catch (...)
195 {
197 << "Exception while creating local clone of robot in onConnectPointCLoudProcessor()";
199 }
200
201 // Setup periodic tasks
202 taskEEFManipulation = new PeriodicTask<HandEyeCalibrationWidgetController>(
203 this, &HandEyeCalibrationWidgetController::taskEEFManipulationCB, 30.0f);
204 taskLocalRobotUpdate = new PeriodicTask<HandEyeCalibrationWidgetController>(
205 this, &HandEyeCalibrationWidgetController::taskLocalRobotUpdateCB, 50.0f);
206
207 // Setup visualizations
208 QMetaObject::invokeMethod(this, "connectQt", Qt::BlockingQueuedConnection);
209
210 // Finally connecting the signals and slots
211 connect(this, SIGNAL(pointCloudUpdated()), this, SLOT(processPointCloud()));
212 connect(widget.comboBox_endEffectorSelection,
213 SIGNAL(currentIndexChanged(QString)),
214 this,
215 SLOT(activeEndEffectorChanged(QString)));
216 connect(widget.horizontalSlider_croppingBox,
217 SIGNAL(valueChanged(int)),
218 this,
219 SLOT(slider_croppingRange_changed(int)));
220 connect(widget.checkBox_croppingActive,
221 SIGNAL(stateChanged(int)),
222 this,
223 SLOT(cb_croppingActive_changed(int)));
224
225 connect(widget.checkBox_offsetInverted,
226 SIGNAL(toggled(bool)),
227 this,
228 SLOT(cb_inverted_changed(bool)));
229 connect(widget.pushButton_copyToClipboard,
230 SIGNAL(clicked()),
231 this,
232 SLOT(btn_copyToClipboard_pressed()));
233 connect(widget.pushButton_resetEndeffector,
234 SIGNAL(clicked()),
235 this,
236 SLOT(btn_resetToModel_pressed()));
237
238 connect(widget.doubleSpinBox_camera_x,
239 SIGNAL(valueChanged(double)),
240 this,
241 SLOT(cameraNodeTransformationChanged(double)));
242 connect(widget.doubleSpinBox_camera_y,
243 SIGNAL(valueChanged(double)),
244 this,
245 SLOT(cameraNodeTransformationChanged(double)));
246 connect(widget.doubleSpinBox_camera_z,
247 SIGNAL(valueChanged(double)),
248 this,
249 SLOT(cameraNodeTransformationChanged(double)));
250 connect(widget.doubleSpinBox_camera_roll,
251 SIGNAL(valueChanged(double)),
252 this,
253 SLOT(cameraNodeTransformationChanged(double)));
254 connect(widget.doubleSpinBox_camera_pitch,
255 SIGNAL(valueChanged(double)),
256 this,
257 SLOT(cameraNodeTransformationChanged(double)));
258 connect(widget.doubleSpinBox_camera_yaw,
259 SIGNAL(valueChanged(double)),
260 this,
261 SLOT(cameraNodeTransformationChanged(double)));
262
263 connect(widget.pushButton_backgroundColor,
264 SIGNAL(clicked()),
265 this,
266 SLOT(btn_backgroundColor_pressed()));
267 connect(widget.pushButton_pointcloudColor,
268 SIGNAL(clicked()),
269 this,
270 SLOT(btn_pointCloudColor_pressed()));
271 connect(
272 widget.spinBox_pointSize, SIGNAL(valueChanged(int)), this, SLOT(sB_pointSize_changed(int)));
273
274 connect(widget.pushButton_changeFile, SIGNAL(clicked()), this, SLOT(selectFile()));
275 connect(widget.pushButton_saveDatapoint, SIGNAL(clicked()), this, SLOT(saveDatapoint()));
276
277 taskEEFManipulation->start();
278 taskLocalRobotUpdate->start();
280}
281
282void
283HandEyeCalibrationWidgetController::connectQt()
284{
285 pointCloudVisu = new PointCloudVisualization();
286 widget.displayWidget->getDisplay()->getRootNode()->addChild(pointCloudVisu);
287
288 manipulatorVisu = new ManipulatorVisualization();
289 widget.displayWidget->getDisplay()->getRootNode()->addChild((SoNode*)manipulatorVisu);
290
291 widget.displayWidget->getDisplay()->cameraViewAll();
292
293 if (manipulatorVisu)
294 {
295 setupEndEffectorSelection(localRobot);
296 }
297 else
298 {
299 ARMARX_WARNING << "ManipulatorVisu not present";
300 }
301 setupCameraNodeSlider(pointcloudRobot);
302 disableGuiElements();
303}
304
305void
307{
308 ARMARX_INFO << "onDisconnectPointCloudProcessor";
309
310 taskEEFManipulation->stop();
311 taskLocalRobotUpdate->stop();
312
313 releasePointCloudProvider(providerName);
314 QMetaObject::invokeMethod(this, "disconnectQt");
315
316 localRobot.reset();
317 pointcloudRobot.reset();
318 activeEndEffector.reset();
319 providerBuffer.reset();
320}
321
322void
323HandEyeCalibrationWidgetController::disconnectQt()
324{
325 disableGuiElements();
326
327 widget.comboBox_endEffectorSelection->clear();
328 manipulatorVisu->removeVisualization();
329 pointCloudVisu->removeAllChildren();
330 widget.displayWidget->getDisplay()->getRootNode()->removeAllChildren();
331
332 // disconnect signals that would interfere with the gui setup
333 QObject::disconnect(widget.comboBox_endEffectorSelection, 0, 0, 0);
334}
335
336void
341
342void
343HandEyeCalibrationWidgetController::setupEndEffectorSelection(VirtualRobot::RobotPtr robot)
344{
345 try
346 {
347 armarx::RemoteRobot::synchronizeLocalClone(robot, robotStateComponentPrx);
348 }
349 catch (...)
350 {
352 }
353
354 std::vector<VirtualRobot::EndEffectorPtr> endEffectors;
355 robot->getEndEffectors(endEffectors);
356 for (VirtualRobot::EndEffectorPtr e : endEffectors)
357 {
358 widget.comboBox_endEffectorSelection->addItem(QString::fromStdString(e->getName()));
359 VirtualRobot::RobotPtr r = e->createEefRobot(e->getName(), e->getName());
360 r->setGlobalPoseForRobotNode(r->getRobotNode(e->getTcp()->getName()),
361 e->getTcp()->getGlobalPose());
362 robotEEFMap.insert(
363 std::make_pair(e->getName(), std::make_pair(r, Eigen::Matrix4f::Identity())));
364 }
365 widget.comboBox_endEffectorSelection->setCurrentIndex(-1);
366}
367
368bool
369HandEyeCalibrationWidgetController::findStringIC(const std::string& strHaystack,
370 const std::string& strNeedle) const
371{
372 auto it =
373 std::search(strHaystack.begin(),
374 strHaystack.end(),
375 strNeedle.begin(),
376 strNeedle.end(),
377 [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); });
378 return (it != strHaystack.end());
379}
380
381void
382HandEyeCalibrationWidgetController::setupCameraNodeSlider(VirtualRobot::RobotPtr robot)
383{
384 if (robot)
385 {
386 ARMARX_CHECK_EXPRESSION(robot->hasRobotNode(referenceFrame))
387 << "Robot " + robot->getName() + " does not have node with name " + referenceFrame;
388 widget.label_cameraNodeName->setText(QString::fromStdString((referenceFrame)));
389
390 cameraNode = robot->getRobotNode(referenceFrame);
391 auto trans = VirtualRobot::MathTools::eigen4f2posrpy(cameraNode->getLocalTransformation());
392
393 widget.doubleSpinBox_camera_x->setValue(trans(0));
394 widget.doubleSpinBox_camera_y->setValue(trans(1));
395 widget.doubleSpinBox_camera_z->setValue(trans(2));
396 widget.doubleSpinBox_camera_roll->setValue(VirtualRobot::MathTools::rad2deg(trans(3)));
397 widget.doubleSpinBox_camera_pitch->setValue(VirtualRobot::MathTools::rad2deg(trans(4)));
398 widget.doubleSpinBox_camera_yaw->setValue(VirtualRobot::MathTools::rad2deg(trans(5)));
399 }
400}
401
403HandEyeCalibrationWidgetController::loadRobotFromFile() const
404{
405 Ice::StringSeq includePaths;
406
407 try
408 {
409 Ice::StringSeq packages = robotStateComponentPrx->getArmarXPackages();
410 packages.push_back(Application::GetProjectName());
411
412 for (const std::string& projectName : packages)
413 {
414 if (projectName.empty())
415 {
416 continue;
417 }
418
419 CMakePackageFinder project(projectName);
420 auto pathsString = project.getDataDir();
421 Ice::StringSeq projectIncludePaths = armarx::Split(pathsString, ";,", true, true);
422 includePaths.insert(
423 includePaths.end(), projectIncludePaths.begin(), projectIncludePaths.end());
424 }
425 }
426 catch (...)
427 {
428 ARMARX_ERROR << "Unable to retrieve robot filename." << std::endl;
429 return VirtualRobot::RobotPtr();
430 }
431
432 try
433 {
434 std::string rfile = robotStateComponentPrx->getRobotFilename();
435 ArmarXDataPath::getAbsolutePath(rfile, rfile, includePaths);
436 return VirtualRobot::RobotIO::loadRobot(rfile);
437 }
438 catch (...)
439 {
440 ARMARX_ERROR << "Unable to load robot from file" << std::endl;
441 return VirtualRobot::RobotPtr();
442 }
443}
444
445std::string
446HandEyeCalibrationWidgetController::getProviderFrame() const
447{
448 std::string frame = "Global";
449 try
450 {
451 visionx::ReferenceFrameInterfacePrx refFramePrx =
452 visionx::ReferenceFrameInterfacePrx::checkedCast(providerInfo.proxy);
453 if (refFramePrx)
454 {
455 frame = refFramePrx->getReferenceFrame();
456 }
457 }
458 catch (...)
459 {
461 }
462 return frame;
463}
464
465std::string
466HandEyeCalibrationWidgetController::formatTransformationMatrix(Eigen::Matrix4f mat,
467 int decimalPlacesOrientation,
468 int decimalPlacesPosition) const
469{
470 std::stringstream ss;
471 ss.imbue(std::locale::classic());
472 ss << std::fixed;
473
474 // The first three rows behave the same
475 for (int i = 0; i < 3; i++)
476 {
477 float x0 = mat(i, 0);
478 float x1 = mat(i, 1);
479 float x2 = mat(i, 2);
480 ss << std::setprecision(decimalPlacesOrientation);
481 if (!std::signbit(x0))
482 {
483 ss << " ";
484 }
485 ss << x0 << " ";
486 if (!std::signbit(x1))
487 {
488 ss << " ";
489 }
490 ss << x1 << " ";
491 if (!std::signbit(x2))
492 {
493 ss << " ";
494 }
495 ss << x2 << " ";
496
497 ss << std::setprecision(decimalPlacesPosition);
498 if (!std::signbit(mat(i, 3)))
499 {
500 ss << " ";
501 }
502 ss << mat(i, 3);
503 ss << std::endl;
504 }
505 return ss.str();
506}
507
508void
509HandEyeCalibrationWidgetController::enableGuiElements()
510{
511 widget.horizontalSlider_croppingBox->setEnabled(true);
512 widget.horizontalSlider_x->setEnabled(true);
513 widget.horizontalSlider_y->setEnabled(true);
514 widget.horizontalSlider_z->setEnabled(true);
515 widget.checkBox_croppingActive->setEnabled(true);
516 widget.checkBox_offsetInverted->setEnabled(true);
517 widget.pushButton_copyToClipboard->setEnabled(true);
518 widget.pushButton_resetEndeffector->setEnabled(true);
519 widget.pushButton_pointcloudColor->setEnabled(true);
520 widget.pushButton_backgroundColor->setEnabled(true);
521 widget.spinBox_pointSize->setEnabled(true);
522 widget.pushButton_changeFile->setEnabled(true);
523 widget.pushButton_saveDatapoint->setEnabled(true);
524 widget.lineEdit_file->setEnabled(true);
525
526 widget.doubleSpinBox_camera_x->setEnabled(true);
527 widget.doubleSpinBox_camera_y->setEnabled(true);
528 widget.doubleSpinBox_camera_z->setEnabled(true);
529 widget.doubleSpinBox_camera_roll->setEnabled(true);
530 widget.doubleSpinBox_camera_pitch->setEnabled(true);
531 widget.doubleSpinBox_camera_yaw->setEnabled(true);
532
533 widget.label_offsetMatrix->setText(QString("No Endeffector selected"));
534 widget.label_offsetMatrix->setStyleSheet("QLabel { color : black; }");
535
536 showPointCloud = true;
537}
538
539void
540HandEyeCalibrationWidgetController::disableGuiElements()
541{
542 widget.horizontalSlider_croppingBox->setEnabled(false);
543 widget.horizontalSlider_x->setEnabled(false);
544 widget.horizontalSlider_y->setEnabled(false);
545 widget.horizontalSlider_z->setEnabled(false);
546 widget.checkBox_croppingActive->setEnabled(false);
547 widget.checkBox_offsetInverted->setEnabled(false);
548 widget.pushButton_copyToClipboard->setEnabled(false);
549 widget.pushButton_resetEndeffector->setEnabled(false);
550 widget.pushButton_pointcloudColor->setEnabled(false);
551 widget.pushButton_backgroundColor->setEnabled(false);
552 widget.spinBox_pointSize->setEnabled(false);
553 widget.pushButton_changeFile->setEnabled(false);
554 widget.pushButton_saveDatapoint->setEnabled(false);
555 widget.lineEdit_file->setEnabled(false);
556
557 widget.doubleSpinBox_camera_x->setEnabled(false);
558 widget.doubleSpinBox_camera_y->setEnabled(false);
559 widget.doubleSpinBox_camera_z->setEnabled(false);
560 widget.doubleSpinBox_camera_roll->setEnabled(false);
561 widget.doubleSpinBox_camera_pitch->setEnabled(false);
562 widget.doubleSpinBox_camera_yaw->setEnabled(false);
563
564 widget.label_offsetMatrix->setText(QString("No Endeffector selected"));
565 widget.label_offsetMatrix->setStyleSheet("QLabel { color : red; }");
566
567 showPointCloud = false;
568}
569
570void
571HandEyeCalibrationWidgetController::updateManipulatorVisualization()
572{
573 if (activeEndEffector && manipulatorVisu)
574 {
575 Eigen::Matrix4f modelPoseInRoot =
576 localRobot->getRobotNode(activeEndEffector->getTcp()->getName())->getPoseInRootFrame();
577 Eigen::Matrix4f offset = getOffsetMatrixForEEF(activeEndEffector);
578 // Apply offset in root frame (multiplication order matters!!)
579 Eigen::Matrix4f pointCloudInRoot = offset * modelPoseInRoot;
580 Eigen::Matrix4f pointCloudGlobal = localRobot->getGlobalPose() * pointCloudInRoot;
581
582 // Apply global pose to manipulator visu
583 manipulatorVisu->setUserDesiredPose(pointCloudGlobal);
584
585 // Update the local eefRobot
586 getEEFRobot(activeEndEffector)
587 ->setGlobalPoseForRobotNode(activeEndEffector->getTcp(), pointCloudGlobal);
588
589 // Update Matrix label
590 if (widget.checkBox_offsetInverted->isChecked())
591 {
592 offset = offset.inverse();
593 }
594 widget.label_offsetMatrix->setText(
595 QString::fromStdString(formatTransformationMatrix(offset)));
596 }
597}
598
599void
601{
602 if (!waitForPointClouds(providerName, 500))
603 {
604 ARMARX_WARNING << "Timeout or error in waiting for pointclouds from provider: "
605 << providerName;
606 }
607 else
608 {
609 getPointClouds(providerName, providerBuffer);
610
611 emit pointCloudUpdated();
612 }
613}
614
615void
616HandEyeCalibrationWidgetController::processPointCloud()
617{
618 if (showPointCloud && pointcloudRobot)
619 {
620 // Copy buffer to be able to edit it
621 pcl::PointCloud<PointT>::Ptr localBufferIn(new pcl::PointCloud<PointT>());
622 pcl::copyPointCloud(*providerBuffer, *localBufferIn);
623 pcl::PointCloud<PointT>::Ptr localBufferOut(new pcl::PointCloud<PointT>());
624
625 Eigen::Matrix4f sourceFrameGlobalPose = Eigen::Matrix4f::Identity();
626 if (referenceFrame != "Global")
627 {
628 visionx::MetaPointCloudFormatPtr info = this->getPointCloudFormat(providerName);
629
630 try
631 {
633 pointcloudRobot, robotStateComponentPrx, info->timeProvided);
634 }
635 catch (...)
636 {
637 ARMARX_ERROR << "Exception while synchronizing robot for pointcloud-processing";
639 }
640
641 sourceFrameGlobalPose = pointcloudRobot->getRobotNode(referenceFrame)->getGlobalPose();
642 }
643 Eigen::Matrix4f cameraToGlobal = sourceFrameGlobalPose;
644
645 // Crop pointcloud around endeffector
646 if (croppingActive && manipulatorVisu && manipulatorVisu->getIsVisualizing())
647 {
648 Eigen::Matrix4f eefGlobal = manipulatorVisu->getUserDesiredPose();
649 Eigen::Matrix4f eefInReferenceFrame = sourceFrameGlobalPose.inverse() * eefGlobal;
650
651 float cropRange = (float)widget.horizontalSlider_croppingBox->value();
652
653 Eigen::Vector3f cropMin;
654 cropMin << eefInReferenceFrame(0, 3) - cropRange, eefInReferenceFrame(1, 3) - cropRange,
655 eefInReferenceFrame(2, 3) - cropRange;
656 Eigen::Vector3f cropMax;
657 cropMax << eefInReferenceFrame(0, 3) + cropRange, eefInReferenceFrame(1, 3) + cropRange,
658 eefInReferenceFrame(2, 3) + cropRange;
659
660 pcl::PassThrough<PointT> pass;
661
662 pass.setInputCloud(localBufferIn);
663 pass.setFilterFieldName("z");
664 pass.setFilterLimits(cropMin(2), cropMax(2));
665 pass.filter(*localBufferOut);
666 localBufferOut.swap(localBufferIn);
667
668 pass.setInputCloud(localBufferIn);
669 pass.setFilterFieldName("x");
670 pass.setFilterLimits(cropMin(0), cropMax(0));
671 pass.filter(*localBufferOut);
672 localBufferOut.swap(localBufferIn);
673
674 pass.setInputCloud(localBufferIn);
675 pass.setFilterFieldName("y");
676 pass.setFilterLimits(cropMin(1), cropMax(1));
677 pass.filter(*localBufferOut);
678 localBufferOut.swap(localBufferIn);
679 }
680
681
682 // Transform pointcloud into GlobalFrame
683 pcl::transformPointCloud(*localBufferIn, *localBufferOut, cameraToGlobal);
684 localBufferOut.swap(localBufferIn);
685
686 if (pointCloudVisu)
687 {
688 pointCloudVisu->setVisualization(localBufferIn);
689 }
690 }
691}
692
693void
694HandEyeCalibrationWidgetController::cb_inverted_changed(bool checked)
695{
696 if (checked)
697 {
698 widget.label_titleOffsetMatrix->setText("Offset from Pointcloud to Model:");
699 }
700 else
701 {
702 widget.label_titleOffsetMatrix->setText("Offset from Model to Pointcloud:");
703 }
704}
705
706void
707HandEyeCalibrationWidgetController::btn_copyToClipboard_pressed()
708{
709 if (activeEndEffector)
710 {
711 Eigen::Matrix4f offset = this->getOffsetMatrixForEEF(activeEndEffector);
712
713 if (widget.checkBox_offsetInverted->isChecked())
714 {
715 offset = offset.inverse();
716 }
717
718 PosePtr pose = new Pose(offset);
719
720 JSONObjectPtr obj = new JSONObject();
721 obj->serializeIceObject(pose);
722
723 QClipboard* clipboard = QApplication::clipboard();
724 clipboard->setText(QString::fromStdString(obj->asString(true)));
725 }
726}
727
728void
729HandEyeCalibrationWidgetController::btn_resetToModel_pressed()
730{
731 if (activeEndEffector)
732 {
733 setOffsetMatrixForEEF(activeEndEffector, Eigen::Matrix4f::Identity());
734 updateManipulatorVisualization();
735 widget.displayWidget->getDisplay()->cameraViewNode((SoNode*)manipulatorVisu, 1.0);
736 }
737}
738
739void
740HandEyeCalibrationWidgetController::btn_backgroundColor_pressed()
741{
742 QColor selectedColor = this->colorDialog.getColor();
743 widget.displayWidget->getDisplay()->setBackgroundColor(SbColor(selectedColor.red() / 255.0f,
744 selectedColor.green() / 255.0f,
745 selectedColor.blue() / 255.0f));
746}
747
748void
749HandEyeCalibrationWidgetController::btn_pointCloudColor_pressed()
750{
751 QColor selectedColor = this->colorDialog.getColor();
752 this->pointCloudVisu->setDrawColor(SbColor(selectedColor.red() / 255.0f,
753 selectedColor.green() / 255.0f,
754 selectedColor.blue() / 255.0f));
755}
756
757void
758HandEyeCalibrationWidgetController::sB_pointSize_changed(int value)
759{
760 this->pointCloudVisu->setPointSize(value);
761}
762
763void
764HandEyeCalibrationWidgetController::cameraNodeTransformationChanged(double value)
765{
766 if (cameraNode)
767 {
768 auto t = VirtualRobot::MathTools::eigen4f2posrpy(cameraNode->getLocalTransformation());
769 QObject* obj = sender();
770 if (obj == widget.doubleSpinBox_camera_x)
771 {
772 t(0) = (float)value;
773 }
774 else if (obj == widget.doubleSpinBox_camera_y)
775 {
776 t(1) = (float)value;
777 }
778 else if (obj == widget.doubleSpinBox_camera_z)
779 {
780 t(2) = (float)value;
781 }
782 else if (obj == widget.doubleSpinBox_camera_roll)
783 {
784 t(3) = VirtualRobot::MathTools::deg2rad((float)value);
785 }
786 else if (obj == widget.doubleSpinBox_camera_pitch)
787 {
788 t(4) = VirtualRobot::MathTools::deg2rad((float)value);
789 }
790 else if (obj == widget.doubleSpinBox_camera_yaw)
791 {
792 t(5) = VirtualRobot::MathTools::deg2rad((float)value);
793 }
794 Eigen::Matrix4f transformation =
795 VirtualRobot::MathTools::posrpy2eigen4f(t(0), t(1), t(2), t(3), t(4), t(5));
796 cameraNode->setLocalTransformation(transformation);
797 }
798}
799
800void
801HandEyeCalibrationWidgetController::taskEEFManipulationCB()
802{
803 float x[3];
804 x[0] = (float)widget.horizontalSlider_x->value();
805 x[1] = (float)widget.horizontalSlider_y->value();
806 x[2] = (float)widget.horizontalSlider_z->value();
807 if (activeEndEffector)
808 {
809 Eigen::Matrix4f offsetInRoot = Eigen::Matrix4f::Identity();
810 offsetInRoot(0, 3) = x[0];
811 offsetInRoot(1, 3) = x[1];
812 offsetInRoot(2, 3) = x[2];
813
814 setOffsetMatrixForEEF(activeEndEffector, offsetInRoot);
815 }
816}
817
818void
819HandEyeCalibrationWidgetController::taskLocalRobotUpdateCB()
820{
821 if (!robotStateComponentPrx)
822 {
823 return;
824 }
825 try
826 {
827 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponentPrx);
828 updateManipulatorVisualization();
829 }
830 catch (...)
831 {
832 }
833}
834
835void
836HandEyeCalibrationWidgetController::activeEndEffectorChanged(QString endEffectorName)
837{
838 if (localRobot && manipulatorVisu)
839 {
840 std::string eefName = endEffectorName.toStdString();
841 if (!eefName.empty())
842 {
843 if (robotEEFMap.count(eefName) == 1)
844 {
845 activeEndEffector = robotEEFMap.at(eefName).first->getEndEffector(eefName);
846 manipulatorVisu->setVisualization(activeEndEffector);
847 widget.displayWidget->getDisplay()->cameraViewNode((SoNode*)manipulatorVisu, 1.0);
848 enableGuiElements();
849 }
850 else
851 {
852 ARMARX_ERROR << "Robot " << localRobot->getName()
853 << " does not have endeffector with name " << eefName;
854 }
855 }
856 }
857}
858
859void
860HandEyeCalibrationWidgetController::slider_croppingRange_changed(int value)
861{
862 this->widget.label_croppingBoxValue->setText(QString::fromStdString(ValueToString(value)));
863}
864
865void
866HandEyeCalibrationWidgetController::cb_croppingActive_changed(int state)
867{
868 if (state == Qt::Unchecked)
869 {
870 this->croppingActive = true;
871 }
872 else
873 {
874 this->croppingActive = false;
875 }
876}
#define float
Definition 16_Level.h:22
const QString defaultFileName("HandEyeCalib_Data.json")
static const std::string & GetProjectName()
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
void enableMainWidgetAsync(bool enable)
This function enables/disables the main widget asynchronously (if called from a non qt thread).
virtual ~HandEyeCalibrationWidgetController()
Controller destructor.
HandEyeCalibrationWidgetController()
Controller Constructor.
void process() override
Process the vision component.
void onExitPointCloudProcessor() override
Exit the ImapeProcessor component.
QPointer< QDialog > getConfigDialog(QWidget *parent=0) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
void onConnectPointCloudProcessor() override
Implement this method in the PointCloudProcessor in order execute parts when the component is fully i...
void configured() override
This function must be implemented by the user, if he supplies a config dialog.
void onDisconnectPointCloudProcessor() override
Implement this method in the PointCloudProcessor in order execute parts when the component looses net...
void onInitPointCloudProcessor() override
Setup the vision component.
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
VirtualRobot::RobotPtr createLocalClone()
Clones the structure of this remote robot to a local instance.
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
static bool synchronizeLocalCloneToTimestamp(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx, Ice::Long timestamp)
Synchronizes a local robot to a robot state at timestamp.
A config-dialog containing one (or multiple) proxy finders.
void AddMatrix(const std::string &key, const Eigen::MatrixXf &mat)
void Add(const std::string &key, const std::string &value)
void releasePointCloudProvider(std::string providerName)
Removes topic subscription and provider proxy dependency to release a point cloud provider.
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
MetaPointCloudFormatPtr getPointCloudFormat(std::string providerName)
void usingPointCloudProvider(std::string providerName)
Registers a delayed topic subscription and a delayed provider proxy retrieval which will be available...
PointCloudProviderInfo getPointCloudProvider(std::string name, bool waitForProxy=false)
Select an PointCloudProvider.
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
#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_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
Eigen::Isometry3f Pose
Definition basic_types.h:31
void project(pcl::PointCloud< pcl::PointXYZ > &cloud, wykobi::Polygon polygon)
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceInternal::Handle< Pose > PosePtr
Definition Pose.h:306
IceInternal::Handle< JSONObject > JSONObjectPtr
Definition JSONObject.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::RobotStateComponentInterface > RobotStateComponentInterfacePrx
std::string ValueToString(const T &value)