Tello无人机SDK使用Python封装+简单示例
import socket
import threading
import time
import traceback
class Tello:
"""Wrapper to simply interactions with the Ryze Tello drone."""
def __init__(self, local_ip, local_port, imperial=True, command_timeout=.3, tello_ip='192.168.10.1', tello_port=8889):
"""Binds to the local IP/port and puts the Tello into command mode.
Args:
local_ip (str): 要绑定的本地 IP 地址.
local_port (int): Local port to bind,本地端口.
imperial (bool): 如果为 True, 速度是 Mph, 距离是英尺
如果 False,速度为 KPH,距离为米
command_timeout (int|float):等待响应命令的秒数.
tello_ip (str): Tello IP.
tello_port (int): Tello port.
Raises:
RuntimeError: If the Tello rejects the attempt to enter command mode.
"""
self.abort_flag = False
self.command_timeout = command_timeout
self.imperial = imperial
self.response = None
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 创建一个UDP的连接
# socket这个是插座的意思,其实有点像
self.tello_address = (tello_ip, tello_port)
# 元组传递ip+端口
self.socket.bind((local_ip, local_port))
self.receive_thread = threading.Thread(target=self._receive_thread)
self.receive_thread.daemon = True
# 守护线程
self.receive_thread.start()
开始一个线程
if self.send_command('command') != 'OK':
raise RuntimeError('Tello 被拒绝尝试进入命令模式')
def __del__(self):
"""关闭Tello端口."""
self.socket.close()
def _receive_thread(self):
"""Listens for responses from the Tello.
Runs as a thread, sets self.response to whatever the Tello last returned.
"""
while True:
try:
self.response, ip = self.socket.recvfrom(256)
except Exception:
break
def flip(self, direction):
"""Flips.
Args:
direction (str): Direction to flip, 'l', 'r', 'f', 'b', 'lb', 'lf', 'rb' or 'rf'.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.send_command('flip %s' % direction)
def get_battery(self):
"""Returns percent battery life remaining.
Returns:
int: Percent battery life remaining.
"""
battery = self.send_command('battery?')
try:
battery = int(battery)
except:
pass
return battery
def get_flight_time(self):
"""Returns the number of seconds elapsed during flight.
Returns:
int: Seconds elapsed during flight.
"""
flight_time = self.send_command('time?')
try:
flight_time = int(flight_time)
except:
pass
return flight_time
def get_speed(self):
"""Returns the current speed.
Returns:
int: Current speed in KPH or MPH.
"""
speed = self.send_command('speed?')
try:
speed = float(speed)
if self.imperial is True:
speed = round((speed / 44.704), 1)
else:
speed = round((speed / 27.7778), 1)
except:
pass
return speed
def land(self):
"""Initiates landing.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.send_command('land')
def move(self, direction, distance):
"""Moves in a direction for a distance.
This method expects meters or feet. The Tello API expects distances
from 20 to 500 centimeters.
Metric: .1 to 5 meters
Imperial: .7 to 16.4 feet
Args:
direction (str): Direction to move, 'forward', 'back', 'right' or 'left'.
distance (int|float): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
distance = float(distance)
if self.imperial is True:
distance = int(round(distance * 30.48))
else:
distance = int(round(distance * 100))
return self.send_command('%s %s' % (direction, distance))
def move_backward(self, distance):
"""Moves backward for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.move('back', distance)
def move_down(self, distance):
"""Moves down for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.move('down', distance)
def move_forward(self, distance):
"""Moves forward for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.move('forward', distance)
def move_left(self, distance):
"""Moves left for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.move('left', distance)
def move_right(self, distance):
"""Moves right for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
"""
return self.move('right', distance)
def move_up(self, distance):
"""Moves up for a distance.
See comments for Tello.move().
Args:
distance (int): Distance to move.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.move('up', distance)
def send_command(self, command):
"""Sends a command to the Tello and waits for a response.
If self.command_timeout is exceeded before a response is received,
a RuntimeError exception is raised.
Args:
command (str): Command to send.
Returns:
str: Response from Tello.
Raises:
RuntimeError: If no response is received within self.timeout seconds.
"""
self.abort_flag = False
timer = threading.Timer(self.command_timeout, self.set_abort_flag)
self.socket.sendto(command.encode('utf-8'), self.tello_address)
timer.start()
while self.response is None:
if self.abort_flag is True:
raise RuntimeError('No response to command')
timer.cancel()
response = self.response.decode('utf-8')
self.response = None
return response
def set_abort_flag(self):
"""Sets self.abort_flag to True.
Used by the timer in Tello.send_command() to indicate to that a response
timeout has occurred.
"""
self.abort_flag = True
def set_speed(self, speed):
"""Sets speed.
This method expects KPH or MPH. The Tello API expects speeds from
1 to 100 centimeters/second.
Metric: .1 to 3.6 KPH
Imperial: .1 to 2.2 MPH
Args:
speed (int|float): Speed.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
speed = float(speed)
if self.imperial is True:
speed = int(round(speed * 44.704))
else:
speed = int(round(speed * 27.7778))
return self.send_command('speed %s' % speed)
def takeoff(self):
"""Initiates take-off.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.send_command('takeoff')
def rotate_cw(self, degrees):
"""Rotates clockwise.
Args:
degrees (int): Degrees to rotate, 1 to 360.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.send_command('cw %s' % degrees)
def rotate_ccw(self, degrees):
"""Rotates counter-clockwise.
Args:
degrees (int): Degrees to rotate, 1 to 360.
Returns:
str: Response from Tello, 'OK' or 'FALSE'.
"""
return self.send_command('ccw %s' % degrees)
先直接放主要的代码一段
import Tello
import time
drone = tello.Tello('192.168.10.2', 8888)
drone.takeoff()
time.sleep(5)
drone.set_speed(2)
time.sleep(1)
drone.move_up(3)
time.sleep(5)
drone.move_forward(10)
time.sleep(10)
drone.rotate_cw(180)
time.sleep(5)
drone.move_forward(10)
time.sleep(10)
drone.land()
print('Flight time: %s' % drone.get_flight_time())
再放一段简单的demo
demo因为封装的好,所以就是函数传参加逻辑控制的模式了~
这样放置使用
对于代码来说,照着SDK写的,按说是没有什么大问题.但是我也没有单元测试过,毕竟也没有人给我工资~而且里面的网络编程,多线程,都是我过年现学的,我还会一点GUI,但是写出来好丑呀~就不放了.
https://docs.python.org/3/search.html?q=traceback&check_keywords=yes&area=default
为了方便debug引入这个库
该模块提供了一个标准接口来提取、格式化和打印 Python 程序的堆栈跟踪结果。它完全模仿Python 解释器在打印堆栈跟踪结果时的行为。当您想要在程序控制下打印堆栈跟踪结果时,例如在“封装”解释器时,这是非常有用的。
这个模块使用 traceback 对象 —— 这是存储在 sys.last_traceback
中的对象类型变量,并作为 sys.exc_info()
的第三项被返回。
可以方便的看这个模块的api
最终就是用了这么多的库
def __init__(self, local_ip, local_port, imperial=True, command_timeout=.3, tello_ip='192.168.10.1', tello_port=8889):
"""Binds to the local IP/port and puts the Tello into command mode.
Args:
local_ip (str): 要绑定的本地 IP 地址.
local_port (int): Local port to bind,本地端口.
imperial (bool): 如果为 True, 速度是 Mph, 距离是英尺
如果 False,速度为 KPH,距离为米
command_timeout (int|float):等待响应命令的秒数.
tello_ip (str): Tello IP.
tello_port (int): Tello port.
Raises:
RuntimeError: If the Tello rejects the attempt to enter command mode.
"""
self.abort_flag = False
self.command_timeout = command_timeout
self.imperial = imperial
self.response = None
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 创建一个UDP的连接
# socket这个是插座的意思,其实有点像
self.tello_address = (tello_ip, tello_port)
# 元组传递ip+端口
self.socket.bind((local_ip, local_port))
self.receive_thread = threading.Thread(target=self._receive_thread)
self.receive_thread.daemon = True
# 守护线程
self.receive_thread.start()
开始一个线程
if self.send_command('command') != 'OK':
raise RuntimeError('Tello 被拒绝尝试进入命令模式')
这个是一个构造函数,对于与飞机的连接,通信,信息处理都是至关重要的
这段是建立一个IPv4的UDP套接字
注意是元组传参
多线程的知识建议自己去看,我有空写教程
接收的话,也是用一个线程来写,接收256字节的数据,因为就是个控制而已
翻滚的函数,没有难度,直接传参数,发送到飞机
电量
再封装这个函数的时候,考虑到了单位
这个函数可以说是很重要啦,是一个发送函数
self.socket.sendto(command.encode('utf-8'), self.tello_address)
sendto函数是把数据按照接收时候的地址,原路发回去
timer.start()
while self.response is None:
if self.abort_flag is True:
raise RuntimeError('No response to command')
timer.cancel()
为了提高代码的健壮性,这个地方做了大量的判断,确保发送成功
剩下就没有上面难点了,感兴趣的可以看注释~
赞 (0)