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}