1use log::{debug, error};
12use std::{
13 collections::HashMap,
14 net::UdpSocket,
15 sync::{Arc, Mutex},
16 thread,
17 time::{Duration, Instant},
18};
19
20const TELLO_ADDR: &'static str = "192.168.10.1:8889";
21const TELLO_STATE_ADDR: &'static str = "0.0.0.0:8890";
22const RESPONSE_TIMEOUT: u64 = 7; const TAKEOFF_TIMEOUT: u64 = 20; const TIME_BTW_COMMANDS: f64 = 0.1; const INT_STATE_FIELDS: &[&str] = &[
28 "mid", "x", "y", "z", "pitch", "roll", "yaw", "vgx", "vgy", "vgz", "templ", "temph", "tof",
29 "h", "bat", "time",
30];
31const FLOAT_STATE_FIELDS: &[&str] = &["baro", "agx", "agy", "agz"];
32
33pub struct Drone {
34 socket: UdpSocket,
35 is_flying: bool,
36 stream_on: bool,
37 retry_count: i32,
38 last_command_time: Instant,
39 shared_response: Arc<Mutex<Option<String>>>,
40 shared_state: Arc<Mutex<HashMap<String, StateValue>>>, read_state: HashMap<String, StateValue>,
42}
43
44#[derive(Clone)]
45#[allow(dead_code)]
46enum StateValue {
47 Int(i32),
48 Float(f64),
49 Str(String),
50}
51
52fn parse_state(state_str: &str) -> Option<HashMap<String, StateValue>> {
53 let state_str = state_str.trim();
54
55 if state_str.eq("ok") {
56 return None;
57 }
58
59 let mut state_map: HashMap<String, StateValue> = HashMap::new();
60
61 for field in state_str.split(';') {
62 let split: Vec<&str> = field.split(':').collect();
63
64 if split.len() < 2 {
65 continue;
66 }
67
68 let key = split[0].to_string();
69 let value_str = split[1];
70 let value: StateValue = match state_field_converter(&key, value_str) {
71 Ok(v) => v,
72 Err(e) => {
73 debug!(
74 "Error parsing state value for {}: {} to {}",
75 key, value_str, e
76 );
77 error!("{}", e);
78 continue;
79 }
80 };
81
82 state_map.insert(key, value);
83 }
84
85 return Some(state_map);
86}
87
88fn state_field_converter(key: &str, value_str: &str) -> Result<StateValue, String> {
90 if INT_STATE_FIELDS.contains(&key) {
91 value_str
92 .parse::<i32>()
93 .map(StateValue::Int)
94 .map_err(|e| e.to_string())
95 } else if FLOAT_STATE_FIELDS.contains(&key) {
96 value_str
97 .parse::<f64>()
98 .map(StateValue::Float)
99 .map_err(|e| e.to_string())
100 } else {
101 Ok(StateValue::Str(value_str.to_string()))
102 }
103}
104
105fn start_state_receiver_thread(response_receiver: Arc<Mutex<HashMap<String, StateValue>>>) {
109 thread::spawn(move || {
110 let socket = UdpSocket::bind(TELLO_STATE_ADDR).expect("Couldn't bind receiver socket");
111 let mut buf = [0; 1024];
112
113 loop {
114 let (amt, _src) = socket.recv_from(&mut buf).expect("Didn't receive message");
115 let received = String::from_utf8_lossy(&buf[..amt]);
116
117 let state_map = match parse_state(&received) {
118 Some(map) => map,
119 None => continue,
120 };
121
122 let mut value = response_receiver.lock().unwrap();
123 *value = state_map;
124 }
125 });
126}
127
128impl Drone {
129 pub fn new() -> Self {
131 let socket = UdpSocket::bind("0.0.0.0:8889")
132 .expect(format!("couldn't bind to address {}", TELLO_ADDR).as_str());
133
134 socket
135 .set_read_timeout(Some(Duration::from_secs(RESPONSE_TIMEOUT)))
136 .expect("set_read_timeout call failed");
137
138 let socket_recv = socket.try_clone().unwrap(); let shared_response = Arc::new(Mutex::new(None::<String>));
142 let response_receiver = Arc::clone(&shared_response);
143
144 thread::spawn(move || {
146 let socket = socket_recv;
147 let mut buf = [0; 1024];
148
149 loop {
150 match socket.recv_from(&mut buf) {
151 Ok((amt, src)) => {
152 if src.to_string() != TELLO_ADDR {
153 println!("{}", src.to_string());
154 continue;
155 }
156 let received = String::from_utf8_lossy(&buf[..amt]);
157 if let Ok(mut value) = response_receiver.lock() {
158 *value = Some(received.to_string()); }
160 }
161 Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
162 continue;
164 }
165 Err(e) => {
166 eprintln!("Error receiving message: {:?}", e);
167 break;
168 }
169 }
170 }
171 });
172
173 Drone {
174 socket,
175 is_flying: false,
176 stream_on: false,
177 retry_count: 3,
178 last_command_time: Instant::now(),
179 shared_response,
180 shared_state: Arc::new(Mutex::new(HashMap::new())),
181 read_state: HashMap::new(),
182 }
183 }
184}
185
186impl Drone {
190 fn send_command_without_return(&self, command: &str) {
193 self.socket
194 .send_to(command.as_bytes(), TELLO_ADDR)
195 .expect("Sending command failed");
196
197 println!("Send Command {}", command);
198 }
199
200 fn send_command_with_return(&mut self, command: &str, timeout: u64) -> Option<String> {
203 let time_since_last_command = Instant::now().duration_since(self.last_command_time);
204 if TIME_BTW_COMMANDS.min(time_since_last_command.as_secs_f64()) != TIME_BTW_COMMANDS {
205 println!(
206 "Command {} executed too soon, waiting {} seconds",
207 command, TIME_BTW_COMMANDS
208 );
209 thread::sleep(Duration::from_secs_f64(TIME_BTW_COMMANDS));
210 }
211
212 let timestamp = Instant::now();
213
214 self.socket
215 .send_to(command.as_bytes(), TELLO_ADDR)
216 .expect("Sending command failed");
217
218 loop {
219 let mut value = self.shared_response.lock().unwrap();
220
221 if !value.is_none() {
222 self.last_command_time = Instant::now();
223 let temp = value.clone();
224 let mut temp = temp.unwrap();
225 temp = String::from(temp.trim_end_matches("\r\n"));
226 *value = None;
227 return Some(temp);
228 }
229
230 if Instant::now().duration_since(timestamp).as_secs() >= timeout {
231 println!("CONFUSED");
232 let temp = format!(
234 "Aborting command '{}'. Did not receive a response after {} seconds",
235 command, timeout
236 );
237 *value = None;
238 return Some(temp);
239 }
240
241 println!("{}", Instant::now().duration_since(timestamp).as_millis());
242 }
243 }
244
245 fn send_control_command(&mut self, command: &str, timeout: u64) -> bool {
247 for i in 0..self.retry_count {
248 let response = self
249 .send_command_with_return(command, timeout)
250 .unwrap_or_else(|| String::from("Attempt failed, retrying"));
251
252 if response.to_lowercase().contains("ok") {
253 println!("{}", response);
254 return true;
255 } else {
256 println!("{}", response);
257 }
258
259 println!("tried {} times: {}", i, response);
260 }
261
262 return false;
263 }
264
265 fn send_read_command(&mut self, command: &str) -> String {
267 let response = self
268 .send_command_with_return(command, RESPONSE_TIMEOUT)
269 .unwrap();
270
271 let error_words = ["error", "ERROR", "False"];
272 if error_words.iter().any(|&word| response.contains(word)) {
273 debug!("uh oh");
274 error!("ruh roh");
275 }
276
277 return response;
278 }
279
280 fn send_read_command_int(&mut self, command: &str) -> i32 {
282 self.send_read_command(command).parse::<i32>().unwrap()
283 }
284
285 fn send_read_command_float(&mut self, command: &str) -> f64 {
287 self.send_read_command(command).parse::<f64>().unwrap()
288 }
289}
290
291impl Drone {
293 fn get_state_field(&mut self, key: &str) -> &StateValue {
295 self.read_state = self.shared_state.lock().unwrap().clone();
298
299 if !self.read_state.contains_key(&key.to_string()) {
301 error!("Could not get state property: {}", key);
302 }
303 self.read_state.get(&key.to_string()).unwrap()
305 }
306
307 pub fn get_pitch(&mut self) -> i32 {
309 match self.get_state_field("pitch") {
310 StateValue::Int(i) => *i,
311 _ => panic!("'pitch' state returned the incorrect Type"),
312 }
313 }
314
315 pub fn get_roll(&mut self) -> i32 {
317 match self.get_state_field("roll") {
318 StateValue::Int(i) => *i,
319 _ => panic!("'roll' state returned the incorrect Type"),
320 }
321 }
322
323 pub fn get_yaw(&mut self) -> i32 {
325 match self.get_state_field("yaw") {
326 StateValue::Int(i) => *i,
327 _ => panic!("'yaw' state returned the incorrect Type"),
328 }
329 }
330
331 pub fn get_speed_x(&mut self) -> i32 {
333 match self.get_state_field("vgx") {
334 StateValue::Int(i) => *i,
335 _ => panic!("'soeed_x' state returned the incorrect Type"),
336 }
337 }
338
339 pub fn get_speed_y(&mut self) -> i32 {
341 match self.get_state_field("vgy") {
342 StateValue::Int(i) => *i,
343 _ => panic!("'speed_y' state returned the incorrect Type"),
344 }
345 }
346
347 pub fn get_speed_z(&mut self) -> i32 {
349 match self.get_state_field("vgz") {
350 StateValue::Int(i) => *i,
351 _ => panic!("'speed_z' state returned the incorrect Type"),
352 }
353 }
354
355 pub fn get_acceleration_x(&mut self) -> f64 {
357 match self.get_state_field("agx") {
358 StateValue::Float(i) => *i,
359 _ => panic!("'accel_x' state returned the incorrect Type"),
360 }
361 }
362
363 pub fn get_acceleration_y(&mut self) -> f64 {
365 match self.get_state_field("agy") {
366 StateValue::Float(i) => *i,
367 _ => panic!("'accel_y' state returned the incorrect Type"),
368 }
369 }
370
371 pub fn get_acceleration_z(&mut self) -> f64 {
373 match self.get_state_field("agz") {
374 StateValue::Float(i) => *i,
375 _ => panic!("'accel_z' state returned the incorrect Type"),
376 }
377 }
378
379 pub fn get_lowest_temperature(&mut self) -> i32 {
381 match self.get_state_field("templ") {
382 StateValue::Int(i) => *i,
383 _ => panic!("'lowest_temperature' state returned the incorrect Type"),
384 }
385 }
386
387 pub fn get_highest_temperature(&mut self) -> i32 {
389 match self.get_state_field("temph") {
390 StateValue::Int(i) => *i,
391 _ => panic!("'highest_temperature' state returned the incorrect Type"),
392 }
393 }
394
395 pub fn get_temperature(&mut self) -> i32 {
397 let templ = self.get_lowest_temperature();
398 let temph = self.get_highest_temperature();
399
400 templ + temph
401 }
402
403 pub fn get_height(&mut self) -> i32 {
405 match self.get_state_field("h") {
406 StateValue::Int(i) => *i,
407 _ => panic!("'height' state returned the incorrect Type"),
408 }
409 }
410
411 pub fn get_distance_tof(&mut self) -> i32 {
413 match self.get_state_field("tof") {
414 StateValue::Int(i) => *i,
415 _ => panic!("'distance_tof' state returned the incorrect Type"),
416 }
417 }
418
419 pub fn get_barometer(&mut self) -> f64 {
421 match self.get_state_field("baro") {
422 StateValue::Float(i) => *i * 100.0,
423 _ => panic!("'baro' state returned the incorrect Type"),
424 }
425 }
426
427 pub fn get_flight_time(&mut self) -> i32 {
429 match self.get_state_field("time") {
430 StateValue::Int(i) => *i,
431 _ => panic!("'time' state returned the incorrect Type"),
432 }
433 }
434
435 pub fn get_battery(&mut self) -> i32 {
436 match self.get_state_field("bat") {
437 StateValue::Int(i) => *i,
438 _ => panic!("'bat' state returned the incorrect Type"),
439 }
440 }
441}
442
443impl Drone {
445 pub fn connect(&mut self) {
446 let state_response = Arc::new(Mutex::new(HashMap::new()));
448 let state_receiver = Arc::clone(&state_response);
449 start_state_receiver_thread(state_receiver);
450 self.send_control_command("command", RESPONSE_TIMEOUT);
451
452 let reps = 20;
453 for _ in 0..reps {
454 {
456 self.read_state = self.shared_state.lock().unwrap().clone();
457 }
458
459 if !self.read_state.is_empty() {
460 println!("trying");
462 break;
464 }
465
466 thread::sleep(Duration::from_secs_f64(1.0 / reps as f64));
467 }
468
469 if self.read_state.is_empty() {
470 }
472 }
473
474 pub fn send_keepalive(&mut self) {
476 self.send_control_command("keepalive", RESPONSE_TIMEOUT);
477 }
478
479 pub fn turn_motor_on(&mut self) {
480 self.send_control_command("motoron", RESPONSE_TIMEOUT);
481 }
482
483 pub fn turn_motor_off(&mut self) {
484 self.send_control_command("motoroff", RESPONSE_TIMEOUT);
485 }
486
487 pub fn initiate_throw_takeoff(&mut self) {
488 self.send_control_command("throwfly", RESPONSE_TIMEOUT);
489 }
490
491 pub fn takeoff(&mut self) {
492 self.send_control_command("takeoff", TAKEOFF_TIMEOUT);
493 self.is_flying = true;
494 }
495
496 pub fn land(&mut self) {
497 self.send_control_command("land", RESPONSE_TIMEOUT);
498 self.is_flying = false;
499 }
500
501 pub fn streamon(&mut self) {
503 self.send_control_command("streamon", RESPONSE_TIMEOUT);
505 self.stream_on = true;
506 }
507
508 pub fn streamoff(&mut self) {
510 self.send_control_command("streamoff", RESPONSE_TIMEOUT);
511 self.stream_on = false;
512
513 }
519
520 pub fn emergency(&mut self) {
522 self.send_command_without_return("emergency");
523 self.is_flying = false;
524 }
525
526 pub fn move_any(&mut self, direction: &str, x: i32) {
530 self.send_control_command(format!("{} {}", direction, x).as_str(), RESPONSE_TIMEOUT);
531 }
532
533 pub fn move_up(&mut self, x: i32) {
536 self.move_any("up", x);
537 }
538
539 pub fn move_down(&mut self, x: i32) {
542 self.move_any("down", x);
543 }
544
545 pub fn move_left(&mut self, x: i32) {
548 self.move_any("left", x);
549 }
550
551 pub fn move_right(&mut self, x: i32) {
554 self.move_any("right", x);
555 }
556
557 pub fn move_forward(&mut self, x: i32) {
560 self.move_any("forward", x);
561 }
562
563 pub fn move_back(&mut self, x: i32) {
566 self.move_any("back", x);
567 }
568
569 pub fn rotate_clockwise(&mut self, x: i32) {
571 self.send_control_command(&format!("cw {}", x), RESPONSE_TIMEOUT);
572 }
573
574 pub fn rotate_counter_clockwise(&mut self, x: i32) {
576 self.send_control_command(&format!("ccw {}", x), RESPONSE_TIMEOUT);
577 }
578
579 pub fn flip(&mut self, direction: &str) {
581 self.send_control_command(&format!("flip {}", direction), RESPONSE_TIMEOUT);
582 }
583
584 pub fn flip_left(&mut self) {
586 self.flip("l");
587 }
588
589 pub fn flip_right(&mut self) {
591 self.flip("r");
592 }
593
594 pub fn flip_forward(&mut self) {
596 self.flip("f");
597 }
598
599 pub fn flip_back(&mut self) {
601 self.flip("b");
602 }
603
604 pub fn go_xyz_speed(&mut self, x: i32, y: i32, z: i32, speed: i32) {
612 let cmd = format!("go {} {} {} {}", x, y, z, speed);
613 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
614 }
615
616 pub fn curve_xyz_speed(
627 &mut self,
628 x1: i32,
629 y1: i32,
630 z1: i32,
631 x2: i32,
632 y2: i32,
633 z2: i32,
634 speed: i32,
635 ) {
636 let cmd = format!("curve {} {} {} {} {} {} {}", x1, y1, z1, x2, y2, z2, speed);
637 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
638 }
639
640 pub fn set_speed(&mut self, speed: i32) {
642 let cmd = format!("speed {}", speed);
643 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
644 }
645
646 pub fn send_rc_control(
653 &mut self,
654 left_right_velocity: i32,
655 forward_backward_velocity: i32,
656 up_down_velocity: i32,
657 yaw_velocity: i32,
658 ) {
659 let clamp100 = |x: i32| -> i32 { x.max(-100).min(100) };
660
661 if Instant::now()
662 .duration_since(self.last_command_time)
663 .as_secs_f64()
664 > TIME_BTW_COMMANDS
665 {
666 self.last_command_time = Instant::now();
667 let cmd = format!(
668 "rc {} {} {} {}",
669 clamp100(left_right_velocity),
670 clamp100(forward_backward_velocity),
671 clamp100(up_down_velocity),
672 clamp100(yaw_velocity)
673 );
674 self.send_command_without_return(&cmd);
675 }
676 }
677
678 pub fn set_wifi_credentials(&mut self, ssid: &str, password: &str) {
680 let cmd = format!("wifi {} {}", ssid, password);
681 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
682 }
683
684 pub fn connect_to_wifi(&mut self, ssid: &str, password: &str) {
687 let cmd = format!("ap {} {}", ssid, password);
688 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
689 }
690
691 pub fn set_network_ports(&mut self, state_packet_port: i32, video_stream_port: i32) {
694 let cmd = format!("port {} {}", state_packet_port, video_stream_port);
695 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
696 }
697
698 pub fn reboot(&mut self) {
700 self.send_command_without_return("reboot");
701 }
702
703 pub fn set_video_bitrate(&mut self, bitrate: i32) {
706 let cmd = format!("setbitrate {}", bitrate);
707 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
708 }
709
710 pub fn set_video_resolution(&mut self, resolution: &str) {
714 let cmd = format!("setresolution {}", resolution);
715 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
716 }
717
718 pub fn set_video_fps(&mut self, fps: &str) {
723 let cmd = format!("setfps {}", fps);
724 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
725 }
726
727 pub fn set_video_direction(&mut self, direction: i32) {
731 let cmd = format!("downvision {}", direction);
732 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
733 }
734}
735
736impl Drone {
738 pub fn go_xyz_speed_mid(&mut self, x: i32, y: i32, z: i32, mid: i32) {
746 let cmd = format!("go {} {} {} m{}", x, y, z, mid);
747 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
748 }
749
750 pub fn curve_xyz_speed_mid(
761 &mut self,
762 x1: i32,
763 y1: i32,
764 z1: i32,
765 x2: i32,
766 y2: i32,
767 z2: i32,
768 speed: i32,
769 mid: i32,
770 ) {
771 let cmd = format!(
772 "curve {} {} {} {} {} {} {} m{}",
773 x1, y1, z1, x2, y2, z2, speed, mid
774 );
775 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
776 }
777
778 pub fn enable_mission_pads(&mut self) {
779 self.send_control_command("mon", RESPONSE_TIMEOUT);
780 }
781
782 pub fn disable_mission_pads(&mut self) {
783 self.send_control_command("moff", RESPONSE_TIMEOUT);
784 }
785
786 pub fn set_mission_pad_detection_direction(&mut self, direction: i32) {
787 let cmd = format!("mdirection {}", direction);
788 self.send_control_command(&cmd, RESPONSE_TIMEOUT);
789 }
790}
791
792impl Drone {
794 pub fn query_speed(&mut self) -> i32 {
795 self.send_read_command_int("speed?")
796 }
797
798 pub fn query_battery(&mut self) -> i32 {
799 self.send_read_command_int("battery?")
800 }
801
802 pub fn query_flight_time(&mut self) -> i32 {
803 self.send_read_command_int("time?")
804 }
805
806 pub fn query_height(&mut self) -> i32 {
807 self.send_read_command_int("height?")
808 }
809
810 pub fn query_temperature(&mut self) -> i32 {
811 self.send_read_command_int("temp?")
812 }
813
814 pub fn query_attitude(&mut self) -> HashMap<String, i32> {
818 let response = self.send_read_command("attitude?");
819
820 let mut attitude: HashMap<String, i32> = HashMap::new();
821
822 for field in response.split(';') {
823 let split: Vec<&str> = field.split(':').collect();
824
825 if split.len() < 2 {
826 continue;
827 }
828
829 let key = split[0].to_string();
830 let value_str = split[1];
831 let value: StateValue = match state_field_converter(&key, value_str) {
832 Ok(v) => v,
833 Err(e) => {
834 debug!(
835 "Error parsing state value for {}: {} to {}",
836 key, value_str, e
837 );
838 error!("{}", e);
839 continue;
840 }
841 };
842
843 let value_i32 = match value {
844 StateValue::Int(i) => i,
845 _ => panic!("'bat' state returned the incorrect Type"),
846 };
847
848 attitude.insert(key, value_i32);
849 }
850
851 return attitude;
852 }
853
854 pub fn query_barometer(&mut self) -> f64 {
855 self.send_read_command_float("baro?") * 100.0
856 }
857
858 pub fn query_distance_tof(&mut self) -> f64 {
859 let tof = self.send_read_command("tof?");
860 tof.trim_end_matches("mm").parse::<f64>().unwrap_or(0.0) / 10.0
861 }
862
863 pub fn query_wifi_signal_noise_ratio(&mut self) -> String {
864 self.send_read_command("wifi?")
865 }
866
867 pub fn query_sdk_version(&mut self) -> String {
868 self.send_read_command("sdk?")
869 }
870
871 pub fn query_serial_number(&mut self) -> String {
872 self.send_read_command("sn?")
873 }
874
875 pub fn query_active(&mut self) -> String {
876 self.send_read_command("active?")
877 }
878}
879
880#[cfg(test)]
881mod tests {
882 use super::*;
883
884 #[test]
885 fn system_time_test() {
886 let socket = UdpSocket::bind(TELLO_ADDR).expect("couldn't bind to address");
887 let shared_response = Arc::new(Mutex::new(None::<String>));
888
889 let state_response = Arc::new(Mutex::new(HashMap::new()));
890 let shared_state = Arc::clone(&state_response);
891
892 let mut d = Drone {
893 socket,
894 is_flying: false,
895 stream_on: false,
896 retry_count: 3,
897 last_command_time: Instant::now(),
898 shared_response,
899 shared_state,
900 read_state: HashMap::new(),
901 };
902
903 d.send_command_with_return("a", 6);
904 }
905}