# djl tello 無人機控制學習
### 實機演示
[點這](https://youtu.be/N_-LxrJo0W8)
### 主要程式碼
```python=
from djitellopy import tello
import keyboardpress as kp
# 命名為kp
import time
import cv2
a = 0
b = 1 # a為輸入除錯用 b為影像畫面除錯用
global img
kp.init() # 初始化
me = tello.Tello()
me.connect() #與tello連線
print(me.get_battery())
if b == 1:
me.streamon() # 打開tello鏡頭
####按鍵函式####
def getKeyboardInput():
speed = 30
lr, fb, ud, yaw = 0, 0, 0, 0
# 左右
if kp.getKey('a'): #kp.getKey()另外拉出來寫
if a == 1: print("a") # 測試輸入
else: lr = -speed # a==1時代表不連接tello測試
###以下同理###
elif kp.getKey('d'):
if a == 1: print("d")
else: lr = speed
#前後
if kp.getKey('s'):
if a == 1: print("s")
else: fb = -speed
elif kp.getKey('w'):
if a == 1: print("w")
else: fb = speed
#上下
if kp.getKey('DOWN'):
if a == 1: print("DOWN")
else: ud = -speed
elif kp.getKey('UP'):
if a == 1: print("UP")
else: ud = speed
#旋轉
if kp.getKey('LEFT'):
if a == 1: print("LEFT")
else: yaw = -speed
elif kp.getKey('RIGHT'):
if a == 1: print("RIGHT")
else: yaw = speed
return [lr, fb, ud, yaw] # 回傳左右上下前後旋轉的速度
while True:
### 起降翻轉拍照 與getKeyboardInput()相同 ###
if kp.getKey('l'):
if a == 1: print("land")
else: me.land()
if kp.getKey('t'):
if a == 1: print("take off")
else: me.takeoff()
if kp.getKey('f'):
if a == 1: print("flip")
else: me.flip("l") ##向左翻轉
if kp.getKey('p'):
cv2.imwrite(f'Resources/Images/{time.time()}.jpg', img)
# f-string 可以在字串裡面透過{}加入自定變數或是函式
#time()可生成完全不重複的檔名
time.sleep(0.5) # 停頓使擷取照片張數減少
vals = getKeyboardInput()
if a != 1:
me.send_rc_control(vals[0], vals[1], vals[2], vals[3]) # 傳送控制速度的訊號
if b == 1: # 測試影像是否正常出來
img = me.get_frame_read().frame # 循環得到每幀影像
img = cv2.resize(img, (360, 240)) # 改變視窗大小
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA) # 無人機本身預設BGR 把畫面更改成RGB
cv2.imshow('Image', img) #
cv2.waitKey(10) #等待10毫秒
```
### 說明
1. djitellopy、pygame、cv2皆為pycharm的模組,在這邊的作用分別是控制tello、輸入、影像呈現。
2. 在學習完基本動作後,首先影片先教了如何呈現tello的影像在電腦上:
```python=
from djitellopy import tello
import cv2
me = tello.Tello()
me.connect()
print(me.get_battery())
me.streamon()
while True:
img = me.get_frame_read().frame
img = cv2.resize(img, (360, 240))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)
# 更改RGB順序
cv2.imshow('Image', img)
cv2.waitKey(1)
```
實際操作時出了問題,是在更改RGB順序前,影像的顏色有類似負片(?)效果,上網搜尋發現是tello預設的色彩訊號(原本是BGR)和電腦不一樣,將訊號改回RGB就變正常了。
3. 再來是鍵盤控制keyboardpress,getKey()就在這裡:
```python=
import pygame
def init():
pygame.init()# 初始化
win = pygame.display.set_mode((400, 400)) # 生成視窗
def getKey(keyName): # 按下按鍵後要回傳ture
ans = False
for event in pygame.event.get(): pass # 不停讀取訊息,pass是因為不需要做任何事
KeyInput = pygame.key.get_pressed() # 偵測鍵盤事件(Ture or False)
myKey = getattr(pygame, 'K_{}'.format(keyName)) # 回傳訊號
if KeyInput[myKey]: # 如果偵測到按下指定按鍵
ans = True
return ans
pygame.display.update() # pygame的視窗更新,應該是為影片後續課程打底
```
在這邊最困難的地方是理解程式碼含意,像是 pygame.key.get_pressed()是回傳布林值、getattr()是回傳物件中的某屬性值等,這些都需要上網爬文才知道。
5. 將第2、3點融合,2負責影像,3負責無人機移動。在測試的時候發現鍵盤怎麼輸入都會有問題,最後發現是在執行程式碼的那一刻,電腦會自動切換成預設輸入法(中文),導致原本按下的"t"在電腦那邊是"ㄔ",只要把電腦預設輸入法改成英文就好了。
6. 最後是增加拍照功能,只要先建立資料夾後使用cv2.imwrite()將照片寫入資料夾就好,這邊我去google了路徑前用f的原因,白話來講加了f就可以讓後面的字串變得不固定,達到每張照片的名字都不同,可以確保照片不複寫。