blob: ae04d6c29b13464164aa04c1fe86373e25104fac [file] [log] [blame]
#include "frc971/control_loops/coerce_goal.h"
#include <unistd.h>
#include "aos/controls/polytope.h"
#include "gtest/gtest.h"
namespace frc971 {
namespace control_loops {
namespace {
aos::controls::HVPolytope<2, 4, 4> MakeBox(double x1_min, double x1_max,
double x2_min, double x2_max) {
Eigen::Matrix<double, 4, 2> box_H;
box_H << /*[[*/ 1.0, 0.0 /*]*/,
/*[*/ -1.0, 0.0 /*]*/,
/*[*/ 0.0, 1.0 /*]*/,
/*[*/ 0.0, -1.0 /*]]*/;
Eigen::Matrix<double, 4, 1> box_k;
box_k << /*[[*/ x1_max /*]*/,
/*[*/ -x1_min /*]*/,
/*[*/ x2_max /*]*/,
/*[*/ -x2_min /*]]*/;
aos::controls::HPolytope<2> t_poly(box_H, box_k);
return aos::controls::HVPolytope<2, 4, 4>(t_poly.H(), t_poly.k(),
t_poly.Vertices());
}
} // namespace
class CoerceGoalTest : public ::testing::Test {
public:
void SetUp() override { aos::controls::HPolytope<2>::Init(); }
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
TEST_F(CoerceGoalTest, Inside) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << /*[[*/ 1, -1 /*]]*/;
Eigen::Matrix<double, 2, 1> R;
R << /*[[*/ 1.5, 1.5 /*]]*/;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(R(0, 0), output(0, 0));
EXPECT_EQ(R(1, 0), output(1, 0));
}
TEST_F(CoerceGoalTest, LineOutside) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
// Make a line equivalent to y = -x, which does not pass through the box and
// is nearest the box at (1, 1).
Eigen::Matrix<double, 1, 2> K;
K << 1, 1;
Eigen::Matrix<double, 2, 1> R;
R << /*[[*/ 0.0, 0.0 /*]]*/;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(1.0, output(0, 0));
EXPECT_EQ(1.0, output(1, 0));
// Test the same line, but on the other side of the box, where the (2, 2)
// vertex will be closest.
output = frc971::control_loops::CoerceGoal<double>(box, K, 5, R);
EXPECT_EQ(2.0, output(0, 0));
EXPECT_EQ(2.0, output(1, 0));
}
TEST_F(CoerceGoalTest, GoalOutsideLineInsideThroughOrigin) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << 1, -1;
Eigen::Matrix<double, 2, 1> R;
R << 5, 5;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(2.0, output(0, 0));
EXPECT_EQ(2.0, output(1, 0));
}
TEST_F(CoerceGoalTest, GoalOutsideLineNotThroughOrigin) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << 1, 1;
Eigen::Matrix<double, 2, 1> R;
R << 0, 3;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 3, R);
EXPECT_EQ(1.0, output(0, 0));
EXPECT_DOUBLE_EQ(2.0, output(1, 0));
}
TEST_F(CoerceGoalTest, GoalOutsideLineThroughVertex) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << 1, -1;
Eigen::Matrix<double, 2, 1> R;
R << 5, 5;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 1, R);
EXPECT_EQ(2.0, output(0, 0));
EXPECT_EQ(1.0, output(1, 0));
}
TEST_F(CoerceGoalTest, LineAndGoalOutside) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(3, 4, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << 1, -1;
Eigen::Matrix<double, 2, 1> R;
R << 5, 5;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(3.0, output(0, 0));
EXPECT_EQ(2.0, output(1, 0));
}
TEST_F(CoerceGoalTest, LineThroughEdgeOfBox) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(0, 4, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << -1, 1;
Eigen::Matrix<double, 2, 1> R;
R << 5, 5;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(2.0, output(0, 0));
EXPECT_EQ(2.0, output(1, 0));
}
TEST_F(CoerceGoalTest, PerpendicularLine) {
aos::controls::HVPolytope<2, 4, 4> box = MakeBox(1, 2, 1, 2);
Eigen::Matrix<double, 1, 2> K;
K << 1, 1;
Eigen::Matrix<double, 2, 1> R;
R << 5, 5;
Eigen::Matrix<double, 2, 1> output =
frc971::control_loops::CoerceGoal<double>(box, K, 0, R);
EXPECT_EQ(1.0, output(0, 0));
EXPECT_EQ(1.0, output(1, 0));
}
TEST_F(CoerceGoalTest, WithinRegion) {
const auto upoly = MakeBox(-12.0, 12.0, -12.0, 12.0);
Eigen::Matrix<double, 1, 2> k;
k << 2, 2;
Eigen::Matrix<double, 2, 1> goal;
goal << -2, 2;
auto result = CoerceGoal<double>(upoly, k, 0, goal);
EXPECT_EQ(result(0, 0), goal(0, 0));
EXPECT_EQ(result(1, 0), goal(1, 0));
}
TEST_F(CoerceGoalTest, VerticalLine) {
const auto upoly = MakeBox(-12.0, 12.0, -12.0, 12.0);
Eigen::Matrix<double, 1, 2> k;
k << 2, 0;
Eigen::Matrix<double, 2, 1> goal;
goal << 0, 13;
auto result = CoerceGoal<double>(upoly, k, 0, goal);
EXPECT_EQ(result(0, 0), 0);
EXPECT_EQ(result(1, 0), 12);
}
TEST_F(CoerceGoalTest, HorizontalLine) {
const auto upoly = MakeBox(-12.0, 12.0, -12.0, 12.0);
Eigen::Matrix<double, 1, 2> k;
k << 0, 2;
Eigen::Matrix<double, 2, 1> goal;
goal << 13, 2;
auto result = CoerceGoal<double>(upoly, k, 0, goal);
EXPECT_EQ(result(0, 0), 12);
EXPECT_EQ(result(1, 0), 0);
}
} // namespace control_loops
} // namespace frc971