You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:45:22