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 
40 using namespace armarx;
41 
42 namespace fs = std::filesystem;
43 
44 void
46 {
47  std::vector<float> data;
48  if (_logRepeatAccuracy)
49  {
50  data.push_back(-1.0f);
51  data.push_back(-1.0f);
52  }
53  logData(data);
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 
64 void
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);
77  logData(data);
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 
93 void
95 {
96  _viconLoggingActive = true;
97 }
98 
99 void
101 {
102  _viconLoggingActive = false;
103 }
104 
105 void
106 DHParameterOptimizationLogger::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 
176 void
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 
207 void
209  const Ice::Current&)
210 {
211  // Not needed
212 }
213 
214 void
215 DHParameterOptimizationLogger::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 
257 void
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 
274 void
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 
296 void
298 {
299  _viconLoggingActive = false;
300 }
301 
302 void
304 {
305 }
306 
309 {
312 }
313 
314 void
315 DHParameterOptimizationLogger::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 
392 void
393 DHParameterOptimizationLogger::logData(std::vector<float>& data)
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 
405 void
406 DHParameterOptimizationLogger::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 
453 void
454 DHParameterOptimizationLogger::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 
466 void
467 DHParameterOptimizationLogger::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 
483 void
484 DHParameterOptimizationLogger::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 
607 void
608 DHParameterOptimizationLogger::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 
640 void
641 DHParameterOptimizationLogger::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 
672 void
673 DHParameterOptimizationLogger::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 
715 StringVector3fMap
716 DHParameterOptimizationLogger::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  {
744  TimeUtil::USleep(10);
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 
830 VirtualRobot::RobotNodePtr
831 DHParameterOptimizationLogger::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 
851 VirtualRobot::RobotNodePtr
852 DHParameterOptimizationLogger::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 
872 std::pair<float, float>
873 DHParameterOptimizationLogger::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 
901 DHParameterOptimizationLogger::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;
944  T.block(0, 0, 3, 3) = R;
945  T.block(0, 3, 3, 1) = t;
946 
947  return T;
948 }
949 
950 StringVector3fMap
951 DHParameterOptimizationLogger::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 
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 }
armarx::DHParameterOptimizationLogger::logDataWithRepeatAccuracy
void logDataWithRepeatAccuracy(const Ice::Current &=Ice::emptyCurrent) override
Definition: DHParameterOptimizationLogger.cpp:65
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
armarx::DHParameterOptimizationLogger::logData
void logData(const Ice::Current &=Ice::emptyCurrent) override
logData logs data for the current position.
Definition: DHParameterOptimizationLogger.cpp:45
TIMING_START
#define TIMING_START(name)
Definition: TimeUtil.h:289
algorithm.h
armarx::CsvWriter
Definition: CsvWriter.h:36
TIMING_END
#define TIMING_END(name)
Definition: TimeUtil.h:306
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
armarx::RemoteRobot::synchronizeLocalClone
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
Definition: RemoteRobot.cpp:522
armarx::RemoteRobot::createLocalCloneFromFile
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...
Definition: RemoteRobot.cpp:512
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
ProsthesisInterface.values
values
Definition: ProsthesisInterface.py:190
armarx::VariantType::Vector3
const VariantTypeId Vector3
Definition: Pose.h:38
armarx::rtfilters::AverageFilter
Definition: AverageFilter.h:32
CsvWriter.h
armarx::DHParameterOptimizationLogger::init
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
Definition: DHParameterOptimizationLogger.cpp:106
IceInternal::Handle
Definition: forward_declarations.h:8
armarx::DHParameterOptimizationLogger::onConnectComponent
void onConnectComponent() override
Definition: DHParameterOptimizationLogger.cpp:275
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::CsvWriter::close
void close()
Definition: CsvWriter.cpp:83
armarx::TimeUtil::USleep
static int USleep(long usec)
like timed_wait on boost condition_variables, but with timeserver support
Definition: TimeUtil.cpp:159
DHParameterOptimizationLogger.h
FramedPose.h
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::Vector3
The Vector3 class.
Definition: Pose.h:112
armarx::DHParameterOptimizationLogger::onInitComponent
void onInitComponent() override
Definition: DHParameterOptimizationLogger.cpp:258
armarx::DHParameterOptimizationLogger::startViconLogging
void startViconLogging(const Ice::Current &=Ice::emptyCurrent) override
Definition: DHParameterOptimizationLogger.cpp:94
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::DHParameterOptimizationLogger::onExitComponent
void onExitComponent() override
Definition: DHParameterOptimizationLogger.cpp:303
armarx::DHParameterOptimizationLogger::reportUnlabeledViconMarkerFrame
void reportUnlabeledViconMarkerFrame(const Vector3fSeq &markerPos, const Ice::Current &=Ice::emptyCurrent) override
Definition: DHParameterOptimizationLogger.cpp:208
armarx::DHParameterOptimizationLogger::reportLabeledViconMarkerFrame
void reportLabeledViconMarkerFrame(const StringVector3fMap &markerPosMap, const Ice::Current &=Ice::emptyCurrent) override
Definition: DHParameterOptimizationLogger.cpp:177
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
armarx::CsvWriter::write
void write(const std::vector< std::string > &row)
Definition: CsvWriter.cpp:43
A
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
TimedVariant.h
armarx::control::common::MPType::hand
@ hand
armarx::ManagedIceObject::usingTopic
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
Definition: ManagedIceObject.cpp:254
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:79
armarx::DHParameterOptimizationLogger::onDisconnectComponent
void onDisconnectComponent() override
Definition: DHParameterOptimizationLogger.cpp:297
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
TimeUtil.h
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::ends_with
bool ends_with(const std::string &haystack, const std::string &needle)
Definition: StringHelpers.cpp:53
memoryx::KBM::Vector3
Eigen::Vector3d Vector3
Definition: kbm.h:43
armarx::DHParameterOptimizationLogger::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: DHParameterOptimizationLogger.cpp:308
armarx::Logging::deactivateSpam
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
armarx::DHParameterOptimizationLoggerPropertyDefinitions
Definition: DHParameterOptimizationLogger.h:44
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:649
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::transpose
std::vector< std::vector< T > > transpose(const std::vector< std::vector< T >> &src, Thrower thrower)
Definition: SimoxCSpace.cpp:772
armarx::DHParameterOptimizationLogger::stopViconLogging
void stopViconLogging(const Ice::Current &=Ice::emptyCurrent) override
Definition: DHParameterOptimizationLogger.cpp:100
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
armarx::ManagedIceObject::getProxy
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
Definition: ManagedIceObject.cpp:407
armarx::ManagedIceObject::usingProxy
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Definition: ManagedIceObject.cpp:154
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::getMapKeys
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition: algorithm.h:173
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
norm
double norm(const Point &a)
Definition: point.hpp:102