13 个不稳定版本 (4 个重大更改)
0.6.3 | 2021 年 9 月 9 日 |
---|---|
0.6.2 | 2021 年 9 月 9 日 |
0.5.2 | 2021 年 9 月 2 日 |
0.5.1 | 2021 年 8 月 30 日 |
0.2.1 | 2020 年 1 月 16 日 |
#36 在 机器人 中排名
每月 29 次下载
415KB
1.5K SLoC
Tello 无人机
Tello 无人机有两种接口。基于文本的接口和非公开接口,由原生应用程序使用。来自 tellopilots 论坛 的人们通过逆向工程这个接口,并为 go、python 等公共存储库提供支持,做了令人惊叹的工作。
这个库结合了与无人机通信并获取元数据的网络协议,并提供了一个远程控制框架,用于简化与键盘或摇杆的连接。
在源代码中,您可以找到如何创建 SDL-Ui 并使用键盘控制无人机的示例。您可以使用以下命令运行它:cargo run --example fly
请注意,高级动作需要在明亮的环境中完成。(翻转、弹跳等)
通信
当无人机接收到启用包(drone.connect(11111);
)时,Tello 无人机将在两个 UDP 通道上发送数据。A 命令通道(端口:8889)和B(WIP)视频通道(默认:端口:11111)。在 AP 模式下,无人机将显示默认 IP 192.168.10.1。所有发送调用都是同步进行的。要接收数据,您必须轮询无人机。以下是一个示例:
示例
use tello::{Drone, Message, Package, PackageData, ResponseMsg};
use std::time::Duration;
fn main() -> Result<(), String> {
let mut drone = Drone::new("192.168.10.1:8889");
drone.connect(11111);
loop {
if let Some(msg) = drone.poll() {
match msg {
Message::Data(Package {data: PackageData::FlightData(d), ..}) => {
println!("battery {}", d.battery_percentage);
}
Message::Response(ResponseMsg::Connected(_)) => {
println!("connected");
drone.throw_and_go().unwrap();
}
_ => ()
}
}
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
}
}
命令模式
您可以将无人机切换到命令模式。要返回到“自由飞行模式”,您必须重新启动无人机。CommandMode 会提供以下信息:
state_receiver(): Option<Receiver<CommandModeState>>
: 解析来自无人机的状态包。您将获得所有权,您只能这样做一次。video_receiver(): Option<Receiver<Vec<u8>>>
: 来自无人机的视频帧(h264)。您将获得所有权,您只能这样做一次。odometry: Odometry
移动测距数据。
示例
use futures::executor::block_on;
use std::{string::String, thread::sleep, time::Duration};
use tello::Drone;
fn main() -> Result<(), String> {
block_on(async {
let mut drone = Drone::new("192.168.10.1:8889").command_mode();
let state = drone.state_receiver().unwrap();
drone.enable().await?;
// if you use "tokio_async" this will be a `tokio::sync::watch::Receiver`
match state.recv_timeout(Duration::from_secs(5)) {
Ok(message) => println!(
"Battery {}% Height {}dm POS {:?}",
message.bat, message.h, drone.odometry
),
_ => println!("No state package received"),
}
println!("take_off {:?}", drone.take_off().await);
for _ in 0..6 {
println!("forward {:?}", drone.forward(30).await);
println!("cw {:?}", drone.cw(60).await);
}
println!("land {:?}", drone.land().await);
Ok(())
})
}
遥控器
此轮询不仅接收来自无人机的消息,还会发送一些默认设置,回复确认,触发关键帧或发送实时移动命令的遥控器状态。
无人机包含一个rc_state来控制移动。例如:drone.rc_state.go_down()
,drone.rc_state.go_forward_back(-0.7)
以下示例展示了如何使用SDL打开窗口,处理键盘输入以及连接游戏手柄或操纵杆。
示例
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use tello::{Drone, Message, Package, PackageData, ResponseMsg};
use std::time::Duration;
fn main() -> Result<(), String> {
let mut drone = Drone::new("192.168.10.1:8889");
drone.connect(11111);
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let window = video_subsystem.window("TELLO drone", 1280, 720).build().unwrap();
let mut canvas = window.into_canvas().build().unwrap();
let mut event_pump = sdl_context.event_pump()?;
'running: loop {
// draw some stuff
canvas.clear();
// [...]
// handle input from a keyboard or something like a game-pad
// ue the keyboard events
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown { keycode: Some(Keycode::Escape), .. } =>
break 'running,
Event::KeyDown { keycode: Some(Keycode::K), .. } =>
drone.take_off().unwrap(),
Event::KeyDown { keycode: Some(Keycode::L), .. } =>
drone.land().unwrap(),
Event::KeyDown { keycode: Some(Keycode::A), .. } =>
drone.rc_state.go_left(),
Event::KeyDown { keycode: Some(Keycode::D), .. } =>
drone.rc_state.go_right(),
Event::KeyUp { keycode: Some(Keycode::A), .. }
| Event::KeyUp { keycode: Some(Keycode::D), .. } =>
drone.rc_state.stop_left_right(),
//...
}
}
// or use a game pad (range from -1 to 1)
// drone.rc_state.go_left_right(dummy_joystick.axis.1);
// drone.rc_state.go_forward_back(dummy_joystick.axis.2);
// drone.rc_state.go_up_down(dummy_joystick.axis.3);
// drone.rc_state.turn(dummy_joystick.axis.4);
// the poll will send the move command to the drone
drone.poll();
canvas.present();
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20));
}
}
依赖项
~1–10MB
~87K SLoC