From ee30cbb7c5cc3f596f5052d2a2477ebd7fb28089 Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Thu, 5 May 2022 09:26:11 +0200 Subject: [PATCH] Move linear prediction code to simox --- .../armem_objects/server/instance/Segment.cpp | 49 +++++-------------- .../armem_objects/server/instance/Segment.h | 6 --- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index 5162ec4e3..8d645a742 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -37,6 +37,7 @@ #include <SimoxUtility/algorithm/string.h> #include <SimoxUtility/json.h> #include <SimoxUtility/math/pose/pose.h> +#include <SimoxUtility/math/regression/linear3d.h> #include <Eigen/Geometry> #include <Eigen/Dense> @@ -629,9 +630,16 @@ namespace armarx::armem::server::obj::instance return result; } - const Eigen::Vector3d prediction = makeLinearPrediction(timestampsSec, positions, predictionTime); - // ToDo: Remove. - ARMARX_IMPORTANT << "Prediction: " << prediction.transpose(); + Eigen::Vector3d prediction; + { + using simox::math::LinearRegression3D; + const bool inputOffset = false; + const LinearRegression3D model = LinearRegression3D::Fit(timestampsSec, positions, inputOffset); + prediction = model.predict(predictionTime); + + // ToDo: Remove. + ARMARX_IMPORTANT << "Prediction: " << prediction.transpose() << "\n (model: " << model << ")"; + } // Used as a template for the returned pose prediction. ObjectPose objectPoseTemplate = getLatestObjectPose(*entity); @@ -649,41 +657,6 @@ namespace armarx::armem::server::obj::instance return result; } - Eigen::Vector3d - Segment::makeLinearPrediction(std::vector<double>& timestamps, - std::vector<Eigen::Vector3d>& positions, - double predictionTime) - { - Eigen::Matrix3Xd positionMatrix(3, positions.size()); - for (long col = 0; col < positionMatrix.cols(); ++col) - { - positionMatrix.col(col) = positions.at(col); - } - - // The matrix of the predictor functions evaluated at the corresponding timestamps. - // Since this is a linear regression, the constant function a(t) = 1 and identity - // b(t) = t are used. - Eigen::MatrixX2d linFuncMatrix(timestamps.size(), 2); - linFuncMatrix.col(0) = Eigen::RowVectorXd::Ones(timestamps.size()); - linFuncMatrix.col(1) = Eigen::Map<Eigen::VectorXd>(timestamps.data(), timestamps.size()); - - // `linFuncMatrix` is poorly conditioned for timestamps that are close together, - // so the normal equation would lose a lot of precision. - auto qrDecomp = linFuncMatrix.colPivHouseholderQr(); - - // Each coordinate can be treated individually (general multivariate regression). - // `coeffs` contains a_i and b_i in a_0 + b_0 * t = x, a_1 + b_1 * t = y, etc. - Eigen::Matrix<double, 3, 2> coeffs; - for (int dim = 0; dim < 3; ++dim) - { - Eigen::VectorXd coords = positionMatrix.row(dim).transpose(); - coeffs.row(dim) = qrDecomp.solve(coords); - } - - Eigen::Vector2d input; - input << 1.0, predictionTime; - return coeffs * input; - } objpose::AttachObjectToRobotNodeOutput Segment::attachObjectToRobotNode(const objpose::AttachObjectToRobotNodeInput& input) diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h index db97c715a..81dab749e 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h @@ -140,12 +140,6 @@ namespace armarx::armem::server::obj::instance std::optional<wm::EntityInstance> findClassInstance(const ObjectID& objectID) const; - - static Eigen::Vector3d makeLinearPrediction(std::vector<double>& timestamps, - std::vector<Eigen::Vector3d>& positions, - double predictionTime); - - friend struct DetachVisitor; -- GitLab