32#include <VirtualRobot/Import/RobotImporterFactory.h>
33#include <VirtualRobot/KinematicChain.h>
34#include <VirtualRobot/MathTools.h>
35#include <VirtualRobot/Nodes/RobotNode.h>
36#include <VirtualRobot/Robot.h>
37#include <VirtualRobot/RuntimeEnvironment.h>
39#include <RobotAPI/interface/core/RobotState.h>
88 Eigen::Map<const memoryx::KBM::Vector>
90 const std::vector<memoryx::KBM::Real>& position)
92 VR_ASSERT_MESSAGE((
int)(position.size()) == kbm.
getNDim(),
93 "position size doesn't match KBM dimensions");
94 return Eigen::Map<const memoryx::KBM::Vector>(position.data(), kbm.
getNDim());
97 Eigen::Map<const memoryx::KBM::Vector>
99 const std::vector<memoryx::KBM::Real>& proprioception)
101 VR_ASSERT_MESSAGE((
int)(proprioception.size()) == kbm.
getNDoF(),
102 "proprioception size doesn't match KBM DoF");
103 return Eigen::Map<const memoryx::KBM::Vector>(proprioception.data(), kbm.
getNDoF());
106 Eigen::Map<const memoryx::KBM::Matrix>
108 const std::vector<memoryx::KBM::Real>& position)
112 if (position.size() % nDim != 0)
120 Eigen::Map<const memoryx::KBM::Matrix>
122 const std::vector<memoryx::KBM::Real>& proprioception)
126 if (proprioception.size() % nDoF != 0)
134 Eigen::Map<const memoryx::KBM::Matrix>
137 if (
data.size() % rows != 0)
142 VR_ASSERT(
data.size() % rows == 0);
143 int cols =
data.size() / rows;
144 return Eigen::Map<const memoryx::KBM::Matrix>(
data.data(), rows, cols);
150 auto it = kbms.find(name);
152 if (it == kbms.end())
154 ARMARX_WARNING <<
"a KBM with the name '" << name <<
"' does not exist";
173 Ice::Float spreadAngle,
174 const Ice::Current&
c)
179 if (kbms.find(name) != kbms.end())
181 ARMARX_ERROR <<
"a KBM with the name '" << name <<
"' already exists";
190 createdFromVirtualRobot[name] =
false;
191 ARMARX_INFO <<
"created a KBM with the name '" << name <<
"'";
196 const Ice::StringSeq& robotNodeNames,
197 const std::vector<memoryx::KBM::Real>& jointValueAverages,
198 const std::vector<memoryx::KBM::Real>& spreadAnglesSequence,
199 const std::string& tcpName,
201 const Ice::Current&
c)
206 if (robotNodeNames.size() != 7)
208 ARMARX_WARNING <<
"createArmar3KBM should only be used with all 7 joints";
211 if (jointValueAverages.size() != robotNodeNames.size())
213 ARMARX_INFO <<
"robotNodeNames: " << robotNodeNames.size();
214 ARMARX_INFO <<
"jointValueAverages: " << jointValueAverages.size();
215 ARMARX_ERROR <<
"jointValueAverages should have the same size as robotNodeNames";
218 if (spreadAnglesSequence.size() != robotNodeNames.size())
220 ARMARX_INFO <<
"robotNodeNames: " << robotNodeNames.size();
221 ARMARX_INFO <<
"spreadAngles: " << spreadAnglesSequence.size();
222 ARMARX_ERROR <<
"spreadAnglesSequence should have the same size as robotNodeNames";
228 if (kbms.find(name) != kbms.end())
230 ARMARX_ERROR <<
"a KBM with the name '" << name <<
"' already exists";
237 Eigen::Map<const memoryx::KBM::Vector> spreadAngles(spreadAnglesSequence.data(),
238 spreadAnglesSequence.size());
244 std::time_t now = std::time(0);
245 std::tm* date = std::localtime(&now);
246 char when[256] = {0};
247 std::strftime(when,
sizeof(when),
"%Y-%m-%d-%H-%M-%S", date);
248 std::string baseFilename =
"data/evaluation/" + std::string(when) +
"-" + name;
250 std::ofstream metaFile(baseFilename +
"-create.txt", std::ios_base::app);
251 Eigen::Map<const memoryx::KBM::Vector> _jointValueAverages(jointValueAverages.data(),
252 jointValueAverages.size());
254 if (metaFile.is_open())
256 metaFile <<
"kbm name: " << name << std::endl;
257 metaFile <<
"joint offsets: " << _jointValueAverages << std::endl;
258 metaFile <<
"spread angles: " << spreadAngles << std::endl;
266 VirtualRobot::RobotImporterFactoryPtr importer =
267 VirtualRobot::RobotImporterFactory::fromFileExtension(
"xml", NULL);
268 std::string filename(
"robots/ArmarIII/ArmarIII.xml");
269 VirtualRobot::RuntimeEnvironment::getDataFileAbsolute(filename);
271 importer->loadFromFile(filename, VirtualRobot::RobotIO::eStructure);
275 ARMARX_ERROR <<
"the ArmarIII.xml file could not be loaded";
284 VirtualRobot::RobotNodeSetPtr nodeSet = VirtualRobot::RobotNodeSet::createRobotNodeSet(
285 robot,
"ToolUseRightArm", robotNodeNames,
"Right Arm Base", tcpName,
true);
297 VirtualRobot::KinematicChainPtr chain;
299 chain.reset(
new VirtualRobot::KinematicChain(
"ToolUseRightArmChain",
301 nodeSet->getAllRobotNodes(),
302 robot->getRobotNode(tcpName)));
316 << chain->getTCP()->getGlobalPose();
318 Ice::FloatSeq jointValues;
320 for (
auto& value : jointValueAverages)
322 jointValues.push_back(value);
325 chain->setJointValues(jointValues);
327 <<
" is at: " << chain->getNode(0)->getJointValue();
329 << chain->getTCP()->getGlobalPose();
331 VirtualRobot::RobotNodePtr FoR = chain->getKinematicRoot();
339 << FoR->getGlobalPose();
341 unsigned int nDoF = chain->getSize();
342 ARMARX_IMPORTANT <<
"degrees of freedom of the VirtualRobot's kinematic chain: " << nDoF;
348 chain, FoR, spreadAngles, useOrientation));
350 createdFromVirtualRobot[name] =
true;
351 ARMARX_INFO <<
"created a KBM with the name '" << name <<
"'";
356 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
357 const std::vector<memoryx::KBM::Real>& positionSequence,
359 Ice::Float threshold,
360 const Ice::Current&
c)
372 if (createdFromVirtualRobot[name])
375 <<
" was created from a VirtualRobot, it does not support batch learning";
382 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
384 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
386 if (proprioception.cols() != position.cols())
388 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
401 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
402 const std::vector<memoryx::KBM::Real>& positionSequence,
403 Ice::Float learningRate,
404 const Ice::Current&
c)
416 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
418 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
420 if (proprioception.cols() != position.cols())
422 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
426 if (createdFromVirtualRobot[name])
432 <<
"reversing proprioception order because KBM was created from VirtualRobot";
433 kbm->online(proprioception.colwise().reverse(), position, learningRate);
439 kbm->online(proprioception, position, learningRate);
445 const std::string& name,
446 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
447 const std::vector<memoryx::KBM::Real>& positionSequence,
448 Ice::Float learningRate,
449 const std::vector<memoryx::KBM::Real>& evaluationProprioceptionSequence,
450 const std::vector<memoryx::KBM::Real>& evaluationPositionSequence,
451 const Ice::Current&
c)
463 Eigen::Map<const memoryx::KBM::Matrix> _proprioception =
465 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
467 Eigen::Map<const memoryx::KBM::Matrix> _evaluationProprioception =
469 Eigen::Map<const memoryx::KBM::Matrix> evaluationPosition =
472 if (_proprioception.cols() != position.cols())
474 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
478 if (_evaluationProprioception.cols() != evaluationPosition.cols())
480 ARMARX_ERROR <<
"evaluation proprioception and evaluation position contain different "
488 if (createdFromVirtualRobot[name])
494 <<
"reversing proprioception order because KBM was created from VirtualRobot";
495 proprioception = _proprioception.colwise().reverse();
496 evaluationProprioception = _evaluationProprioception.colwise().reverse();
500 proprioception = _proprioception;
501 evaluationProprioception = _evaluationProprioception;
505 ARMARX_IMPORTANT <<
"evaluation samples: " << evaluationProprioception.cols();
511 std::time_t now = std::time(0);
512 std::tm* date = std::localtime(&now);
513 char when[256] = {0};
514 std::strftime(when,
sizeof(when),
"%Y-%m-%d-%H-%M-%S", date);
515 std::string baseFilename =
"data/evaluation/" + std::string(when) +
"-" + name;
517 std::ofstream metaFile(baseFilename +
"-meta.txt", std::ios_base::app);
518 std::string evaluationFilename(baseFilename +
"-evaluation.txt");
519 std::ofstream evaluationFile(evaluationFilename, std::ios_base::app);
520 std::string trainingProprioceptionsFilename(baseFilename +
"-training-proprioceptions.txt");
521 std::ofstream trainingProprioceptionsFile(trainingProprioceptionsFilename,
523 std::string trainingPositionsFilename(baseFilename +
"-training-positions.txt");
524 std::ofstream trainingPositionsFile(trainingPositionsFilename, std::ios_base::app);
525 std::string testProprioceptionsFilename(baseFilename +
"-test-proprioceptions.txt");
526 std::ofstream testProprioceptionsFile(testProprioceptionsFilename, std::ios_base::app);
527 std::string testPositionsFilename(baseFilename +
"-test-positions.txt");
528 std::ofstream testPositionsFile(testPositionsFilename, std::ios_base::app);
530 if (metaFile.is_open())
532 metaFile <<
"kbm name: " << name << std::endl;
533 metaFile <<
"learning rate: " << learningRate << std::endl;
534 metaFile <<
"degress of freedom: " << kbm->getNDoF() << std::endl;
535 metaFile <<
"dimensions: " << kbm->getNDim() << std::endl;
536 metaFile <<
"training samples: " << proprioception.cols() << std::endl;
537 metaFile <<
"test samples: " << evaluationProprioception.cols() << std::endl;
538 metaFile <<
"evaluation columns: mean, std, median, iqr, max" << std::endl;
543 if (!trainingProprioceptionsFile.is_open())
545 ARMARX_ERROR <<
"file " << trainingProprioceptionsFilename
546 <<
" could not be opened / created";
549 if (!trainingPositionsFile.is_open())
552 <<
" could not be opened / created";
555 if (!testProprioceptionsFile.is_open())
558 <<
" could not be opened / created";
561 if (!testPositionsFile.is_open())
563 ARMARX_ERROR <<
"file " << testPositionsFilename <<
" could not be opened / created";
566 trainingProprioceptionsFile << proprioception.transpose() << std::endl;
567 trainingPositionsFile << position.transpose() << std::endl;
568 testProprioceptionsFile << evaluationProprioception.transpose() << std::endl;
569 testPositionsFile << evaluationPosition.transpose() << std::endl;
571 trainingProprioceptionsFile.close();
572 trainingPositionsFile.close();
573 testProprioceptionsFile.close();
574 testPositionsFile.close();
579 if (!evaluationFile.is_open())
581 ARMARX_ERROR <<
"file " << evaluationFilename <<
" could not be opened / created";
585 kbm->getErrors(evaluationProprioception, evaluationPosition);
587 evaluationFile << errors.
Mean <<
", " << errors.
STD <<
", " << errors.
Median <<
", "
588 << errors.
IQR <<
", " << errors.
Max << std::endl;
590 for (
int i = 0; i < proprioception.cols(); i++)
592 kbm->online(proprioception.col(i), position.col(i), learningRate);
596 errors = kbm->getErrors(evaluationProprioception, evaluationPosition);
597 ARMARX_IMPORTANT <<
"online learning error after step " << (i + 1) <<
": " << errors;
598 evaluationFile << errors.
Mean <<
", " << errors.
STD <<
", " << errors.
Median <<
", "
599 << errors.
IQR <<
", " << errors.
Max << std::endl;
602 evaluationFile.close();
605 std::vector<memoryx::KBM::Real>
607 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
608 const Ice::Current&
c)
614 return std::vector<memoryx::KBM::Real>();
617 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
620 int nDim = kbm->getNDim();
621 int nSamples = proprioception.cols();
622 std::vector<memoryx::KBM::Real> predictionSequence(nDim * nSamples);
623 Eigen::Map<memoryx::KBM::Matrix> prediction(predictionSequence.data(), nDim, nSamples);
625 if (createdFromVirtualRobot[name])
630 prediction = kbm->predict(proprioception.colwise().reverse());
634 prediction = kbm->predict(proprioception);
637 ARMARX_INFO <<
"KBM '" << name <<
"' predicted: " << prediction.transpose();
638 return predictionSequence;
643 const std::vector<memoryx::KBM::Real>& proprioceptionSequence,
644 const std::vector<memoryx::KBM::Real>& positionSequence,
645 const Ice::Current&
c)
657 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
659 Eigen::Map<const memoryx::KBM::Matrix> position =
mapPositions(*kbm, positionSequence);
661 if (proprioception.cols() != position.cols())
663 ARMARX_ERROR <<
"proprioception and position contain different number of samples";
671 if (createdFromVirtualRobot[name])
676 errors = kbm->getErrors(proprioception.colwise().reverse(), position);
680 errors = kbm->getErrors(proprioception, position);
689 Eigen::Map<const memoryx::KBM::Matrix> proprioception =
690 mapMatrix(nDoF, proprioceptionAccumulator);
691 Eigen::Map<const memoryx::KBM::Matrix> position =
mapMatrix(nDim, positionAccumulator);
693 ARMARX_VERBOSE <<
"proprioception samples: " << proprioception.cols();
697 << proprioception.rowwise().minCoeff().transpose();
699 << proprioception.rowwise().maxCoeff().transpose();
700 ARMARX_VERBOSE <<
"proprioception average: " << proprioception.rowwise().mean().transpose();
701 ARMARX_VERBOSE <<
"position minima: " << position.rowwise().minCoeff().transpose();
702 ARMARX_VERBOSE <<
"position maxima: " << position.rowwise().maxCoeff().transpose();
703 ARMARX_VERBOSE <<
"position average: " << position.rowwise().mean().transpose();
709 Eigen::Map<const memoryx::KBM::Matrix> rawJointValues =
710 mapMatrix(nDoF, rawJointValuesAccumulator);
712 ARMARX_VERBOSE <<
"raw jointValue samples: " << rawJointValues.cols();
714 std::vector<memoryx::KBM::Real> result(nDoF);
715 Eigen::Map<memoryx::KBM::Vector> averages(result.data(), nDoF);
716 averages = rawJointValues.rowwise().mean();
718 Ice::DoubleSeq resultFloat(result.begin(), result.end());
725 Eigen::Map<const memoryx::KBM::Matrix> proprioceptions =
726 mapMatrix(nDoF, proprioceptionAccumulator);
728 ARMARX_VERBOSE <<
"proprioception samples: " << proprioceptions.cols();
730 std::vector<memoryx::KBM::Real> result(nDoF);
731 Eigen::Map<memoryx::KBM::Vector> spreadAngles(result.data(), nDoF);
738 for (
int i = 0; i < nDoF; i++)
740 spreadAngles[i] = fmin(fabs(leftSpreadAngles[i]), fabs(rightSpreadAngles[i]));
745 Ice::DoubleSeq resultFloat(result.begin(), result.end());
751 const std::vector<memoryx::KBM::Real>& rawJointValuesAverages,
752 const Ice::Current&
c)
754 if (proprioceptionAccumulator.size() != 0)
756 ARMARX_ERROR <<
"proprioception accumulator should be empty, when using setting it "
757 "from raw joint accumulator";
760 if (rawJointValuesAccumulator.size() % rawJointValuesAverages.size() != 0)
762 ARMARX_ERROR <<
"rawJointValuesAverages size is incompatible to accumulator size";
765 ARMARX_INFO <<
"rawJointValuesAccumualtor: " << rawJointValuesAccumulator;
766 std::vector<memoryx::KBM::Real> proprioceptionsFromRawJointAccumulator;
769 for (
auto jointValue : rawJointValuesAccumulator)
771 if (i == rawJointValuesAverages.size())
776 float offset = rawJointValuesAverages[i];
782 proprioceptionsFromRawJointAccumulator.push_back(jointValue - offset);
785 ARMARX_INFO <<
"proprioceptionsFromRawJointAccumulator: "
786 << proprioceptionsFromRawJointAccumulator;
787 proprioceptionAccumulator = proprioceptionsFromRawJointAccumulator;
797 Eigen::Map<const memoryx::KBM::Matrix> positions =
mapMatrix(nDim, positionAccumulator);
798 minima = positions.rowwise().minCoeff();
799 maxima = positions.rowwise().maxCoeff();
806 Ice::Float learningRate,
807 const Ice::Current&
c)
809 online(name, proprioceptionAccumulator, positionAccumulator, learningRate,
c);
814 Ice::Float learningRate,
815 const Ice::Current&
c)
818 proprioceptionAccumulator,
821 evaluationProprioceptionAccumulator,
822 evaluationPositionAccumulator,
829 Ice::Float threshold,
830 const Ice::Current&
c)
832 batch(name, proprioceptionAccumulator, positionAccumulator, method, threshold,
c);
838 printErrors(name, proprioceptionAccumulator, positionAccumulator,
c);
844 predict(name, proprioceptionAccumulator,
c);
857 const Ice::Current&
c)
862 positionAccumulator.insert(positionAccumulator.end(), position.begin(), position.end());
869 const Ice::Current&
c)
874 proprioceptionAccumulator.insert(
875 proprioceptionAccumulator.end(), proprioception.begin(), proprioception.end());
882 const std::vector<memoryx::KBM::Real>& rawJointValuesSequence,
883 const Ice::Current&
c)
888 rawJointValuesAccumulator.insert(rawJointValuesAccumulator.end(),
889 rawJointValuesSequence.begin(),
890 rawJointValuesSequence.end());
897 const Ice::Current&
c)
902 evaluationPositionAccumulator.insert(
903 evaluationPositionAccumulator.end(), position.begin(), position.end());
910 const std::vector<memoryx::KBM::Real>& proprioception,
911 const Ice::Current&
c)
916 evaluationProprioceptionAccumulator.insert(evaluationProprioceptionAccumulator.end(),
917 proprioception.begin(),
918 proprioception.end());
923 std::vector<memoryx::KBM::Real>
925 const std::vector<memoryx::KBM::Real>& targetPosition,
926 const Ice::Current&
c)
936 return std::vector<memoryx::KBM::Real>();
939 Eigen::Map<const memoryx::KBM::Vector> target(
mapPosition(*kbm, targetPosition));
944 std::vector<memoryx::KBM::Real> result(kbm->getNDoF());
945 Eigen::Map<memoryx::KBM::Vector> solution(result.data(), kbm->getNDoF());
954 for (
unsigned int i = 0; i < solutions.size(); ++i)
961 if (createdFromVirtualRobot[name])
963 ARMARX_ERROR <<
"solveGlobalIK does not yet support KBMs created from Virtual Robot!";
969 std::vector<memoryx::KBM::Real>
971 const std::string& name,
972 const std::vector<memoryx::KBM::Real>& targetPosition,
973 const std::vector<memoryx::KBM::Real>& currentPosition,
974 const std::vector<memoryx::KBM::Real>& currentProprioception,
975 const std::vector<memoryx::KBM::Real>& lowerProprioceptionLimitsSequence,
976 const std::vector<memoryx::KBM::Real>& upperProprioceptionLimitsSequence,
977 const Ice::Current&
c)
987 return std::vector<memoryx::KBM::Real>();
990 Eigen::Map<const memoryx::KBM::Vector> target(
mapPosition(*kbm, targetPosition));
991 Eigen::Map<const memoryx::KBM::Vector> current(
mapPosition(*kbm, currentPosition));
992 Eigen::Map<const memoryx::KBM::Vector> proprioception(
994 Eigen::Map<const memoryx::KBM::Vector> lowerProprioceptionLimits(
996 Eigen::Map<const memoryx::KBM::Vector> upperProprioceptionLimits(
1002 if (minima.size() != target.size())
1004 ARMARX_ERROR <<
"minima and target have different size";
1005 return std::vector<memoryx::KBM::Real>();
1008 if (maxima.size() != target.size())
1011 ARMARX_ERROR <<
"maxima and target have different size";
1012 return std::vector<memoryx::KBM::Real>();
1015 for (
int i = 0; i < kbm->getNDim(); i++)
1017 if (target[i] < minima[i] - 90)
1019 ARMARX_ERROR <<
"target[" << i <<
"] = " << target[i] <<
" is smaller than minima "
1021 return std::vector<memoryx::KBM::Real>();
1024 if (target[i] > maxima[i] + 90)
1026 ARMARX_ERROR <<
"target[" << i <<
"] = " << target[i] <<
" is greater than maxima "
1028 return std::vector<memoryx::KBM::Real>();
1035 std::vector<memoryx::KBM::Real> result(kbm->getNDoF());
1036 Eigen::Map<memoryx::KBM::Vector> solution(result.data(), kbm->getNDoF());
1043 if (createdFromVirtualRobot[name])
1048 ARMARX_IMPORTANT <<
"reversing proprioception and limits order because KBM was created "
1049 "from VirtualRobot";
1053 proprioception.reverse(),
1054 lowerProprioceptionLimits.reverse(),
1055 upperProprioceptionLimits.reverse(),
1064 lowerProprioceptionLimits,
1065 upperProprioceptionLimits,
1069 if (createdFromVirtualRobot[name])
1075 solution = solution.colwise().reverse();
1100 return LO +
static_cast<float>(rand()) / (
static_cast<float>(RAND_MAX / (HI - LO)));
1108 float stepSizeFactor,
1117 if (positionDeltas.norm() > maxStepSize)
1119 positionDeltas *= maxStepSize / positionDeltas.norm();
1131#ifdef KBM_USE_DOUBLE_PRECISION
1148 if (lowerProprioceptionLimits.size() != upperProprioceptionLimits.size())
1153 int n = lowerProprioceptionLimits.size();
1156 for (
int i = 0; i < n; i++)
1158 float l = lowerProprioceptionLimits(i);
1159 float u = upperProprioceptionLimits(i);
1175 int n = solution.size();
1177 if (lowerProprioceptionLimits.size() != n)
1179 ARMARX_ERROR_S <<
"lower proprioception limits have wrong length: "
1180 << lowerProprioceptionLimits.size() <<
", should be " << n;
1183 if (upperProprioceptionLimits.size() != n)
1185 ARMARX_ERROR_S <<
"upper proprioception limits have wrong length: "
1186 << upperProprioceptionLimits.size() <<
", should be " << n;
1192 for (
int i = 0; i < n; i++)
1194 if ((solution(i) < lowerProprioceptionLimits(i)) ||
1195 (solution(i) > upperProprioceptionLimits(i)))
1206 Eigen::Map<memoryx::KBM::Vector>& solution,
1213 int n = solution.size();
1215 if (lowerProprioceptionLimits.size() != n)
1217 ARMARX_ERROR_S <<
"lower proprioception limits have wrong length: "
1218 << lowerProprioceptionLimits.size() <<
", should be " << n;
1221 if (upperProprioceptionLimits.size() != n)
1223 ARMARX_ERROR_S <<
"upper proprioception limits have wrong length: "
1224 << upperProprioceptionLimits.size() <<
", should be " << n;
1230 bool inLimits =
true;
1232 for (
int i = 0; i < n; i++)
1234 if (solution(i) < lowerProprioceptionLimits(i))
1236 solution(i) = lowerProprioceptionLimits(i);
1240 if (solution(i) > upperProprioceptionLimits(i))
1242 solution(i) = upperProprioceptionLimits(i);
1257 Eigen::Map<memoryx::KBM::Vector>& solution,
1260 float positionTolerance,
1262 bool requireImprovment,
1264 float stepSizeFactor,
1268 float bestDistance = FLT_MAX;
1269 bool inLimits =
false;
1271 std::vector<memoryx::KBM::Real> newSolutionSequence(kbm.
getNDoF());
1272 Eigen::Map<memoryx::KBM::Vector> newSolution(newSolutionSequence.data(), kbm.
getNDoF());
1274 for (
int i = 0; i < maxSolves; i++)
1280 startProprioception = currentProprioception;
1284 startProprioception =
1289 <<
" proprioception: " << startProprioception.transpose();
1299 startProprioception,
1321 float distance = (targetPosition - testPosition).
norm();
1329 newSolution, lowerProprioceptionLimits, upperProprioceptionLimits);
1335 <<
"solution was not within limits, but enforced limits so now it is";
1341 testPosition = kbm.
predict(newSolution);
1351 newSolution, lowerProprioceptionLimits, upperProprioceptionLimits);
1354 if (applyLimits && !currentInLimits)
1358 ARMARX_ERROR_S <<
"lower proprioception limits: " << lowerProprioceptionLimits;
1359 ARMARX_ERROR_S <<
"upper proprioception limits: " << upperProprioceptionLimits;
1362 if (inLimits && !currentInLimits)
1365 <<
"ignoring solution because we already found one that is within the limits";
1370 float distance = (targetPosition - newPosition).
norm();
1375 if ((
distance < bestDistance) || (currentInLimits && !inLimits))
1378 inLimits = currentInLimits;
1379 solution = newSolution;
1382 if (inLimits && (bestDistance < positionTolerance))
1391 ARMARX_IMPORTANT_S <<
"final distance: " << bestDistance <<
", in limits: " << inLimits;
1393 if (bestDistance < positionTolerance)
1408 Eigen::Map<memoryx::KBM::Vector>& solution,
1409 float positionTolerance,
1411 bool requireImprovment,
1413 float stepSizeFactor,
1417 assert(targetPosition.size() == kbm.
getNDim());
1418 assert(currentPosition.size() == kbm.
getNDim());
1419 assert(currentProprioception.size() == kbm.
getNDoF());
1420 assert(solution.size() == kbm.
getNDoF());
1425 solution = currentProprioception;
1430 float bestDistance = (targetPosition - currentPosition).
norm();
1435 if (bestDistance <= positionTolerance)
1455 for (
int step = 0; step < maxSteps; ++step)
1463 simulatedProprioception,
1470 simulatedProprioception +=
deltas;
1475 predictedPosition = kbm.
predict(simulatedProprioception);
1481 float distance = (targetPosition - predictedPosition).
norm();
1486 solution = simulatedProprioception;
1493 if (requireImprovment && (
distance >= bestDistance))
1504 solution = simulatedProprioception;
1511 if (
deltas.norm() < minimumDelta)
1523 std::vector<std::string> kbmKeys;
1525 for (
auto it : kbms)
1527 kbmKeys.push_back(it.first);
1536 positionAccumulator.clear();
1537 proprioceptionAccumulator.clear();
1538 rawJointValuesAccumulator.clear();
1543 const std::string& nodeSetName,
1544 const std::string& referenceFrameName,
1545 const std::string& robotName,
1546 const Ice::Current&
c)
1552 auto kbmSeg = this->longtermMemoryPrx->getKBMSegment();
1561 kbmSeg->addEntity(kbmData);
1566 ARMARX_WARNING <<
"Could not store KBM! No KBM segment in longterm memory!";
1574 const std::string& nodeSetName,
1575 const std::string& referenceFrameName,
1576 const std::string& robotName,
1577 const Ice::Current&
c)
1580 auto kbmSeg = this->longtermMemoryPrx->getKBMSegment();
1581 std::string kbmEntityName = robotName +
"_" + referenceFrameName +
"_" + nodeSetName;
1583 if (kbmSeg && kbmSeg->hasEntityByName(kbmEntityName))
1585 auto entity = kbmSeg->getEntityByName(kbmEntityName);
1592 int nDoF = robot->getRobotNodeSet(nodeSetName)->getSize();
1595 armarx::MatrixVariantPtr::dynamicCast(kbmData->getControlNet());
1600 Eigen::VectorXd::Zero(nDoF),
1601 Eigen::VectorXd::Constant(nDoF,
M_PI / 4.0f),
1602 controlNet->toEigen().cast<
double>());
1603 createdFromVirtualRobot[kbmName] =
1608 ARMARX_WARNING <<
"Could not restore KBM entity specified by: " << kbmEntityName;
1617 const std::string& referenceFrameName,
1618 const std::string& robotName,
1619 const Ice::Current&
c)
1621 std::string kbmEntityName = robotName +
"_" + referenceFrameName +
"_" + nodeSetName;
1623 return (this->longtermMemoryPrx->getKBMSegment() &&
1624 this->longtermMemoryPrx->getKBMSegment()->hasEntityByName(kbmEntityName));
1630 return "KBMComponent";
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
Wrapper for the KBM class.
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
static std::string GetDefaultName()
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): .