blob: bcd9d4c00e1c7e06cba553ed1477db8ab6f790c7 [file] [log] [blame]
Austin Schuh941b46d2018-12-19 18:06:05 +11001#include "frc971/control_loops/drivetrain/distance_spline.h"
2
Philipp Schrader790cb542023-07-05 21:06:52 -07003#include "glog/logging.h"
4
Austin Schuha6e7b212019-01-20 13:53:01 -08005#include "aos/logging/logging.h"
Austin Schuh941b46d2018-12-19 18:06:05 +11006#include "frc971/control_loops/drivetrain/spline.h"
7
Stephan Pleinesf63bde82024-01-13 15:59:33 -08008namespace frc971::control_loops::drivetrain {
Austin Schuh941b46d2018-12-19 18:06:05 +11009
James Kuszmaul75a18c52021-03-10 22:02:07 -080010::std::vector<float> DistanceSpline::BuildDistances(size_t num_alpha) {
Austin Schuhf7c65202022-11-04 21:28:20 -070011 num_alpha = num_alpha == 0 ? 100 * splines().size() : num_alpha;
James Kuszmaul75a18c52021-03-10 22:02:07 -080012 ::std::vector<float> distances;
Austin Schuh280996e2019-01-19 17:43:37 -080013 distances.push_back(0.0);
Austin Schuh941b46d2018-12-19 18:06:05 +110014
Austin Schuhf7c65202022-11-04 21:28:20 -070015 if (splines().size() > 1) {
Austin Schuha6e7b212019-01-20 13:53:01 -080016 // We've got a multispline to follow!
Ethan Wing20da69a2021-10-13 20:37:36 -070017 // Confirm that the ends line up to the correct number of derivatives.
Austin Schuhf7c65202022-11-04 21:28:20 -070018 for (size_t i = 1; i < splines().size(); ++i) {
19 const Spline &spline0 = splines()[i - 1];
20 const Spline &spline1 = splines()[i];
Austin Schuha6e7b212019-01-20 13:53:01 -080021
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,
Ethan Wing20da69a2021-10-13 20:37:36 -070038 "Splines %d and %d don't line up in the first derivative. [%f, "
Austin Schuha6e7b212019-01-20 13:53:01 -080039 "%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 Schuh7a105de2023-04-09 20:04:53 -070050 "Splines %d and %d don't line up in the second derivative. [%.7f, "
51 "%.7f] != [%.7f, %.7f]\n",
Austin Schuha6e7b212019-01-20 13:53:01 -080052 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
Philipp Schrader790cb542023-07-05 21:06:52 -070058 const double dalpha = static_cast<double>(splines().size()) /
59 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)),
Austin Schuhf7c65202022-11-04 21:28:20 -070068 splines().size() - 1);
69 return this->splines()[spline_index]
Austin Schuh280996e2019-01-19 17:43:37 -080070 .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
James Kuszmaul75a18c52021-03-10 22:02:07 -080079std::vector<Spline> FlatbufferToSplines(const MultiSpline *fb) {
80 CHECK_NOTNULL(fb);
81 const size_t spline_count = fb->spline_count();
82 CHECK_EQ(fb->spline_x()->size(), static_cast<size_t>(spline_count * 5 + 1));
83 CHECK_EQ(fb->spline_y()->size(), static_cast<size_t>(spline_count * 5 + 1));
84 std::vector<Spline> splines;
85 for (size_t ii = 0; ii < spline_count; ++ii) {
86 Eigen::Matrix<double, 2, 6> points;
87 for (int jj = 0; jj < 6; ++jj) {
88 points(0, jj) = fb->spline_x()->Get(ii * 5 + jj);
89 points(1, jj) = fb->spline_y()->Get(ii * 5 + jj);
90 }
91 splines.emplace_back(Spline(points));
92 }
93 return splines;
94}
95
Austin Schuhf7c65202022-11-04 21:28:20 -070096aos::SizedArray<Spline, FinishedDistanceSpline::kMaxSplines>
97SizedFlatbufferToSplines(const MultiSpline *fb) {
98 CHECK_NOTNULL(fb);
99 const size_t spline_count = fb->spline_count();
100 CHECK_EQ(fb->spline_x()->size(), static_cast<size_t>(spline_count * 5 + 1));
101 CHECK_EQ(fb->spline_y()->size(), static_cast<size_t>(spline_count * 5 + 1));
102 aos::SizedArray<Spline, FinishedDistanceSpline::kMaxSplines> splines;
103 for (size_t ii = 0; ii < spline_count; ++ii) {
104 Eigen::Matrix<double, 2, 6> points;
105 for (int jj = 0; jj < 6; ++jj) {
106 points(0, jj) = fb->spline_x()->Get(ii * 5 + jj);
107 points(1, jj) = fb->spline_y()->Get(ii * 5 + jj);
108 }
109 splines.emplace_back(Spline(points));
110 }
111 return splines;
112}
113
Austin Schuh280996e2019-01-19 17:43:37 -0800114DistanceSpline::DistanceSpline(::std::vector<Spline> &&splines, int num_alpha)
115 : splines_(::std::move(splines)), distances_(BuildDistances(num_alpha)) {}
116
117DistanceSpline::DistanceSpline(const Spline &spline, int num_alpha)
118 : splines_({spline}), distances_(BuildDistances(num_alpha)) {}
119
James Kuszmaul75a18c52021-03-10 22:02:07 -0800120DistanceSpline::DistanceSpline(const MultiSpline *fb, int num_alpha)
121 : splines_(FlatbufferToSplines(fb)),
122 distances_(BuildDistances(num_alpha)) {}
123
124// TODO(james): Directly use the flatbuffer vector for accessing distances,
125// rather than doing this redundant copy.
Austin Schuhf7c65202022-11-04 21:28:20 -0700126FinishedDistanceSpline::FinishedDistanceSpline(const fb::DistanceSpline &fb)
127 : splines_(SizedFlatbufferToSplines(fb.spline())),
128 distances_(fb.distances()->data(), fb.distances()->size()) {}
James Kuszmaul75a18c52021-03-10 22:02:07 -0800129
Austin Schuhf7c65202022-11-04 21:28:20 -0700130flatbuffers::Offset<fb::DistanceSpline> DistanceSplineBase::Serialize(
James Kuszmaul75a18c52021-03-10 22:02:07 -0800131 flatbuffers::FlatBufferBuilder *fbb,
132 flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Constraint>>>
133 constraints) const {
Austin Schuhf7c65202022-11-04 21:28:20 -0700134 if (splines().empty()) {
James Kuszmaul75a18c52021-03-10 22:02:07 -0800135 return {};
136 }
Austin Schuhf7c65202022-11-04 21:28:20 -0700137 const size_t num_points = splines().size() * 5 + 1;
James Kuszmaul75a18c52021-03-10 22:02:07 -0800138 float *spline_x_vector = nullptr;
139 float *spline_y_vector = nullptr;
140 const flatbuffers::Offset<flatbuffers::Vector<float>> spline_x_offset =
141 fbb->CreateUninitializedVector(num_points, &spline_x_vector);
142 const flatbuffers::Offset<flatbuffers::Vector<float>> spline_y_offset =
143 fbb->CreateUninitializedVector(num_points, &spline_y_vector);
144 CHECK_NOTNULL(spline_x_vector);
145 CHECK_NOTNULL(spline_y_vector);
Austin Schuhf7c65202022-11-04 21:28:20 -0700146 spline_x_vector[0] = splines()[0].control_points()(0, 0);
147 spline_y_vector[0] = splines()[0].control_points()(1, 0);
148 for (size_t spline_index = 0; spline_index < splines().size();
James Kuszmaul75a18c52021-03-10 22:02:07 -0800149 ++spline_index) {
150 for (size_t point = 1; point < 6u; ++point) {
151 spline_x_vector[spline_index * 5 + point] =
Austin Schuhf7c65202022-11-04 21:28:20 -0700152 splines()[spline_index].control_points()(0, point);
James Kuszmaul75a18c52021-03-10 22:02:07 -0800153 spline_y_vector[spline_index * 5 + point] =
Austin Schuhf7c65202022-11-04 21:28:20 -0700154 splines()[spline_index].control_points()(1, point);
James Kuszmaul75a18c52021-03-10 22:02:07 -0800155 }
156 }
157 MultiSpline::Builder multi_spline_builder(*fbb);
Austin Schuhf7c65202022-11-04 21:28:20 -0700158 multi_spline_builder.add_spline_count(splines().size());
James Kuszmaul75a18c52021-03-10 22:02:07 -0800159 multi_spline_builder.add_spline_x(spline_x_offset);
160 multi_spline_builder.add_spline_y(spline_y_offset);
161 multi_spline_builder.add_constraints(constraints);
162 const flatbuffers::Offset<MultiSpline> multi_spline_offset =
163 multi_spline_builder.Finish();
164 const flatbuffers::Offset<flatbuffers::Vector<float>> distances_offset =
Austin Schuhf7c65202022-11-04 21:28:20 -0700165 fbb->CreateVector(distances().data(), distances().size());
James Kuszmaul75a18c52021-03-10 22:02:07 -0800166 fb::DistanceSpline::Builder spline_builder(*fbb);
167 spline_builder.add_spline(multi_spline_offset);
168 spline_builder.add_distances(distances_offset);
169 return spline_builder.Finish();
170}
171
Austin Schuhf7c65202022-11-04 21:28:20 -0700172::Eigen::Matrix<double, 2, 1> DistanceSplineBase::DDXY(double distance) const {
Austin Schuh280996e2019-01-19 17:43:37 -0800173 const AlphaAndIndex a = DistanceToAlpha(distance);
174 const ::Eigen::Matrix<double, 2, 1> dspline_point =
Austin Schuhf7c65202022-11-04 21:28:20 -0700175 splines()[a.index].DPoint(a.alpha);
Austin Schuh280996e2019-01-19 17:43:37 -0800176 const ::Eigen::Matrix<double, 2, 1> ddspline_point =
Austin Schuhf7c65202022-11-04 21:28:20 -0700177 splines()[a.index].DDPoint(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +1100178
179 const double squared_norm = dspline_point.squaredNorm();
180
181 return ddspline_point / squared_norm -
Austin Schuhd749d932020-12-30 21:38:40 -0800182 dspline_point *
183 (dspline_point(0) * ddspline_point(0) +
184 dspline_point(1) * ddspline_point(1)) /
Austin Schuh941b46d2018-12-19 18:06:05 +1100185 ::std::pow(squared_norm, 2);
186}
187
Austin Schuhf7c65202022-11-04 21:28:20 -0700188double DistanceSplineBase::DDTheta(double distance) const {
Austin Schuh280996e2019-01-19 17:43:37 -0800189 const AlphaAndIndex a = DistanceToAlpha(distance);
Austin Schuh941b46d2018-12-19 18:06:05 +1100190
191 // TODO(austin): We are re-computing DPoint here even worse
Austin Schuh280996e2019-01-19 17:43:37 -0800192 const ::Eigen::Matrix<double, 2, 1> dspline_point =
Austin Schuhf7c65202022-11-04 21:28:20 -0700193 splines()[a.index].DPoint(a.alpha);
Austin Schuh280996e2019-01-19 17:43:37 -0800194 const ::Eigen::Matrix<double, 2, 1> ddspline_point =
Austin Schuhf7c65202022-11-04 21:28:20 -0700195 splines()[a.index].DDPoint(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +1100196
Austin Schuhf7c65202022-11-04 21:28:20 -0700197 const double dtheta = splines()[a.index].DTheta(a.alpha);
198 const double ddtheta = splines()[a.index].DDTheta(a.alpha);
Austin Schuh941b46d2018-12-19 18:06:05 +1100199
200 const double squared_norm = dspline_point.squaredNorm();
201
Austin Schuhd749d932020-12-30 21:38:40 -0800202 return ddtheta / squared_norm - dtheta *
203 (dspline_point(0) * ddspline_point(0) +
204 dspline_point(1) * ddspline_point(1)) /
205 ::std::pow(squared_norm, 2);
Austin Schuh941b46d2018-12-19 18:06:05 +1100206}
207
Austin Schuhf7c65202022-11-04 21:28:20 -0700208DistanceSplineBase::AlphaAndIndex DistanceSplineBase::DistanceToAlpha(
Austin Schuh280996e2019-01-19 17:43:37 -0800209 double distance) const {
Austin Schuh941b46d2018-12-19 18:06:05 +1100210 if (distance <= 0.0) {
Austin Schuh280996e2019-01-19 17:43:37 -0800211 return {0, 0.0};
Austin Schuh941b46d2018-12-19 18:06:05 +1100212 }
213 if (distance >= length()) {
Austin Schuhf7c65202022-11-04 21:28:20 -0700214 return {splines().size() - 1, 1.0};
Austin Schuh941b46d2018-12-19 18:06:05 +1100215 }
216
217 // Find the distance right below our number using a binary search.
218 size_t after = ::std::distance(
Austin Schuhf7c65202022-11-04 21:28:20 -0700219 distances().begin(),
220 ::std::lower_bound(distances().begin(), distances().end(), distance));
Austin Schuh941b46d2018-12-19 18:06:05 +1100221 size_t before = after - 1;
222 const double distance_step_size =
Austin Schuhf7c65202022-11-04 21:28:20 -0700223 (splines().size() / static_cast<double>(distances().size() - 1));
Austin Schuh941b46d2018-12-19 18:06:05 +1100224
Austin Schuhf7c65202022-11-04 21:28:20 -0700225 const double alpha = (distance - distances()[before]) /
226 (distances()[after] - distances()[before]) *
Austin Schuh280996e2019-01-19 17:43:37 -0800227 distance_step_size +
228 static_cast<double>(before) * distance_step_size;
229 const size_t index = static_cast<size_t>(::std::floor(alpha));
230
231 return {index, alpha - index};
Austin Schuh941b46d2018-12-19 18:06:05 +1100232}
233
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800234} // namespace frc971::control_loops::drivetrain