30#include <VirtualRobot/Import/RobotImporterFactory.h>
31#include <VirtualRobot/KinematicChain.h>
32#include <VirtualRobot/MathTools.h>
33#include <VirtualRobot/Nodes/RobotNode.h>
34#include <VirtualRobot/Robot.h>
35#include <VirtualRobot/RuntimeEnvironment.h>
37#include <RobotAPI/interface/core/RobotState.h>
86 Eigen::Map<const memoryx::KBM::Vector>
88 const std::vector<memoryx::KBM::Real>& position)
90 VR_ASSERT_MESSAGE((
int)(position.size()) == kbm.
getNDim(),
91 "position size doesn't match KBM dimensions");
92 return Eigen::Map<const memoryx::KBM::Vector>(position.data(), kbm.
getNDim());
95 Eigen::Map<const memoryx::KBM::Vector>
97 const std::vector<memoryx::KBM::Real>& proprioception)
99 VR_ASSERT_MESSAGE((
int)(proprioception.size()) == kbm.
getNDoF(),
100 "proprioception size doesn't match KBM DoF");
101 return Eigen::Map<const memoryx::KBM::Vector>(proprioception.data(), kbm.
getNDoF());
104 Eigen::Map<const memoryx::KBM::Matrix>
106 const std::vector<memoryx::KBM::Real>& position)
110 if (position.size() % nDim != 0)
118 Eigen::Map<const memoryx::KBM::Matrix>
120 const std::vector<memoryx::KBM::Real>& proprioception)
124 if (proprioception.size() % nDoF != 0)
132 Eigen::Map<const memoryx::KBM::Matrix>
135 if (
data.size() % rows != 0)
140 VR_ASSERT(
data.size() % rows == 0);
141 int cols =
data.size() / rows;
142 return Eigen::Map<const memoryx::KBM::Matrix>(
data.data(), rows, cols);
148 auto it = kbms.find(name);
150 if (it == kbms.end())
152 ARMARX_WARNING <<
"a KBM with the name '" << name <<
"' does not exist";
171 Ice::Float spreadAngle,
172 const Ice::Current&
c)
177 if (kbms.find(name) != kbms.end())
179 ARMARX_ERROR <<
"a KBM with the name '" << name <<
"' already exists";
188 createdFromVirtualRobot[name] =
false;
189 ARMARX_INFO <<
"created a KBM with the name '" << name <<
"'";
194 const Ice::StringSeq& robotNodeNames,
195 const std::vector<memoryx::KBM::Real>& jointValueAverages,
196 const std::vector<memoryx::KBM::Real>& spreadAnglesSequence,
197 const std::string& tcpName,
199 const Ice::Current&
c)
204 if (robotNodeNames.size() != 7)
206 ARMARX_WARNING <<
"createArmar3KBM should only be used with all 7 joints";
209 if (jointValueAverages.size() != robotNodeNames.size())
211 ARMARX_INFO <<
"robotNodeNames: " << robotNodeNames.size();
212 ARMARX_INFO <<
"jointValueAverages: " << jointValueAverages.size();
213 ARMARX_ERROR <<
"jointValueAverages should have the same size as robotNodeNames";
216 if (spreadAnglesSequence.size() != robotNodeNames.size())
218 ARMARX_INFO <<
"robotNodeNames: " << robotNodeNames.size();
219 ARMARX_INFO <<
"spreadAngles: " << spreadAnglesSequence.size();
220 ARMARX_ERROR <<
"spreadAnglesSequence should have the same size as robotNodeNames";
226 if (kbms.find(name) != kbms.end())
228 ARMARX_ERROR <<
"a KBM with the name '" << name <<
"' already exists";
235 Eigen::Map<const memoryx::KBM::Vector> spreadAngles(spreadAnglesSequence.data(),
236 spreadAnglesSequence.size());
242 std::time_t now = std::time(0);
243 std::tm* date = std::localtime(&now);
244 char when[256] = {0};
245 std::strftime(when,
sizeof(when),
"%Y-%m-%d-%H-%M-%S", date);
246 std::string baseFilename =
"data/evaluation/" + std::string(when) +
"-" + name;
248 std::ofstream metaFile(baseFilename +
"-create.txt", std::ios_base::app);
249 Eigen::Map<const memoryx::KBM::Vector> _jointValueAverages(jointValueAverages.data(),
250 jointValueAverages.size());
252 if (metaFile.is_open())
254 metaFile <<
"kbm name: " << name << std::endl;
255 metaFile <<
"joint offsets: " << _jointValueAverages << std::endl;
256 metaFile <<
"spread angles: " << spreadAngles << std::endl;
264 VirtualRobot::RobotImporterFactoryPtr importer =
265 VirtualRobot::RobotImporterFactory::fromFileExtension(
"xml", NULL);
266 std::string filename(
"robots/ArmarIII/ArmarIII.xml");
267 VirtualRobot::RuntimeEnvironment::getDataFileAbsolute(filename);
269 importer->loadFromFile(filename, VirtualRobot::RobotIO::eStructure);
273 ARMARX_ERROR <<
"the ArmarIII.xml file could not be loaded";
282 VirtualRobot::RobotNodeSetPtr nodeSet = VirtualRobot::RobotNodeSet::createRobotNodeSet(
283 robot,
"ToolUseRightArm", robotNodeNames,
"Right Arm Base", tcpName,
true);
295 VirtualRobot::KinematicChainPtr chain;
297 chain.reset(
new VirtualRobot::KinematicChain(
"ToolUseRightArmChain",
299 nodeSet->getAllRobotNodes(),
300 robot->getRobotNode(tcpName)));
314 << chain->getTCP()->getGlobalPose();
316 Ice::FloatSeq jointValues;
318 for (
auto& value : jointValueAverages)
320 jointValues.push_back(value);
323 chain->setJointValues(jointValues);
325 <<
" is at: " << chain->getNode(0)->getJointValue();
327 << chain->getTCP()->getGlobalPose();
329 VirtualRobot::RobotNodePtr FoR = chain->getKinematicRoot();
337 << FoR->getGlobalPose();
339 unsigned int nDoF = chain->getSize();
340 ARMARX_IMPORTANT <<
"degrees of freedom of the VirtualRobot's kinematic chain: " << nDoF;
346 chain, FoR, spreadAngles, useOrientation));
348 createdFromVirtualRobot[name] =
true;
349 ARMARX_INFO <<
"created a KBM with the name '" << name <<
"'";
354 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
355 const std::vector<memoryx::KBM::Real>& positionSequence,
357 Ice::Float threshold,
358 const Ice::Current&
c)
370 if (createdFromVirtualRobot[name])
373 <<
" was created from a VirtualRobot, it does not support batch learning";
380 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
382 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
384 if (proprioception.cols() != position.cols())
386 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
399 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
400 const std::vector<memoryx::KBM::Real>& positionSequence,
401 Ice::Float learningRate,
402 const Ice::Current&
c)
414 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
416 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
418 if (proprioception.cols() != position.cols())
420 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
424 if (createdFromVirtualRobot[name])
430 <<
"reversing proprioception order because KBM was created from VirtualRobot";
431 kbm->online(proprioception.colwise().reverse(), position, learningRate);
437 kbm->online(proprioception, position, learningRate);
443 const std::string& name,
444 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
445 const std::vector<memoryx::KBM::Real>& positionSequence,
446 Ice::Float learningRate,
447 const std::vector<memoryx::KBM::Real>& evaluationProprioceptionSequence,
448 const std::vector<memoryx::KBM::Real>& evaluationPositionSequence,
449 const Ice::Current&
c)
461 Eigen::Map<const memoryx::KBM::Matrix> _proprioception =
463 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
465 Eigen::Map<const memoryx::KBM::Matrix> _evaluationProprioception =
467 Eigen::Map<const memoryx::KBM::Matrix> evaluationPosition =
470 if (_proprioception.cols() != position.cols())
472 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
476 if (_evaluationProprioception.cols() != evaluationPosition.cols())
478 ARMARX_ERROR <<
"evaluation proprioception and evaluation position contain different "
486 if (createdFromVirtualRobot[name])
492 <<
"reversing proprioception order because KBM was created from VirtualRobot";
493 proprioception = _proprioception.colwise().reverse();
494 evaluationProprioception = _evaluationProprioception.colwise().reverse();
498 proprioception = _proprioception;
499 evaluationProprioception = _evaluationProprioception;
503 ARMARX_IMPORTANT <<
"evaluation samples: " << evaluationProprioception.cols();
509 std::time_t now = std::time(0);
510 std::tm* date = std::localtime(&now);
511 char when[256] = {0};
512 std::strftime(when,
sizeof(when),
"%Y-%m-%d-%H-%M-%S", date);
513 std::string baseFilename =
"data/evaluation/" + std::string(when) +
"-" + name;
515 std::ofstream metaFile(baseFilename +
"-meta.txt", std::ios_base::app);
516 std::string evaluationFilename(baseFilename +
"-evaluation.txt");
517 std::ofstream evaluationFile(evaluationFilename, std::ios_base::app);
518 std::string trainingProprioceptionsFilename(baseFilename +
"-training-proprioceptions.txt");
519 std::ofstream trainingProprioceptionsFile(trainingProprioceptionsFilename,
521 std::string trainingPositionsFilename(baseFilename +
"-training-positions.txt");
522 std::ofstream trainingPositionsFile(trainingPositionsFilename, std::ios_base::app);
523 std::string testProprioceptionsFilename(baseFilename +
"-test-proprioceptions.txt");
524 std::ofstream testProprioceptionsFile(testProprioceptionsFilename, std::ios_base::app);
525 std::string testPositionsFilename(baseFilename +
"-test-positions.txt");
526 std::ofstream testPositionsFile(testPositionsFilename, std::ios_base::app);
528 if (metaFile.is_open())
530 metaFile <<
"kbm name: " << name << std::endl;
531 metaFile <<
"learning rate: " << learningRate << std::endl;
532 metaFile <<
"degress of freedom: " << kbm->getNDoF() << std::endl;
533 metaFile <<
"dimensions: " << kbm->getNDim() << std::endl;
534 metaFile <<
"training samples: " << proprioception.cols() << std::endl;
535 metaFile <<
"test samples: " << evaluationProprioception.cols() << std::endl;
536 metaFile <<
"evaluation columns: mean, std, median, iqr, max" << std::endl;
541 if (!trainingProprioceptionsFile.is_open())
543 ARMARX_ERROR <<
"file " << trainingProprioceptionsFilename
544 <<
" could not be opened / created";
547 if (!trainingPositionsFile.is_open())
550 <<
" could not be opened / created";
553 if (!testProprioceptionsFile.is_open())
556 <<
" could not be opened / created";
559 if (!testPositionsFile.is_open())
561 ARMARX_ERROR <<
"file " << testPositionsFilename <<
" could not be opened / created";
564 trainingProprioceptionsFile << proprioception.transpose() << std::endl;
565 trainingPositionsFile << position.transpose() << std::endl;
566 testProprioceptionsFile << evaluationProprioception.transpose() << std::endl;
567 testPositionsFile << evaluationPosition.transpose() << std::endl;
569 trainingProprioceptionsFile.close();
570 trainingPositionsFile.close();
571 testProprioceptionsFile.close();
572 testPositionsFile.close();
577 if (!evaluationFile.is_open())
579 ARMARX_ERROR <<
"file " << evaluationFilename <<
" could not be opened / created";
583 kbm->getErrors(evaluationProprioception, evaluationPosition);
585 evaluationFile << errors.
Mean <<
", " << errors.
STD <<
", " << errors.
Median <<
", "
586 << errors.
IQR <<
", " << errors.
Max << std::endl;
588 for (
int i = 0; i < proprioception.cols(); i++)
590 kbm->online(proprioception.col(i), position.col(i), learningRate);
594 errors = kbm->getErrors(evaluationProprioception, evaluationPosition);
595 ARMARX_IMPORTANT <<
"online learning error after step " << (i + 1) <<
": " << errors;
596 evaluationFile << errors.
Mean <<
", " << errors.
STD <<
", " << errors.
Median <<
", "
597 << errors.
IQR <<
", " << errors.
Max << std::endl;
600 evaluationFile.close();
603 std::vector<memoryx::KBM::Real>
605 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
606 const Ice::Current&
c)
612 return std::vector<memoryx::KBM::Real>();
615 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
618 int nDim = kbm->getNDim();
619 int nSamples = proprioception.cols();
620 std::vector<memoryx::KBM::Real> predictionSequence(nDim * nSamples);
621 Eigen::Map<memoryx::KBM::Matrix> prediction(predictionSequence.data(), nDim, nSamples);
623 if (createdFromVirtualRobot[name])
628 prediction = kbm->predict(proprioception.colwise().reverse());
632 prediction = kbm->predict(proprioception);
635 ARMARX_INFO <<
"KBM '" << name <<
"' predicted: " << prediction.transpose();
636 return predictionSequence;
641 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
642 const std::vector<memoryx::KBM::Real>& positionSequence,
643 const Ice::Current&
c)
655 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
657 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
659 if (proprioception.cols() != position.cols())
661 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
669 if (createdFromVirtualRobot[name])
674 errors = kbm->getErrors(proprioception.colwise().reverse(), position);
678 errors = kbm->getErrors(proprioception, position);
687 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
688 mapMatrix(nDoF, proprioceptionAccumulator);
689 Eigen::Map<const memoryx::KBM::Matrix> position =
mapMatrix(nDim, positionAccumulator);
691 ARMARX_VERBOSE <<
"proprioception samples: " << proprioception.cols();
695 << proprioception.rowwise().minCoeff().transpose();
697 << proprioception.rowwise().maxCoeff().transpose();
698 ARMARX_VERBOSE <<
"proprioception average: " << proprioception.rowwise().mean().transpose();
699 ARMARX_VERBOSE <<
"position minima: " << position.rowwise().minCoeff().transpose();
700 ARMARX_VERBOSE <<
"position maxima: " << position.rowwise().maxCoeff().transpose();
701 ARMARX_VERBOSE <<
"position average: " << position.rowwise().mean().transpose();
707 Eigen::Map<const memoryx::KBM::Matrix> rawJointValues =
708 mapMatrix(nDoF, rawJointValuesAccumulator);
710 ARMARX_VERBOSE <<
"raw jointValue samples: " << rawJointValues.cols();
712 std::vector<memoryx::KBM::Real> result(nDoF);
713 Eigen::Map<memoryx::KBM::Vector> averages(result.data(), nDoF);
714 averages = rawJointValues.rowwise().mean();
716 Ice::DoubleSeq resultFloat(result.begin(), result.end());
723 Eigen::Map<const memoryx::KBM::Matrix> proprioceptions =
724 mapMatrix(nDoF, proprioceptionAccumulator);
726 ARMARX_VERBOSE <<
"proprioception samples: " << proprioceptions.cols();
728 std::vector<memoryx::KBM::Real> result(nDoF);
729 Eigen::Map<memoryx::KBM::Vector> spreadAngles(result.data(), nDoF);
736 for (
int i = 0; i < nDoF; i++)
738 spreadAngles[i] = fmin(fabs(leftSpreadAngles[i]), fabs(rightSpreadAngles[i]));
743 Ice::DoubleSeq resultFloat(result.begin(), result.end());
749 const std::vector<memoryx::KBM::Real>& rawJointValuesAverages,
750 const Ice::Current&
c)
752 if (proprioceptionAccumulator.size() != 0)
754 ARMARX_ERROR <<
"proprioception accumulator should be empty, when using setting it "
755 "from raw joint accumulator";
758 if (rawJointValuesAccumulator.size() % rawJointValuesAverages.size() != 0)
760 ARMARX_ERROR <<
"rawJointValuesAverages size is incompatible to accumulator size";
763 ARMARX_INFO <<
"rawJointValuesAccumualtor: " << rawJointValuesAccumulator;
764 std::vector<memoryx::KBM::Real> proprioceptionsFromRawJointAccumulator;
767 for (
auto jointValue : rawJointValuesAccumulator)
769 if (i == rawJointValuesAverages.size())
774 float offset = rawJointValuesAverages[i];
780 proprioceptionsFromRawJointAccumulator.push_back(jointValue - offset);
783 ARMARX_INFO <<
"proprioceptionsFromRawJointAccumulator: "
784 << proprioceptionsFromRawJointAccumulator;
785 proprioceptionAccumulator = proprioceptionsFromRawJointAccumulator;
795 Eigen::Map<const memoryx::KBM::Matrix> positions =
mapMatrix(nDim, positionAccumulator);
796 minima = positions.rowwise().minCoeff();
797 maxima = positions.rowwise().maxCoeff();
804 Ice::Float learningRate,
805 const Ice::Current&
c)
807 online(name, proprioceptionAccumulator, positionAccumulator, learningRate,
c);
812 Ice::Float learningRate,
813 const Ice::Current&
c)
816 proprioceptionAccumulator,
819 evaluationProprioceptionAccumulator,
820 evaluationPositionAccumulator,
827 Ice::Float threshold,
828 const Ice::Current&
c)
830 batch(name, proprioceptionAccumulator, positionAccumulator, method, threshold,
c);
836 printErrors(name, proprioceptionAccumulator, positionAccumulator,
c);
842 predict(name, proprioceptionAccumulator,
c);
855 const Ice::Current&
c)
860 positionAccumulator.insert(positionAccumulator.end(), position.begin(), position.end());
867 const Ice::Current&
c)
872 proprioceptionAccumulator.insert(
873 proprioceptionAccumulator.end(), proprioception.begin(), proprioception.end());
880 const std::vector<memoryx::KBM::Real>& rawJointValuesSequence,
881 const Ice::Current&
c)
886 rawJointValuesAccumulator.insert(rawJointValuesAccumulator.end(),
887 rawJointValuesSequence.begin(),
888 rawJointValuesSequence.end());
895 const Ice::Current&
c)
900 evaluationPositionAccumulator.insert(
901 evaluationPositionAccumulator.end(), position.begin(), position.end());
908 const std::vector<memoryx::KBM::Real>& proprioception,
909 const Ice::Current&
c)
914 evaluationProprioceptionAccumulator.insert(evaluationProprioceptionAccumulator.end(),
915 proprioception.begin(),
916 proprioception.end());
921 std::vector<memoryx::KBM::Real>
923 const std::vector<memoryx::KBM::Real>& targetPosition,
924 const Ice::Current&
c)
934 return std::vector<memoryx::KBM::Real>();
937 Eigen::Map<const memoryx::KBM::Vector> target(
mapPosition(*kbm, targetPosition));
942 std::vector<memoryx::KBM::Real> result(kbm->getNDoF());
943 Eigen::Map<memoryx::KBM::Vector> solution(result.data(), kbm->getNDoF());
952 for (
unsigned int i = 0; i < solutions.size(); ++i)
959 if (createdFromVirtualRobot[name])
961 ARMARX_ERROR <<
"solveGlobalIK does not yet support KBMs created from Virtual Robot!";
967 std::vector<memoryx::KBM::Real>
969 const std::string& name,
970 const std::vector<memoryx::KBM::Real>& targetPosition,
971 const std::vector<memoryx::KBM::Real>& currentPosition,
972 const std::vector<memoryx::KBM::Real>& currentProprioception,
973 const std::vector<memoryx::KBM::Real>& lowerProprioceptionLimitsSequence,
974 const std::vector<memoryx::KBM::Real>& upperProprioceptionLimitsSequence,
975 const Ice::Current&
c)
985 return std::vector<memoryx::KBM::Real>();
988 Eigen::Map<const memoryx::KBM::Vector> target(
mapPosition(*kbm, targetPosition));
989 Eigen::Map<const memoryx::KBM::Vector> current(
mapPosition(*kbm, currentPosition));
990 Eigen::Map<const memoryx::KBM::Vector> proprioception(
992 Eigen::Map<const memoryx::KBM::Vector> lowerProprioceptionLimits(
994 Eigen::Map<const memoryx::KBM::Vector> upperProprioceptionLimits(
1000 if (minima.size() != target.size())
1002 ARMARX_ERROR <<
"minima and target have different size";
1003 return std::vector<memoryx::KBM::Real>();
1006 if (maxima.size() != target.size())
1009 ARMARX_ERROR <<
"maxima and target have different size";
1010 return std::vector<memoryx::KBM::Real>();
1013 for (
int i = 0; i < kbm->getNDim(); i++)
1015 if (target[i] < minima[i] - 90)
1017 ARMARX_ERROR <<
"target[" << i <<
"] = " << target[i] <<
" is smaller than minima "
1019 return std::vector<memoryx::KBM::Real>();
1022 if (target[i] > maxima[i] + 90)
1024 ARMARX_ERROR <<
"target[" << i <<
"] = " << target[i] <<
" is greater than maxima "
1026 return std::vector<memoryx::KBM::Real>();
1033 std::vector<memoryx::KBM::Real> result(kbm->getNDoF());
1034 Eigen::Map<memoryx::KBM::Vector> solution(result.data(), kbm->getNDoF());
1041 if (createdFromVirtualRobot[name])
1046 ARMARX_IMPORTANT <<
"reversing proprioception and limits order because KBM was created "
1047 "from VirtualRobot";
1051 proprioception.reverse(),
1052 lowerProprioceptionLimits.reverse(),
1053 upperProprioceptionLimits.reverse(),
1062 lowerProprioceptionLimits,
1063 upperProprioceptionLimits,
1067 if (createdFromVirtualRobot[name])
1073 solution = solution.colwise().reverse();
1098 return LO +
static_cast<float>(rand()) / (
static_cast<float>(RAND_MAX / (HI - LO)));
1106 float stepSizeFactor,
1115 if (positionDeltas.norm() > maxStepSize)
1117 positionDeltas *= maxStepSize / positionDeltas.norm();
1129#ifdef KBM_USE_DOUBLE_PRECISION
1146 if (lowerProprioceptionLimits.size() != upperProprioceptionLimits.size())
1151 int n = lowerProprioceptionLimits.size();
1154 for (
int i = 0; i < n; i++)
1156 float l = lowerProprioceptionLimits(i);
1157 float u = upperProprioceptionLimits(i);
1173 int n = solution.size();
1175 if (lowerProprioceptionLimits.size() != n)
1177 ARMARX_ERROR_S <<
"lower proprioception limits have wrong length: "
1178 << lowerProprioceptionLimits.size() <<
", should be " << n;
1181 if (upperProprioceptionLimits.size() != n)
1183 ARMARX_ERROR_S <<
"upper proprioception limits have wrong length: "
1184 << upperProprioceptionLimits.size() <<
", should be " << n;
1190 for (
int i = 0; i < n; i++)
1192 if ((solution(i) < lowerProprioceptionLimits(i)) ||
1193 (solution(i) > upperProprioceptionLimits(i)))
1204 Eigen::Map<memoryx::KBM::Vector>& solution,
1211 int n = solution.size();
1213 if (lowerProprioceptionLimits.size() != n)
1215 ARMARX_ERROR_S <<
"lower proprioception limits have wrong length: "
1216 << lowerProprioceptionLimits.size() <<
", should be " << n;
1219 if (upperProprioceptionLimits.size() != n)
1221 ARMARX_ERROR_S <<
"upper proprioception limits have wrong length: "
1222 << upperProprioceptionLimits.size() <<
", should be " << n;
1228 bool inLimits =
true;
1230 for (
int i = 0; i < n; i++)
1232 if (solution(i) < lowerProprioceptionLimits(i))
1234 solution(i) = lowerProprioceptionLimits(i);
1238 if (solution(i) > upperProprioceptionLimits(i))
1240 solution(i) = upperProprioceptionLimits(i);
1255 Eigen::Map<memoryx::KBM::Vector>& solution,
1258 float positionTolerance,
1260 bool requireImprovment,
1262 float stepSizeFactor,
1266 float bestDistance = FLT_MAX;
1267 bool inLimits =
false;
1269 std::vector<memoryx::KBM::Real> newSolutionSequence(kbm.
getNDoF());
1270 Eigen::Map<memoryx::KBM::Vector> newSolution(newSolutionSequence.data(), kbm.
getNDoF());
1272 for (
int i = 0; i < maxSolves; i++)
1278 startProprioception = currentProprioception;
1282 startProprioception =
1287 <<
" proprioception: " << startProprioception.transpose();
1297 startProprioception,
1319 float distance = (targetPosition - testPosition).
norm();
1327 newSolution, lowerProprioceptionLimits, upperProprioceptionLimits);
1333 <<
"solution was not within limits, but enforced limits so now it is";
1339 testPosition = kbm.
predict(newSolution);
1349 newSolution, lowerProprioceptionLimits, upperProprioceptionLimits);
1352 if (applyLimits && !currentInLimits)
1356 ARMARX_ERROR_S <<
"lower proprioception limits: " << lowerProprioceptionLimits;
1357 ARMARX_ERROR_S <<
"upper proprioception limits: " << upperProprioceptionLimits;
1360 if (inLimits && !currentInLimits)
1363 <<
"ignoring solution because we already found one that is within the limits";
1368 float distance = (targetPosition - newPosition).
norm();
1373 if ((
distance < bestDistance) || (currentInLimits && !inLimits))
1376 inLimits = currentInLimits;
1377 solution = newSolution;
1380 if (inLimits && (bestDistance < positionTolerance))
1389 ARMARX_IMPORTANT_S <<
"final distance: " << bestDistance <<
", in limits: " << inLimits;
1391 if (bestDistance < positionTolerance)
1406 Eigen::Map<memoryx::KBM::Vector>& solution,
1407 float positionTolerance,
1409 bool requireImprovment,
1411 float stepSizeFactor,
1415 assert(targetPosition.size() == kbm.
getNDim());
1416 assert(currentPosition.size() == kbm.
getNDim());
1417 assert(currentProprioception.size() == kbm.
getNDoF());
1418 assert(solution.size() == kbm.
getNDoF());
1423 solution = currentProprioception;
1428 float bestDistance = (targetPosition - currentPosition).
norm();
1433 if (bestDistance <= positionTolerance)
1453 for (
int step = 0; step < maxSteps; ++step)
1461 simulatedProprioception,
1468 simulatedProprioception +=
deltas;
1473 predictedPosition = kbm.
predict(simulatedProprioception);
1479 float distance = (targetPosition - predictedPosition).
norm();
1484 solution = simulatedProprioception;
1491 if (requireImprovment && (
distance >= bestDistance))
1502 solution = simulatedProprioception;
1509 if (
deltas.norm() < minimumDelta)
1521 std::vector<std::string> kbmKeys;
1523 for (
auto it : kbms)
1525 kbmKeys.push_back(it.first);
1534 positionAccumulator.clear();
1535 proprioceptionAccumulator.clear();
1536 rawJointValuesAccumulator.clear();
1541 const std::string& nodeSetName,
1542 const std::string& referenceFrameName,
1543 const std::string& robotName,
1544 const Ice::Current&
c)
1550 auto kbmSeg = this->longtermMemoryPrx->getKBMSegment();
1559 kbmSeg->addEntity(kbmData);
1564 ARMARX_WARNING <<
"Could not store KBM! No KBM segment in longterm memory!";
1572 const std::string& nodeSetName,
1573 const std::string& referenceFrameName,
1574 const std::string& robotName,
1575 const Ice::Current&
c)
1578 auto kbmSeg = this->longtermMemoryPrx->getKBMSegment();
1579 std::string kbmEntityName = robotName +
"_" + referenceFrameName +
"_" + nodeSetName;
1581 if (kbmSeg && kbmSeg->hasEntityByName(kbmEntityName))
1583 auto entity = kbmSeg->getEntityByName(kbmEntityName);
1590 int nDoF = robot->getRobotNodeSet(nodeSetName)->getSize();
1593 armarx::MatrixVariantPtr::dynamicCast(kbmData->getControlNet());
1598 Eigen::VectorXd::Zero(nDoF),
1599 Eigen::VectorXd::Constant(nDoF,
M_PI / 4.0f),
1600 controlNet->toEigen().cast<
double>());
1601 createdFromVirtualRobot[kbmName] =
1606 ARMARX_WARNING <<
"Could not restore KBM entity specified by: " << kbmEntityName;
1615 const std::string& referenceFrameName,
1616 const std::string& robotName,
1617 const Ice::Current&
c)
1619 std::string kbmEntityName = robotName +
"_" + referenceFrameName +
"_" + nodeSetName;
1621 return (this->longtermMemoryPrx->getKBMSegment() &&
1622 this->longtermMemoryPrx->getKBMSegment()->hasEntityByName(kbmEntityName));
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
void onlineAccumulatorVerbose(const std::string &name, Ice::Float learningRate, const Ice::Current &c=Ice::emptyCurrent) override
onlineAccumulatorVerbose same as onlineAccumulator, but evaluates after each learning step
void predictAccumulator(const std::string &name, const Ice::Current &c=Ice::emptyCurrent) override
the same as predict but with the data from the accumulator, however the results are currently just pr...
void onInitComponent() override
Eigen::Map< const memoryx::KBM::Matrix > mapPositions(const memoryx::KBM::Models::KBM &kbm, const std::vector< memoryx::KBM::Real > &position)
mapPositions converts the position sequence into an Eigen::Map of a Matrix
void accumulateEvaluationPositions(const std::vector< memoryx::KBM::Real > &positionSequence, const Ice::Current &c=Ice::emptyCurrent) override
accumulates the given position in the evaluation accumulator
void setProprioceptionAccumulatorFromRawJointAccumulator(const std::vector< memoryx::KBM::Real > &rawJointValuesAverages, const Ice::Current &c=Ice::emptyCurrent) override
setProprioceptionAccumulatorFromRawJointAccumulator updates the proprioception accumulator
void printAccumulatorStatistics(int nDim, int nDoF, const Ice::Current &c=Ice::emptyCurrent) override
printAccumulatorStatistics prints information about the values in the accumulators
void accumulateEvaluationProprioceptions(const std::vector< memoryx::KBM::Real > &proprioceptions, const Ice::Current &c=Ice::emptyCurrent) override
accumualteProprioceptions accumulates proprioceptions in the evaluate accumulator
void onDisconnectComponent() override
Eigen::Map< const memoryx::KBM::Vector > mapPosition(const memoryx::KBM::Models::KBM &kbm, const std::vector< memoryx::KBM::Real > &position)
mapPosition converts the position sequence into an Eigen::Map of a Vector
void onlineVerbose(const std::string &name, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const std::vector< memoryx::KBM::Real > &positionSequence, Ice::Float learningRate, const std::vector< memoryx::KBM::Real > &evaluationProprioceptionSequence, const std::vector< memoryx::KBM::Real > &evaluationPositionSequence, const Ice::Current &c=Ice::emptyCurrent) override
same as online, but evaluates after each learning iteration
std::vector< memoryx::KBM::Real > solveGlobalIK(const std::string &name, const std::vector< memoryx::KBM::Real > &targetPosition, const Ice::Current &c=Ice::emptyCurrent) override
solveGlobalIK solves the global inverse kinematics for the given position
std::vector< memoryx::KBM::Real > solveDifferentialIK(const std::string &name, const std::vector< memoryx::KBM::Real > &targetPosition, const std::vector< memoryx::KBM::Real > ¤tPosition, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const std::vector< memoryx::KBM::Real > &lowerProprioceptionLimitsSequence, const std::vector< memoryx::KBM::Real > &upperProprioceptionLimitsSequence, const Ice::Current &c=Ice::emptyCurrent) override
solveDifferentialIK solves the differential inverse kinematics for the given position
bool isInMemory(const std::string &nodeSetName, const std::string &referenceFrameName, const std::string &robotName, const Ice::Current &c) override
Ice::StringSeq kbmNames(const Ice::Current &c) override
Returns the names of the existing KBMs.
void onlineAccumulator(const std::string &name, Ice::Float learningRate, const Ice::Current &c=Ice::emptyCurrent) override
onlineAccumulator calls online after transforming the raw joint accumulator to proprioceptions
Ice::DoubleSeq getRawJointValuesAverages(int nDoF, const Ice::Current &c=Ice::emptyCurrent) override
getRawJointValuesAverages calculates the average raw joint values for each joint from the data stored...
void createArmar3KBM(const std::string &name, const Ice::StringSeq &robotNodeNames, const std::vector< memoryx::KBM::Real > &jointValueAverages, const std::vector< memoryx::KBM::Real > &spreadAnglesSequence, const std::string &tcpName, bool useOrientation, const Ice::Current &c=Ice::emptyCurrent) override
createArmar3KBM creates a KBM from a VirtualRobot model
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void clearAccumulators(const Ice::Current &c) override
Clears the accumulators.
std::vector< memoryx::KBM::Real > predict(const std::string &name, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const Ice::Current &c=Ice::emptyCurrent) override
predict the position for n samples of proprioception (forward kinematics)
void printErrors(const std::string &name, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const std::vector< memoryx::KBM::Real > &positionSequence, const Ice::Current &c=Ice::emptyCurrent) override
calls getErrors on the KBM and prints the result
void accumulateProprioceptions(const std::vector< memoryx::KBM::Real > &proprioceptions, const Ice::Current &c=Ice::emptyCurrent) override
accumualteProprioceptions accumulates proprioceptions
Ice::DoubleSeq getSpreadAngles(int nDoF, const Ice::Current &c=Ice::emptyCurrent) override
getSpreadAngles returns the spreadAngles calculated using the data in the proprioceptionAccumulator
void online(const std::string &name, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const std::vector< memoryx::KBM::Real > &positionSequence, Ice::Float learningRate, const Ice::Current &c=Ice::emptyCurrent) override
online learning of n training samples
void accumulateRawJointValues(const std::vector< memoryx::KBM::Real > &rawJointValuesSequence, const Ice::Current &c=Ice::emptyCurrent) override
accumualteRawJointValues accumulates raw joint values that will be transformed to proprioceptions lat...
void createKBM(const std::string &name, Ice::Int nDoF, Ice::Int dim, Ice::Float spreadAngle, const Ice::Current &c=Ice::emptyCurrent) override
createKBM creates a new KBM and makes it available under the given name
void batchAccumulator(const std::string &name, Ice::Int method, Ice::Float threshold, const Ice::Current &c=Ice::emptyCurrent) override
the same as batch but with the data from the accumulator
memoryx::KBM::Models::KBM_ptr getKBM(const std::string &name)
returns a pointer to the KBM with the given name if it exists or a nullptr if it doesn't
void onConnectComponent() override
void storeToMemory(const std::string &, const std::string &, const std::string &, const std::string &, const Ice::Current &) override
void printErrorsAccumulator(const std::string &name, const Ice::Current &c=Ice::emptyCurrent) override
the same as printErrors but with the data from the accumulator
void restoreFromMemory(const std::string &, const std::string &, const std::string &, const std::string &, const Ice::Current &) override
Eigen::Map< const memoryx::KBM::Matrix > mapProprioceptions(const memoryx::KBM::Models::KBM &kbm, const std::vector< memoryx::KBM::Real > &proprioception)
mapProprioceptions converts the proprioception sequence into an Eigen::Map of a Matrix
void accumulatePositions(const std::vector< memoryx::KBM::Real > &positionSequence, const Ice::Current &c=Ice::emptyCurrent) override
accumulate adds the given position to the accumulator to use it later
Eigen::Map< const memoryx::KBM::Vector > mapProprioception(const memoryx::KBM::Models::KBM &kbm, const std::vector< memoryx::KBM::Real > &proprioception)
mapProprioception converts the proprioception sequence into an Eigen::Map of a Vector
void batch(const std::string &name, const std::vector< memoryx::KBM::Real > &proprioceptionSequence, const std::vector< memoryx::KBM::Real > &positionSequence, Ice::Int method, Ice::Float threshold, const Ice::Current &c=Ice::emptyCurrent) override
batch learning of n training samples
void onExitComponent() override
void setPositionLimits(int nDim, const Ice::Current &c=Ice::emptyCurrent) override
setPositionLimits sets the position limits using the data in the position accumulator
Eigen::Map< const memoryx::KBM::Matrix > mapMatrix(int rows, const std::vector< memoryx::KBM::Real > &data)
maps a sequence to an Eigen::Map
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
VirtualRobot::RobotPtr createLocalClone()
Clones the structure of this remote robot to a local instance.
The Kinematic B\'ezier Maps.
Matrix predict(const Matrix &proprioception, int dim=0) const
Predicts a value of the FK given a set of joint angles.
Matrix getJacobian(const Vector &proprioception) const
Computes the partial derivative with respect to a configuration.
Optimization
Enum for the preferred optimization method during batch learning.
static KBM_ptr createKBM(int nDoF, int dim, const Vector ¢er, const Vector &spreadAngles, const Matrix &controlNet)
Factory methods.
static KBM_ptr createFromVirtualRobot(VirtualRobot::KinematicChainPtr chain, VirtualRobot::SceneObjectPtr FoR, const Vector &spreadAngles, bool useOrientation=false)
int getNDoF() const
Get the number of degrees of freedom (DoF).
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_IMPORTANT_S
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::shared_ptr< class Robot > RobotPtr
bool applyProprioceptionLimits(Eigen::Map< memoryx::KBM::Vector > &solution, const memoryx::KBM::Vector &lowerProprioceptionLimits, const memoryx::KBM::Vector &upperProprioceptionLimits)
apply limits to solution and return true, if solution has been changed = solution was not in limits
bool solveMany(const memoryx::KBM::Models::KBM &kbm, const memoryx::KBM::Vector &targetPosition, const memoryx::KBM::Vector ¤tPosition, const memoryx::KBM::Vector ¤tProprioception, const memoryx::KBM::Vector &lowerProprioceptionLimits, const memoryx::KBM::Vector &upperProprioceptionLimits, Eigen::Map< memoryx::KBM::Vector > &solution, bool applyLimits=true, int maxSolves=25, float positionTolerance=5.0f, float minimumDelta=0.0f, bool requireImprovment=false, int maxSteps=50, float stepSizeFactor=0.2f, float maxStepSize=FLT_MAX)
KBMDifferentialIK::solveMany runs solve many times.
bool solve(const memoryx::KBM::Models::KBM &kbm, const memoryx::KBM::Vector &targetPosition, const memoryx::KBM::Vector ¤tPostion, const memoryx::KBM::Vector ¤tProprioception, Eigen::Map< memoryx::KBM::Vector > &solution, float positionTolerance=5.0f, float minimumDelta=0.0f, bool requireImprovment=false, int maxSteps=50, float stepSizeFactor=0.2f, float maxStepSize=FLT_MAX)
solves the inverse kinematics
bool checkProprioceptionLimits(const memoryx::KBM::Vector &solution, const memoryx::KBM::Vector &lowerProprioceptionLimits, const memoryx::KBM::Vector &upperProprioceptionLimits)
check if solution is within the limits
memoryx::KBM::Vector calculateJointDeltas(const memoryx::KBM::Models::KBM &kbm, const memoryx::KBM::Vector &target, const memoryx::KBM::Vector &position, const memoryx::KBM::Vector &proprioception, float stepSizeFactor, float maxStepSize)
calculateJointDeltas is in internal function called by solve
float randomFloat(float LO, float HI)
randomFloat creates a random float between LO and HI
memoryx::KBM::Vector randomProprioception(const memoryx::KBM::Vector &lowerProprioceptionLimits, const memoryx::KBM::Vector &upperProprioceptionLimits)
Creates a vector of random values between the limits.
This file offers overloads of toIce() and fromIce() functions for STL container types.
armarx::MatrixDouble MatrixVariant
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
armarx::MatrixDoublePtr MatrixVariantPtr
std::vector< Solution > SolutionSet
Return type of the global inverse kinematics solvers.
void solveGlobalIK(unsigned int recursion, int side, SolutionSet &solutionSet, Models::KBM_ptr kbm, const Vector &lower, const Vector &upper, Real resolution, Vector spreadAngles, Vector center)
std::shared_ptr< KBM > KBM_ptr
IceInternal::Handle< KBMData > KBMDataPtr
Eigen::MatrixXd pseudoInverse(const Eigen::MatrixXd &a, double epsilon=std::numeric_limits< double >::epsilon())
double norm(const Point &a)
double distance(const Point &a, const Point &b)
Return type of the evaluation (KBM::getErrors()) function providing insight in the statistics of the ...
Real Median
Median of the error.
Real STD
Standard deviation.
Real IQR
Inerquartile range (50% of all errors): .