blob: 0868c2c9e743ee92aa11e9031fc5ee567bb632db [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(
11 const aos::controls::HPolytope<2> &region,
12 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
23 aos::controls::HPolytope<1> t_poly(
24 region.H() * parallel_vector,
25 region.k() - region.H() * perpendicular_vector * w);
26
27 Eigen::Matrix<double, 1, Eigen::Dynamic> vertices = t_poly.Vertices();
28 if (vertices.innerSize() > 0) {
29 double min_distance_sqr = 0;
30 Eigen::Matrix<double, 2, 1> closest_point;
31 for (int i = 0; i < vertices.innerSize(); i++) {
32 Eigen::Matrix<double, 2, 1> point;
33 point = parallel_vector * vertices(0, i) + perpendicular_vector * w;
34 const double length = (R - point).squaredNorm();
35 if (i == 0 || length < min_distance_sqr) {
36 closest_point = point;
37 min_distance_sqr = length;
38 }
39 }
Brian Silverman6dd2c532014-03-29 23:34:39 -070040 if (is_inside) *is_inside = true;
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070041 return closest_point;
42 } else {
43 Eigen::Matrix<double, 2, Eigen::Dynamic> region_vertices =
44 region.Vertices();
Brian Silverman4e1b0662016-01-31 18:03:19 -050045 CHECK_GT(region_vertices.outerSize(), 0);
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070046 double min_distance = INFINITY;
47 int closest_i = 0;
48 for (int i = 0; i < region_vertices.outerSize(); i++) {
49 const double length = ::std::abs(
50 (perpendicular_vector.transpose() * (region_vertices.col(i)))(0, 0));
51 if (i == 0 || length < min_distance) {
52 closest_i = i;
53 min_distance = length;
54 }
55 }
Brian Silverman6dd2c532014-03-29 23:34:39 -070056 if (is_inside) *is_inside = false;
James Kuszmaulf63b0ae2014-03-25 16:52:11 -070057 return (Eigen::Matrix<double, 2, 1>() << region_vertices(0, closest_i),
58 region_vertices(1, closest_i)).finished();
James Kuszmaulfb0e0ae2014-03-25 07:04:47 -070059 }
60}
61
62} // namespace control_loops
63} // namespace frc971