1use core::{
2 f64::consts::{FRAC_PI_2, PI},
3 future::Future,
4 pin::Pin,
5 task::Poll,
6 time::Duration,
7};
8
9use vexide::{
10 devices::smart::Motor,
11 time::{Instant, Sleep, sleep},
12};
13
14use evian_control::{
15 Tolerances,
16 loops::{AngularPid, ControlLoop, Pid},
17};
18use evian_drivetrain::Drivetrain;
19use evian_drivetrain::differential::{Differential, Voltages};
20use evian_math::{Angle, IntoAngle, Vec2};
21use evian_tracking::{TracksHeading, TracksPosition, TracksVelocity};
22
23pub(crate) struct State {
24 sleep: Sleep,
25 crossed: bool,
26 prev_facing_point: bool,
27 prev_time: Instant,
28 start_time: Instant,
29}
30
31pub struct MoveToPointFuture<
33 'a,
34 L: ControlLoop<Input = f64, Output = f64> + Unpin,
35 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
36 T: TracksPosition + TracksHeading + TracksVelocity,
37> {
38 pub(crate) target_point: Vec2<f64>,
39 pub(crate) reverse: bool,
40 pub(crate) timeout: Option<Duration>,
41 pub(crate) tolerances: Tolerances,
42 pub(crate) linear_controller: L,
43 pub(crate) angular_controller: A,
44 pub(crate) drivetrain: &'a mut Drivetrain<Differential, T>,
45 pub(crate) state: Option<State>,
46}
47
48impl<
51 L: ControlLoop<Input = f64, Output = f64> + Unpin,
52 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
53 T: TracksPosition + TracksHeading + TracksVelocity,
54> Future for MoveToPointFuture<'_, L, A, T>
55{
56 type Output = ();
57
58 fn poll(
59 self: core::pin::Pin<&mut Self>,
60 cx: &mut core::task::Context<'_>,
61 ) -> Poll<Self::Output> {
62 let this = self.get_mut();
63 let state = this.state.get_or_insert_with(|| {
64 let now = Instant::now();
65 let angle_error = (this.drivetrain.tracking.heading()
66 - (this.target_point - this.drivetrain.tracking.position())
67 .angle()
68 .rad())
69 .wrapped();
70
71 State {
72 sleep: sleep(Duration::from_millis(5)),
73 start_time: now,
74 prev_time: now,
75 crossed: false,
76 prev_facing_point: (angle_error.as_radians().abs() < FRAC_PI_2) ^ this.reverse,
77 }
78 });
79
80 if Pin::new(&mut state.sleep).poll(cx).is_pending() {
81 return Poll::Pending;
82 }
83
84 let dt = state.prev_time.elapsed();
85
86 let position = this.drivetrain.tracking.position();
87 let heading = this.drivetrain.tracking.heading();
88
89 let local_target = this.target_point - position;
90
91 let mut distance_error = local_target.length();
92 let mut angle_error = (heading - local_target.angle().rad()).wrapped();
93
94 if this.reverse {
95 distance_error *= -1.0;
96 angle_error = (PI.rad() - angle_error).wrapped();
97 }
98
99 let facing_point = angle_error.as_radians().abs() < FRAC_PI_2;
100
101 state.crossed = !state.crossed && state.prev_facing_point && !facing_point;
102 state.prev_facing_point = facing_point;
103
104 if state.crossed && !facing_point {
105 distance_error *= -1.0;
106 angle_error = (PI.rad() - angle_error).wrapped();
107 }
108
109 if this
110 .tolerances
111 .check(distance_error, this.drivetrain.tracking.linear_velocity())
112 || this
113 .timeout
114 .is_some_and(|timeout| state.start_time.elapsed() > timeout)
115 {
116 _ = this.drivetrain.motors.set_voltages((0.0, 0.0));
117 return Poll::Ready(());
118 }
119
120 let angular_output = this
121 .angular_controller
122 .update(-angle_error, Angle::ZERO, dt);
123 let linear_output =
124 this.linear_controller.update(-distance_error, 0.0, dt) * angle_error.cos();
125
126 _ = this.drivetrain.motors.set_voltages(
127 Voltages::from_arcade(linear_output, angular_output).normalized(Motor::V5_MAX_VOLTAGE),
128 );
129
130 state.sleep = sleep(Duration::from_millis(5));
131 state.prev_time = Instant::now();
132
133 cx.waker().wake_by_ref();
134 Poll::Pending
135 }
136}
137
138
139impl<
142 L: ControlLoop<Input = f64, Output = f64> + Unpin,
143 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
144 T: TracksPosition + TracksHeading + TracksVelocity,
145> MoveToPointFuture<'_, L, A, T>
146{
147 pub fn reverse(&mut self) -> &mut Self {
149 self.reverse = true;
150 self
151 }
152
153 pub fn with_linear_controller(&mut self, controller: L) -> &mut Self {
155 self.linear_controller = controller;
156 self
157 }
158
159 pub fn with_angular_controller(&mut self, controller: A) -> &mut Self {
161 self.angular_controller = controller;
162 self
163 }
164
165 pub const fn with_timeout(&mut self, timeout: Duration) -> &mut Self {
167 self.timeout = Some(timeout);
168 self
169 }
170
171 pub const fn without_timeout(&mut self) -> &mut Self {
173 self.timeout = None;
174 self
175 }
176
177 pub const fn with_tolerances(&mut self, tolerances: Tolerances) -> &mut Self {
179 self.tolerances = tolerances;
180 self
181 }
182
183 pub const fn with_error_tolerance(&mut self, tolerance: f64) -> &mut Self {
185 self.tolerances.error_tolerance = Some(tolerance);
186 self
187 }
188
189 pub const fn withear_error_tolerance(&mut self) -> &mut Self {
191 self.tolerances.error_tolerance = None;
192 self
193 }
194
195 pub const fn with_velocity_tolerance(&mut self, tolerance: f64) -> &mut Self {
197 self.tolerances.velocity_tolerance = Some(tolerance);
198 self
199 }
200
201 pub const fn withear_velocity_tolerance(&mut self) -> &mut Self {
203 self.tolerances.velocity_tolerance = None;
204 self
205 }
206
207 pub const fn with_tolerance_duration(&mut self, duration: Duration) -> &mut Self {
209 self.tolerances.duration = Some(duration);
210 self
211 }
212
213 pub const fn withear_tolerance_duration(&mut self) -> &mut Self {
215 self.tolerances.duration = None;
216 self
217 }
218}
219
220impl<
223 A: ControlLoop<Input = Angle, Output = f64> + Unpin,
224 T: TracksPosition + TracksHeading + TracksVelocity,
225> MoveToPointFuture<'_, Pid, A, T>
226{
227 pub const fn with_linear_gains(&mut self, kp: f64, ki: f64, kd: f64) -> &mut Self {
229 self.linear_controller.set_gains(kp, ki, kd);
230 self
231 }
232
233 pub const fn with_linear_kp(&mut self, kp: f64) -> &mut Self {
235 self.linear_controller.set_kp(kp);
236 self
237 }
238
239 pub const fn with_linear_ki(&mut self, ki: f64) -> &mut Self {
241 self.linear_controller.set_ki(ki);
242 self
243 }
244
245 pub const fn with_linear_kd(&mut self, kd: f64) -> &mut Self {
247 self.linear_controller.set_kd(kd);
248 self
249 }
250
251 pub const fn with_linear_integration_range(&mut self, integration_range: f64) -> &mut Self {
253 self.linear_controller
254 .set_integration_range(Some(integration_range));
255 self
256 }
257
258 pub const fn without_linear_integration_range(&mut self) -> &mut Self {
260 self.linear_controller.set_integration_range(None);
261 self
262 }
263
264 pub const fn with_linear_output_limit(&mut self, limit: f64) -> &mut Self {
266 self.linear_controller.set_output_limit(Some(limit));
267 self
268 }
269
270 pub const fn without_linear_output_limit(&mut self) -> &mut Self {
272 self.linear_controller.set_output_limit(None);
273 self
274 }
275}
276
277impl<
280 L: ControlLoop<Input = f64, Output = f64> + Unpin,
281 T: TracksPosition + TracksHeading + TracksVelocity,
282> MoveToPointFuture<'_, L, AngularPid, T>
283{
284 pub const fn with_angular_gains(&mut self, kp: f64, ki: f64, kd: f64) -> &mut Self {
286 self.angular_controller.set_gains(kp, ki, kd);
287 self
288 }
289
290 pub const fn with_angular_kp(&mut self, kp: f64) -> &mut Self {
292 self.angular_controller.set_kp(kp);
293 self
294 }
295
296 pub const fn with_angular_ki(&mut self, ki: f64) -> &mut Self {
298 self.angular_controller.set_ki(ki);
299 self
300 }
301
302 pub const fn with_angular_kd(&mut self, kd: f64) -> &mut Self {
304 self.angular_controller.set_kd(kd);
305 self
306 }
307
308 pub const fn with_angular_integration_range(&mut self, integration_range: Angle) -> &mut Self {
310 self.angular_controller
311 .set_integration_range(Some(integration_range));
312 self
313 }
314
315 pub const fn with_angular_output_limit(&mut self, limit: f64) -> &mut Self {
317 self.angular_controller.set_output_limit(Some(limit));
318 self
319 }
320
321 pub const fn without_angular_integration_range(&mut self) -> &mut Self {
323 self.angular_controller.set_integration_range(None);
324 self
325 }
326
327 pub const fn without_angular_output_limit(&mut self) -> &mut Self {
329 self.angular_controller.set_output_limit(None);
330 self
331 }
332}