blob: cdb7fb9d1fb0df995ffae4b36e0dd91b1e9ec1bb [file] [log] [blame]
Austin Schuh941b46d2018-12-19 18:06:05 +11001#include "frc971/control_loops/drivetrain/distance_spline.h"
2
Austin Schuha6e7b212019-01-20 13:53:01 -08003#include "aos/logging/logging.h"
Austin Schuh941b46d2018-12-19 18:06:05 +11004#include "frc971/control_loops/drivetrain/spline.h"
5
6namespace frc971 {
7namespace control_loops {
8namespace drivetrain {
9
Austin Schuh280996e2019-01-19 17:43:37 -080010::std::vector<double> DistanceSpline::BuildDistances(size_t num_alpha) {
11 num_alpha = num_alpha == 0 ? 100 * splines_.size() : num_alpha;
12 ::std::vector<double> distances;
13 distances.push_back(0.0);
Austin Schuh941b46d2018-12-19 18:06:05 +110014
Austin Schuha6e7b212019-01-20 13:53:01 -080015 if (splines_.size() > 1) {
16 // We've got a multispline to follow!
17 // Confirm that the ends line up to the correct number of derivitives.
18 for (size_t i = 1; i < splines_.size(); ++i) {
19 const Spline &spline0 = splines_[i - 1];
20 const Spline &spline1 = splines_[i];
21
22 const ::Eigen::Matrix<double, 2, 1> end0 = spline0.Point(1.0);
23 const ::Eigen::Matrix<double, 2, 1> start1 = spline1.Point(0.0);
24
25 if (!end0.isApprox(start1, 1e-6)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070026 AOS_LOG(ERROR,
27 "Splines %d and %d don't line up. [%f, %f] != [%f, %f]\n",
28 static_cast<int>(i - 1), static_cast<int>(i), end0(0, 0),
29 end0(1, 0), start1(0, 0), start1(1, 0));
Austin Schuha6e7b212019-01-20 13:53:01 -080030 }
31
32 const ::Eigen::Matrix<double, 2, 1> dend0 = spline0.DPoint(1.0);
33 const ::Eigen::Matrix<double, 2, 1> dstart1 = spline1.DPoint(0.0);
34
35 if (!dend0.isApprox(dstart1, 1e-6)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070036 AOS_LOG(
37 ERROR,
Austin Schuha6e7b212019-01-20 13:53:01 -080038 "Splines %d and %d don't line up in the first derivitive. [%f, "
39 "%f] != [%f, %f]\n",
40 static_cast<int>(i - 1), static_cast<int>(i), dend0(0, 0),
41 dend0(1, 0), dstart1(0, 0), dstart1(1, 0));
42 }
43
44 const ::Eigen::Matrix<double, 2, 1> ddend0 = spline0.DDPoint(1.0);
45 const ::Eigen::Matrix<double, 2, 1> ddstart1 = spline1.DDPoint(0.0);
46
47 if (!ddend0.isApprox(ddstart1, 1e-6)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070048 AOS_LOG(
49 ERROR,
Austin Schuha6e7b212019-01-20 13:53:01 -080050 "Splines %d and %d don't line up in the second derivitive. [%f, "
51 "%f] != [%f, %f]\n",
52 static_cast<int>(i - 1), static_cast<int>(i), ddend0(0, 0),
53 ddend0(1, 0), ddstart1(0, 0), ddstart1(1, 0));
54 }
55 }
56 }
57
Austin Schuh280996e2019-01-19 17:43:37 -080058 const double dalpha =
59 static_cast<double>(splines_.size()) / static_cast<double>(num_alpha - 1);
Austin Schuh941b46d2018-12-19 18:06:05 +110060 double last_alpha = 0.0;
Austin Schuh280996e2019-01-19 17:43:37 -080061 for (size_t i = 1; i < num_alpha; ++i) {
Austin Schuh941b46d2018-12-19 18:06:05 +110062 const double alpha = dalpha * i;
Austin Schuh280996e2019-01-19 17:43:37 -080063 distances.push_back(distances.back() +
64 GaussianQuadrature5(
65 [this](double alpha) {
66 const size_t spline_index = ::std::min(
67 static_cast<size_t>(::std::floor(alpha)),
68 splines_.size() - 1);
69 return this->splines_[spline_index]
70 .DPoint(alpha - spline_index)
71 .norm();
72 },
73 last_alpha, alpha));
Austin Schuh941b46d2018-12-19 18:06:05 +110074 last_alpha = alpha;
75 }
Austin Schuh280996e2019-01-19 17:43:37 -080076 return distances;
Austin Schuh941b46d2018-12-19 18:06:05 +110077}
78
Austin Schuh280996e2019-01-19 17:43:37 -080079DistanceSpline::DistanceSpline(::std::vector<Spline> &&splines, int num_alpha)
80 : splines_(::std::move(splines)), distances_(BuildDistances(num_alpha)) {}
81
82DistanceSpline::DistanceSpline(const Spline &spline, int num_alpha)
83 : splines_({spline}), distances_(BuildDistances(num_alpha)) {}
84
Austin Schuh941b46d2018-12-19 18:06:05 +110085::Eigen::Matrix<double, 2, 1> DistanceSpline::DDXY(double distance) const {
Austin Schuh280996e2019-01-19 17:43:37 -080086 const AlphaAndIndex a = DistanceToAlpha(distance);
87 const ::Eigen::Matrix<double, 2, 1> dspline_point =
88 splines_[a.index].DPoint(a.alpha);
89 const ::Eigen::Matrix<double, 2, 1> ddspline_point =
90 splines_[a.index].DDPoint(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +110091
92 const double squared_norm = dspline_point.squaredNorm();
93
94 return ddspline_point / squared_norm -
95 dspline_point * (dspline_point(0) * ddspline_point(0) +
96 dspline_point(1) * ddspline_point(1)) /
97 ::std::pow(squared_norm, 2);
98}
99
100double DistanceSpline::DDTheta(double distance) const {
Austin Schuh280996e2019-01-19 17:43:37 -0800101 const AlphaAndIndex a = DistanceToAlpha(distance);
Austin Schuh941b46d2018-12-19 18:06:05 +1100102
103 // TODO(austin): We are re-computing DPoint here even worse
Austin Schuh280996e2019-01-19 17:43:37 -0800104 const ::Eigen::Matrix<double, 2, 1> dspline_point =
105 splines_[a.index].DPoint(a.alpha);
106 const ::Eigen::Matrix<double, 2, 1> ddspline_point =
107 splines_[a.index].DDPoint(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +1100108
Austin Schuh280996e2019-01-19 17:43:37 -0800109 const double dtheta = splines_[a.index].DTheta(a.alpha);
110 const double ddtheta = splines_[a.index].DDTheta(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +1100111
112 const double squared_norm = dspline_point.squaredNorm();
113
114 return ddtheta / squared_norm -
115 dtheta * (dspline_point(0) * ddspline_point(0) +
116 dspline_point(1) * ddspline_point(1)) /
117 ::std::pow(squared_norm, 2);
118}
119
Austin Schuh280996e2019-01-19 17:43:37 -0800120DistanceSpline::AlphaAndIndex DistanceSpline::DistanceToAlpha(
121 double distance) const {
Austin Schuh941b46d2018-12-19 18:06:05 +1100122 if (distance <= 0.0) {
Austin Schuh280996e2019-01-19 17:43:37 -0800123 return {0, 0.0};
Austin Schuh941b46d2018-12-19 18:06:05 +1100124 }
125 if (distance >= length()) {
Austin Schuh280996e2019-01-19 17:43:37 -0800126 return {splines_.size() - 1, 1.0};
Austin Schuh941b46d2018-12-19 18:06:05 +1100127 }
128
129 // Find the distance right below our number using a binary search.
130 size_t after = ::std::distance(
131 distances_.begin(),
132 ::std::lower_bound(distances_.begin(), distances_.end(), distance));
133 size_t before = after - 1;
134 const double distance_step_size =
Austin Schuh280996e2019-01-19 17:43:37 -0800135 (splines_.size() / static_cast<double>(distances_.size() - 1));
Austin Schuh941b46d2018-12-19 18:06:05 +1100136
Austin Schuh280996e2019-01-19 17:43:37 -0800137 const double alpha = (distance - distances_[before]) /
138 (distances_[after] - distances_[before]) *
139 distance_step_size +
140 static_cast<double>(before) * distance_step_size;
141 const size_t index = static_cast<size_t>(::std::floor(alpha));
142
143 return {index, alpha - index};
Austin Schuh941b46d2018-12-19 18:06:05 +1100144}
145
146} // namespace drivetrain
147} // namespace control_loops
148} // namespace frc971