ev3dev_rs/pupdevices/
motor.rs1use fixed::types::I32F32;
2use scopeguard::defer;
3use tokio::time::interval;
4
5use crate::{
6 attribute::AttributeName,
7 enum_str,
8 enum_string::AsStr,
9 error::{Ev3Error, Ev3Result},
10 motor_driver::MotorDriver,
11 parameters::{Direction, MotorPort, Stop},
12};
13use std::{cell::Cell, collections::HashSet, str::FromStr, time::Duration};
14
15enum_str! {
16 Command,
17
18 (RunForever, "run-forever"),
19 (RunToAbsolutePosition, "run-to-abs-pos"),
20 (RunToRelativePosition, "run-to-rel-pos"),
21 (RunTimed, "run-timed"),
22 (RunDirect, "run-direct"),
23 (Stop, "stop"),
24 (Reset, "reset"),
25}
26
27enum_str! {
28 State,
29
30 (Running, "running"),
31 (Ramping, "ramping"),
32 (Holding, "holding"),
33 (Overloaded, "overloaded"),
34 (Stalled, "stalled"),
35}
36
37#[allow(dead_code)]
39pub struct Motor {
40 driver: MotorDriver,
41 direction: Direction,
42 last_command: Cell<Option<Command>>,
43 count_per_rot: u32,
44 count_per_degree: u32,
45 pub(crate) max_speed: I32F32,
46}
47
48impl Motor {
49 pub fn new(port: MotorPort, direction: Direction) -> Ev3Result<Self> {
66 let driver = MotorDriver::new(port)?;
67
68 driver.set_attribute_enum(AttributeName::Command, Command::Reset)?;
70
71 driver.set_attribute_enum(AttributeName::Polarity, direction)?;
72
73 let count_per_rot: u32 = driver
74 .read_attribute(AttributeName::CountPerRotation)?
75 .parse()?;
76
77 Ok(Self {
78 driver,
79 direction,
80 last_command: Cell::new(None),
81 count_per_rot,
82 count_per_degree: count_per_rot / 360,
83 max_speed: I32F32::from_num(1000),
84 })
85 }
86
87 fn get_states(&self) -> Ev3Result<HashSet<State>> {
88 let mut states = HashSet::new();
89
90 for flag in self
91 .driver
92 .read_attribute(AttributeName::State)?
93 .split_ascii_whitespace()
94 {
95 if let Ok(state) = State::from_str(flag) {
96 states.insert(state);
97 }
98 }
99
100 Ok(states)
101 }
102
103 fn send_command(&self, command: Command) -> Ev3Result<()> {
104 self.driver
105 .set_attribute_enum(AttributeName::Command, command)?;
106 self.last_command.set(Some(command));
107 Ok(())
108 }
109
110 pub fn set_stop_action(&self, action: Stop) -> Ev3Result<()> {
112 self.driver
113 .set_attribute_enum(AttributeName::StopAction, action)
114 }
115
116 async fn wait_for_stop(&self) -> Ev3Result<()> {
117 defer! {
118 _ = self.send_command(Command::Stop);
119 }
120
121 let mut timer = interval(Duration::from_millis(5));
122
123 timer.tick().await;
125
126 while self.get_states()?.contains(&State::Running) {
127 timer.tick().await;
128 }
129
130 Ok(())
131 }
132
133 fn set_speed(&self, speed: i32) -> Ev3Result<()> {
134 self.driver
135 .set_attribute(AttributeName::SpeedSetpoint, speed)
136 }
137
138 pub fn set_ramp_up_setpoint(&self, sp: u32) -> Ev3Result<()> {
144 self.driver.set_attribute(AttributeName::RampUpSetpoint, sp)
145 }
146
147 pub fn set_ramp_down_setpoint(&self, sp: u32) -> Ev3Result<()> {
153 self.driver
154 .set_attribute(AttributeName::RampDownSetpoint, sp)
155 }
156
157 pub fn reset(&self) -> Ev3Result<()> {
161 self.send_command(Command::Reset)?;
162 self.driver
163 .set_attribute_enum(AttributeName::Polarity, self.direction)
164 }
165
166 pub fn stop_prev_action(&self) -> Ev3Result<()> {
168 self.send_command(Command::Stop)
169 }
170
171 pub fn stop(&self) -> Ev3Result<()> {
175 self.set_stop_action(Stop::Coast)?;
176 self.send_command(Command::Stop)
177 }
178
179 pub fn brake(&self) -> Ev3Result<()> {
183 self.set_stop_action(Stop::Brake)?;
184 self.send_command(Command::Stop)
185 }
186
187 pub fn hold(&self) -> Ev3Result<()> {
191 self.set_stop_action(Stop::Hold)?;
192 self.send_command(Command::Stop)
193 }
194
195 pub fn angle(&self) -> Ev3Result<i32> {
197 Ok(self
198 .driver
199 .read_attribute(AttributeName::Position)?
200 .parse::<i32>()?
201 / self.count_per_degree as i32)
202 }
203
204 pub async fn run_angle(&self, speed: i32, rotation_angle: i32) -> Ev3Result<()> {
206 self.set_speed(speed)?;
207
208 self.driver
209 .set_attribute(AttributeName::PositionSetpoint, rotation_angle)?;
210
211 self.send_command(Command::RunToRelativePosition)?;
212
213 self.wait_for_stop().await
214 }
215
216 pub async fn run_target(&self, speed: i32, target_angle: i32) -> Ev3Result<()> {
224 self.set_speed(speed)?;
225
226 self.driver
227 .set_attribute(AttributeName::PositionSetpoint, target_angle)?;
228
229 self.send_command(Command::RunToAbsolutePosition)?;
230
231 self.wait_for_stop().await
232 }
233
234 pub fn run(&self, speed: i32) -> Ev3Result<()> {
238 self.set_speed(speed)?;
239
240 self.send_command(Command::RunForever)
241 }
242
243 pub async fn run_time(&self, speed: i32, time: Duration) -> Ev3Result<()> {
245 self.set_speed(speed)?;
246
247 self.driver
248 .set_attribute(AttributeName::TimeSetpoint, time.as_millis())?;
249
250 self.send_command(Command::RunTimed)?;
251
252 self.wait_for_stop().await
253 }
254
255 pub async fn run_until_stalled(&self, power: i32) -> Ev3Result<()> {
257 defer! {
258 _ = self.send_command(Command::Stop)
259 }
260
261 self.dc(power)?;
262 let mut timer = interval(Duration::from_millis(5));
263
264 let mut states = self.get_states()?;
265
266 timer.tick().await;
268
269 while states.contains(&State::Running) && !states.contains(&State::Stalled) {
270 timer.tick().await;
271 states = self.get_states()?;
272 }
273
274 Ok(())
275 }
276
277 pub fn dc(&self, duty: i32) -> Ev3Result<()> {
279 if self.last_command.get() != Some(Command::RunDirect) {
280 self.send_command(Command::RunDirect)?;
281 }
282
283 self.driver
284 .set_attribute(AttributeName::DutyCycleSetpoint, duty)
285 }
286}