ChoreoLib
Choreo support library.
Loading...
Searching...
No Matches
DifferentialSample.h
1// Copyright (c) Choreo contributors
2
3#pragma once
4
5#include <functional>
6#include <type_traits>
7
8#include <Eigen/Core>
9#include <frc/geometry/Pose2d.h>
10#include <frc/kinematics/ChassisSpeeds.h>
11#include <frc/system/NumericalIntegration.h>
12#include <units/acceleration.h>
13#include <units/angle.h>
14#include <units/angular_acceleration.h>
15#include <units/angular_velocity.h>
16#include <units/force.h>
17#include <units/length.h>
18#include <units/time.h>
19#include <units/velocity.h>
20#include <wpi/MathExtras.h>
21#include <wpi/json_fwd.h>
22
23#include "choreo/util/AllianceFlipperUtil.h"
24
25namespace choreo {
26
31 public:
35 constexpr DifferentialSample() = default;
36
53 constexpr DifferentialSample(units::second_t timestamp, units::meter_t x,
54 units::meter_t y, units::radian_t heading,
55 units::meters_per_second_t vl,
56 units::meters_per_second_t vr,
57 units::radians_per_second_t omega,
58 units::meters_per_second_squared_t al,
59 units::meters_per_second_squared_t ar,
60 units::newton_t fl, units::newton_t fr)
62 x{x},
63 y{y},
65 vl{vl},
66 vr{vr},
67 omega{omega},
68 al{al},
69 ar{ar},
70 fl{fl},
71 fr{fr} {}
72
78 units::second_t GetTimestamp() const { return timestamp; }
79
85 constexpr frc::Pose2d GetPose() const {
86 return frc::Pose2d{x, y, frc::Rotation2d{heading}};
87 }
88
94 constexpr frc::ChassisSpeeds GetChassisSpeeds() const {
95 return frc::ChassisSpeeds{(vl + vr) / 2.0, 0_mps, omega};
96 }
97
104 constexpr DifferentialSample OffsetBy(units::second_t timeStampOffset) const {
105 return DifferentialSample{timestamp + timeStampOffset,
106 x,
107 y,
108 heading,
109 vl,
110 vr,
111 omega,
112 al,
113 ar,
114 fl,
115 fr};
116 }
117
126 units::second_t t) const {
127 units::scalar_t scale = (t - timestamp) / (endValue.timestamp - timestamp);
128
129 // Integrate the acceleration to get the rest of the state, since linearly
130 // interpolating the state gives an inaccurate result if the accelerations
131 // are changing between states
132 Eigen::Vector<double, 6> initialState{x.value(), y.value(),
133 heading.value(), vl.value(),
134 vr.value(), omega.value()};
135
136 auto width = (vr - vl) / omega;
137
138 // FIXME: this means the function cant be constexpr without c++23
139 std::function<Eigen::Vector<double, 6>(Eigen::Vector<double, 6>,
140 Eigen::Vector<double, 2>)>
141 f = [width](Eigen::Vector<double, 6> state,
142 Eigen::Vector<double, 2> input) {
143 // state = [x, y, θ, vₗ, vᵣ, ω]
144 // input = [aₗ, aᵣ]
145 //
146 // v = (vₗ + vᵣ)/2
147 // ω = (vᵣ − vₗ)/width
148 // α = (aᵣ − aₗ)/width
149 //
150 // ẋ = v cosθ
151 // ẏ = v sinθ
152 // θ̇ = ω
153 // v̇ₗ = aₗ
154 // v̇ᵣ = aᵣ
155 // ω̇ = α
156 auto θ = state(2, 0);
157 auto vl = state(3, 0);
158 auto vr = state(4, 0);
159 auto ω = state(5, 0);
160 auto al = input(0, 0);
161 auto ar = input(1, 0);
162 auto v = (vl + vr) / 2;
163 auto α = (ar - al) / width.value();
164 return Eigen::Vector<double, 6>{
165 v * std::cos(θ), v * std::sin(θ), ω, al, ar, α};
166 };
167
168 units::second_t τ = t - timestamp;
169 auto sample =
170 frc::RKDP(f, initialState, Eigen::Vector<double, 2>(al, ar), τ);
171
172 auto dt = endValue.timestamp - timestamp;
173 auto jl = (endValue.al - al) / dt;
174 auto jr = (endValue.ar - ar) / dt;
175
176 return DifferentialSample{
177 wpi::Lerp(timestamp, endValue.timestamp, scale),
178 units::meter_t{sample(0, 0)},
179 units::meter_t{sample(1, 0)},
180 units::radian_t{sample(2, 0)},
181 units::meters_per_second_t{sample(3, 0)},
182 units::meters_per_second_t{sample(4, 0)},
183 units::radians_per_second_t{sample(5, 0)},
184 al + jl * τ,
185 ar + jr * τ,
186 wpi::Lerp(fl, endValue.fl, scale),
187 wpi::Lerp(fr, endValue.fr, scale),
188 };
189 }
190
197 template <int Year = util::kDefaultYear>
198 constexpr DifferentialSample Flipped() const {
199 constexpr auto flipper = choreo::util::GetFlipperForYear<Year>();
200 if constexpr (flipper.isMirrored) {
201 return DifferentialSample(timestamp, flipper.FlipX(x), flipper.FlipY(y),
202 flipper.FlipHeading(heading), vr, vl, -omega,
203 ar, al, fr, fl);
204 } else {
205 return DifferentialSample(timestamp, flipper.FlipX(x), flipper.FlipY(y),
206 flipper.FlipHeading(heading), vl, vr, omega, al,
207 ar, fl, fr);
208 }
209 }
210
217 constexpr bool operator==(const DifferentialSample& other) const {
218 constexpr double epsilon = 1e-6;
219
220 auto compare_units = [epsilon](const auto& a, const auto& b) {
221 using UnitType =
222 std::remove_const_t<std::remove_reference_t<decltype(a)>>;
223 return units::math::abs(a - b) < UnitType(epsilon);
224 };
225
226 return compare_units(timestamp, other.timestamp) &&
227 compare_units(x, other.x) && compare_units(y, other.y) &&
228 compare_units(heading, other.heading) &&
229 compare_units(vl, other.vl) && compare_units(vr, other.vr) &&
230 compare_units(omega, other.omega) && compare_units(al, other.al) &&
231 compare_units(ar, other.ar) && compare_units(fl, other.fl) &&
232 compare_units(fr, other.fr);
233 }
234
236 units::second_t timestamp = 0_s;
237
239 units::meter_t x = 0_m;
240
242 units::meter_t y = 0_m;
243
245 units::radian_t heading = 0_rad;
246
248 units::meters_per_second_t vl = 0_mps;
249
251 units::meters_per_second_t vr = 0_mps;
252
254 units::radians_per_second_t omega = 0_rad_per_s;
255
257 units::meters_per_second_squared_t al = 0_mps_sq;
258
260 units::meters_per_second_squared_t ar = 0_mps_sq;
261
263 units::newton_t fl = 0_N;
264
266 units::newton_t fr = 0_N;
267};
268
269void to_json(wpi::json& json, const DifferentialSample& trajectorySample);
270void from_json(const wpi::json& json, DifferentialSample& trajectorySample);
271
272} // namespace choreo
273
274#include "choreo/trajectory/struct/DifferentialSampleStruct.h"
Definition DifferentialSample.h:30
units::newton_t fl
The force of the left wheels.
Definition DifferentialSample.h:263
units::meter_t y
The Y position of the sample relative to the blue alliance wall origin.
Definition DifferentialSample.h:242
constexpr bool operator==(const DifferentialSample &other) const
Definition DifferentialSample.h:217
units::second_t timestamp
The timestamp of this sample relative to the beginning of the trajectory.
Definition DifferentialSample.h:236
constexpr DifferentialSample Flipped() const
Definition DifferentialSample.h:198
units::radian_t heading
The heading of the sample, with 0 being in the +X direction.
Definition DifferentialSample.h:245
units::newton_t fr
The force of the right wheels.
Definition DifferentialSample.h:266
units::radians_per_second_t omega
The chassis angular velocity.
Definition DifferentialSample.h:254
units::second_t GetTimestamp() const
Definition DifferentialSample.h:78
units::meters_per_second_t vr
The velocity of the right wheels.
Definition DifferentialSample.h:251
constexpr DifferentialSample()=default
constexpr frc::Pose2d GetPose() const
Definition DifferentialSample.h:85
constexpr frc::ChassisSpeeds GetChassisSpeeds() const
Definition DifferentialSample.h:94
units::meters_per_second_t vl
The velocity of the left wheels.
Definition DifferentialSample.h:248
units::meters_per_second_squared_t al
The acceleration of the left wheels.
Definition DifferentialSample.h:257
constexpr DifferentialSample OffsetBy(units::second_t timeStampOffset) const
Definition DifferentialSample.h:104
constexpr DifferentialSample(units::second_t timestamp, units::meter_t x, units::meter_t y, units::radian_t heading, units::meters_per_second_t vl, units::meters_per_second_t vr, units::radians_per_second_t omega, units::meters_per_second_squared_t al, units::meters_per_second_squared_t ar, units::newton_t fl, units::newton_t fr)
Definition DifferentialSample.h:53
units::meter_t x
The X position of the sample relative to the blue alliance wall origin.
Definition DifferentialSample.h:239
units::meters_per_second_squared_t ar
The acceleration of the right wheels.
Definition DifferentialSample.h:260
DifferentialSample Interpolate(const DifferentialSample &endValue, units::second_t t) const
Definition DifferentialSample.h:125