// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #pragma once #include #include "Eigen/Core" namespace frc { inline double NormalizeAngle(double angle) { static constexpr double tau = 2 * wpi::math::pi; angle -= std::floor(angle / tau) * tau; if (angle > wpi::math::pi) { angle -= tau; } return angle; } /** * Subtracts a and b while normalizing the resulting value in the selected row * as if it were an angle. * * @param a A vector to subtract from. * @param b A vector to subtract with. * @param angleStateIdx The row containing angles to be normalized. */ template Eigen::Matrix AngleResidual( const Eigen::Matrix& a, const Eigen::Matrix& b, int angleStateIdx) { Eigen::Matrix ret = a - b; ret[angleStateIdx] = NormalizeAngle(ret[angleStateIdx]); return ret; } /** * Returns a function that subtracts two vectors while normalizing the resulting * value in the selected row as if it were an angle. * * @param angleStateIdx The row containing angles to be normalized. */ template std::function< Eigen::Matrix(const Eigen::Matrix&, const Eigen::Matrix&)> AngleResidual(int angleStateIdx) { return [=](auto a, auto b) { return AngleResidual(a, b, angleStateIdx); }; } /** * Adds a and b while normalizing the resulting value in the selected row as an * angle. * * @param a A vector to add with. * @param b A vector to add with. * @param angleStateIdx The row containing angles to be normalized. */ template Eigen::Matrix AngleAdd( const Eigen::Matrix& a, const Eigen::Matrix& b, int angleStateIdx) { Eigen::Matrix ret = a + b; ret[angleStateIdx] = NormalizeAngle(ret[angleStateIdx]); return ret; } /** * Returns a function that adds two vectors while normalizing the resulting * value in the selected row as an angle. * * @param angleStateIdx The row containing angles to be normalized. */ template std::function< Eigen::Matrix(const Eigen::Matrix&, const Eigen::Matrix&)> AngleAdd(int angleStateIdx) { return [=](auto a, auto b) { return AngleAdd(a, b, angleStateIdx); }; } /** * Computes the mean of sigmas with the weights Wm while computing a special * angle mean for a select row. * * @param sigmas Sigma points. * @param Wm Weights for the mean. * @param angleStateIdx The row containing the angles. */ template Eigen::Matrix AngleMean( const Eigen::Matrix& sigmas, const Eigen::Matrix& Wm, int angleStatesIdx) { double sumSin = sigmas.row(angleStatesIdx) .unaryExpr([](auto it) { return std::sin(it); }) .sum(); double sumCos = sigmas.row(angleStatesIdx) .unaryExpr([](auto it) { return std::cos(it); }) .sum(); Eigen::Matrix ret = sigmas * Wm; ret[angleStatesIdx] = std::atan2(sumSin, sumCos); return ret; } /** * Returns a function that computes the mean of sigmas with the weights Wm while * computing a special angle mean for a select row. * * @param angleStateIdx The row containing the angles. */ template std::function( const Eigen::Matrix&, const Eigen::Matrix&)> AngleMean(int angleStateIdx) { return [=](auto sigmas, auto Wm) { return AngleMean(sigmas, Wm, angleStateIdx); }; } } // namespace frc