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//