ev3dev_lang_rust/motors/
tacho_motor_macro.rs

1//! The TachoMotor provides a uniform interface for using motors with positional
2//! and directional feedback such as the EV3 and NXT motors.
3//! This feedback allows for precise control of the motors.
4
5/// The TachoMotor provides a uniform interface for using motors with positional
6/// and directional feedback such as the EV3 and NXT motors.
7/// This feedback allows for precise control of the motors.
8#[macro_export]
9macro_rules! tacho_motor {
10    () => {
11        /// Causes the motor to run until another command is sent.
12        pub const COMMAND_RUN_FOREVER: &'static str = "run-forever";
13
14        /// Runs the motor to an absolute position specified by `position_sp`
15        /// and then stops the motor using the command specified in `stop_action`.
16        pub const COMMAND_RUN_TO_ABS_POS: &'static str = "run-to-abs-pos";
17
18        /// Runs the motor to a position relative to the current position value.
19        /// The new position will be current `position` + `position_sp`.
20        /// When the new position is reached, the motor will stop using the command specified by `stop_action`.
21        pub const COMMAND_RUN_TO_REL_POS: &'static str = "run-to-rel-pos";
22
23        /// Run the motor for the amount of time specified in `time_sp`
24        /// and then stops the motor using the command specified by `stop_action`.
25        pub const COMMAND_RUN_TIMED: &'static str = "run-timed";
26
27        /// Runs the motor using the duty cycle specified by `duty_cycle_sp`.
28        /// Unlike other run commands, changing `duty_cycle_sp` while running will take effect immediately.
29        pub const COMMAND_RUN_DIRECT: &'static str = "run-direct";
30
31        /// Stop any of the run commands before they are complete using the command specified by `stop_action`.
32        pub const COMMAND_STOP: &'static str = "stop";
33
34        /// Resets all of the motor parameter attributes to their default values.
35        /// This will also have the effect of stopping the motor.
36        pub const COMMAND_RESET: &'static str = "reset";
37
38        /// A positive duty cycle will cause the motor to rotate clockwise.
39        pub const POLARITY_NORMAL: &'static str = "normal";
40
41        /// A positive duty cycle will cause the motor to rotate counter-clockwise.
42        pub const POLARITY_INVERSED: &'static str = "inversed";
43
44        /// Power is being sent to the motor.
45        pub const STATE_RUNNING: &'static str = "running";
46
47        /// The motor is ramping up or down and has not yet reached a pub constant output level.
48        pub const STATE_RAMPING: &'static str = "ramping";
49
50        /// The motor is not turning, but rather attempting to hold a fixed position.
51        pub const STATE_HOLDING: &'static str = "holding";
52
53        /// The motor is turning as fast as possible, but cannot reach its `speed_sp`.
54        pub const STATE_OVERLOADED: &'static str = "overloaded";
55
56        /// The motor is trying to run but is not turning at all.
57        pub const STATE_STALLED: &'static str = "stalled";
58
59        /// Removes power from the motor. The motor will freely coast to a stop.
60        pub const STOP_ACTION_COAST: &'static str = "coast";
61
62        /// Removes power from the motor and creates a passive electrical load.
63        /// This is usually done by shorting the motor terminals together.
64        /// This load will absorb the energy from the rotation of the motors
65        /// and cause the motor to stop more quickly than coasting.
66        pub const STOP_ACTION_BRAKE: &'static str = "brake";
67
68        /// Causes the motor to actively try to hold the current position.
69        /// If an external force tries to turn the motor, the motor will “push back” to maintain its position.
70        pub const STOP_ACTION_HOLD: &'static str = "hold";
71
72        /// Returns the number of tacho counts in one rotation of the motor.
73        ///
74        /// Tacho counts are used by the position and speed attributes,
75        /// so you can use this value to convert from rotations or degrees to tacho counts.
76        /// (rotation motors only)
77        ///
78        /// # Examples
79        ///
80        /// ```no_run
81        /// use ev3dev_lang_rust::motors::LargeMotor;
82        ///
83        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
84        /// // Init a tacho motor.
85        /// let motor = LargeMotor::find()?;
86        ///
87        /// // Get position and count_per_rot as f32.
88        /// let position = motor.get_position()? as f32;
89        /// let count_per_rot = motor.get_count_per_rot()? as f32;
90        ///
91        /// // Calculate the rotation count.
92        /// let rotations = position / count_per_rot;
93        ///
94        /// println!("The motor did {:.2} rotations", rotations);
95        /// # Ok(())
96        /// # }
97        /// ```
98        pub fn get_count_per_rot(&self) -> Ev3Result<i32> {
99            self.get_attribute("count_per_rot").get()
100        }
101
102        /// Returns the number of tacho counts in one meter of travel of the motor.
103        ///
104        /// Tacho counts are used by the position and speed attributes,
105        /// so you can use this value to convert from distance to tacho counts.
106        /// (linear motors only)
107        pub fn get_count_per_m(&self) -> Ev3Result<i32> {
108            self.get_attribute("count_per_m").get()
109        }
110
111        /// Returns the number of tacho counts in the full travel of the motor.
112        ///
113        /// When combined with the count_per_m attribute,
114        /// you can use this value to calculate the maximum travel distance of the motor.
115        /// (linear motors only)
116        pub fn get_full_travel_count(&self) -> Ev3Result<i32> {
117            self.get_attribute("full_travel_count").get()
118        }
119
120        /// Returns the current duty cycle of the motor. Units are percent.
121        ///
122        /// Values are -100 to 100.
123        ///
124        /// # Examples
125        ///
126        /// ```no_run
127        /// use ev3dev_lang_rust::motors::LargeMotor;
128        /// use std::thread;
129        /// use std::time::Duration;
130        ///
131        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
132        /// // Init a tacho motor.
133        /// let motor = LargeMotor::find()?;
134        ///
135        /// // Set the motor command `run-direct` to start rotation.
136        /// motor.run_direct()?;
137        ///
138        /// // Rotate motor forward and wait 5 seconds.
139        /// motor.set_duty_cycle_sp(50)?;
140        /// thread::sleep(Duration::from_secs(5));
141        ///
142        /// assert_eq!(motor.get_duty_cycle()?, 50);
143        /// # Ok(())
144        /// # }
145        pub fn get_duty_cycle(&self) -> Ev3Result<i32> {
146            self.get_attribute("duty_cycle").get()
147        }
148
149        /// Returns the current duty cycle setpoint of the motor.
150        ///
151        /// Units are in percent.
152        /// Valid values are -100 to 100. A negative value causes the motor to rotate in reverse.
153        ///
154        /// # Examples
155        ///
156        /// ```no_run
157        /// use ev3dev_lang_rust::motors::LargeMotor;
158        /// use std::thread;
159        /// use std::time::Duration;
160        ///
161        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
162        /// // Init a tacho motor.
163        /// let motor = LargeMotor::find()?;
164        ///
165        /// // Rotate motor forward and wait 5 seconds.
166        /// motor.set_duty_cycle_sp(50)?;
167        /// thread::sleep(Duration::from_secs(5));
168        ///
169        /// assert_eq!(motor.get_duty_cycle()?, 50);
170        /// # Ok(())
171        /// # }
172        pub fn get_duty_cycle_sp(&self) -> Ev3Result<i32> {
173            self.get_attribute("duty_cycle_sp").get()
174        }
175
176        /// Sets the duty cycle setpoint of the motor.
177        ///
178        /// Units are in percent.
179        /// Valid values are -100 to 100. A negative value causes the motor to rotate in reverse.
180        ///
181        /// # Examples
182        ///
183        /// ```no_run
184        /// use ev3dev_lang_rust::motors::LargeMotor;
185        /// use std::thread;
186        /// use std::time::Duration;
187        ///
188        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
189        /// // Init a tacho motor.
190        /// let motor = LargeMotor::find()?;
191        ///
192        /// // Set the motor command `run-direct` to start rotation.
193        /// motor.run_direct()?;
194        ///
195        /// // Rotate motor forward and wait 5 seconds.
196        /// motor.set_duty_cycle_sp(50)?;
197        /// thread::sleep(Duration::from_secs(5));
198        ///
199        /// // Rotate motor backward and wait 5 seconds.
200        /// motor.set_duty_cycle_sp(-50)?;
201        /// thread::sleep(Duration::from_secs(5));
202        /// # Ok(())
203        /// # }
204        pub fn set_duty_cycle_sp(&self, duty_cycle: i32) -> Ev3Result<()> {
205            self.get_attribute("duty_cycle_sp").set(duty_cycle)
206        }
207
208        /// Returns the current polarity of the motor.
209        pub fn get_polarity(&self) -> Ev3Result<String> {
210            self.get_attribute("polarity").get()
211        }
212
213        /// Sets the polarity of the motor.
214        pub fn set_polarity(&self, polarity: &str) -> Ev3Result<()> {
215            self.get_attribute("polarity").set_str_slice(polarity)
216        }
217
218        /// Returns the current position of the motor in pulses of the rotary encoder.
219        ///
220        /// When the motor rotates clockwise, the position will increase.
221        /// Likewise, rotating counter-clockwise causes the position to decrease.
222        /// The range is -2,147,483,648 and +2,147,483,647 tachometer counts (32-bit signed integer)
223        ///
224        /// # Examples
225        ///
226        /// ```no_run
227        /// use ev3dev_lang_rust::motors::LargeMotor;
228        ///
229        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
230        /// // Init a tacho motor.
231        /// let motor = LargeMotor::find()?;
232        ///
233        /// // Get position and count_per_rot as f32.
234        /// let position = motor.get_position()? as f32;
235        /// let count_per_rot = motor.get_count_per_rot()? as f32;
236        ///
237        /// // Calculate the rotation count.
238        /// let rotations: f32 = position / count_per_rot;
239        ///
240        /// println!("The motor did {:.2} rotations", rotations);
241        /// # Ok(())
242        /// # }
243        /// ```
244        pub fn get_position(&self) -> Ev3Result<i32> {
245            self.get_attribute("position").get()
246        }
247
248        /// Sets the current position of the motor in pulses of the rotary encoder.
249        ///
250        /// When the motor rotates clockwise, the position will increase.
251        /// Likewise, rotating counter-clockwise causes the position to decrease.
252        /// The range is -2,147,483,648 and +2,147,483,647 tachometer counts (32-bit signed integer)
253        ///
254        /// # Examples
255        ///
256        /// ```no_run
257        /// use ev3dev_lang_rust::motors::LargeMotor;
258        ///
259        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
260        /// // Init a tacho motor.
261        /// let motor = LargeMotor::find()?;
262        ///
263        /// motor.set_position(0)?;
264        /// let position = motor.get_position()?;
265        ///
266        /// // If the motor is not moving, the position value
267        /// // should not change between set and get operation.
268        /// assert_eq!(position, 0);
269        /// # Ok(())
270        /// # }
271        /// ```
272        pub fn set_position(&self, position: i32) -> Ev3Result<()> {
273            self.get_attribute("position").set(position)
274        }
275
276        /// Returns the proportional pub constant for the position PID.
277        pub fn get_hold_pid_kp(&self) -> Ev3Result<f32> {
278            self.get_attribute("hold_pid/Kp").get()
279        }
280
281        /// Sets the proportional pub constant for the position PID.
282        pub fn set_hold_pid_kp(&self, kp: f32) -> Ev3Result<()> {
283            self.get_attribute("hold_pid/Kp").set(kp)
284        }
285
286        /// Returns the integral pub constant for the position PID.
287        pub fn get_hold_pid_ki(&self) -> Ev3Result<f32> {
288            self.get_attribute("hold_pid/Ki").get()
289        }
290
291        /// Sets the integral pub constant for the position PID.
292        pub fn set_hold_pid_ki(&self, ki: f32) -> Ev3Result<()> {
293            self.get_attribute("hold_pid/Ki").set(ki)
294        }
295
296        /// Returns the derivative pub constant for the position PID.
297        pub fn get_hold_pid_kd(&self) -> Ev3Result<f32> {
298            self.get_attribute("hold_pid/Kd").get()
299        }
300
301        /// Sets the derivative pub constant for the position PID.
302        pub fn set_hold_pid_kd(&self, kd: f32) -> Ev3Result<()> {
303            self.get_attribute("hold_pid/Kd").set(kd)
304        }
305
306        /// Returns the maximum value that is accepted by the `speed_sp` attribute.
307        ///
308        /// This value is the speed of the motor at 9V with no load.
309        /// Note: The actual maximum obtainable speed will be less than this
310        /// and will depend on battery voltage and mechanical load on the motor.
311        pub fn get_max_speed(&self) -> Ev3Result<i32> {
312            self.get_attribute("max_speed").get()
313        }
314
315        /// Returns the current target position for the `run-to-abs-pos` and `run-to-rel-pos` commands.
316        ///
317        /// Units are in tacho counts.
318        /// You can use the value returned by `counts_per_rot` to convert tacho counts to/from rotations or degrees.
319        ///
320        /// The range is -2,147,483,648 and +2,147,483,647 tachometer counts (32-bit signed integer).
321        pub fn get_position_sp(&self) -> Ev3Result<i32> {
322            self.get_attribute("position_sp").get()
323        }
324
325        /// Sets the target position for the `run-to-abs-pos` and `run-to-rel-pos` commands.
326        ///
327        /// Units are in tacho counts.
328        /// You can use the value returned by `counts_per_rot` to convert tacho counts to/from rotations or degrees.
329        ///
330        /// The range is -2,147,483,648 and +2,147,483,647 tachometer counts (32-bit signed integer).
331        ///
332        /// # Examples
333        ///
334        /// ```ignore
335        /// use ev3dev_lang_rust::motors::LargeMotor;
336        /// use std::thread;
337        /// use std::time::Duration;
338        ///
339        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
340        /// // Init a tacho motor.
341        /// let motor = LargeMotor::find()?;
342        ///
343        /// // Save the current position.
344        /// let old_position = motor.get_position()?;
345        ///
346        /// // Rotate by 100 ticks
347        /// let position = motor.set_position_sp(100)?;
348        /// motor.run_to_rel_pos(None)?;
349        ///
350        /// // Wait till rotation is finished.
351        /// motor.wait_until_not_moving(None);
352        ///
353        /// // The new position should be 100 ticks larger.
354        /// let new_position = motor.get_position()?;
355        /// assert_eq!(old_position + 100, new_position);
356        /// # Ok(())
357        /// # }
358        /// ```
359        pub fn set_position_sp(&self, position_sp: i32) -> Ev3Result<()> {
360            self.get_attribute("position_sp").set(position_sp)
361        }
362
363        /// Returns the current motor speed in tacho counts per second.
364        ///
365        /// Note, this is not necessarily degrees (although it is for LEGO motors).
366        /// Use the `count_per_rot` attribute to convert this value to RPM or deg/sec.
367        pub fn get_speed(&self) -> Ev3Result<i32> {
368            self.get_attribute("speed").get()
369        }
370
371        /// Returns the target speed in tacho counts per second used for all run-* commands except run-direct.
372        ///
373        /// A negative value causes the motor to rotate in reverse
374        /// with the exception of run-to-*-pos commands where the sign is ignored.
375        /// Use the `count_per_rot` attribute to convert RPM or deg/sec to tacho counts per second.
376        /// Use the `count_per_m` attribute to convert m/s to tacho counts per second.
377        pub fn get_speed_sp(&self) -> Ev3Result<i32> {
378            self.get_attribute("speed_sp").get()
379        }
380
381        /// Sets the target speed in tacho counts per second used for all run-* commands except run-direct.
382        ///
383        /// A negative value causes the motor to rotate in reverse
384        /// with the exception of run-to-*-pos commands where the sign is ignored.
385        /// Use the `count_per_rot` attribute to convert RPM or deg/sec to tacho counts per second.
386        /// Use the `count_per_m` attribute to convert m/s to tacho counts per second.
387        pub fn set_speed_sp(&self, speed_sp: i32) -> Ev3Result<()> {
388            self.get_attribute("speed_sp").set(speed_sp)
389        }
390
391        /// Returns the current ramp up setpoint.
392        ///
393        /// Units are in milliseconds and must be positive. When set to a non-zero value,
394        /// the motor speed will increase from 0 to 100% of `max_speed` over the span of this setpoint.
395        /// The actual ramp time is the ratio of the difference between the speed_sp
396        /// and the current speed and max_speed multiplied by ramp_up_sp. Values must not be negative.
397        pub fn get_ramp_up_sp(&self) -> Ev3Result<i32> {
398            self.get_attribute("ramp_up_sp").get()
399        }
400
401        /// Sets the ramp up setpoint.
402        ///
403        /// Units are in milliseconds and must be positive. When set to a non-zero value,
404        /// the motor speed will increase from 0 to 100% of `max_speed` over the span of this setpoint.
405        /// The actual ramp time is the ratio of the difference between the speed_sp
406        /// and the current speed and max_speed multiplied by ramp_up_sp. Values must not be negative.
407        pub fn set_ramp_up_sp(&self, ramp_up_sp: i32) -> Ev3Result<()> {
408            self.get_attribute("ramp_up_sp").set(ramp_up_sp)
409        }
410
411        /// Returns the current ramp down setpoint.
412        ///
413        /// Units are in milliseconds and must be positive. When set to a non-zero value,
414        /// the motor speed will decrease from 100% down to 0 of `max_speed` over the span of this setpoint.
415        /// The actual ramp time is the ratio of the difference between the speed_sp
416        /// and the current speed and 0 multiplied by ramp_down_sp. Values must not be negative.
417        pub fn get_ramp_down_sp(&self) -> Ev3Result<i32> {
418            self.get_attribute("ramp_down_sp").get()
419        }
420
421        /// Sets the ramp down setpoint.
422        ///
423        /// Units are in milliseconds and must be positive. When set to a non-zero value,
424        /// the motor speed will decrease from 100% down to 0 of `max_speed` over the span of this setpoint.
425        /// The actual ramp time is the ratio of the difference between the speed_sp
426        /// and the current speed and 0 multiplied by ramp_down_sp. Values must not be negative.
427        pub fn set_ramp_down_sp(&self, ramp_down_sp: i32) -> Ev3Result<()> {
428            self.get_attribute("ramp_down_sp").set(ramp_down_sp)
429        }
430
431        /// Returns the proportional pub constant for the speed regulation PID.
432        pub fn get_speed_pid_kp(&self) -> Ev3Result<f32> {
433            self.get_attribute("speed_pid/Kp").get()
434        }
435
436        /// Sets the proportional pub constant for the speed regulation PID.
437        pub fn set_speed_pid_kp(&self, kp: f32) -> Ev3Result<()> {
438            self.get_attribute("speed_pid/Kp").set(kp)
439        }
440
441        /// Returns the integral pub constant for the speed regulation PID.
442        pub fn get_speed_pid_ki(&self) -> Ev3Result<f32> {
443            self.get_attribute("speed_pid/Ki").get()
444        }
445
446        /// Sets the integral pub constant for the speed regulation PID.
447        pub fn set_speed_pid_ki(&self, ki: f32) -> Ev3Result<()> {
448            self.get_attribute("speed_pid/Ki").set(ki)
449        }
450
451        /// Returns the derivative pub constant for the speed regulation PID.
452        pub fn get_speed_pid_kd(&self) -> Ev3Result<f32> {
453            self.get_attribute("speed_pid/Kd").get()
454        }
455
456        /// Sets the derivative pub constant for the speed regulation PID.
457        pub fn set_speed_pid_kd(&self, kd: f32) -> Ev3Result<()> {
458            self.get_attribute("speed_pid/Kd").set(kd)
459        }
460
461        /// Returns a list of state flags.
462        pub fn get_state(&self) -> Ev3Result<Vec<String>> {
463            self.get_attribute("state").get_vec()
464        }
465
466        /// Returns the current stop action.
467        ///
468        /// The value determines the motors behavior when command is set to stop.
469        pub fn get_stop_action(&self) -> Ev3Result<String> {
470            self.get_attribute("stop_action").get()
471        }
472
473        /// Sets the stop action.
474        ///
475        /// The value determines the motors behavior when command is set to stop.
476        pub fn set_stop_action(&self, stop_action: &str) -> Ev3Result<()> {
477            self.get_attribute("stop_action").set_str_slice(stop_action)
478        }
479
480        /// Returns a list of stop actions supported by the motor controller.
481        pub fn get_stop_actions(&self) -> Ev3Result<Vec<String>> {
482            self.get_attribute("stop_actions").get_vec()
483        }
484
485        /// Returns the current amount of time the motor will run when using the run-timed command.
486        ///
487        /// Units are in milliseconds. Values must not be negative.
488        pub fn get_time_sp(&self) -> Ev3Result<i32> {
489            self.get_attribute("time_sp").get()
490        }
491
492        /// Sets the amount of time the motor will run when using the run-timed command.
493        ///
494        /// Units are in milliseconds. Values must not be negative.
495        pub fn set_time_sp(&self, time_sp: i32) -> Ev3Result<()> {
496            self.get_attribute("time_sp").set(time_sp)
497        }
498
499        /// Runs the motor using the duty cycle specified by `duty_cycle_sp`.
500        ///
501        /// Unlike other run commands, changing `duty_cycle_sp` while running will take effect immediately.
502        pub fn run_direct(&self) -> Ev3Result<()> {
503            self.set_command(Self::COMMAND_RUN_DIRECT)
504        }
505
506        /// Causes the motor to run until another command is sent.
507        pub fn run_forever(&self) -> Ev3Result<()> {
508            self.set_command(Self::COMMAND_RUN_FOREVER)
509        }
510
511        /// Runs the motor to an absolute position specified by `position_sp`
512        ///
513        /// and then stops the motor using the command specified in `stop_action`.
514        pub fn run_to_abs_pos(&self, position_sp: Option<i32>) -> Ev3Result<()> {
515            if let Some(p) = position_sp {
516                self.set_position_sp(p)?;
517            }
518            self.set_command(Self::COMMAND_RUN_TO_ABS_POS)
519        }
520
521        /// Runs the motor to a position relative to the current position value.
522        ///
523        /// The new position will be current `position` + `position_sp`.
524        /// When the new position is reached, the motor will stop using the command specified by `stop_action`.
525        pub fn run_to_rel_pos(&self, position_sp: Option<i32>) -> Ev3Result<()> {
526            if let Some(p) = position_sp {
527                self.set_position_sp(p)?;
528            }
529            self.set_command(Self::COMMAND_RUN_TO_REL_POS)
530        }
531
532        /// Run the motor for the amount of time specified in `time_sp`
533        ///
534        /// and then stops the motor using the command specified by `stop_action`.
535        pub fn run_timed(&self, time_sp: Option<Duration>) -> Ev3Result<()> {
536            if let Some(duration) = time_sp {
537                let p = duration.as_millis() as i32;
538                self.set_time_sp(p)?;
539            }
540            self.set_command(Self::COMMAND_RUN_TIMED)
541        }
542
543        /// Stop any of the run commands before they are complete using the command specified by `stop_action`.
544        pub fn stop(&self) -> Ev3Result<()> {
545            self.set_command(Self::COMMAND_STOP)
546        }
547
548        /// Resets all of the motor parameter attributes to their default values.
549        /// This will also have the effect of stopping the motor.
550        pub fn reset(&self) -> Ev3Result<()> {
551            self.set_command(Self::COMMAND_RESET)
552        }
553
554        /// Power is being sent to the motor.
555        pub fn is_running(&self) -> Ev3Result<bool> {
556            Ok(self
557                .get_state()?
558                .iter()
559                .any(|state| state == Self::STATE_RUNNING))
560        }
561
562        /// The motor is ramping up or down and has not yet reached a pub constant output level.
563        pub fn is_ramping(&self) -> Ev3Result<bool> {
564            Ok(self
565                .get_state()?
566                .iter()
567                .any(|state| state == Self::STATE_RAMPING))
568        }
569
570        /// The motor is not turning, but rather attempting to hold a fixed position.
571        pub fn is_holding(&self) -> Ev3Result<bool> {
572            Ok(self
573                .get_state()?
574                .iter()
575                .any(|state| state == Self::STATE_HOLDING))
576        }
577
578        /// The motor is turning as fast as possible, but cannot reach its `speed_sp`.
579        pub fn is_overloaded(&self) -> Ev3Result<bool> {
580            Ok(self
581                .get_state()?
582                .iter()
583                .any(|state| state == Self::STATE_OVERLOADED))
584        }
585
586        /// The motor is trying to run but is not turning at all.
587        pub fn is_stalled(&self) -> Ev3Result<bool> {
588            Ok(self
589                .get_state()?
590                .iter()
591                .any(|state| state == Self::STATE_STALLED))
592        }
593
594        /// Wait until condition `cond` returns true or the `timeout` is reached.
595        ///
596        /// The condition is checked when to the `state` attribute has changed.
597        /// If the `timeout` is `None` it will wait an infinite time.
598        ///
599        /// # Examples
600        ///
601        /// ```no_run
602        /// use ev3dev_lang_rust::motors::LargeMotor;
603        /// use std::time::Duration;
604        ///
605        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
606        /// // Init a tacho motor.
607        /// let motor = LargeMotor::find()?;
608        ///
609        /// motor.run_timed(Some(Duration::from_secs(5)))?;
610        ///
611        /// let cond = || {
612        ///     motor.get_state()
613        ///         .unwrap_or_else(|_| vec![])
614        ///         .iter()
615        ///         .all(|s| s != LargeMotor::STATE_RUNNING)
616        /// };
617        /// motor.wait(cond, None);
618        ///
619        /// println!("Motor has stopped!");
620        /// # Ok(())
621        /// # }
622        /// ```
623        pub fn wait<F>(&self, cond: F, timeout: Option<Duration>) -> bool
624        where
625            F: Fn() -> bool,
626        {
627            let fd = self.get_attribute("state").get_raw_fd();
628            wait::wait(fd, cond, timeout)
629        }
630
631        /// Wait while the `state` is in the vector `self.get_state()` or the `timeout` is reached.
632        ///
633        /// If the `timeout` is `None` it will wait an infinite time.
634        ///
635        /// # Example
636        ///
637        /// ```no_run
638        /// use ev3dev_lang_rust::motors::LargeMotor;
639        /// use std::time::Duration;
640        ///
641        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
642        /// // Init a tacho motor.
643        /// let motor = LargeMotor::find()?;
644        ///
645        /// motor.run_timed(Some(Duration::from_secs(5)))?;
646        ///
647        /// motor.wait_while(LargeMotor::STATE_RUNNING, None);
648        ///
649        /// println!("Motor has stopped!");
650        /// # Ok(())
651        /// # }
652        /// ```
653        pub fn wait_while(&self, state: &str, timeout: Option<Duration>) -> bool {
654            let cond = || {
655                self.get_state()
656                    .unwrap_or_else(|_| vec![])
657                    .iter()
658                    .all(|s| s != state)
659            };
660            self.wait(cond, timeout)
661        }
662
663        /// Wait until the `state` is in the vector `self.get_state()` or the `timeout` is reached.
664        ///
665        /// If the `timeout` is `None` it will wait an infinite time.
666        ///
667        /// # Example
668        ///
669        /// ```no_run
670        /// use ev3dev_lang_rust::motors::LargeMotor;
671        /// use std::time::Duration;
672        ///
673        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
674        /// // Init a tacho motor.
675        /// let motor = LargeMotor::find()?;
676        ///
677        /// motor.run_timed(Some(Duration::from_secs(5)))?;
678        ///
679        /// motor.wait_until(LargeMotor::STATE_RUNNING, None);
680        ///
681        /// println!("Motor has started!");
682        /// # Ok(())
683        /// # }
684        /// ```
685        pub fn wait_until(&self, state: &str, timeout: Option<Duration>) -> bool {
686            let cond = || {
687                self.get_state()
688                    .unwrap_or_else(|_| vec![])
689                    .iter()
690                    .any(|s| s == state)
691            };
692            self.wait(cond, timeout)
693        }
694
695        /// Wait until the motor is not moving or the timeout is reached.
696        ///
697        /// This is equal to `wait_while(STATE_RUNNING, timeout)`.
698        /// If the `timeout` is `None` it will wait an infinite time.
699        ///
700        /// # Example
701        ///
702        /// ```no_run
703        /// use ev3dev_lang_rust::motors::LargeMotor;
704        /// use std::time::Duration;
705        ///
706        /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
707        /// // Init a tacho motor.
708        /// let motor = LargeMotor::find()?;
709        ///
710        /// motor.run_timed(Some(Duration::from_secs(5)))?;
711        ///
712        /// motor.wait_until_not_moving(None);
713        ///
714        /// println!("Motor has stopped!");
715        /// # Ok(())
716        /// # }
717        /// ```
718        pub fn wait_until_not_moving(&self, timeout: Option<Duration>) -> bool {
719            self.wait_while(Self::STATE_RUNNING, timeout)
720        }
721    };
722}