syact/
act.rs

1use core::future::Future;
2
3use syunit::*;
4
5use crate::Setup;
6
7// ####################
8// #    SUBMODULES    #
9// ####################
10    /// A module for async components like a basic DC-motor. These components cannot move certain distances or to absolute positions
11    pub mod asyn;
12
13    mod comps;
14    pub use comps::{Conveyor, Gear, LinearAxis};
15
16    /// A module for component groups, as they are used in various robots. The components are all sharing the same 
17    /// [StepperConfig](crate::data::StepperConfig) and their movements are coordinated. 
18    pub mod group;
19    pub use group::SyncActuatorGroup;
20
21    /// ALl the parent structures used
22    pub mod parent;
23
24    /// Stepper motors and their unique methods and traits
25    pub mod stepper;
26    pub use stepper::{StepperActuator, Stepper};
27//
28
29// #####################
30// #    Interruptor    #
31// #####################
32    /// A trait for structs that help interrupting or watching movement processes, the most common use are measurement systems
33    pub trait Interruptor {
34        /// Direction of the interruptor
35        /// - If `None` the interruptor is not dependent on a movement direction
36        /// - If `Some` the interruptor is only active when moving in the given direction
37        /// 
38        /// ### Temporary dependence
39        /// 
40        /// If an interruptor was previously triggered by a movement, the control applies a temporary direction that lasts as long as
41        /// the interruptor is triggered. Otherwise a not direction dependent switch would block movements completely
42        fn dir(&self) -> Option<Direction>;
43        
44        /// Set temporary direction used to prevent locking of the axis
45        /// 
46        /// - A `Some` value sets the direction
47        /// - A `None` value resets the direction
48        /// 
49        /// See `dir` for information about temporary direction
50        fn set_temp_dir(&mut self, dir_opt : Option<Direction>);
51
52        /// Runs a check of the movement process and Interrupts if it has a reason to
53        fn check(&mut self, gamma : Gamma) -> Option<InterruptReason>;
54    }
55
56    /// Reasons why an interrupt was triggered
57    #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
58    pub enum InterruptReason {
59        /// A virtual end or a switch has been reached
60        EndReached,
61        /// The component has been overloaded
62        Overload,
63        /// Another error has occured
64        Error
65    }
66
67    /// Represents an interruptible component, meaning `Interruptors` can be attached to modify the movement process
68    pub trait Interruptible {
69        /// Add an interruptor to the component, often used for measurements or other processes checking the movement
70        fn add_interruptor(&mut self, interruptor : Box<dyn Interruptor + Send>);
71
72        /// Calls `add_interruptor` on an owned object
73        fn add_interruptor_inline(mut self, interruptor : Box<dyn Interruptor + Send>) -> Self 
74        where 
75            Self : Sized 
76        {
77            self.add_interruptor(interruptor);
78            self
79        }
80
81        /// Returns the interrupt reason if there is any (returns `None` otherwise)
82        /// 
83        /// # Note
84        /// 
85        /// Executing this function will replace the reason with `None`, so if you need to access the value multiple times, you have to store it yourself
86        fn intr_reason(&mut self) -> Option<InterruptReason>;
87    }
88//
89
90// ######################
91// #    SyncActuator    #
92// ######################
93    /// General Error type for `SyncActuators`
94    #[derive(Clone, Debug)]
95    pub enum SyncActuatorError {
96        /// The delta distance given is invalid
97        InvaldDeltaDistance(Delta),
98
99        // Motor specific errors
100        /// An error that occured with the `StepperBuilder` for a stepper motor
101        StepperBuilderError(crate::act::stepper::BuilderError),
102        /// An error that occured with the `StepperController` of a stepper motor
103        StepperCtrlError(crate::act::stepper::ControllerError),
104    }
105
106    impl core::fmt::Display for SyncActuatorError {
107        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108            f.write_fmt(format_args!("{:?}", self))
109        }
110    }
111
112    impl std::error::Error for SyncActuatorError { }
113    
114    /// A `Future` for drive operations
115    pub enum SyncDriveFuture {
116        /// The movement is still in process
117        Driving,
118        /// The movement is done, eiter successfully or not
119        Done(Result<(), SyncActuatorError>)
120    }
121
122    impl Future for SyncDriveFuture {
123        type Output = Result<(), SyncActuatorError>;
124
125        fn poll(self: core::pin::Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> std::task::Poll<Self::Output> {
126            match self.get_mut() {
127                Self::Driving => core::task::Poll::Pending,
128                Self::Done(v) => core::task::Poll::Ready(v.clone())
129            }
130        }
131    }
132
133
134    /// Trait for defining controls and components of synchronous actuators
135    /// 
136    /// # Parent components
137    /// 
138    /// Components can have multiple layers, for example take a stepper motor with a geaerbox attached to it. The stepper motor and both combined will be a component, the later having 
139    /// the stepper motor component defined as it's parent component. (See [Gear])
140    pub trait SyncActuator : Setup {
141        // Movement
142            /// Moves the component by the relative distance as fast as possible, halts the script until 
143            /// the movement is finshed and returns the actual **relative** distance travelled
144            fn drive_rel(&mut self, delta : Delta, speed : Factor) -> SyncDriveFuture;
145
146            /// Moves the component to the given position as fast as possible, halts the script until the 
147            /// movement is finished and returns the actual **relative** distance travelled.
148            #[inline]
149            fn drive_abs(&mut self, gamma : Gamma, speed : Factor) -> SyncDriveFuture {
150                let delta = gamma - self.gamma();
151                self.drive_rel(delta, speed)
152            }
153        // 
154
155        // Position
156            /// Returns the **absolute** position of the component.
157            /// 
158            /// ```rust
159            /// use syact::prelude::*;
160            /// 
161            /// // Position of components
162            /// const POS : Gamma = Gamma(10.0);
163            /// 
164            /// // Create a new cylinder (implements SyncComp)
165            /// let mut cylinder = LinearAxis::new(
166            ///     // Stepper Motor as subcomponent (also implements SyncComp)
167            ///     Stepper::new_gen().unwrap(), 
168            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the cylinder moves for 0.5 mm
169            /// 
170            /// cylinder.set_gamma(POS);
171            /// 
172            /// assert!((cylinder.gamma() - POS).abs() < Delta(0.05));      // Check with small tolerance
173            /// ```
174            fn gamma(&self) -> Gamma;
175
176            /// Overwrite the current **absolute** position of the component without triggering actual movements. 
177            /// 
178            /// Be aware that only full steps can be written in distance, meaning that for position comparision a 
179            /// small tolerance has to be considered, as the value written won't be the exact gamma value given.
180            /// 
181            /// ```rust
182            /// use syact::prelude::*;
183            /// 
184            /// // Position of components
185            /// const POS : Gamma = Gamma(10.0);
186            /// 
187            /// // Create a new cylinder (implements SyncComp)
188            /// let mut cylinder = LinearAxis::new(
189            ///     // Stepper Motor as subcomponent (also implements SyncComp)
190            ///     Stepper::new_gen().unwrap(), 
191            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the cylinder moves for 0.5 mm
192            /// 
193            /// cylinder.set_gamma(POS);
194            /// 
195            /// assert!((cylinder.gamma() - POS).abs() < Delta(0.05));      // Check with small tolerance
196            /// ```
197            fn set_gamma(&mut self, gamma : Gamma);
198
199            /// Returns the maximum velocity of the component. It can be set using `SyncComp::set_velocity_max()`. 
200            /// The component cannot move faster than the velocity  given (valid for all movement operations)
201            /// 
202            /// # Panics
203            /// 
204            /// - Panics if no parent component or an override is provided
205            fn velocity_max(&self) -> Velocity;
206
207            /// Set the maximum velocity of the component, current maximum velocity  can be access with `SyncComp::velocity_max()`
208            /// 
209            /// # Panics
210            /// 
211            /// - Panics if no parent component or an override is provided
212            /// - Panics if the velocity  given is higher than the maximum velocity  recommended (e.g. `StepperConst::velocity_max()`)
213            fn set_velocity_max(&mut self, velocity_max : Velocity);
214
215            /// Returns if any limit positions have been reached. The value returned can either be radians or millimeters, 
216            /// depending on the type of component.
217            /// 
218            /// # Limits
219            /// 
220            /// If the return value
221            /// - greater than 0, the maximum has been reached by the returned amount
222            /// - is smaller than 0, the minimum has been reached by the returned amount
223            /// - equal to 0, no limit has been reached
224            /// - NaN, no limit has been set yet
225            /// 
226            /// # Example 
227            /// 
228            /// ```rust
229            /// use syact::prelude::*;
230            /// 
231            /// // Limits
232            /// const LIM_MAX : Gamma = Gamma(1.0);
233            /// const LIM_MIN : Gamma = Gamma(-2.0);
234            /// 
235            /// const LIM_MIN_LOWER : Gamma = Gamma(-3.0);
236            /// 
237            /// // Create a new gear bearing (implements SyncComp)
238            /// let mut gear = Gear::new(
239            ///     // Stepper Motor as subcomponent (also implements SyncComp)
240            ///     Stepper::new_gen().unwrap(), 
241            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
242            /// 
243            /// gear.set_limits(Some(LIM_MIN), Some(LIM_MAX));
244            /// 
245            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
246            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
247            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-2.0));   // Under the minimum
248            /// 
249            /// gear.set_limits(Some(LIM_MIN_LOWER), None);                // Overwriting only `min` limit
250            /// 
251            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
252            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
253            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
254            /// 
255            /// gear.overwrite_limits(Some(LIM_MIN_LOWER), None);              // Overwriting only both limits with [overwrite_limits()]
256            /// 
257            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta::ZERO);    // In range, as the `max` limit has been deleted
258            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
259            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
260            /// ```
261            fn limits_for_gamma(&self, gamma : Gamma) -> Delta;
262
263            /// Sets an endpoint in the current direction by modifying the components limits. For example, when the component is moving
264            /// in the positive direction and the endpoint is set, this function will overwrite the current maximum limit with the current
265            /// gamma value. The component is then not allowed to move in the current direction anymore. 
266            fn set_end(&mut self, set_gamma : Gamma);
267
268            /// Set the limits for the minimum and maximum angles that the component can reach, note that the limit will 
269            /// be converted and transfered to the parent component if defined. 
270            /// 
271            /// Unlike [SyncComp::overwrite_limits()], this function does not overwrite the current `min` or `max` limits if they
272            /// are set to `None`. 
273            /// 
274            /// ```rust
275            /// use syact::prelude::*;
276            /// 
277            /// // Limits
278            /// const LIM_MAX : Gamma = Gamma(1.0);
279            /// const LIM_MIN : Gamma = Gamma(-2.0);
280            /// 
281            /// const LIM_MIN_LOWER : Gamma = Gamma(-3.0);
282            /// 
283            /// // Create a new gear bearing (implements SyncComp)
284            /// let mut gear = Gear::new(
285            ///     // Stepper Motor as subcomponent (also implements SyncComp)
286            ///     Stepper::new_gen().unwrap(), 
287            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
288            /// 
289            /// gear.set_limits(Some(LIM_MIN), Some(LIM_MAX));
290            /// 
291            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
292            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
293            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-2.0));   // Under the minimum
294            /// 
295            /// gear.set_limits(Some(LIM_MIN_LOWER), None);                // Overwriting only `min` limit
296            /// 
297            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
298            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
299            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
300            /// 
301            /// gear.overwrite_limits(Some(LIM_MIN_LOWER), None);              // Overwriting only both limits with [overwrite_limits()]
302            /// 
303            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta::ZERO);    // In range, as the `max` limit has been deleted
304            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
305            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
306            /// ```
307            fn set_limits(&mut self, min : Option<Gamma>, max : Option<Gamma>);
308
309            /// Set the limits for the minimum and maximum angles that the component can reach, note that the limit will 
310            /// be converted and transfered to the parent component if this component has one. 
311            /// 
312            /// The difference to [SyncComp::set_limits()] is that this function **overwrites** the current limits set.
313            /// 
314            /// ```rust
315            /// use syact::prelude::*;
316            /// 
317            /// // Limits
318            /// const LIM_MAX : Gamma = Gamma(1.0);
319            /// const LIM_MIN : Gamma = Gamma(-2.0);
320            /// 
321            /// const LIM_MIN_LOWER : Gamma = Gamma(-3.0);
322            /// 
323            /// // Create a new gear bearing (implements SyncComp)
324            /// let mut gear = Gear::new(
325            ///     // Stepper Motor as subcomponent (also implements SyncComp)
326            ///     Stepper::new_gen().unwrap(), 
327            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
328            /// 
329            /// gear.set_limits(Some(LIM_MIN), Some(LIM_MAX));
330            /// 
331            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
332            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
333            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-2.0));   // Under the minimum
334            /// 
335            /// gear.set_limits(Some(LIM_MIN_LOWER), None);                // Overwriting only `min` limit
336            /// 
337            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta(0.5));     // Over the maximum
338            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
339            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
340            /// 
341            /// gear.overwrite_limits(Some(LIM_MIN_LOWER), None);              // Overwriting only both limits with [overwrite_limits()]
342            /// 
343            /// assert_eq!(gear.limits_for_gamma(Gamma(1.5)), Delta::ZERO);    // In range, as the `max` limit has been deleted
344            /// assert_eq!(gear.limits_for_gamma(Gamma(0.5)), Delta::ZERO);    // In range
345            /// assert_eq!(gear.limits_for_gamma(Gamma(-4.0)), Delta(-1.0));   // Under the minimum, but less
346            /// ```
347            fn overwrite_limits(&mut self, min : Option<Gamma>, max : Option<Gamma>);
348        // 
349
350        // Load calculation
351            /// Will always be positive
352            fn force_gen(&self) -> Force;
353
354            /// Positive means CW direction
355            fn force_dir(&self) -> Force;
356
357            /// Apply a load force to the component, slowing down movements 
358            /// 
359            /// ### General force
360            /// 
361            /// Force value will always be made positive, as it will be subtracted in the calculation no matter how 
362            /// 
363            /// ```rust
364            /// use syact::prelude::*;
365            /// 
366            /// // Force to act upon the component
367            /// const FORCE : Force = Force(0.2);
368            /// 
369            /// // Create a new gear bearing (implements SyncComp)
370            /// let mut gear = Gear::new(
371            ///     // Stepper Motor as subcomponent (also implements SyncComp)
372            ///     Stepper::new_gen().unwrap(), 
373            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
374            /// 
375            /// gear.apply_gen_force(FORCE);
376            /// 
377            /// assert_eq!(Gamma(2.0), gear.gamma_for_child(Gamma(1.0)));
378            /// assert_eq!(Force(0.1), gear.child().force_gen());     // Forces get smaller for smaller gears
379            /// ```
380            fn apply_gen_force(&mut self, force : Force) -> Result<(), crate::Error>;
381
382            /// Value positive in CW direction
383            fn apply_dir_force(&mut self, force : Force) -> Result<(), crate::Error>;
384
385            // Inertia
386            /// Returns the inertia applied to the component
387            fn inertia(&self) -> Inertia;
388            
389            /// Apply a load inertia to the component, slowing down movements
390            /// 
391            /// # Panics
392            /// 
393            /// Panics if no parent component or override of the function has been provided.
394            /// 
395            /// ```rust
396            /// use syact::prelude::*;
397            /// 
398            /// // Inertia to act upon the component
399            /// const INERTIA : Inertia = Inertia(4.0);
400            /// 
401            /// // Create a new gear bearing (implements SyncComp)
402            /// let mut gear = Gear::new(
403            ///     // Stepper Motor as subcomponent (also implements SyncComp)
404            ///     Stepper::new_gen().unwrap(), 
405            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
406            /// 
407            /// // Applies the inertia to the gearbearing component
408            /// gear.apply_inertia(INERTIA);
409            /// 
410            /// assert_eq!(Gamma(2.0), gear.gamma_for_child(Gamma(1.0)));
411            /// assert_eq!(Inertia(1.0), gear.child().inertia());
412            /// ```
413            fn apply_inertia(&mut self, inertia : Inertia);
414        // 
415    }
416//