blob: 0c98560b2fb4f4ca0845dceef801fa2d69978fe1 [file] [log] [blame]
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -07001#include "frc971/control_loops/coerce_goal.h"
2
3#include "Eigen/Dense"
4
Briana6553ed2014-04-02 21:26:46 -07005#include "aos/common/controls/polytope.h"
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -07006
7namespace frc971 {
8namespace control_loops {
9
Brian Silverman4e1b0662016-01-31 18:03:19 -050010Eigen::Matrix<double, 2, 1> DoCoerceGoal(
Austin Schuhc7a0a3d2016-10-15 16:22:47 -070011 const aos::controls::HVPolytope<2, 4, 4> &region,
Brian Silverman4e1b0662016-01-31 18:03:19 -050012 const Eigen::Matrix<double, 1, 2> &K, double w,
13 const Eigen::Matrix<double, 2, 1> &R, bool *is_inside) {
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070014 if (region.IsInside(R)) {
Brian Silverman6dd2c532014-03-29 23:34:39 -070015 if (is_inside) *is_inside = true;
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070016 return R;
17 }
18 Eigen::Matrix<double, 2, 1> parallel_vector;
19 Eigen::Matrix<double, 2, 1> perpendicular_vector;
20 perpendicular_vector = K.transpose().normalized();
21 parallel_vector << perpendicular_vector(1, 0), -perpendicular_vector(0, 0);
22
Austin Schuhc7a0a3d2016-10-15 16:22:47 -070023 Eigen::Matrix<double, 4, 1> projectedh = region.static_H() * parallel_vector;
24 Eigen::Matrix<double, 4, 1> projectedk =
25 region.static_k() - region.static_H() * perpendicular_vector * w;
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070026
Austin Schuhc7a0a3d2016-10-15 16:22:47 -070027 double min_boundary = ::std::numeric_limits<double>::lowest();
28 double max_boundary = ::std::numeric_limits<double>::max();
29 for (int i = 0; i < 4; ++i) {
30 if (projectedh(i, 0) > 0) {
31 max_boundary =
32 ::std::min(max_boundary, projectedk(i, 0) / projectedh(i, 0));
33 } else {
34 min_boundary =
35 ::std::max(min_boundary, projectedk(i, 0) / projectedh(i, 0));
36 }
37 }
38
39 Eigen::Matrix<double, 1, 2> vertices;
40 vertices << max_boundary, min_boundary;
41
42 if (max_boundary > min_boundary) {
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070043 double min_distance_sqr = 0;
44 Eigen::Matrix<double, 2, 1> closest_point;
45 for (int i = 0; i < vertices.innerSize(); i++) {
46 Eigen::Matrix<double, 2, 1> point;
47 point = parallel_vector * vertices(0, i) + perpendicular_vector * w;
48 const double length = (R - point).squaredNorm();
49 if (i == 0 || length < min_distance_sqr) {
50 closest_point = point;
51 min_distance_sqr = length;
52 }
53 }
Brian Silverman6dd2c532014-03-29 23:34:39 -070054 if (is_inside) *is_inside = true;
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070055 return closest_point;
56 } else {
Austin Schuhc7a0a3d2016-10-15 16:22:47 -070057 Eigen::Matrix<double, 2, 4> region_vertices =
58 region.StaticVertices();
Brian Silverman4e1b0662016-01-31 18:03:19 -050059 CHECK_GT(region_vertices.outerSize(), 0);
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070060 double min_distance = INFINITY;
61 int closest_i = 0;
62 for (int i = 0; i < region_vertices.outerSize(); i++) {
63 const double length = ::std::abs(
64 (perpendicular_vector.transpose() * (region_vertices.col(i)))(0, 0));
65 if (i == 0 || length < min_distance) {
66 closest_i = i;
67 min_distance = length;
68 }
69 }
Brian Silverman6dd2c532014-03-29 23:34:39 -070070 if (is_inside) *is_inside = false;
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070071 return (Eigen::Matrix<double, 2, 1>() << region_vertices(0, closest_i),
72 region_vertices(1, closest_i)).finished();
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070073 }
74}
75
76} // namespace control_loops
77} // namespace frc971