---
# System prepended metadata

title: tello drone python控制學習

---

# 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就可以讓後面的字串變得不固定，達到每張照片的名字都不同，可以確保照片不複寫。