blob: b1d5c3cb8956a8bfdd5d04b605e31d579a79946b [file] [log] [blame]
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -07001#ifndef FRC971_CONTROL_LOOPS_COERCE_GOAL_H_
2#define FRC971_CONTROL_LOOPS_COERCE_GOAL_H_
3
4#include "Eigen/Dense"
5
Briana6553ed2014-04-02 21:26:46 -07006#include "aos/common/controls/polytope.h"
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -07007
8namespace frc971 {
9namespace control_loops {
10
Austin Schuhbcce26a2018-03-26 23:41:24 -070011template <typename Scalar = double>
12Eigen::Matrix<Scalar, 2, 1> DoCoerceGoal(
13 const aos::controls::HVPolytope<2, 4, 4, Scalar> &region,
14 const Eigen::Matrix<Scalar, 1, 2> &K, Scalar w,
15 const Eigen::Matrix<Scalar, 2, 1> &R, bool *is_inside);
Brian Silverman6dd2c532014-03-29 23:34:39 -070016
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070017// Intersects a line with a region, and finds the closest point to R.
18// Finds a point that is closest to R inside the region, and on the line
19// defined by K X = w. If it is not possible to find a point on the line,
20// finds a point that is inside the region and closest to the line.
Austin Schuhbcce26a2018-03-26 23:41:24 -070021template <typename Scalar = double>
22static inline Eigen::Matrix<Scalar, 2, 1> CoerceGoal(
23 const aos::controls::HVPolytope<2, 4, 4, Scalar> &region,
24 const Eigen::Matrix<Scalar, 1, 2> &K, Scalar w,
25 const Eigen::Matrix<Scalar, 2, 1> &R) {
Brian Silverman6dd2c532014-03-29 23:34:39 -070026 return DoCoerceGoal(region, K, w, R, nullptr);
27}
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070028
Austin Schuhbcce26a2018-03-26 23:41:24 -070029template <typename Scalar>
30Eigen::Matrix<Scalar, 2, 1> DoCoerceGoal(
31 const aos::controls::HVPolytope<2, 4, 4, Scalar> &region,
32 const Eigen::Matrix<Scalar, 1, 2> &K, Scalar w,
33 const Eigen::Matrix<Scalar, 2, 1> &R, bool *is_inside) {
34 if (region.IsInside(R)) {
35 if (is_inside) *is_inside = true;
36 return R;
37 }
38 Eigen::Matrix<Scalar, 2, 1> parallel_vector;
39 Eigen::Matrix<Scalar, 2, 1> perpendicular_vector;
40 perpendicular_vector = K.transpose().normalized();
41 parallel_vector << perpendicular_vector(1, 0), -perpendicular_vector(0, 0);
42
43 Eigen::Matrix<Scalar, 4, 1> projectedh = region.static_H() * parallel_vector;
44 Eigen::Matrix<Scalar, 4, 1> projectedk =
45 region.static_k() - region.static_H() * perpendicular_vector * w;
46
47 Scalar min_boundary = ::std::numeric_limits<Scalar>::lowest();
48 Scalar max_boundary = ::std::numeric_limits<Scalar>::max();
49 for (int i = 0; i < 4; ++i) {
50 if (projectedh(i, 0) > 0) {
51 max_boundary =
52 ::std::min(max_boundary, projectedk(i, 0) / projectedh(i, 0));
53 } else {
54 min_boundary =
55 ::std::max(min_boundary, projectedk(i, 0) / projectedh(i, 0));
56 }
57 }
58
59 Eigen::Matrix<Scalar, 1, 2> vertices;
60 vertices << max_boundary, min_boundary;
61
62 if (max_boundary > min_boundary) {
63 Scalar min_distance_sqr = 0;
64 Eigen::Matrix<Scalar, 2, 1> closest_point;
65 for (int i = 0; i < vertices.innerSize(); i++) {
66 Eigen::Matrix<Scalar, 2, 1> point;
67 point = parallel_vector * vertices(0, i) + perpendicular_vector * w;
68 const Scalar length = (R - point).squaredNorm();
69 if (i == 0 || length < min_distance_sqr) {
70 closest_point = point;
71 min_distance_sqr = length;
72 }
73 }
74 if (is_inside) *is_inside = true;
75 return closest_point;
76 } else {
77 Eigen::Matrix<Scalar, 2, 4> region_vertices = region.StaticVertices();
78#ifdef __linux__
79 CHECK_GT(region_vertices.outerSize(), 0);
80#else
81 assert(region_vertices.outerSize() > 0);
82#endif
83 Scalar min_distance = INFINITY;
84 int closest_i = 0;
85 for (int i = 0; i < region_vertices.outerSize(); i++) {
86 const Scalar length = ::std::abs(
87 (perpendicular_vector.transpose() * (region_vertices.col(i)))(0, 0));
88 if (i == 0 || length < min_distance) {
89 closest_i = i;
90 min_distance = length;
91 }
92 }
93 if (is_inside) *is_inside = false;
94 return (Eigen::Matrix<Scalar, 2, 1>() << region_vertices(0, closest_i),
95 region_vertices(1, closest_i))
96 .finished();
97 }
98}
99
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -0700100} // namespace control_loops
101} // namespace frc971
102
103#endif // FRC971_CONTROL_LOOPS_COERCE_GOAL_H_