1#[allow(unused_imports)] use crate::CummulativeSteps;
3#[cfg(not(feature = "std"))]
4#[allow(unused_imports)]
5use libm::F32Ext;
6
7use crate::{
8 utils::{Clamp, DurationHelpers},
9 Device, StepContext, SystemClock,
10};
11use core::{f32::EPSILON, time::Duration};
12
13#[derive(Debug, Default, PartialEq)]
20pub struct Driver {
21 max_speed: f32,
22 acceleration: f32,
23 current_position: i64,
24 step_interval: Duration,
25 speed: f32,
26 target_position: i64,
27 last_step_time: Duration,
28
29 step_counter: i64,
31 initial_step_size: Duration,
32 last_step_size: Duration,
33 min_step_size: Duration,
35}
36
37impl Driver {
38 pub fn new() -> Driver {
39 let mut d = Driver::default();
40
41 d.set_max_speed(1.0);
44 d.set_acceleration(1.0);
45
46 d
47 }
48
49 #[inline]
52 pub fn move_to(&mut self, location: i64) {
53 if self.target_position() != location {
54 self.target_position = location;
55 self.compute_new_speed();
56 }
57 }
58
59 #[inline]
61 pub fn move_by(&mut self, delta: i64) {
62 self.move_to(self.current_position() + delta);
63 }
64
65 #[inline]
72 pub fn set_max_speed(&mut self, steps_per_second: f32) {
73 debug_assert!(steps_per_second > 0.0);
74
75 self.max_speed = steps_per_second;
76 self.min_step_size =
77 Duration::from_secs_f32_2(steps_per_second.recip());
78 }
79
80 #[inline]
82 pub fn max_speed(&self) -> f32 { self.max_speed }
83
84 #[inline]
86 pub fn set_acceleration(&mut self, acceleration: f32) {
87 if acceleration == 0.0 {
88 return;
89 }
90
91 let acceleration = acceleration.abs();
92
93 if (self.acceleration - acceleration).abs() > EPSILON {
94 self.step_counter = (self.step_counter as f32 * self.acceleration
96 / acceleration) as i64;
97 let initial_step_size = 0.676 * (2.0 / acceleration).sqrt();
100 self.initial_step_size =
101 Duration::from_secs_f32_2(initial_step_size);
102 self.acceleration = acceleration;
103 self.compute_new_speed();
104 }
105 }
106
107 #[inline]
109 pub fn acceleration(&self) -> f32 { self.acceleration }
110
111 pub fn set_speed(&mut self, speed: f32) {
119 if (speed - self.speed).abs() < EPSILON {
120 return;
121 }
122
123 let speed = Clamp::clamp(speed, -self.max_speed, self.max_speed);
124
125 if speed == 0.0 || !speed.is_finite() {
126 self.step_interval = Duration::new(0, 0);
127 } else {
128 let duration_nanos = (1e9 / speed).abs().round();
129 self.step_interval = Duration::from_nanos(duration_nanos as u64);
130 }
131
132 self.speed = speed;
133 }
134
135 #[inline]
137 pub fn speed(&self) -> f32 { self.speed }
138
139 #[inline]
141 pub fn distance_to_go(&self) -> i64 {
142 self.target_position() - self.current_position()
143 }
144
145 #[inline]
147 pub fn target_position(&self) -> i64 { self.target_position }
148
149 #[inline]
155 pub fn set_current_position(&mut self, position: i64) {
156 self.current_position = position;
157 self.target_position = position;
158 self.step_interval = Duration::new(0, 0);
159 self.speed = 0.0;
160 }
161
162 #[inline]
170 pub fn current_position(&self) -> i64 { self.current_position }
171
172 #[inline]
175 pub fn stop(&mut self) {
176 if self.speed == 0.0 {
177 return;
178 }
179
180 let stopping_distance =
181 (self.speed * self.speed) / (2.0 * self.acceleration);
182 let steps_to_stop = stopping_distance.round() as i64 + 1;
183
184 if self.speed > 0.0 {
185 self.move_by(steps_to_stop);
186 } else {
187 self.move_by(-steps_to_stop);
188 }
189 }
190
191 #[inline]
193 pub fn is_running(&self) -> bool {
194 self.speed != 0.0 || self.target_position() != self.current_position()
195 }
196
197 fn compute_new_speed(&mut self) {
198 let distance_to = self.distance_to_go();
199 let distance_to_stop =
200 (self.speed() * self.speed()) / (2.0 * self.acceleration());
201 let steps_to_stop = distance_to_stop.round() as i64;
202
203 if distance_to == 0 && steps_to_stop <= 1 {
204 self.step_interval = Duration::new(0, 0);
206 self.speed = 0.0;
207 self.step_counter = 0;
208 return;
209 }
210
211 if distance_to > 0 {
212 if self.step_counter > 0 {
215 if steps_to_stop >= distance_to || distance_to < 0 {
218 self.step_counter = -steps_to_stop; }
220 } else if self.step_counter < 0 {
221 if steps_to_stop < distance_to && distance_to > 0 {
223 self.step_counter = -self.step_counter; }
225 }
226 } else if distance_to < 0 {
227 if self.step_counter > 0 {
230 if steps_to_stop >= -distance_to || distance_to > 0 {
233 self.step_counter = -steps_to_stop;
234 }
235 } else if self.step_counter < 0 {
236 if steps_to_stop < -distance_to && distance_to < 0 {
238 self.step_counter = -self.step_counter;
239 }
240 }
241 }
242
243 if self.step_counter == 0 {
244 self.last_step_size = self.initial_step_size;
246 } else {
247 let last_step_size = self.last_step_size.as_secs_f32_2();
250 let last_step_size = last_step_size
251 - last_step_size * 2.0
252 / ((4.0 * self.step_counter as f32) + 1.0);
253 self.last_step_size = Duration::from_secs_f32_2(last_step_size);
254 if self.last_step_size < self.min_step_size {
255 self.last_step_size = self.min_step_size;
256 }
257 }
258
259 self.step_counter += 1;
260 self.step_interval = self.last_step_size;
261 self.speed = self.last_step_size.as_secs_f32_2().recip();
262
263 if distance_to < 0 {
264 self.speed *= -1.0;
265 }
266 }
267
268 #[inline]
283 pub fn poll<C, D>(&mut self, device: D, clock: C) -> Result<(), D::Error>
284 where
285 C: SystemClock,
286 D: Device,
287 {
288 if self.poll_at_constant_speed(device, clock)? {
289 self.compute_new_speed();
290 }
291
292 Ok(())
293 }
294
295 pub fn poll_at_constant_speed<C, D>(
301 &mut self,
302 mut device: D,
303 clock: C,
304 ) -> Result<bool, D::Error>
305 where
306 C: SystemClock,
307 D: Device,
308 {
309 if self.step_interval == Duration::new(0, 0) {
311 return Ok(false);
312 }
313
314 let now = clock.elapsed();
315
316 if now - self.last_step_time >= self.step_interval {
317 let new_position = if self.distance_to_go() > 0 {
322 self.current_position + 1
323 } else {
324 self.current_position - 1
325 };
326
327 let ctx = StepContext {
328 position: new_position,
329 step_time: now,
330 };
331 device.step(&ctx)?;
332
333 self.current_position = new_position;
334 self.last_step_time = now; Ok(true)
337 } else {
338 Ok(false)
339 }
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use std::cell::Cell;
347
348 #[derive(Debug, Copy, Clone, PartialEq, Default)]
349 struct NopDevice;
350
351 impl Device for NopDevice {
352 type Error = ();
353
354 fn step(&mut self, _ctx: &StepContext) -> Result<(), Self::Error> {
355 Ok(())
356 }
357 }
358
359 #[derive(Debug, Default)]
360 struct DummyClock {
361 ticks: Cell<u32>,
362 }
363
364 impl SystemClock for DummyClock {
365 fn elapsed(&self) -> Duration {
366 let ticks = self.ticks.get();
367 self.ticks.set(ticks + 1);
368
369 Duration::new(ticks as u64, 0)
370 }
371 }
372
373 #[test]
374 fn compute_new_speeds_when_already_at_target() {
375 let mut driver = Driver::default();
376 driver.target_position = driver.current_position;
377
378 driver.compute_new_speed();
379
380 assert_eq!(driver.speed(), 0.0);
381 assert_eq!(driver.step_interval, Duration::new(0, 0));
382 }
383
384 #[test]
385 fn dont_step_when_already_at_target() {
386 let mut forward = 0;
387 let mut back = 0;
388 let clock = DummyClock::default();
389
390 {
391 let mut dev = crate::func_device(|| forward += 1, || back += 1);
392 let mut driver = Driver::new();
393 driver.target_position = driver.current_position;
394
395 for _ in 0..100 {
396 driver.poll(&mut dev, &clock).unwrap();
397 }
398 }
399
400 assert_eq!(forward, 0);
401 assert_eq!(back, 0);
402 }
403}