rex_ucph/
lib.rs

1//! rex-ucph is a libary for the Arlo robots in use in the
2//! rex course on University of Copenhagen
3
4extern crate serialport;
5
6use serialport::SerialPortSettings;
7use serialport::posix::*;
8use serialport::Error as sError;
9
10use std::{thread, time};
11use std::io::{Write, Read};
12use std::str;
13use std::path::Path;
14
15pub struct Arlo {
16    #[allow(dead_code)]
17    connection: TTYPort,
18    pub speed: Option<u8>,
19    pub turn_speed: Option<u8>,
20    pub step_time: Option<usize>,
21    pub turn_time: Option<usize>,
22}
23
24impl Arlo {
25    pub fn new() -> Result<Self, sError> {
26        let mut settings = SerialPortSettings::default();
27        settings.timeout = time::Duration::from_secs(60);
28        let conn = TTYPort::open(Path::new("/dev/ttyACM0"), &settings)?;
29        let wait = time::Duration::from_secs(2);
30        thread::sleep(wait);
31        Ok(Arlo {
32            connection: conn,
33            speed: None,
34            turn_speed: None,
35            step_time: None,
36            turn_time: None,
37        })
38    }
39
40    pub fn new_port(port: &str) -> Result<Self, sError> {
41        let mut settings = SerialPortSettings::default();
42        settings.timeout = time::Duration::from_secs(60);
43        let conn = TTYPort::open(Path::new(port), &settings)?;
44        let wait = time::Duration::from_secs(2);
45        thread::sleep(wait);
46        Ok(Arlo {
47            connection: conn,
48            speed: None,
49            turn_speed: None,
50            step_time: None,
51            turn_time: None,
52        })
53    }
54
55    /// Sends a command to the Arduino robot controller
56    fn send_command(&mut self, cmd: &str, sleep: Option<u64>) -> String {
57        use std::io::BufReader;
58        use std::io::BufRead;
59        let wait = match sleep {
60            Some(n) => n,
61            None => 0,
62        };
63        let conn: &mut TTYPort = &mut self.connection;
64        conn.write(cmd.as_bytes()).expect("Write failed");
65        thread::sleep(time::Duration::from_millis(wait));
66        let mut reader = BufReader::new(conn);
67        let mut line = String::new();
68        let _len = reader.read_line(&mut line).expect("Read failed");
69        //println!("line: {}, len: {}", line.trim(), _len);
70        line.trim().to_string()
71    }
72
73    /// Start left motor with motor power powerLeft (in [0;127]) and direction dirLeft (0=reverse, 1=forward)
74    /// and right motor with motor power powerRight (in [0;127]) and direction dirRight (0=reverse, 1=forward).
75    ///       
76    /// NOTE: Does NOT use wheel encoders.
77    pub fn go_diff(&mut self, power_left: u8, power_right: u8, dir_left: u8, dir_right: u8) -> String {
78        if power_left > 127 || power_right > 127 || dir_left > 1 || dir_right > 1 {
79            panic!("Reason: Variables set too high");
80        }
81        let cmd = format!("d{},{},{},{}\n", power_left, power_right, dir_left, dir_right);
82        self.send_command(&cmd, None)
83    }
84
85    /// Send a stop command to stop motors. Sets the motor power on both wheels to zero.
86    ///
87    /// NOTE: Does NOT use wheel encoders.
88    pub fn stop(&mut self) -> String {
89        self.send_command("s\n", None)
90    }
91
92    /// Send a go command for continuous forward driving using the wheel encoders
93    pub fn go(&mut self) -> String {
94        if self.speed.is_none() {
95            panic!("Speed not set!");
96        }
97        let cmd = "g\n";
98        self.send_command(&cmd, None)
99    }
100
101    /// Send a backward command for continuous reverse driving using the wheel encoders
102    pub fn backward(&mut self) -> String {
103        if self.speed.is_none() {
104            panic!("Speed not set!");
105        }
106        let cmd = "v\n";
107        self.send_command(&cmd, None)
108    }
109
110    /// Send a rotate left command for continuous rotating left using the wheel encoders
111    pub fn left(&mut self) -> String {
112        if self.speed.is_none() {
113            panic!("Speed not set!");
114        }
115        let cmd = "n\n";
116        self.send_command(&cmd, None)
117    }
118
119    /// Send a rotate right command for continuous rotating right using the wheel encoders
120    pub fn right(&mut self) -> String {
121        if self.speed.is_none() {
122            panic!("Speed not set!");
123        }
124        let cmd = "m\n";
125        self.send_command(&cmd, None)
126    }
127
128    /// Send a step forward command for driving forward using the wheel encoders for a 
129    /// predefined amount of time
130    pub fn step_forward(&mut self) -> String {
131        if self.step_time.is_none() {
132            panic!("step_time not set!")
133        }
134        let cmd = "f\n";
135        self.send_command(&cmd, None)
136    }
137
138    /// Send a step backward command for driving backward using the wheel encoders for a 
139    /// predefined amount of time
140    pub fn step_backward(&mut self) -> String {
141        if self.step_time.is_none() {
142            panic!("step_time not set!")
143        }
144        let cmd = "b\n";
145        self.send_command(&cmd, None)
146    }
147
148    /// Send a step rotate left command for rotating left using the wheel encoders for a 
149    /// predefined amount of time
150    pub fn step_rotate_left(&mut self) -> String {
151        if self.turn_time.is_none() {
152            panic!("turn_time not set!")
153        }
154        let cmd = "l\n";
155        self.send_command(&cmd, None)
156    }
157
158    /// Send a step rotate right command for rotating right using the wheel encoders for 
159    /// a predefined amount of time
160    pub fn step_rotate_right(&mut self) -> String {
161        if self.turn_time.is_none() {
162            panic!("turn_time not set!")
163        }
164        let cmd = "r\n";
165        self.send_command(&cmd, None)
166    }
167
168    /// Send a read sensor command with sensorid and return sensor value.
169    fn read_sensor(&mut self, sensor_id: u8) -> Result<usize, ()> {
170        let cmd = format!("{}\n", sensor_id);
171        let return_value = self.send_command(&cmd, None).parse::<usize>().map_err(|_| ())?;
172        //println!("Ret: {}", return_value);
173        if return_value <= 0 {
174            Err(())
175        } else {
176            Ok(return_value)
177        }
178    }
179    /// Read the front sonar ping sensor and return the measured range in milimeters [mm]
180    pub fn read_front_ping_sensor(&mut self) -> Result<usize, ()> {
181        self.read_sensor(0)
182    }
183
184    /// Read the back sonar ping sensor and return the measured range in milimeters [mm]
185    pub fn read_back_ping_sensor(&mut self) -> Result<usize, ()> {
186        self.read_sensor(1)
187    }
188    /// Read the left sonar ping sensor and return the measured range in milimeters [mm]
189    pub fn read_left_ping_sensor(&mut self) -> Result<usize, ()> {
190        self.read_sensor(2)
191    }
192
193    /// Read the right sonar ping sensor and return the measured range in milimeters [mm]
194    pub fn read_right_ping_sensor(&mut self) -> Result<usize, ()> {
195        self.read_sensor(3)
196    }
197
198    /// Speed must be a value in the range [0; 255]. This speed is used in commands based on 
199    /// using the wheel encoders.
200    pub fn set_speed(&mut self, speed: u8) -> String {
201        self.speed = Some(speed);
202        let cmd = format!("z{}\n", speed);
203        self.send_command(&cmd, None)
204    }
205
206    /// Turnspeed must be a value in the range [0; 255]. This speed is used in commands based on 
207    /// using the wheel encoders.
208    pub fn set_turnspeed(&mut self, turn_speed: u8) -> String {
209        self.turn_speed = Some(turn_speed);
210        let cmd = format!("x{}\n", turn_speed);
211        self.send_command(&cmd, None)
212    }
213
214    /// steptime is the amount of miliseconds used in the step_forward and step_backwards 
215    /// commands.
216    pub fn set_step_time(&mut self, step_time: usize) -> String {
217        self.step_time = Some(step_time);
218        let cmd = format!("t{}\n", step_time);
219        self.send_command(&cmd, None)
220    }
221
222    /// turntime is the amount of miliseconds used in the step_rotate_left and 
223    /// step_rotate_right commands.
224    pub fn set_turn_time(&mut self, step_time: usize) -> String {
225        self.step_time = Some(step_time);
226        let cmd = format!("y{}\n", step_time);
227        self.send_command(&cmd, None)
228    }
229
230    /// Reads the left wheel encoder counts since last reset_encoder_counts command.
231    /// The encoder has 144 counts for one complete wheel revolution.
232    pub fn read_left_wheel_encoder(&mut self) -> usize {
233        let cmd = "e0\n";
234        self.send_command(&cmd, Some(45)).parse::<usize>().unwrap()
235    }
236
237    /// Reads the right wheel encoder counts since last clear reset_encoder_counts command.
238    /// The encoder has 144 counts for one complete wheel revolution.
239    pub fn read_right_wheel_encoder(&mut self) -> usize {
240        let cmd = "e1\n";
241        self.send_command(&cmd, Some(45)).parse::<usize>().unwrap()
242    }
243
244    /// Reset the wheel encoder counts.
245    pub fn reset_encoder_counts(&mut self) -> String {
246        self.send_command("c\n", None)
247    }
248}
249
250impl Drop for Arlo {
251    fn drop(&mut self) {
252        println!("Shutting down the robot ...");
253        let wait = time::Duration::from_millis(5);
254        let long_wait = time::Duration::from_millis(10);
255        thread::sleep(wait);
256        self.stop();
257        thread::sleep(long_wait);
258        self.send_command("k\n", None);
259    }
260}