28 #include <Eigen/Geometry>
30 #include <VirtualRobot/Nodes/Sensor.h>
31 #include <VirtualRobot/RobotNodeSet.h>
42 namespace fs = std::filesystem;
47 std::vector<float>
data;
48 if (_logRepeatAccuracy)
50 data.push_back(-1.0f);
51 data.push_back(-1.0f);
56 CsvWriter writer(_filePath, std::vector<std::string>(),
true);
67 if (!_logRepeatAccuracy)
73 std::vector<float>
data;
78 std::pair<float, float> repeatErrors;
79 repeatErrors = calculateRepeatError();
80 data[0] = repeatErrors.first;
81 data[1] = repeatErrors.second;
85 CsvWriter writer(_filePath, std::vector<std::string>(),
true);
90 ARMARX_DEBUG <<
"Logging data with repeat accuracy finished";
96 _viconLoggingActive =
true;
102 _viconLoggingActive =
false;
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,
117 _neckMarkerMapping = neckMarkerMapping;
118 _handMarkerMapping = handMarkerMapping;
123 for (
auto& pair : neckMarkerMapping)
125 _neckMarker.push_back(pair.first);
127 for (
auto& pair : handMarkerMapping)
129 _handMarker.push_back(pair.first);
131 for (
auto&
s : _neckMarker)
133 if (std::find(_handMarker.begin(), _handMarker.end(),
s) != _handMarker.end())
135 ARMARX_ERROR <<
"HandMarker and NeckMarker can not contain the same marker!! Abort.";
139 std::vector<VirtualRobot::SensorPtr> sensors = localRobot->getSensors();
140 for (
auto& pair : neckMarkerMapping)
142 auto& i = pair.second;
145 [i](VirtualRobot::SensorPtr
s)
146 { return s->getName() == i; }) != sensors.end())
147 <<
"Robot does not have a sensor with name '" + i +
"'";
149 for (
auto& pair : handMarkerMapping)
151 auto& i = pair.second;
154 [i](VirtualRobot::SensorPtr
s)
155 { return s->getName() == i; }) != sensors.end())
156 <<
"Robot does not have a sensor with name '" + i +
"'";
159 _kcName = kinematicChainName;
161 <<
"Robot " + localRobot->getName() +
" does not have a kinematic chain with name " +
163 _kc = localRobot->getRobotNodeSet(_kcName);
164 _jointNames = _kc->getNodeNames();
165 _logRepeatAccuracy = logRepeatAccuracy;
167 setupFile(loggingFileName);
170 CsvWriter writer(_filePath, _header,
true);
182 StringVector3fMap copyMap;
183 for (
auto& it : markerPosMap)
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;
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));
198 if (_viconLoggingActive)
200 std::unique_lock lock(_bufferMutex);
201 _viconMarkerBuffer = copyMap;
203 _viconBufferUpdated =
true;
215 DHParameterOptimizationLogger::setupFile(
const std::string& fileName)
217 std::string localFileName = fileName;
218 using namespace std::filesystem;
220 auto timeToString = []()
222 std::time_t now = std::time(
nullptr);
223 std::tm* nowTm = std::localtime(&now);
225 std::stringstream ss;
226 ss << std::put_time(nowTm,
"%Y%m%d_%H%M%S");
233 localFileName = localFileName.substr(0, localFileName.size() - 4);
235 localFileName +=
"_";
236 localFileName += timeToString();
237 localFileName +=
".csv";
239 std::string pathOrig = getProperty<std::string>(
"LoggingFilePath").getValue();
240 if (!pathOrig.empty() && pathOrig[0] ==
'~')
243 <<
"LoggingFilePath isviconValues not valid: '~' has to be followed by ’/’";
244 char const* home = std::getenv(
"HOME");
246 pathOrig.replace(0, 1, home);
248 fs::path filePath(pathOrig);
249 if (!fs::exists(filePath))
251 fs::create_directory(filePath);
253 filePath /= path(localFileName);
254 _filePath = filePath.string();
260 usingTopic(getProperty<std::string>(
"ViconDataTopicName").getValue());
261 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
262 usingProxy(getProperty<std::string>(
"RobotUnitObserverName").getValue());
264 _initialized =
false;
266 int size = getProperty<int>(
"FilterWindowSize").getValue();
270 _viconObjectName_neck = getProperty<std::string>(
"Neck_ViconObjectName").getValue();
271 _viconObjectName_hand = getProperty<std::string>(
"Hand_ViconObjectName").getValue();
277 getProxy(robotStateComponent, getProperty<std::string>(
"RobotStateComponentName").getValue());
278 getProxy(robotUnitObserver, getProperty<std::string>(
"RobotUnitObserverName").getValue());
279 _viconLoggingActive =
true;
281 debugObserverPrx = getTopic<DebugObserverInterfacePrx>(
282 getProperty<std::string>(
"DebugObserverTopicName").getValue());
283 debugDrawerPrx = getTopic<DebugDrawerInterfacePrx>(
"DebugDrawerUpdates");
287 robotStateComponent, VirtualRobot::RobotIO::RobotDescription::eStructure);
289 std::vector<VirtualRobot::SensorPtr>
s = localRobot->getSensors();
299 _viconLoggingActive =
false;
315 DHParameterOptimizationLogger::setupHeader()
317 std::vector<std::string> header;
322 if (_logRepeatAccuracy)
324 header.push_back(
"Error_Translation");
325 header.push_back(
"Error_Orientation");
329 for (
auto& m : _neckMarker)
331 header.push_back(m +
"_x");
332 header.push_back(m +
"_y");
333 header.push_back(m +
"_z");
337 for (
auto& m : _handMarker)
339 header.push_back(m +
"_x");
340 header.push_back(m +
"_y");
341 header.push_back(m +
"_z");
345 for (
auto& node : _jointNames)
347 header.push_back(
"JointValue_" + node);
349 header.push_back(
"JointValue_TorsoJoint");
352 for (
auto& m : _handMarker)
354 header.push_back(
"FK_" + m +
"_x");
355 header.push_back(
"FK_" + m +
"_y");
356 header.push_back(
"FK_" + m +
"_z");
360 header.push_back(
"Error_translation");
361 header.push_back(
"Error_orientation");
364 for (
auto& node : _jointNames)
366 header.push_back(node +
"_torqueTicks");
370 for (
auto& node : _jointNames)
372 header.push_back(node +
"_torque");
376 if (_kc->getTCP()->getName() ==
"Hand R TCP")
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");
382 else if (_kc->getTCP()->getName() ==
"Hand L TCP")
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");
396 logViconMarkerPositions(
data);
397 logJointValues(
data);
398 logForwardKinematicToViconMarker(
data);
399 logErrorBetweenModelAndVicon(
data);
400 logRawTorqueTicks(
data);
401 logTorqueValues(
data);
402 logFTSensorValues(
data);
406 DHParameterOptimizationLogger::logViconMarkerPositions(std::vector<float>&
data)
410 if (!_viconLoggingActive)
413 size_t sum = 3 * (_neckMarker.size() + _handMarker.size());
414 for (
size_t i = 0; i < sum; i++)
416 data.push_back(0.0f);
422 StringVector3fMap
values = waitBlockingForAllMarkersFiltered();
425 size_t sum = 3 * (_neckMarker.size() + _handMarker.size());
426 for (
size_t i = 0; i < sum; i++)
428 data.push_back(0.0f);
433 values = transformViconMarkerPositionsIntoRobotRootFrame(
values);
434 for (
auto& m : _neckMarker)
440 for (
auto& m : _handMarker)
447 _filteredViconMarkerPositions_robotRootFrame =
values;
448 _filteredViconMarkerPositionsUpdated =
true;
454 DHParameterOptimizationLogger::logJointValues(std::vector<float>&
data)
const
459 for (
auto& node : _kc->getAllRobotNodes())
461 data.push_back(node->getJointValue());
463 data.push_back(localRobot->getRobotNode(
"TorsoJoint")->getJointValue());
467 DHParameterOptimizationLogger::logForwardKinematicToViconMarker(std::vector<float>&
data)
const
469 ARMARX_DEBUG <<
"Logging forwardKinematicToViconMarker";
472 VirtualRobot::RobotNodePtr
hand = getHandMarkerRootNode();
474 for (VirtualRobot::SensorPtr
const& sensor :
hand->getSensors())
476 Eigen::Matrix4f m = sensor->getTransformationFrom(localRobot->getRootNode());
477 data.push_back(m(0, 3));
478 data.push_back(m(1, 3));
479 data.push_back(m(2, 3));
484 DHParameterOptimizationLogger::logErrorBetweenModelAndVicon(std::vector<float>&
data)
488 if (!_viconLoggingActive || !_filteredViconMarkerPositionsUpdated)
490 data.push_back(0.0f);
491 data.push_back(0.0f);
496 VirtualRobot::RobotNodePtr neck = getNeckMarkerRootNode();
497 VirtualRobot::RobotNodePtr
hand = getHandMarkerRootNode();
498 VirtualRobot::RobotNodePtr root = localRobot->getRootNode();
500 _lastObservedHandRootPose = _newObservedHandRootPose;
505 Eigen::MatrixXf observedNeckPositions_robotRootFrame(3, _neckMarker.size());
506 Eigen::MatrixXf modelNeckPositions_neckFrame(3, _neckMarker.size());
510 for (
auto& it : _neckMarker)
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;
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);
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);
537 Eigen::MatrixXf observedHandPositions_robotRootFrame(3, _handMarker.size());
538 Eigen::MatrixXf modelHandPositions_handFrame(3, _handMarker.size());
542 for (
auto& it : _handMarker)
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;
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);
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);
570 <<
VAROUT(observedHandPositions_robotRootFrame);
572 registration3d(modelHandPositions_handFrame.transpose(),
573 observedHandPositions_robotRootFrame.transpose());
575 _newObservedHandRootPose = observedHandRootPose_robotRootFrame;
576 _observedHandPosesUpdated =
true;
578 debugDrawerPrx->setPoseVisu(
581 new Pose(root->getGlobalPose() * observedHandRootPose_robotRootFrame));
582 debugDrawerPrx->setPoseVisu(
"MarkerVisu",
"kinematicTCP",
new Pose(
hand->getGlobalPose()));
585 float errorPos = (
hand->getPoseInRootFrame().block<3, 1>(0, 3) -
586 observedHandRootPose_robotRootFrame.block<3, 1>(0, 3))
593 observedHandRootPose_robotRootFrame.block<3, 3>(0, 0).inverse();
594 Eigen::AngleAxisf aa(oriDir);
595 float errorOri = aa.angle();
597 ARMARX_INFO <<
"Error (Hand) in rootFrame between model and vicon ---- Position-Error: "
598 << errorPos <<
" mm, Orientation-Error: " << errorOri <<
" rad";
600 data.push_back(errorPos);
601 data.push_back(errorOri);
603 _filteredViconMarkerPositionsUpdated =
false;
608 DHParameterOptimizationLogger::logRawTorqueTicks(std::vector<float>&
data)
const
612 if (robotUnitObserver->existsChannel(
"SensorDevices"))
614 for (
auto& node : _jointNames)
616 if (robotUnitObserver->existsDataField(
"SensorDevices",
617 node +
"_SensorValueArmar6Actuator_torqueTicks"))
620 (
float)robotUnitObserver
621 ->getDatafieldByName(
"SensorDevices",
622 node +
"_SensorValueArmar6Actuator_torqueTicks")
627 data.push_back(0.0f);
633 for (
size_t i = 0; i < _jointNames.size(); i++)
635 data.push_back(0.0f);
641 DHParameterOptimizationLogger::logTorqueValues(std::vector<float>&
data)
const
645 if (robotUnitObserver->existsChannel(
"SensorDevices"))
647 for (
auto& node : _jointNames)
649 if (robotUnitObserver->existsDataField(
"SensorDevices",
650 node +
"_SensorValueArmar6Actuator_torque"))
652 data.push_back(robotUnitObserver
653 ->getDatafieldByName(
"SensorDevices",
654 node +
"_SensorValueArmar6Actuator_torque")
659 data.push_back(0.0f);
665 for (
size_t i = 0; i < _jointNames.size(); i++)
667 data.push_back(0.0f);
673 DHParameterOptimizationLogger::logFTSensorValues(std::vector<float>&
data)
const
677 std::string datafieldName;
678 if (_kc->getTCP()->getName() ==
"Hand R TCP")
680 datafieldName =
"FT R_FTSensorDataValue_torque";
682 else if (_kc->getTCP()->getName() ==
"Hand L TCP")
684 datafieldName =
"FT L_FTSensorDataValue_torque";
687 if (robotUnitObserver->existsChannel(
"SensorDevices"))
689 if (robotUnitObserver->existsDataField(
"SensorDevices", datafieldName))
692 robotUnitObserver->getDatafieldByName(
"SensorDevices", datafieldName));
696 data.push_back(
v->x);
697 data.push_back(
v->y);
698 data.push_back(
v->z);
702 data.push_back(0.0f);
703 data.push_back(0.0f);
704 data.push_back(0.0f);
709 data.push_back(0.0f);
710 data.push_back(0.0f);
711 data.push_back(0.0f);
716 DHParameterOptimizationLogger::waitBlockingForAllMarkersFiltered()
719 std::map<std::string, armarx::rtfilters::AverageFilter> viconDataFilters;
722 viconDataFilters.clear();
723 for (
auto&
s : _neckMarker)
729 for (
auto&
s : _handMarker)
737 StringVector3fMap viconValues;
738 bool viconValuesSet =
false;
739 while (_viconLoggingActive && !viconValuesSet)
742 if (!_viconBufferUpdated)
748 _viconBufferUpdated =
false;
751 std::unique_lock lock(_bufferMutex);
752 viconValues = _viconMarkerBuffer;
755 for (
const std::string&
s : _neckMarker)
760 Vector3f
v = viconValues.at(
s);
761 if (
v.e0 == 0.0f &&
v.e1 == 0.0f &&
v.e2 == 0.0f)
766 for (
const std::string&
s : _handMarker)
769 Vector3f
v = viconValues.at(
s);
770 if (
v.e0 == 0.0f &&
v.e1 == 0.0f &&
v.e2 == 0.0f)
777 for (
const std::string&
s : _neckMarker)
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);
784 for (
const std::string&
s : _handMarker)
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);
791 if (i >= _filterSize)
794 for (
const std::string&
s : _neckMarker)
796 float x = viconDataFilters.at(
s +
"_x").calculate();
797 float y = viconDataFilters.at(
s +
"_y").calculate();
798 float z = viconDataFilters.at(
s +
"_z").calculate();
803 viconValues.insert(std::make_pair(
s,
v));
805 for (
const std::string&
s : _handMarker)
807 float x = viconDataFilters.at(
s +
"_x").calculate();
808 float y = viconDataFilters.at(
s +
"_y").calculate();
809 float z = viconDataFilters.at(
s +
"_z").calculate();
814 viconValues.insert(std::make_pair(
s,
v));
816 viconValuesSet =
true;
825 TIMING_END(waitBlockingForAllMarkersFiltered);
826 viconDataFilters.clear();
830 VirtualRobot::RobotNodePtr
831 DHParameterOptimizationLogger::getNeckMarkerRootNode()
const
834 VirtualRobot::RobotNodePtr node;
835 if (_kc->getTCP()->getName() ==
"Hand R TCP")
837 node = localRobot->getRobotNode(
"DHParameterOptimization_NeckRight");
839 else if (_kc->getTCP()->getName() ==
"Hand L TCP")
841 node = localRobot->getRobotNode(
"DHParameterOptimization_NeckLeft");
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?!";
851 VirtualRobot::RobotNodePtr
852 DHParameterOptimizationLogger::getHandMarkerRootNode()
const
855 VirtualRobot::RobotNodePtr node;
856 if (_kc->getTCP()->getName() ==
"Hand R TCP")
858 node = localRobot->getRobotNode(
"DHParameterOptimization_HandRight");
860 else if (_kc->getTCP()->getName() ==
"Hand L TCP")
862 node = localRobot->getRobotNode(
"DHParameterOptimization_HandLeft");
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?!";
872 std::pair<float, float>
873 DHParameterOptimizationLogger::calculateRepeatError()
875 if (!_observedHandPosesUpdated)
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);
881 _observedHandPosesUpdated =
false;
887 Eigen::Vector3f errorV = oldPose.block<3, 1>(0, 3) - newPose.block<3, 1>(0, 3);
888 float errorPos = errorV.norm();
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();
894 ARMARX_INFO <<
"Repeat Accuracy: Error between old pose and new pose ---- Position-Error: "
895 << errorPos <<
" mm, Orientation-Error: " << errorOri <<
" rad";
897 return std::make_pair(errorPos, errorOri);
901 DHParameterOptimizationLogger::registration3d(
const Eigen::MatrixXf&
A,
902 const Eigen::MatrixXf& B)
const
907 assert(
A.rows() == B.rows());
908 assert(
A.cols() == B.cols());
910 assert(
A.cols() == 3 ||
A.cols() == 4);
911 assert(
A.rows() >= 3);
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();
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());
920 Eigen::MatrixXf H = (AA).
transpose() * BB;
923 Eigen::JacobiSVD<Eigen::MatrixXf> svd(H, Eigen::ComputeThinU | Eigen::ComputeThinV);
931 if (R.determinant() < 0)
937 R = V * U.transpose();
941 Eigen::Vector3f t = -R * centroid_A + centroid_B;
944 T.block(0, 0, 3, 3) = R;
945 T.block(0, 3, 3, 1) = t;
951 DHParameterOptimizationLogger::transformViconMarkerPositionsIntoRobotRootFrame(
952 const StringVector3fMap&
values)
const
955 VirtualRobot::RobotNodePtr neck = getNeckMarkerRootNode();
957 Eigen::MatrixXf observedNeckPositions_viconRootFrame(3, _neckMarker.size());
958 Eigen::MatrixXf modelNeckPositions_neckFrame(3, _neckMarker.size());
961 for (
auto& it : _neckMarker)
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);
976 modelNeckPositions_neckFrame.transpose(), observedNeckPositions_viconRootFrame.transpose());
977 localRobot->setGlobalPoseForRobotNode(neck, observedNeckRootPose_viconRootFrame);
978 Eigen::Matrix4f realRobotToVicon = localRobot->getGlobalPose().inverse();
994 StringVector3fMap transformedValues;
997 std::string markerName = it.first;
998 armarx::Vector3f pos_viconRootFrame = it.second;
1001 mat(0, 3) = pos_viconRootFrame.e0;
1002 mat(1, 3) = pos_viconRootFrame.e1;
1003 mat(2, 3) = pos_viconRootFrame.e2;
1005 mat = realRobotToVicon * mat;
1011 transformedValues[markerName] = r;
1014 return transformedValues;