remote_control/
remote_control.rs1extern crate tello_edu;
20
21use sdl2::controller::Axis;
22use sdl2::controller::Button;
23use sdl2::event::Event;
24
25
26use tello_edu::{TelloOptions, Tello, Result, TelloCommandSender, TelloCommand};
27
28
29fn main() {
30 let mut options = TelloOptions::default();
31
32 let command_sender = options.with_command();
34
35 std::thread::spawn(move || {
37 let tokio_runtime = tokio::runtime::Builder::new_multi_thread()
38 .enable_all()
39 .build()
40 .unwrap();
41
42 tokio_runtime.block_on(async {
43 fly(options).await.unwrap();
44 });
45 });
46
47 run_control(command_sender).expect("failed to run control");
48}
49
50fn run_control(command_sender: TelloCommandSender) -> anyhow::Result<(), String> {
51 sdl2::hint::set("SDL_JOYSTICK_THREAD", "1");
54
55 let sdl_context = sdl2::init()?;
56 let game_controller_subsystem = sdl_context.game_controller()?;
57
58 let num_controllers = game_controller_subsystem
59 .num_joysticks()
60 .map_err(|e| format!("can't enumerate controllers: {}", e))?;
61
62
63 if num_controllers == 0 {
64 return Err("no game controllers found".to_string());
65 }
66
67 let controller = (0..num_controllers)
69 .find_map(|id| {
70 if !game_controller_subsystem.is_game_controller(id) {
71 println!("{} is not a game controller", id);
72 return None;
73 }
74
75 match game_controller_subsystem.open(id) {
76 Ok(c) => {
77 println!("using controller \"{}\"", c.name());
78 Some(c)
79 }
80 Err(e) => {
81 println!("failed to open controller {id}: {e:?}");
82 None
83 }
84 }
85 })
86 .expect("failed to use any controller");
87
88 let mut left_right:i8 = 0;
90 let mut forwards_backwards:i8 = 0;
91 let mut up_down:i8 = 0;
92 let mut yaw:i8 = 0;
93
94 for event in sdl_context.event_pump()?.wait_iter() {
95
96 match event {
97 Event::ControllerButtonDown { button: Button::LeftShoulder, .. }
99 | Event::ControllerButtonDown { button: Button::RightShoulder, .. } => {
100 if controller.button(Button::LeftShoulder) && controller.button(Button::RightShoulder) {
101 command_sender.send(TelloCommand::EmergencyStop)
102 }
103 else {
104 Ok(())
105 }
106 }
107
108 Event::ControllerButtonUp { button: Button::Start, .. } => {
110 command_sender.send(TelloCommand::TakeOff)
111 }
112
113 Event::ControllerButtonDown { button: Button::X, .. } => {
115 left_right = 0;
116 forwards_backwards = 0;
117 up_down = 0;
118 yaw = 0;
119 command_sender.send(TelloCommand::Land)
120 }
121
122 Event::ControllerButtonDown { button: Button::B, .. } => {
124 left_right = 0;
125 forwards_backwards = 0;
126 up_down = 0;
127 yaw = 0;
128 command_sender.send(TelloCommand::RemoteControl { left_right, forwards_backwards, up_down, yaw} )
129 }
131
132 Event::ControllerAxisMotion { axis: Axis::LeftY, value, .. } => {
134 forwards_backwards = -remote_control_value(value);
135 command_sender.send(TelloCommand::RemoteControl { left_right, forwards_backwards, up_down, yaw} )
136 }
137
138 Event::ControllerAxisMotion { axis: Axis::LeftX, value, .. } => {
140 yaw = remote_control_value(value);
141 command_sender.send(TelloCommand::RemoteControl { left_right, forwards_backwards, up_down, yaw} )
142 }
143
144 Event::ControllerAxisMotion { axis: Axis::RightY, value, .. } => {
146 up_down = -remote_control_value(value);
147 command_sender.send(TelloCommand::RemoteControl { left_right, forwards_backwards, up_down, yaw} )
148 }
149
150 Event::ControllerAxisMotion { axis: Axis::RightX, value, .. } => {
152 left_right = remote_control_value(value);
153 command_sender.send(TelloCommand::RemoteControl { left_right, forwards_backwards, up_down, yaw} )
154 }
155
156 Event::ControllerButtonDown { button: Button::DPadLeft, .. } => {
158 command_sender.send(TelloCommand::FlipLeft)
159 }
160 Event::ControllerButtonDown { button: Button::DPadRight, .. } => {
161 command_sender.send(TelloCommand::FlipRight)
162 }
163 Event::ControllerButtonDown { button: Button::DPadUp, .. } => {
164 command_sender.send(TelloCommand::FlipForward)
165 }
166 Event::ControllerButtonDown { button: Button::DPadDown, .. } => {
167 command_sender.send(TelloCommand::FlipBack)
168 }
169
170 Event::Quit { .. } => break,
171 _ => Ok(()),
172 }.map_err(|err| format!("error sending command: {err}"))?;
173
174 }
175
176 Ok(())
177}
178
179const DEAD_ZONE:i16 = 10;
182const AXIS_MAX:f32 = 32767.0;
183
184fn normalize_axis_value(value:i16) -> Option<f32> {
186 if value > DEAD_ZONE || value < -DEAD_ZONE {
187 let normalized_value = value as f32 / AXIS_MAX;
189 if normalized_value > 1.0 {
190 Some(1.0)
191 }
192 else if normalized_value < -1.0 {
193 Some(-1.0)
194 }
195 else {
196 Some(normalized_value)
197 }
198 }
199 else {
200 None
202 }
203}
204
205fn remote_control_value(value:i16) -> i8 {
207 match normalize_axis_value(value) {
208 Some(v) => (v * 100.0) as i8,
209 None => 0
210 }
211}
212
213async fn fly(options:TelloOptions) -> Result<()> {
216 let drone = Tello::new()
217 .wait_for_wifi().await?;
218
219 let drone = drone.connect_with(options).await?;
220
221 drone.handle_commands().await?;
222
223 Ok(())
224}