1. 环境准备:Python与Tello的第一次握手
第一次接触无人机编程时,我也觉得这是个高大上的领域。直到遇到DJI Tello这款亲民的教育无人机,才发现用Python控制飞行器原来这么简单。Tello最大的优势在于它开放了完整的SDK接口,配合Python这种易上手的语言,即使是编程新手也能快速实现创意飞行。
先说说我的踩坑经历。第一次尝试时,我兴冲冲地安装了Python就直接开始写代码,结果发现根本连不上无人机。后来才知道,Tello需要通过Wi-Fi直连的方式与电脑通信,而Windows系统默认的防火墙设置会拦截这种连接。所以第一步要确保你的电脑已经关闭防火墙或者添加了Tello的通信例外。
硬件准备很简单:一台Tello无人机、满电电池、一台安装了Windows/MacOS/Linux的电脑。软件方面需要Python 3.6或更高版本,推荐使用3.8这个长期支持版本。这里有个小技巧:安装Python时一定要勾选"Add Python to PATH"选项,否则后续命令行操作会非常麻烦。
验证Python安装是否成功,可以打开命令提示符输入:
python --version如果看到类似"Python 3.8.10"的版本号输出,说明环境基本就绪。接下来我们需要一个趁手的代码编辑器,VS Code或PyCharm都是不错的选择,它们对Python的支持非常友好。
2. 核心工具链:djitellopy库深度解析
在Tello的Python生态中,djitellopy库绝对是明星选手。这个第三方库封装了Tello的所有基础指令,让开发者可以用面向对象的方式控制无人机。我对比过直接使用SDK和djitellopy的代码量,后者至少能减少70%的样板代码。
安装djitellopy很简单,但国内用户可能会遇到网络问题。建议使用国内镜像源加速下载:
pip install djitellopy -i https://pypi.douban.com/simple/这个命令会同时安装依赖的opencv-python、numpy等库。如果安装过程中报错,可以尝试先升级pip工具:
python -m pip install --upgrade pipdjitellopy的核心是Tello类,它提供了二十多个常用方法。我整理了几个最常用的:
connect():建立与无人机的Wi-Fi连接takeoff()/land():起飞/降落move_方向(distance):向指定方向移动rotate_方向(angle):旋转机身get_battery():获取电量
实际使用时,每个指令执行都需要一定时间。新手常犯的错误是连续发送多个指令导致无人机"卡死"。我的经验是使用time.sleep()给足执行间隔,比如起飞后至少等待3秒再发送下一个指令。
3. 基础飞行控制:你的第一个飞行程序
现在我们来编写第一个真正的飞行程序。这个示例会让Tello完成起飞→悬停→旋转→降落的基本流程,全程约15秒。建议在2米×2米的空旷区域进行测试。
完整代码如下:
from djitellopy import Tello import time drone = Tello() drone.connect() print(f"当前电量:{drone.get_battery()}%") try: drone.takeoff() time.sleep(3) drone.rotate_clockwise(90) # 顺时针旋转90度 time.sleep(2) drone.move_up(50) # 上升50厘米 time.sleep(2) drone.flip_forward() # 前空翻特技 time.sleep(3) finally: drone.land()几个关键点需要注意:
- 务必在
try-finally块中执行飞行指令,确保即使程序崩溃也能安全降落 - 每次动作后都要预留足够的
time.sleep - 首次飞行前建议先调用
get_battery()检查电量 - 特技动作需要至少80%电量才能执行
如果程序报错,最常见的三个问题是:
- 未连接Wi-Fi:检查电脑是否连上了Tello的热点
- 电量不足:Tello在电量低于20%时会拒绝执行指令
- 指令冲突:前一个动作未完成就发送新指令
4. 创意飞行:用代码绘制空中轨迹
掌握了基础控制后,我们可以尝试更有趣的创意飞行。比如让Tello在空中画出正方形、八字形等轨迹。这需要组合使用移动和旋转指令,并精确计算距离和角度。
下面是一个绘制正方形的示例:
def draw_square(drone, side_length): for _ in range(4): drone.move_forward(side_length) time.sleep(2) drone.rotate_clockwise(90) time.sleep(2) # 在主程序中调用 draw_square(drone, 100) # 绘制边长100cm的正方形要让飞行轨迹更精准,有几个参数需要微调:
- 移动速度:默认是中等速度,可以通过
set_speed()调整 - 旋转精度:实际旋转角度可能有±5度的误差
- 环境因素:室内飞行要注意气流影响
进阶玩法可以结合计算机视觉。比如用Tello自带的摄像头配合OpenCV实现人脸跟踪:
drone.streamon() frame = drone.get_frame_read().frame # 使用OpenCV处理图像 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: # 根据人脸位置调整无人机位置 center_x = x + w//2 if center_x < frame.shape[1]//3: drone.move_left(20) elif center_x > 2*frame.shape[1]//3: drone.move_right(20)5. 项目实战:智能巡检小助手
最后我们来看一个实用案例——用Tello实现简单的室内巡检。这个程序会让无人机按预定路线飞行,并在关键位置拍照记录。
首先定义巡检路径点:
checkpoints = [ {"x": 100, "y": 0, "z": 80, "pause": 3}, # 位置1,悬停3秒 {"x": 100, "y": 100, "z": 120, "pause": 2}, {"x": 0, "y": 100, "z": 120, "pause": 2}, {"x": 0, "y": 0, "z": 80, "pause": 0} ]然后实现自动飞行逻辑:
def auto_inspect(drone, checkpoints): drone.takeoff() time.sleep(3) for point in checkpoints: # 计算移动距离(相对当前位置) dx = point["x"] - drone.get_position_x() dy = point["y"] - drone.get_position_y() dz = point["z"] - drone.get_position_z() # 分段移动避免碰撞 if dz != 0: drone.move_up(dz) if dz > 0 else drone.move_down(-dz) time.sleep(2) if dx != 0: drone.move_forward(dx) if dx > 0 else drone.move_back(-dx) time.sleep(2) if dy != 0: drone.move_right(dy) if dy > 0 else drone.move_left(-dy) time.sleep(2) # 悬停拍照 time.sleep(point["pause"]) if point["pause"] > 0: frame = drone.get_frame_read().frame timestamp = time.strftime("%Y%m%d_%H%M%S") cv2.imwrite(f"inspect_{timestamp}.jpg", frame) drone.land()这个项目有几个优化方向:
- 添加异常检测,遇到低电量或强风时自动返航
- 使用SLAM算法实现更精准的定位
- 将巡检数据实时传输到地面站
- 开发Web界面进行任务规划
6. 安全飞行与调试技巧
在办公室测试Tello程序时,我有次差点让它撞上玻璃幕墙。这让我深刻意识到安全飞行的重要性。以下是我总结的几条黄金法则:
- 飞行空间至少是无人机最大移动距离的2倍
- 始终保持视线接触,避免飞入盲区
- 程序开头强制检查电量,低于30%立即报警
- 给每个移动指令设置合理的超时时间
- 准备紧急停止方案,我的习惯是预留一个命令行控制台
调试方面,推荐使用日志记录飞行数据:
import logging logging.basicConfig( filename='tello.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) def safe_move(drone, direction, distance): try: getattr(drone, f"move_{direction}")(distance) logging.info(f"{direction} {distance}cm 成功") return True except Exception as e: logging.error(f"{direction}移动失败: {str(e)}") return False遇到连接问题时,可以按这个流程排查:
- 检查Wi-Fi连接状态
- 重启Tello电源
- 重置网络设置
- 尝试更换USB无线网卡
- 更新固件到最新版本
最后分享一个实用小技巧:用get_position_x()等函数获取实时位置时,数据会有小幅波动。我通常会用移动平均滤波处理这些数据,使控制更稳定。