1use core::{
2 future::Future,
3 pin::Pin,
4 task::{Context, Poll},
5 time::Duration,
6};
7
8use vexide::{
9 devices::smart::Motor,
10 time::{Instant, Sleep, sleep},
11};
12
13use evian_control::{
14 Tolerances,
15 loops::{AngularPid, ControlLoop, Pid},
16};
17use evian_drivetrain::{
18 Drivetrain,
19 differential::{Differential, Voltages},
20};
21use evian_math::Angle;
22use evian_tracking::{TracksForwardTravel, TracksHeading, TracksVelocity};
23
24pub(crate) struct State {
25 sleep: Sleep,
26 initial_forward_travel: f64,
27 start_time: Instant,
28 prev_time: Instant,
29 linear_settled: bool,
30 angular_settled: bool,
31}
32
33pub struct DriveDistanceAtHeadingFuture<
35 'a,
36 L: ControlLoop<Input = f64, Output = f64> + Unpin,
37 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
38 T: TracksForwardTravel + TracksHeading + TracksVelocity,
39> {
40 pub(crate) target_distance: f64,
41 pub(crate) target_heading: Angle,
42 pub(crate) timeout: Option<Duration>,
43 pub(crate) linear_tolerances: Tolerances,
44 pub(crate) angular_tolerances: Tolerances,
45 pub(crate) linear_controller: L,
46 pub(crate) angular_controller: A,
47 pub(crate) drivetrain: &'a mut Drivetrain<Differential, T>,
48
49 pub(crate) state: Option<State>,
51}
52
53impl<
56 L: ControlLoop<Input = f64, Output = f64> + Unpin,
57 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
58 T: TracksForwardTravel + TracksHeading + TracksVelocity,
59> Future for DriveDistanceAtHeadingFuture<'_, L, A, T>
60{
61 type Output = ();
62
63 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
64 let this = self.get_mut();
65 let state = this.state.get_or_insert_with(|| {
66 let now = Instant::now();
67 State {
68 sleep: sleep(Duration::from_millis(5)),
69 initial_forward_travel: this.drivetrain.tracking.forward_travel(),
70 start_time: now,
71 prev_time: now,
72 linear_settled: false,
73 angular_settled: false,
74 }
75 });
76
77 if Pin::new(&mut state.sleep).poll(cx).is_pending() {
78 return Poll::Pending;
79 }
80
81 let dt = state.prev_time.elapsed();
82
83 let forward_travel = this.drivetrain.tracking.forward_travel();
84 let heading = this.drivetrain.tracking.heading();
85
86 let linear_error = (this.target_distance + state.initial_forward_travel) - forward_travel;
87 let angular_error = (this.target_heading - heading).wrapped();
88
89 if this
90 .linear_tolerances
91 .check(linear_error, this.drivetrain.tracking.linear_velocity())
92 {
93 state.linear_settled = true;
94 }
95 if this.angular_tolerances.check(
96 angular_error.as_radians(),
97 this.drivetrain.tracking.angular_velocity(),
98 ) {
99 state.angular_settled = true;
100 }
101
102 if (state.linear_settled && state.angular_settled)
103 || this
104 .timeout
105 .is_some_and(|timeout| state.start_time.elapsed() > timeout)
106 {
107 _ = this.drivetrain.motors.set_voltages((0.0, 0.0));
108 return Poll::Ready(());
109 }
110
111 let linear_output = this.linear_controller.update(
112 forward_travel,
113 this.target_distance + state.initial_forward_travel,
114 dt,
115 );
116 let angular_output = this
117 .angular_controller
118 .update(heading, this.target_heading, dt);
119
120 _ = this.drivetrain.motors.set_voltages(
121 Voltages(
122 linear_output + angular_output,
123 linear_output - angular_output,
124 )
125 .normalized(Motor::V5_MAX_VOLTAGE),
126 );
127
128 state.sleep = sleep(Duration::from_millis(5));
129 state.prev_time = Instant::now();
130
131 cx.waker().wake_by_ref();
132 Poll::Pending
133 }
134}
135
136impl<
139 L: ControlLoop<Input = f64, Output = f64> + Unpin,
140 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
141 T: TracksForwardTravel + TracksHeading + TracksVelocity,
142> DriveDistanceAtHeadingFuture<'_, L, A, T>
143{
144 pub fn with_linear_controller(&mut self, controller: L) -> &mut Self {
146 self.linear_controller = controller;
147 self
148 }
149
150 pub fn with_angular_controller(&mut self, controller: A) -> &mut Self {
152 self.angular_controller = controller;
153 self
154 }
155
156 pub const fn with_timeout(&mut self, timeout: Duration) -> &mut Self {
158 self.timeout = Some(timeout);
159 self
160 }
161
162 pub const fn without_timeout(&mut self) -> &mut Self {
164 self.timeout = None;
165 self
166 }
167
168 pub const fn with_linear_tolerances(&mut self, tolerances: Tolerances) -> &mut Self {
170 self.linear_tolerances = tolerances;
171 self
172 }
173
174 pub const fn with_linear_error_tolerance(&mut self, tolerance: f64) -> &mut Self {
176 self.linear_tolerances.error_tolerance = Some(tolerance);
177 self
178 }
179
180 pub const fn without_linear_error_tolerance(&mut self) -> &mut Self {
182 self.linear_tolerances.error_tolerance = None;
183 self
184 }
185
186 pub const fn with_linear_velocity_tolerance(&mut self, tolerance: f64) -> &mut Self {
188 self.linear_tolerances.velocity_tolerance = Some(tolerance);
189 self
190 }
191
192 pub const fn without_linear_velocity_tolerance(&mut self) -> &mut Self {
194 self.linear_tolerances.velocity_tolerance = None;
195 self
196 }
197
198 pub const fn with_linear_tolerance_duration(&mut self, duration: Duration) -> &mut Self {
200 self.linear_tolerances.duration = Some(duration);
201 self
202 }
203
204 pub const fn without_linear_tolerance_duration(&mut self) -> &mut Self {
206 self.linear_tolerances.duration = None;
207 self
208 }
209
210 pub const fn with_angular_tolerances(&mut self, tolerances: Tolerances) -> &mut Self {
212 self.angular_tolerances = tolerances;
213 self
214 }
215
216 pub const fn with_angular_error_tolerance(&mut self, tolerance: f64) -> &mut Self {
218 self.angular_tolerances.error_tolerance = Some(tolerance);
219 self
220 }
221
222 pub const fn without_angular_error_tolerance(&mut self) -> &mut Self {
224 self.angular_tolerances.error_tolerance = None;
225 self
226 }
227
228 pub const fn with_angular_velocity_tolerance(&mut self, tolerance: f64) -> &mut Self {
230 self.angular_tolerances.velocity_tolerance = Some(tolerance);
231 self
232 }
233
234 pub const fn without_angular_velocity_tolerance(&mut self) -> &mut Self {
236 self.angular_tolerances.velocity_tolerance = None;
237 self
238 }
239
240 pub const fn with_angular_tolerance_duration(&mut self, duration: Duration) -> &mut Self {
242 self.angular_tolerances.duration = Some(duration);
243 self
244 }
245
246 pub const fn without_angular_tolerance_duration(&mut self) -> &mut Self {
248 self.angular_tolerances.duration = None;
249 self
250 }
251}
252
253impl<
256 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
257 T: TracksForwardTravel + TracksHeading + TracksVelocity,
258> DriveDistanceAtHeadingFuture<'_, Pid, A, T>
259{
260 pub const fn with_linear_gains(&mut self, kp: f64, ki: f64, kd: f64) -> &mut Self {
262 self.linear_controller.set_gains(kp, ki, kd);
263 self
264 }
265
266 pub const fn with_linear_kp(&mut self, kp: f64) -> &mut Self {
268 self.linear_controller.set_kp(kp);
269 self
270 }
271
272 pub const fn with_linear_ki(&mut self, ki: f64) -> &mut Self {
274 self.linear_controller.set_ki(ki);
275 self
276 }
277
278 pub const fn with_linear_kd(&mut self, kd: f64) -> &mut Self {
280 self.linear_controller.set_kd(kd);
281 self
282 }
283
284 pub const fn with_linear_integration_range(&mut self, integration_range: f64) -> &mut Self {
286 self.linear_controller
287 .set_integration_range(Some(integration_range));
288 self
289 }
290
291 pub const fn without_linear_integration_range(&mut self) -> &mut Self {
293 self.linear_controller.set_integration_range(None);
294 self
295 }
296
297 pub const fn with_linear_output_limit(&mut self, limit: f64) -> &mut Self {
299 self.linear_controller.set_output_limit(Some(limit));
300 self
301 }
302
303 pub const fn without_linear_output_limit(&mut self) -> &mut Self {
305 self.linear_controller.set_output_limit(None);
306 self
307 }
308}
309
310impl<
313 L: ControlLoop<Input = f64, Output = f64> + Unpin,
314 T: TracksForwardTravel + TracksHeading + TracksVelocity,
315> DriveDistanceAtHeadingFuture<'_, L, AngularPid, T>
316{
317 pub const fn with_angular_gains(&mut self, kp: f64, ki: f64, kd: f64) -> &mut Self {
319 self.angular_controller.set_gains(kp, ki, kd);
320 self
321 }
322
323 pub const fn with_angular_kp(&mut self, kp: f64) -> &mut Self {
325 self.angular_controller.set_kp(kp);
326 self
327 }
328
329 pub const fn with_angular_ki(&mut self, ki: f64) -> &mut Self {
331 self.angular_controller.set_ki(ki);
332 self
333 }
334
335 pub const fn with_angular_kd(&mut self, kd: f64) -> &mut Self {
337 self.angular_controller.set_kd(kd);
338 self
339 }
340
341 pub const fn with_angular_integration_range(&mut self, integration_range: Angle) -> &mut Self {
343 self.angular_controller
344 .set_integration_range(Some(integration_range));
345 self
346 }
347
348 pub const fn with_angular_output_limit(&mut self, limit: f64) -> &mut Self {
350 self.angular_controller.set_output_limit(Some(limit));
351 self
352 }
353
354 pub const fn without_angular_integration_range(&mut self) -> &mut Self {
356 self.angular_controller.set_integration_range(None);
357 self
358 }
359
360 pub const fn without_angular_output_limit(&mut self) -> &mut Self {
362 self.angular_controller.set_output_limit(None);
363 self
364 }
365}