Skip to main content

syact/
lib.rs

1#![doc = include_str!("../README.md")]
2#![crate_name = "syact"]
3#![no_std]
4#![deny(missing_docs)]
5
6// Modules
7extern crate alloc;
8
9// Private imports
10use alloc::boxed::Box;
11use syunit::*;
12
13// ####################
14// #    SUBMODULES    #
15// ####################
16    // Core
17        /// Everything about actuators that work asynchronously
18        mod asyn;
19        pub use asyn::AsyncActuator;
20
21        /// Common components and their implementations, like gears, linear axes etc.
22        pub mod comps;
23
24        /// Structs for storing characteristics of stepper motors and so on
25        pub mod data;
26
27        /// Functions and Structs for taking measurements with a robot for e.g. position calculation
28        pub mod meas;
29
30        /// Component parent relations and their implementation
31        pub mod parent;
32        pub use parent::{ActuatorParent, RatioActuatorParent};
33
34        /// Everything about actuators that work synchronously
35        pub mod sync;
36        pub use sync::{SyncActuator, SyncActuatorState, SyncActuatorBlocking, SyncActuatorNB}; 
37    // 
38
39    /// Embed unit system library
40    pub mod prelude;
41    pub use syunit as units;
42
43    // Testing
44    #[cfg(any(feature = "testing", test))]
45    mod tests;
46    #[cfg(any(feature = "testing", test))]
47    pub use tests::*;
48
49    use crate::data::ActuatorVars;
50// 
51
52// Macros
53    // TODO: Improve docs for this macro
54    /// Helper macro for merging multiple Actuator traits into one, useful for group implementation
55    #[macro_export]
56    macro_rules! merge_actuator_traits {
57        ($name:ident, $trait1:ident, $trait2:ident) => {
58            pub trait $name : $trait1 + $trait2 { }
59            impl<T : $trait1 + $trait2> $name for T { }
60        };
61        ($name:ident, $trait1:ident, $trait2:ident, $trait3:ident) => {
62            pub trait $name : $trait1 + $trait2 + $trait3 { }
63            impl<T : $trait1 + $trait2 + $trait3> $name for T { }
64        };
65        ($name:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
66            pub trait $name : $trait1 + $trait2 + $trait3 + $trait4 { }
67            impl<T : $trait1 + $trait2 + $trait3 + $trait4> $name for T { }
68        };
69    }
70// 
71
72// #####################
73// #    Interruptor    #
74// #####################
75    /// A trait for structs that help interrupting or watching movement processes, the most common use are measurement systems
76    pub trait Interruptor<U : UnitSet = Rotary> {
77        /// Direction of the interruptor
78        /// - If `None` the interruptor is not dependent on a movement direction
79        /// - If `Some` the interruptor is only active when moving in the given direction
80        /// 
81        /// ### Temporary dependence
82        /// 
83        /// If an interruptor was previously triggered by a movement, the control applies a temporary direction that lasts as long as
84        /// the interruptor is triggered. Otherwise a not direction dependent switch would block movements completely
85        fn dir(&self) -> Option<Direction>;
86        
87        /// Set temporary direction used to prevent locking of the axis
88        /// 
89        /// - A `Some` value sets the direction
90        /// - A `None` value resets the direction
91        /// 
92        /// See `dir` for information about temporary direction
93        fn set_temp_dir(&mut self, dir_opt : Option<Direction>);
94
95        /// Runs a check of the movement process and Interrupts if it has a reason to
96        fn check(&mut self, pos : U::Position) -> Option<InterruptReason>;
97    }
98
99    /// Reasons why an interrupt was triggered
100    #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
101    pub enum InterruptReason {
102        /// A virtual end or a switch has been reached
103        EndReached,
104        /// The component has been overloaded
105        Overload,
106        /// Another error has occured
107        Error
108    }
109
110    /// Represents an interruptible component, meaning `Interruptors` can be attached to modify the movement process
111    pub trait Interruptible<U : UnitSet = Rotary> {
112        /// Add an interruptor to the component, often used for measurements or other processes checking the movement
113        fn add_interruptor(&mut self, interruptor : Box<dyn Interruptor<U> + Send>);
114
115        /// Calls `add_interruptor` on an owned object
116        fn add_interruptor_inline(mut self, interruptor : Box<dyn Interruptor<U> + Send>) -> Self 
117        where 
118            Self : Sized 
119        {
120            self.add_interruptor(interruptor);
121            self
122        }
123
124        /// Returns the stored interrupt reason if there is any (returns `None` otherwise)
125        /// 
126        /// # Note
127        /// 
128        /// 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
129        fn intr_reason(&mut self) -> Option<InterruptReason>;
130    }
131//
132
133// #######################
134// #    ActuatorError    #
135// #######################
136    /// General Error type for `SyncActuators`
137    #[derive(Clone, Debug)]
138    pub enum ActuatorError<U : UnitSet = Rotary> {
139        /// The rel_dist distance given is invalid
140        InvaldRelativeDistance(U::Distance),
141
142        // U::Velocity errors
143            /// The velocity given is invalid somehow, depending on the context (see the function description)
144            InvalidVelocity(U::Velocity),
145            /// The velocity given is too high, depending on the context, see the function description
146            /// - 0: [U::Velocity] - The given velocity
147            /// - 1: [U::Velocity] - The maximum velocity
148            VelocityTooHigh(U::Velocity, U::Velocity),
149        //
150
151        // Acceleration
152            /// The [Acceleration] given is invalid somehow, depending on the context (see the function description)
153            InvalidAcceleration(U::Acceleration),
154        // 
155
156        // Jolt
157            /// The `Jolt` given is invalid somehow, depending on the context (see the function description)
158            InvalidJolt(U::Jolt),
159        // 
160
161        // Time errors
162            /// The `Time` given is invalid somehow, depending on the context, see the function description
163            InvalidTime(U::Time),
164        // 
165
166        // IO 
167            /// Something is wrong with the IO connections of the actuator (PINs etc.)
168            IOError,
169        // 
170
171        // Load
172            /// The component has been overloaded
173            Overload
174        // 
175    }
176
177    impl<U : UnitSet> core::fmt::Display for ActuatorError<U> {
178        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179            f.write_fmt(format_args!("ActuatorError: {:?}", self))
180        }
181    }
182
183    // TODO: Implement std errors
184    // impl std::error::Error for ActuatorError { }
185//
186
187// ###########################
188// #    Advanced Actuator    #
189// ###########################
190    /// An advanced actuator allows applying loads that alter the actuators movement
191    pub trait AdvancedActuator<U : UnitSet = Rotary> {
192        // Load calculation
193            // TODO: Documentation sucks
194            /// Will always be positive
195            fn force_gen(&self) -> U::Force;
196
197            // TODO: Documentation sucks
198            /// Positive means CW direction
199            fn force_dir(&self) -> U::Force;
200
201            /// Apply a load force to the component, slowing down movements 
202            /// 
203            /// ### General force
204            /// 
205            /// Force value will always be made positive, as it will be subtracted in the calculation no matter how 
206            /// 
207            /// ```rust
208            /// use syact::prelude::*;
209            /// 
210            /// // Force to act upon the component
211            /// const FORCE : NewtonMeters = NewtonMeters(0.2);
212            /// 
213            /// // Create a new gear bearing (implements AdvancedActuator)
214            /// let mut gear = Gear::new(
215            ///     // Stepper Motor as subcomponent (also implements AdvancedActuator), `default()` function is only available for tests!
216            ///     DemoActuator::new(), 
217            ///     // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
218            ///     0.5
219            /// );  
220            /// 
221            /// gear.apply_gen_force(FORCE);
222            /// 
223            /// assert_eq!(PositionRad(2.0), gear.pos_for_child(PositionRad(1.0)));
224            /// assert_eq!(NewtonMeters(0.1), gear.child().force_gen());     // Resistance gets smaller for this gear ratio
225            /// ```
226            fn apply_gen_force(&mut self, force : U::Force) -> Result<(), ActuatorError<U>>;
227
228            // TODO: Documentation sucks
229            /// Value positive in CW direction
230            fn apply_dir_force(&mut self, force : U::Force) -> Result<(), ActuatorError<U>>;
231
232            // Inertia
233            /// Returns the inertia applied to the component, see [AdvancedActuator::apply_inertia]
234            fn inertia(&self) -> U::Inertia;
235            
236            /// Apply a load inertia to the component, slowing down movements
237            /// 
238            /// # Panics
239            /// 
240            /// Panics if no parent component or override of the function has been provided.
241            /// 
242            /// ```rust
243            /// use syact::prelude::*;
244            /// 
245            /// // Inertia to act upon the component
246            /// const INERTIA : KgMeter2 = KgMeter2(4.0);
247            /// 
248            /// // Create a new gear bearing (implements AdvancedActuator)
249            /// let mut gear = Gear::new(
250            ///     // Stepper Motor as subcomponent (also implements AdvancedActuator), `default()` function is only available for tests!
251            ///     DemoActuator::new(), 
252            /// 0.5);    // Ratio is set to 0.5, which means for each radian the motor moves, the bearing moves for half a radian
253            /// 
254            /// // Applies the inertia to the gearbearing component
255            /// gear.apply_inertia(INERTIA);
256            /// 
257            /// assert_eq!(PositionRad(2.0), gear.pos_for_child(PositionRad(1.0)));
258            /// assert_eq!(KgMeter2(1.0), gear.child().inertia());          // Inertias get smaller with the ratio^2 !
259            /// ```
260            fn apply_inertia(&mut self, inertia : U::Inertia) -> Result<(), ActuatorError<U>> ;
261        // 
262    }
263
264    /// An actuator that has a defined time to move for a PTP (Point-To-Point) movement
265    pub trait DefinedActuator<U : UnitSet = Rotary> {
266        /// The time required to perform a certain PTP (Point-To-Point movement)
267        fn ptp_time_for_distance(&self, abs_pos_0 : U::Position, abs_pos_t : U::Position) -> U::Time;
268    }
269//