如何用Python通过UDP服务器从DJI Tello无人机采集视频数据
解决Tello无人机视频流接收与
streamon命令错误问题 嘿,我看到你在折腾Tello的视频流时遇到了两个头疼的问题:streamon命令返回“Unknown command”,以及11111端口完全收不到数据。咱们一步步拆解解决:
1. 先搞定最基础的代码错误
你代码里的takeoff和land函数缩进完全错了——它们应该是Tello类的方法,但现在定义在类外面,这不仅会导致调用失败,还可能间接影响命令发送的逻辑。先把这个小问题修正:
class Tello: # ... 你已有的__init__、receive_response等方法 ... def send_command(self, command): self.socket.sendto(command.encode('utf-8'), self.address) # 把takeoff和land缩进,变成类的成员方法 def takeoff(self): self.send_command('takeoff') def land(self): self.send_command('land')
关于streamon的错误提示,先确认命令拼写:Tello的正确命令确实是streamon,但要注意没有拼写错误(比如别写成streamon)。另外,发送streamon前一定要确保command命令已经成功得到OK响应——你代码里的等待逻辑是对的,但可以加个小延迟,给无人机一点准备时间。
2. 修复视频流接收逻辑
Tello的视频流是通过UDP在11111端口发送分片的H.264编码数据,不是明文,所以直接打印str(data)会看到乱码,但至少能收到数据。如果完全没数据,大概率是streamon命令没成功执行。
调整视频socket的初始化时机,确保在发送streamon前就准备好接收:
def __init__(self): self.ip = '192.168.10.1' self.command_port = 8889 self.address = (self.ip, self.command_port) self.response = None self.overtime = 3 self.lock = threading.RLock() self.video_port = 11111 # 先初始化命令socket并绑定 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind(('', self.command_port)) # 启动响应接收线程 self.receive_thread = threading.Thread(target=self.receive_response) self.receive_thread.daemon = True self.receive_thread.start() # 发送command命令并等待OK响应 self.socket.sendto(b'command', self.address) print('sent: command') last_send = time.time() while self.response != b'OK': if time.time() - last_send >= self.overtime: self.socket.sendto(b'command', self.address) print('sent: command') last_send = time.time() time.sleep(0.1) # 加延迟避免循环占用过多CPU # 先启动视频接收线程,再发送streamon self.video_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.video_socket.bind(('', self.video_port)) self.receive_video_thread = threading.Thread(target=self.receive_video_data) self.receive_video_thread.daemon = True self.receive_video_thread.start() # 发送streamon命令 self.socket.sendto(b'streamon', self.address) print('sent: streamon') time.sleep(1) # 给无人机一点推流准备时间
另外,receive_video_data里别打印str(data),换成打印数据长度更直观:
def receive_video_data(self): while True: data, ip = self.video_socket.recvfrom(2048) if data: print(f"收到视频分片,来自{ip},长度:{len(data)}")
3. 额外注意事项
- 确保你的电脑稳定连接Tello的WiFi,没有其他网络干扰
- 如果还是收不到数据,可以尝试重启无人机,或者检查固件版本是否需要更新
- 如果要播放视频,你需要用H.264解码器(比如
opencv-python)来拼接这些分片数据,Tello发送的是原始编码帧,没法直接播放
最后,修正后的完整代码如下:
import socket import threading import time class Tello: def __init__(self): self.ip = '192.168.10.1' self.command_port = 8889 self.address = (self.ip, self.command_port) self.response = None self.overtime = 3 self.lock = threading.RLock() self.video_port = 11111 # 命令socket初始化 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind(('', self.command_port)) # 启动响应接收线程 self.receive_thread = threading.Thread(target=self.receive_response) self.receive_thread.daemon = True self.receive_thread.start() # 发送command命令并等待确认 self.socket.sendto(b'command', self.address) print('sent: command') last_send = time.time() while self.response != b'OK': if time.time() - last_send >= self.overtime: self.socket.sendto(b'command', self.address) print('sent: command') last_send = time.time() time.sleep(0.1) # 初始化视频接收socket和线程 self.video_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.video_socket.bind(('', self.video_port)) self.receive_video_thread = threading.Thread(target=self.receive_video_data) self.receive_video_thread.daemon = True self.receive_video_thread.start() # 启动视频流 self.socket.sendto(b'streamon', self.address) print('sent: streamon') time.sleep(1) def receive_response(self): while True: with self.lock: self.response, ip = self.socket.recvfrom(3000) if self.response: print(f"收到响应:{self.response.decode('utf-8')}") def receive_video_data(self): while True: data, ip = self.video_socket.recvfrom(2048) if data: print(f"收到视频分片,来自{ip},长度:{len(data)}") def send_command(self, command): self.socket.sendto(command.encode('utf-8'), self.address) print(f'sent: {command}') def takeoff(self): self.send_command('takeoff') def land(self): self.send_command('land') # 实例化并保持程序运行 if __name__ == "__main__": drone = Tello() # 可以在这里测试起飞降落 # drone.takeoff() # time.sleep(5) # drone.land() while True: time.sleep(1)
这样调整后,应该能解决streamon的错误,并且在11111端口收到视频分片数据了。如果还是有问题,试试重启无人机或者检查WiFi连接稳定性。
内容的提问来源于stack exchange,提问作者Noé Terrier
相关产品推荐
相关产品推荐

