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