DHParameterOptimizationLogger.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::ArmarXObjects::DHParameterOptimizationLogger
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 <ctime>
26#include <iomanip>
27
28#include <Eigen/Geometry>
29
30#include <VirtualRobot/Nodes/Sensor.h>
31#include <VirtualRobot/RobotNodeSet.h>
32
37
39
40using namespace armarx;
41
42namespace fs = std::filesystem;
43
44void
46{
47 std::vector<float> data;
48 if (_logRepeatAccuracy)
49 {
50 data.push_back(-1.0f);
51 data.push_back(-1.0f);
52 }
54 if (!data.empty())
55 {
56 CsvWriter writer(_filePath, std::vector<std::string>(), true);
57 writer.write(data);
58 writer.close();
59 }
60
61 ARMARX_DEBUG << "Logging data finished";
62}
63
64void
66{
67 if (!_logRepeatAccuracy)
68 {
69 ARMARX_WARNING << "Loging of repeatAccuracy is not activated!";
70 return;
71 }
72
73 std::vector<float> data;
74 // placeholder for error of repeat accuracy
75 data.push_back(0.0f);
76 data.push_back(0.0f);
78 std::pair<float, float> repeatErrors;
79 repeatErrors = calculateRepeatError();
80 data[0] = repeatErrors.first;
81 data[1] = repeatErrors.second;
82
83 if (data.size() > 2)
84 {
85 CsvWriter writer(_filePath, std::vector<std::string>(), true);
86 writer.write(data);
87 writer.close();
88 }
89
90 ARMARX_DEBUG << "Logging data with repeat accuracy finished";
91}
92
93void
95{
96 _viconLoggingActive = true;
97}
98
99void
101{
102 _viconLoggingActive = false;
103}
104
105void
106DHParameterOptimizationLogger::init(const std::string& kinematicChainName,
107 const std::map<std::string, std::string>& neckMarkerMapping,
108 const std::map<std::string, std::string>& handMarkerMapping,
109 const std::string& loggingFileName,
110 bool logRepeatAccuracy,
111 const Ice::Current&)
112{
113 ARMARX_CHECK_EXPRESSION(!neckMarkerMapping.empty());
114 ARMARX_CHECK_EXPRESSION(!handMarkerMapping.empty());
115 ARMARX_CHECK_EXPRESSION(!kinematicChainName.empty());
116
117 _neckMarkerMapping = neckMarkerMapping;
118 _handMarkerMapping = handMarkerMapping;
119
120 _neckMarker.clear();
121 _handMarker.clear();
122
123 for (auto& pair : neckMarkerMapping)
124 {
125 _neckMarker.push_back(pair.first);
126 }
127 for (auto& pair : handMarkerMapping)
128 {
129 _handMarker.push_back(pair.first);
130 }
131 for (auto& s : _neckMarker)
132 {
133 if (std::find(_handMarker.begin(), _handMarker.end(), s) != _handMarker.end())
134 {
135 ARMARX_ERROR << "HandMarker and NeckMarker can not contain the same marker!! Abort.";
136 return;
137 }
138 }
139 std::vector<VirtualRobot::SensorPtr> sensors = localRobot->getSensors();
140 for (auto& pair : neckMarkerMapping)
141 {
142 auto& i = pair.second;
143 ARMARX_CHECK_EXPRESSION(std::find_if(sensors.begin(),
144 sensors.end(),
145 [i](VirtualRobot::SensorPtr s)
146 { return s->getName() == i; }) != sensors.end())
147 << "Robot does not have a sensor with name '" + i + "'";
148 }
149 for (auto& pair : handMarkerMapping)
150 {
151 auto& i = pair.second;
152 ARMARX_CHECK_EXPRESSION(std::find_if(sensors.begin(),
153 sensors.end(),
154 [i](VirtualRobot::SensorPtr s)
155 { return s->getName() == i; }) != sensors.end())
156 << "Robot does not have a sensor with name '" + i + "'";
157 }
158
159 _kcName = kinematicChainName;
160 ARMARX_CHECK_EXPRESSION(localRobot->hasRobotNodeSet(_kcName))
161 << "Robot " + localRobot->getName() + " does not have a kinematic chain with name " +
162 _kcName;
163 _kc = localRobot->getRobotNodeSet(_kcName);
164 _jointNames = _kc->getNodeNames();
165 _logRepeatAccuracy = logRepeatAccuracy;
166
167 setupFile(loggingFileName);
168 setupHeader();
169 ARMARX_INFO << VAROUT(_header);
170 CsvWriter writer(_filePath, _header, true);
171 writer.close();
172
173 _initialized = true;
174}
175
176void
178 const Ice::Current&)
179{
180 // Format of received data: ObjectName:MarkerName x y z
181
182 StringVector3fMap copyMap;
183 for (auto& it : markerPosMap)
184 {
185 std::string key = it.first;
186 int i = key.find(':') + 1;
187 copyMap[key.erase(0, i)] = it.second;
188 Vector3f v = it.second;
189 // ARMARX_INFO << it.first << " " << v.e0 << " " << v.e1 << " " << v.e2;
190 debugObserverPrx->setDebugDatafield(
191 "DHParameterOptimization", it.first + "_x", new Variant(v.e0));
192 debugObserverPrx->setDebugDatafield(
193 "DHParameterOptimization", it.first + "_y", new Variant(v.e1));
194 debugObserverPrx->setDebugDatafield(
195 "DHParameterOptimization", it.first + "_z", new Variant(v.e2));
196 }
197
198 if (_viconLoggingActive)
199 {
200 std::unique_lock lock(_bufferMutex);
201 _viconMarkerBuffer = copyMap;
202 _timeStampLastViconDataUpdate = TimeUtil::GetTime();
203 _viconBufferUpdated = true;
204 }
205}
206
207void
209 const Ice::Current&)
210{
211 // Not needed
212}
213
214void
215DHParameterOptimizationLogger::setupFile(const std::string& fileName)
216{
217 std::string localFileName = fileName;
218 using namespace std::filesystem;
219
220 auto timeToString = []()
221 {
222 std::time_t now = std::time(nullptr);
223 std::tm* nowTm = std::localtime(&now);
224
225 std::stringstream ss;
226 ss << std::put_time(nowTm, "%Y%m%d_%H%M%S");
227 return ss.str();
228 };
229
230 // Setup logging file
231 if (ends_with(localFileName, ".csv"))
232 {
233 localFileName = localFileName.substr(0, localFileName.size() - 4);
234 }
235 localFileName += "_";
236 localFileName += timeToString();
237 localFileName += ".csv";
238
239 std::string pathOrig = getProperty<std::string>("LoggingFilePath").getValue();
240 if (!pathOrig.empty() && pathOrig[0] == '~')
241 {
242 ARMARX_CHECK_EXPRESSION(pathOrig.size() == 1 || pathOrig[1] == '/')
243 << "LoggingFilePath isviconValues not valid: '~' has to be followed by ’/’";
244 char const* home = std::getenv("HOME");
245 ARMARX_CHECK_EXPRESSION(home) << "HOME environment variable is not set!";
246 pathOrig.replace(0, 1, home);
247 }
248 fs::path filePath(pathOrig);
249 if (!fs::exists(filePath))
250 {
251 fs::create_directory(filePath);
252 }
253 filePath /= path(localFileName);
254 _filePath = filePath.string();
255}
256
257void
259{
260 usingTopic(getProperty<std::string>("ViconDataTopicName").getValue());
261 usingProxy(getProperty<std::string>("RobotStateComponentName").getValue());
262 usingProxy(getProperty<std::string>("RobotUnitObserverName").getValue());
263
264 _initialized = false;
265
266 int size = getProperty<int>("FilterWindowSize").getValue();
267 ARMARX_CHECK_EXPRESSION(size > 0);
268 _filterSize = size;
269
270 _viconObjectName_neck = getProperty<std::string>("Neck_ViconObjectName").getValue();
271 _viconObjectName_hand = getProperty<std::string>("Hand_ViconObjectName").getValue();
272}
273
274void
276{
277 getProxy(robotStateComponent, getProperty<std::string>("RobotStateComponentName").getValue());
278 getProxy(robotUnitObserver, getProperty<std::string>("RobotUnitObserverName").getValue());
279 _viconLoggingActive = true;
280
281 debugObserverPrx = getTopic<DebugObserverInterfacePrx>(
282 getProperty<std::string>("DebugObserverTopicName").getValue());
283 debugDrawerPrx = getTopic<DebugDrawerInterfacePrx>("DebugDrawerUpdates");
284
285
287 robotStateComponent, VirtualRobot::RobotIO::RobotDescription::eStructure);
288
289 std::vector<VirtualRobot::SensorPtr> s = localRobot->getSensors();
290 for (auto& sp : s)
291 {
292 ARMARX_INFO << sp->getName();
293 }
294}
295
296void
298{
299 _viconLoggingActive = false;
300}
301
302void
306
313
314void
315DHParameterOptimizationLogger::setupHeader()
316{
317 std::vector<std::string> header;
318
319 // order is important!! do not change without adapting the order of logging calls in logData(std::vector<std::string> &data) !!
320
321 // Accuracy columns
322 if (_logRepeatAccuracy)
323 {
324 header.push_back("Error_Translation");
325 header.push_back("Error_Orientation");
326 }
327
328 // ViconMarker columns neck --> 12
329 for (auto& m : _neckMarker)
330 {
331 header.push_back(m + "_x");
332 header.push_back(m + "_y");
333 header.push_back(m + "_z");
334 }
335
336 // ViconMarker columns hand --> 12
337 for (auto& m : _handMarker)
338 {
339 header.push_back(m + "_x");
340 header.push_back(m + "_y");
341 header.push_back(m + "_z");
342 }
343
344 // JointValues --> ~8
345 for (auto& node : _jointNames)
346 {
347 header.push_back("JointValue_" + node);
348 }
349 header.push_back("JointValue_TorsoJoint");
350
351 // ForwardKinematic to vicon marker --> 12
352 for (auto& m : _handMarker)
353 {
354 header.push_back("FK_" + m + "_x");
355 header.push_back("FK_" + m + "_y");
356 header.push_back("FK_" + m + "_z");
357 }
358
359 // Error between model and vicon data --> 2
360 header.push_back("Error_translation");
361 header.push_back("Error_orientation");
362
363 // Raw torque ticks --> ~8
364 for (auto& node : _jointNames)
365 {
366 header.push_back(node + "_torqueTicks");
367 }
368
369 // TorqueValues --> ~8
370 for (auto& node : _jointNames)
371 {
372 header.push_back(node + "_torque");
373 }
374
375 // FT Sensor torque --> 3
376 if (_kc->getTCP()->getName() == "Hand R TCP")
377 {
378 header.push_back("FT R_FT_torque_x");
379 header.push_back("FT R_FT_torque_y");
380 header.push_back("FT R_FT_torque_z");
381 }
382 else if (_kc->getTCP()->getName() == "Hand L TCP")
383 {
384 header.push_back("FT L_FT_torque_x");
385 header.push_back("FT L_FT_torque_y");
386 header.push_back("FT L_FT_torque_z");
387 }
388
389 _header = header;
390}
391
392void
394{
395 // order is important!! do not change without adapting the order of setting up the header in setupHeader() !!
396 logViconMarkerPositions(data);
397 logJointValues(data);
398 logForwardKinematicToViconMarker(data);
399 logErrorBetweenModelAndVicon(data);
400 logRawTorqueTicks(data);
401 logTorqueValues(data);
402 logFTSensorValues(data);
403}
404
405void
406DHParameterOptimizationLogger::logViconMarkerPositions(std::vector<float>& data)
407{
408 ARMARX_DEBUG << "Logging viconMarkerPositions";
409
410 if (!_viconLoggingActive)
411 {
412 ARMARX_DEBUG << deactivateSpam(1) << "ViconLogging not active";
413 size_t sum = 3 * (_neckMarker.size() + _handMarker.size());
414 for (size_t i = 0; i < sum; i++)
415 {
416 data.push_back(0.0f);
417 }
418 }
419 else
420 {
421 // blocking wait until all marker are visible --> no marker has 0 values, and enough data frames for filtering arrived
422 StringVector3fMap values = waitBlockingForAllMarkersFiltered();
423 if (values.empty())
424 {
425 size_t sum = 3 * (_neckMarker.size() + _handMarker.size());
426 for (size_t i = 0; i < sum; i++)
427 {
428 data.push_back(0.0f);
429 }
430 }
431 else
432 {
433 values = transformViconMarkerPositionsIntoRobotRootFrame(values);
434 for (auto& m : _neckMarker)
435 {
436 data.push_back(values.at(m).e0);
437 data.push_back(values.at(m).e1);
438 data.push_back(values.at(m).e2);
439 }
440 for (auto& m : _handMarker)
441 {
442 data.push_back(values.at(m).e0);
443 data.push_back(values.at(m).e1);
444 data.push_back(values.at(m).e2);
445 }
446
447 _filteredViconMarkerPositions_robotRootFrame = values;
448 _filteredViconMarkerPositionsUpdated = true;
449 }
450 }
451}
452
453void
454DHParameterOptimizationLogger::logJointValues(std::vector<float>& data) const
455{
456 ARMARX_DEBUG << "Logging jointValues";
457
458 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponent);
459 for (auto& node : _kc->getAllRobotNodes())
460 {
461 data.push_back(node->getJointValue());
462 }
463 data.push_back(localRobot->getRobotNode("TorsoJoint")->getJointValue());
464}
465
466void
467DHParameterOptimizationLogger::logForwardKinematicToViconMarker(std::vector<float>& data) const
468{
469 ARMARX_DEBUG << "Logging forwardKinematicToViconMarker";
470
471 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponent);
472 VirtualRobot::RobotNodePtr hand = getHandMarkerRootNode();
473
474 for (VirtualRobot::SensorPtr const& sensor : hand->getSensors())
475 {
476 Eigen::Matrix4f m = sensor->getTransformationFrom(localRobot->getRootNode());
477 data.push_back(m(0, 3)); // x
478 data.push_back(m(1, 3)); // y
479 data.push_back(m(2, 3)); // z
480 }
481}
482
483void
484DHParameterOptimizationLogger::logErrorBetweenModelAndVicon(std::vector<float>& data)
485{
486 ARMARX_DEBUG << "Logging errorBetweenModelAndVicon";
487
488 if (!_viconLoggingActive || !_filteredViconMarkerPositionsUpdated)
489 {
490 data.push_back(0.0f);
491 data.push_back(0.0f);
492 }
493 else
494 {
495 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponent);
496 VirtualRobot::RobotNodePtr neck = getNeckMarkerRootNode();
497 VirtualRobot::RobotNodePtr hand = getHandMarkerRootNode();
498 VirtualRobot::RobotNodePtr root = localRobot->getRootNode();
499
500 _lastObservedHandRootPose = _newObservedHandRootPose;
501
502 // Eigen::Matrix4f modelRelativePose = hand->getTransformationFrom(neck);
503
504 // Calculation of neck pose from vicon data
505 Eigen::MatrixXf observedNeckPositions_robotRootFrame(3, _neckMarker.size());
506 Eigen::MatrixXf modelNeckPositions_neckFrame(3, _neckMarker.size());
507
508
509 size_t i = 0;
510 for (auto& it : _neckMarker)
511 {
512 observedNeckPositions_robotRootFrame(0, i) =
513 _filteredViconMarkerPositions_robotRootFrame.at(it).e0;
514 observedNeckPositions_robotRootFrame(1, i) =
515 _filteredViconMarkerPositions_robotRootFrame.at(it).e1;
516 observedNeckPositions_robotRootFrame(2, i) =
517 _filteredViconMarkerPositions_robotRootFrame.at(it).e2;
518
519 modelNeckPositions_neckFrame(0, i) =
520 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(0, 3);
521 modelNeckPositions_neckFrame(1, i) =
522 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(1, 3);
523 modelNeckPositions_neckFrame(2, i) =
524 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(2, 3);
525
526 // visu
527 Eigen::Vector3f position =
528 (root->getGlobalPose() * observedNeckPositions_robotRootFrame).block<3, 1>(0, i);
529 debugDrawerPrx->setSphereVisu(
530 "markerVisu", it, new Vector3(position), DrawColor{0, 1, 1, 1}, 7);
531
532 i++;
533 }
534
535
536 // Calculation of hand pose from vicon data
537 Eigen::MatrixXf observedHandPositions_robotRootFrame(3, _handMarker.size());
538 Eigen::MatrixXf modelHandPositions_handFrame(3, _handMarker.size());
539
540
541 i = 0;
542 for (auto& it : _handMarker)
543 {
544 observedHandPositions_robotRootFrame(0, i) =
545 _filteredViconMarkerPositions_robotRootFrame.at(it).e0;
546 observedHandPositions_robotRootFrame(1, i) =
547 _filteredViconMarkerPositions_robotRootFrame.at(it).e1;
548 observedHandPositions_robotRootFrame(2, i) =
549 _filteredViconMarkerPositions_robotRootFrame.at(it).e2;
550
551 modelHandPositions_handFrame(0, i) =
552 hand->getSensor(_handMarkerMapping.at(it))->getTransformationFrom(hand)(0, 3);
553 modelHandPositions_handFrame(1, i) =
554 hand->getSensor(_handMarkerMapping.at(it))->getTransformationFrom(hand)(1, 3);
555 modelHandPositions_handFrame(2, i) =
556 hand->getSensor(_handMarkerMapping.at(it))->getTransformationFrom(hand)(2, 3);
557
558 // visu
559 Eigen::Vector3f position =
560 (root->getGlobalPose() * observedHandPositions_robotRootFrame).block<3, 1>(0, i);
561 debugDrawerPrx->setSphereVisu(
562 "markerVisu", it, new Vector3(position), DrawColor{0, 1, 0, 1}, 7);
563
564
565 i++;
566 }
567
568
569 ARMARX_DEBUG << VAROUT(modelHandPositions_handFrame)
570 << VAROUT(observedHandPositions_robotRootFrame);
571 Eigen::Matrix4f observedHandRootPose_robotRootFrame =
572 registration3d(modelHandPositions_handFrame.transpose(),
573 observedHandPositions_robotRootFrame.transpose());
574
575 _newObservedHandRootPose = observedHandRootPose_robotRootFrame;
576 _observedHandPosesUpdated = true;
577
578 debugDrawerPrx->setPoseVisu(
579 "MarkerVisu",
580 "observedTCP",
581 new Pose(root->getGlobalPose() * observedHandRootPose_robotRootFrame));
582 debugDrawerPrx->setPoseVisu("MarkerVisu", "kinematicTCP", new Pose(hand->getGlobalPose()));
583
584 // Eigen::Matrix4f viconRelativePose = observedNeckRootPose.inverse() * observedHandRootPose;
585 float errorPos = (hand->getPoseInRootFrame().block<3, 1>(0, 3) -
586 observedHandRootPose_robotRootFrame.block<3, 1>(0, 3))
587 .norm();
588 // Calculate error
589 // Eigen::Vector3f errorV = viconRelativePose.block<3, 1>(0, 3) - modelRelativePose.block<3, 1>(0, 3);
590 // float errorPos = errorV.norm();
591
592 Eigen::Matrix3f oriDir = hand->getPoseInRootFrame().block<3, 3>(0, 0) *
593 observedHandRootPose_robotRootFrame.block<3, 3>(0, 0).inverse();
594 Eigen::AngleAxisf aa(oriDir);
595 float errorOri = aa.angle();
596
597 ARMARX_INFO << "Error (Hand) in rootFrame between model and vicon ---- Position-Error: "
598 << errorPos << " mm, Orientation-Error: " << errorOri << " rad";
599
600 data.push_back(errorPos);
601 data.push_back(errorOri);
602
603 _filteredViconMarkerPositionsUpdated = false;
604 }
605}
606
607void
608DHParameterOptimizationLogger::logRawTorqueTicks(std::vector<float>& data) const
609{
610 ARMARX_DEBUG << "Logging rawTorqueTicks";
611
612 if (robotUnitObserver->existsChannel("SensorDevices"))
613 {
614 for (auto& node : _jointNames)
615 {
616 if (robotUnitObserver->existsDataField("SensorDevices",
617 node + "_SensorValueArmar6Actuator_torqueTicks"))
618 {
619 data.push_back(
620 (float)robotUnitObserver
621 ->getDatafieldByName("SensorDevices",
622 node + "_SensorValueArmar6Actuator_torqueTicks")
623 ->getInt());
624 }
625 else
626 {
627 data.push_back(0.0f);
628 }
629 }
630 }
631 else
632 {
633 for (size_t i = 0; i < _jointNames.size(); i++)
634 {
635 data.push_back(0.0f);
636 }
637 }
638}
639
640void
641DHParameterOptimizationLogger::logTorqueValues(std::vector<float>& data) const
642{
643 ARMARX_DEBUG << "Logging torqueValues";
644
645 if (robotUnitObserver->existsChannel("SensorDevices"))
646 {
647 for (auto& node : _jointNames)
648 {
649 if (robotUnitObserver->existsDataField("SensorDevices",
650 node + "_SensorValueArmar6Actuator_torque"))
651 {
652 data.push_back(robotUnitObserver
653 ->getDatafieldByName("SensorDevices",
654 node + "_SensorValueArmar6Actuator_torque")
655 ->getFloat());
656 }
657 else
658 {
659 data.push_back(0.0f);
660 }
661 }
662 }
663 else
664 {
665 for (size_t i = 0; i < _jointNames.size(); i++)
666 {
667 data.push_back(0.0f);
668 }
669 }
670}
671
672void
673DHParameterOptimizationLogger::logFTSensorValues(std::vector<float>& data) const
674{
675 ARMARX_DEBUG << "Logging FTSensorValues";
676
677 std::string datafieldName;
678 if (_kc->getTCP()->getName() == "Hand R TCP")
679 {
680 datafieldName = "FT R_FTSensorDataValue_torque";
681 }
682 else if (_kc->getTCP()->getName() == "Hand L TCP")
683 {
684 datafieldName = "FT L_FTSensorDataValue_torque";
685 }
686
687 if (robotUnitObserver->existsChannel("SensorDevices"))
688 {
689 if (robotUnitObserver->existsDataField("SensorDevices", datafieldName))
690 {
691 TimedVariantPtr tv = TimedVariantPtr::dynamicCast(
692 robotUnitObserver->getDatafieldByName("SensorDevices", datafieldName));
694 Vector3Ptr v = tv->get<Vector3>();
695
696 data.push_back(v->x);
697 data.push_back(v->y);
698 data.push_back(v->z);
699 }
700 else
701 {
702 data.push_back(0.0f);
703 data.push_back(0.0f);
704 data.push_back(0.0f);
705 }
706 }
707 else
708 {
709 data.push_back(0.0f);
710 data.push_back(0.0f);
711 data.push_back(0.0f);
712 }
713}
714
715StringVector3fMap
716DHParameterOptimizationLogger::waitBlockingForAllMarkersFiltered()
717{
718 TIMING_START(waitBlockingForAllMarkersFiltered);
719 std::map<std::string, armarx::rtfilters::AverageFilter> viconDataFilters;
720
721 // Setup filter
722 viconDataFilters.clear();
723 for (auto& s : _neckMarker)
724 {
725 viconDataFilters.insert(std::make_pair(s + "_x", rtfilters::AverageFilter(_filterSize)));
726 viconDataFilters.insert(std::make_pair(s + "_y", rtfilters::AverageFilter(_filterSize)));
727 viconDataFilters.insert(std::make_pair(s + "_z", rtfilters::AverageFilter(_filterSize)));
728 }
729 for (auto& s : _handMarker)
730 {
731 viconDataFilters.insert(std::make_pair(s + "_x", rtfilters::AverageFilter(_filterSize)));
732 viconDataFilters.insert(std::make_pair(s + "_y", rtfilters::AverageFilter(_filterSize)));
733 viconDataFilters.insert(std::make_pair(s + "_z", rtfilters::AverageFilter(_filterSize)));
734 }
735
736 size_t i = 0; // Counter to make sure the whole filter is filled
737 StringVector3fMap viconValues;
738 bool viconValuesSet = false;
739 while (_viconLoggingActive && !viconValuesSet)
740 {
741 // Waiting for new vicon data
742 if (!_viconBufferUpdated)
743 {
745 }
746 else
747 {
748 _viconBufferUpdated = false;
749 // copying viconData
750 {
751 std::unique_lock lock(_bufferMutex);
752 viconValues = _viconMarkerBuffer;
753 }
754 // Check if all data is valid, if not, continue waiting for next data frame
755 for (const std::string& s : _neckMarker)
756 {
757 ARMARX_CHECK_EXPRESSION(viconValues.count(s) > 0)
758 << armarx::getMapKeys(viconValues) << "\n"
759 << s;
760 Vector3f v = viconValues.at(s);
761 if (v.e0 == 0.0f && v.e1 == 0.0f && v.e2 == 0.0f)
762 {
763 goto invalidData; // rare case where goto is actually useful
764 }
765 }
766 for (const std::string& s : _handMarker)
767 {
768 ARMARX_CHECK_EXPRESSION(viconValues.count(s) > 0);
769 Vector3f v = viconValues.at(s);
770 if (v.e0 == 0.0f && v.e1 == 0.0f && v.e2 == 0.0f)
771 {
772 goto invalidData; // rare case where goto is actually useful
773 }
774 }
775
776 // All data is valid, we can push it to the filters
777 for (const std::string& s : _neckMarker)
778 {
779 Vector3f v = viconValues.at(s);
780 viconDataFilters.at(s + "_x").update(_timeStampLastViconDataUpdate, v.e0);
781 viconDataFilters.at(s + "_y").update(_timeStampLastViconDataUpdate, v.e1);
782 viconDataFilters.at(s + "_z").update(_timeStampLastViconDataUpdate, v.e2);
783 }
784 for (const std::string& s : _handMarker)
785 {
786 Vector3f v = viconValues.at(s);
787 viconDataFilters.at(s + "_x").update(_timeStampLastViconDataUpdate, v.e0);
788 viconDataFilters.at(s + "_y").update(_timeStampLastViconDataUpdate, v.e1);
789 viconDataFilters.at(s + "_z").update(_timeStampLastViconDataUpdate, v.e2);
790 }
791 if (i >= _filterSize)
792 {
793 viconValues.clear();
794 for (const std::string& s : _neckMarker)
795 {
796 float x = viconDataFilters.at(s + "_x").calculate();
797 float y = viconDataFilters.at(s + "_y").calculate();
798 float z = viconDataFilters.at(s + "_z").calculate();
799 Vector3f v;
800 v.e0 = x;
801 v.e1 = y;
802 v.e2 = z;
803 viconValues.insert(std::make_pair(s, v));
804 }
805 for (const std::string& s : _handMarker)
806 {
807 float x = viconDataFilters.at(s + "_x").calculate();
808 float y = viconDataFilters.at(s + "_y").calculate();
809 float z = viconDataFilters.at(s + "_z").calculate();
810 Vector3f v;
811 v.e0 = x;
812 v.e1 = y;
813 v.e2 = z;
814 viconValues.insert(std::make_pair(s, v));
815 }
816 viconValuesSet = true;
817 }
818 else
819 {
820 i++;
821 }
822 }
823 invalidData:; // rare case where goto is actually useful
824 }
825 TIMING_END(waitBlockingForAllMarkersFiltered);
826 viconDataFilters.clear();
827 return viconValues;
828}
829
830VirtualRobot::RobotNodePtr
831DHParameterOptimizationLogger::getNeckMarkerRootNode() const
832{
834 VirtualRobot::RobotNodePtr node;
835 if (_kc->getTCP()->getName() == "Hand R TCP")
836 {
837 node = localRobot->getRobotNode("DHParameterOptimization_NeckRight");
838 }
839 else if (_kc->getTCP()->getName() == "Hand L TCP")
840 {
841 node = localRobot->getRobotNode("DHParameterOptimization_NeckLeft");
842 }
843 else
844 {
845 ARMARX_ERROR << "Kinematic chain does not have a tcp with name 'Hand R TCP' or 'Hand L "
846 "TCP'. Maybe the used robot is not Armar-6?!";
847 }
848 return node;
849}
850
851VirtualRobot::RobotNodePtr
852DHParameterOptimizationLogger::getHandMarkerRootNode() const
853{
855 VirtualRobot::RobotNodePtr node;
856 if (_kc->getTCP()->getName() == "Hand R TCP")
857 {
858 node = localRobot->getRobotNode("DHParameterOptimization_HandRight");
859 }
860 else if (_kc->getTCP()->getName() == "Hand L TCP")
861 {
862 node = localRobot->getRobotNode("DHParameterOptimization_HandLeft");
863 }
864 else
865 {
866 ARMARX_ERROR << "Kinematic chain does not have a tcp with name 'Hand R TCP' or 'Hand L "
867 "TCP'. Maybe the used robot is not Armar-6?!";
868 }
869 return node;
870}
871
872std::pair<float, float>
873DHParameterOptimizationLogger::calculateRepeatError()
874{
875 if (!_observedHandPosesUpdated)
876 {
877 ARMARX_WARNING << "Pose of HandViconMarker have not been updated. No repeat accuracy "
878 "calculated. (writes -1.0 in log)";
879 return std::make_pair(-1.0f, -1.0f);
880 }
881 _observedHandPosesUpdated = false;
882
883 Eigen::Matrix4f oldPose = _lastObservedHandRootPose;
884 Eigen::Matrix4f newPose = _newObservedHandRootPose;
885
886 // Calculate error
887 Eigen::Vector3f errorV = oldPose.block<3, 1>(0, 3) - newPose.block<3, 1>(0, 3);
888 float errorPos = errorV.norm();
889
890 Eigen::Matrix3f oriDir = oldPose.block<3, 3>(0, 0) * newPose.block<3, 3>(0, 0).inverse();
891 Eigen::AngleAxisf aa(oriDir);
892 float errorOri = aa.angle();
893
894 ARMARX_INFO << "Repeat Accuracy: Error between old pose and new pose ---- Position-Error: "
895 << errorPos << " mm, Orientation-Error: " << errorOri << " rad";
896
897 return std::make_pair(errorPos, errorOri);
898}
899
900Eigen::Matrix4f
901DHParameterOptimizationLogger::registration3d(const Eigen::MatrixXf& A,
902 const Eigen::MatrixXf& B) const
903{
904
905 // std::cout << "A:\n" << A<< std::endl;
906 // std::cout << "B:\n" << B<< std::endl;
907 assert(A.rows() == B.rows()); // Same number of points
908 assert(A.cols() == B.cols()); // Same dimension
909 // assert(A.cols()==3);
910 assert(A.cols() == 3 || A.cols() == 4); // Homogeneous coordinates?
911 assert(A.rows() >= 3);
912
913
914 Eigen::Vector3f centroid_A = A.block(0, 0, A.rows(), 3).colwise().mean();
915 Eigen::Vector3f centroid_B = B.block(0, 0, A.rows(), 3).colwise().mean();
916 // std::cout << "cA & cB: \n" << centroid_A << std::endl << std::endl << centroid_B << std::endl;
917 Eigen::MatrixXf AA = A.block(0, 0, A.rows(), 3).rowwise() - centroid_A.transpose();
918 Eigen::MatrixXf BB = (B.block(0, 0, A.rows(), 3).rowwise() - centroid_B.transpose());
919 // std::cout << VAROUT(AA) << VAROUT(BB);
920 Eigen::MatrixXf H = (AA).transpose() * BB;
921 // std::cout << "H: " << H<< std::endl;
922
923 Eigen::JacobiSVD<Eigen::MatrixXf> svd(H, Eigen::ComputeThinU | Eigen::ComputeThinV);
924 Eigen::Matrix3f U = svd.matrixU();
925 // std::cout << "U: " << U<< std::endl;
926 Eigen::Matrix3f V = svd.matrixV();
927 // std::cout << "V: " << V<< std::endl;
928 Eigen::Matrix3f R = V * U.transpose();
929 // std::cout << "R: " << R<< std::endl;
930
931 if (R.determinant() < 0)
932 {
933 // Reflection detected
934 // abort();
935 // ARMARX_INFO << "Reflection detected";
936 V.col(2) *= -1;
937 R = V * U.transpose();
938 // R.col(2) *= -1;
939 }
940
941 Eigen::Vector3f t = -R * centroid_A + centroid_B;
942 // std::cout << "t: " << t << std::endl;
943 Eigen::Matrix4f T = Eigen::Matrix4f::Identity();
944 T.block(0, 0, 3, 3) = R;
945 T.block(0, 3, 3, 1) = t;
946
947 return T;
948}
949
950StringVector3fMap
951DHParameterOptimizationLogger::transformViconMarkerPositionsIntoRobotRootFrame(
952 const StringVector3fMap& values) const
953{
954 RemoteRobot::synchronizeLocalClone(localRobot, robotStateComponent);
955 VirtualRobot::RobotNodePtr neck = getNeckMarkerRootNode();
956
957 Eigen::MatrixXf observedNeckPositions_viconRootFrame(3, _neckMarker.size());
958 Eigen::MatrixXf modelNeckPositions_neckFrame(3, _neckMarker.size());
959
960 size_t i = 0;
961 for (auto& it : _neckMarker)
962 {
963 observedNeckPositions_viconRootFrame(0, i) = values.at(it).e0;
964 observedNeckPositions_viconRootFrame(1, i) = values.at(it).e1;
965 observedNeckPositions_viconRootFrame(2, i) = values.at(it).e2;
966 modelNeckPositions_neckFrame(0, i) =
967 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(0, 3);
968 modelNeckPositions_neckFrame(1, i) =
969 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(1, 3);
970 modelNeckPositions_neckFrame(2, i) =
971 neck->getSensor(_neckMarkerMapping.at(it))->getTransformationFrom(neck)(2, 3);
972
973 i++;
974 }
975 Eigen::Matrix4f observedNeckRootPose_viconRootFrame = registration3d(
976 modelNeckPositions_neckFrame.transpose(), observedNeckPositions_viconRootFrame.transpose());
977 localRobot->setGlobalPoseForRobotNode(neck, observedNeckRootPose_viconRootFrame);
978 Eigen::Matrix4f realRobotToVicon = localRobot->getGlobalPose().inverse();
979
980
981 // Eigen::Matrix4f realGlobalRootPose = localRobot->getGlobalPose();
982 // ARMARX_DEBUG << VAROUT(observedNeckRootPose_robotRootFrame) << VAROUT(modelNeckPositions_neckFrame) << VAROUT(observedNeckPositions_robotRootFrame);
983 // Eigen::Matrix4f realGlobalRootPose = localRobot->getGlobalPose();
984 // localRobot->setGlobalPoseForRobotNode(neck, observedNeckRootPose_robotRootFrame);
985
986 // debugDrawerPrx->setRobotVisu("markerVisu", "robot", robotStateComponent->getRobotFilename(), "armar6_rt", FullModel);
987 // debugDrawerPrx->updateRobotPose("markerVisu", "robot", new Pose(localRobot->getGlobalPose()));
988 // debugDrawerPrx->updateRobotConfig("markerVisu", "robot", localRobot->getConfig()->getRobotNodeJointValueMap());
989
990 // Eigen::Matrix4f realRobotToVicon = realGlobalRootPose.inverse() * localRobot->getGlobalPose();
991 // ARMARX_INFO << VAROUT(realRobotToVicon) << VAROUT(realGlobalRootPose) << VAROUT(localRobot->getGlobalPose()) << VAROUT(neck->getGlobalPose()) << VAROUT(root->getGlobalPose());
992
993
994 StringVector3fMap transformedValues;
995 for (auto& it : values)
996 {
997 std::string markerName = it.first;
998 armarx::Vector3f pos_viconRootFrame = it.second;
999
1000 Eigen::Matrix4f mat = Eigen::Matrix4f::Identity();
1001 mat(0, 3) = pos_viconRootFrame.e0;
1002 mat(1, 3) = pos_viconRootFrame.e1;
1003 mat(2, 3) = pos_viconRootFrame.e2;
1004
1005 mat = realRobotToVicon * mat;
1006
1007 armarx::Vector3f r;
1008 r.e0 = mat(0, 3);
1009 r.e1 = mat(1, 3);
1010 r.e2 = mat(2, 3);
1011 transformedValues[markerName] = r;
1012 }
1013
1014 return transformedValues;
1015}
uint8_t data[1]
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
#define VAROUT(x)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void write(const std::vector< std::string > &row)
Definition CsvWriter.cpp:43
void stopViconLogging(const Ice::Current &=Ice::emptyCurrent) override
void startViconLogging(const Ice::Current &=Ice::emptyCurrent) override
void init(const std::string &kinematicChainName, const std::map< std::string, std::string > &neckMarkerMapping, const std::map< std::string, std::string > &handMarkerMapping, const std::string &loggingFileName, bool logRepeatAccuracy, const Ice::Current &=Ice::emptyCurrent) override
void reportLabeledViconMarkerFrame(const StringVector3fMap &markerPosMap, const Ice::Current &=Ice::emptyCurrent) override
void reportUnlabeledViconMarkerFrame(const Vector3fSeq &markerPos, const Ice::Current &=Ice::emptyCurrent) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void logData(const Ice::Current &=Ice::emptyCurrent) override
logData logs data for the current position.
void logDataWithRepeatAccuracy(const Ice::Current &=Ice::emptyCurrent) override
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
static VirtualRobot::RobotPtr createLocalCloneFromFile(RobotStateComponentInterfacePrx robotStatePrx, VirtualRobot::RobotIO::RobotDescription loadMode=VirtualRobot::RobotIO::eFull)
This is a convenience function for createLocalClone, which automatically gets the filename from the R...
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
static int USleep(long usec)
like timed_wait on boost condition_variables, but with timeserver support
Definition TimeUtil.cpp:159
The Variant class is described here: Variants.
Definition Variant.h:224
#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_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define TIMING_START(name)
Helper macro to do timing tests.
Definition TimeUtil.h:289
#define TIMING_END(name)
Prints duration.
Definition TimeUtil.h:306
const VariantTypeId Vector3
Definition Pose.h:38
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39
Eigen::Isometry3f Pose
Definition basic_types.h:31
This file offers overloads of toIce() and fromIce() functions for STL container types.
bool ends_with(const std::string &haystack, const std::string &needle)
IceInternal::Handle< Vector3 > Vector3Ptr
Definition Pose.h:165
IceInternal::Handle< TimedVariant > TimedVariantPtr
std::vector< std::vector< T > > transpose(const std::vector< std::vector< T > > &src, Thrower thrower)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
Eigen::Vector3d Vector3
Definition kbm.h:43