ドローンのスティックコントロールをTelloで練習するなら、積極的に、TelloをスマホでなくＰＣで操作するシステムを構築した方がいい

　一般的にTelloをＰＣで操作しようとするとき（Python使用、が楽）、その目的が「プログラミングの練習、あるいは興味」ということが多い。

　　https://python.joho.info/robot/tello-python-sdk/

　だが、例外的に、「ドローン認定試験の実地試験でＧＰＳ制御機構のないドローンがつかわれるので、ＧＰＳ制御機構のないTelloで事前練習する」という目的の場合、積極的に、TelloをスマホでなくＰＣで操作するシステムを構築した方がいい。

　理由は、スマホにBluetooth接続する「TELLO専用GameSir T1dコントローラー」( https://kenchan3.com/tello-gamesirt1d/ ) よりも、ＰＣにつないだ「汎用性の普通のゲームコントローラー（任天堂やＸｂｏｘ）」のほうが、スティックコントロールがよりスムーズ（動かしたとき早く反応する、あるいは、「電波連携が切れる」頻度が少ない）からである。 とはいえ、それこの結果はあくまでぼくの主観ではあるが。

 　TelloのスマホやPCとの接続はWi-Fi（APモード）。実用的な通信距離はだいたい10～30メートル前後。 一方、DJI NEO（Miniシリーズなどのドローン）はOcuSync4.0（専用RF通信）。通信距離は最大10ｋｍとも。 ただ、DJI NEO（Miniシリーズなどのドローン）でも、状況によってはWi-FiのSSIDが見えることがある。ただし、それは ドローン本体の映像伝送や操作通信（OcuSync）とは別の用途でWi-Fiが使われている可能性が高い。

 　あまり、目がむけられてないことだが、

　TelloをスマホやPCで操作する場合、PCはインターネットに接続されている必要はない。つまりPCが「TelloのWi-Fi」に直接つながっていればOKで、他のネットワーク（インターネットや社内LAN）と繋がっている必要はない（例えば、Telloは野外などオフラインでPCで動く）。 というより、スマホ（PC）がWi-FiでTelloとつながると、通常はスマホ（PC）は他のインターネットやLANにはつながらない。

　そして、そこには「同時接続制限」という問題がある。

　スマホ（PC）がWi-FiでTelloとつながると、通常はインターネットやLANにはつながらない。なので、（Wi-Fiとは違うがやはり電波接続である） Bluetoothデバイス（Telloコントローラー）と安定通信できるかどうかは、スマホ（PC）性能とOSに依存する。つまり、もともと「Bluetooth接続が不安定」。 このせいなのか、しばしば、理由なくTelloのコントローラーがTelloとうまくつながらなくなる現象がおこる。 なので、PCにコントローラーを有線接続することで、この現象が改善される可能性があるのだ（もちろん、ここでＰＣのBluetoothデバイスは使わない。というか、もともと多くのゲームコントローラーはＰＣでのBluetoothデバイス非対応のものが多い）。 

　なにはともあれ、準備として下記のような、tello_gamepad_rc.pyを用意。もちろん、ＰＣにPythonはインストールされてなければならないし、足りないモジュールは、適宜、ＰＣにインストールしなければならい。

tello_gamepad_rc.py
  
    import cv2
    import time
    import pygame
    from djitellopy import Tello
    # --- 初期化 ---
    pygame.init()
    pygame.joystick.init()
    joystick = pygame.joystick.Joystick(0)
    joystick.init()
    print(f"接続されたコントローラー: {joystick.get_name()}")
     # --- Tello 接続 ---
    tello = Tello()
    tello.connect()
    tello.streamon()
    print(f"Battery: {tello.get_battery()}%")
    # --- 動画保存設定（初期は録画OFF） ---
    recording = False
    video_writer = None
    fps = 30
    frame_width = 960
    frame_height = 720
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    # --- 飛行状態 ---
    flying = False
    tello.send_rc_control(0, 0, 0, 0)
    
    try:
    while True:
        pygame.event.pump()

        # --- 離陸・着陸（A=0, B=1） ---
        if joystick.get_button(0):  # A
            if not flying:
                tello.takeoff()
                flying = True
        if joystick.get_button(1):  # B
            if flying:
                tello.land()
                flying = False

        # --- 録画開始・停止（Y=3, X=2） ---
        if joystick.get_button(3):  # Yボタン → 録画開始
            if not recording:
                print("🎥 録画開始")
                video_writer = cv2.VideoWriter('tello_record.mp4', fourcc, fps, (frame_width, frame_height))
                recording = True
        if joystick.get_button(2):  # Xボタン → 録画停止
            if recording:
                print("🛑 録画停止")
                recording = False
                if video_writer:
                    video_writer.release()
                    video_writer = None

        # --- スティック操作 ---
        yaw = int(joystick.get_axis(0) * 100)   # 左スティック左右
        ud = int(joystick.get_axis(1) * -100)   # 左スティック上下
        lr = int(joystick.get_axis(2) * 100)    # 右スティック左右
        fb = int(joystick.get_axis(3) * -100)   # 右スティック上下

        def deadzone(val, threshold=10):
            return val if abs(val) > threshold else 0

        tello.send_rc_control(deadzone(lr), deadzone(fb), deadzone(ud), deadzone(yaw))

        # --- カメラ処理 ---
        frame = tello.get_frame_read().frame
        frame = cv2.resize(frame, (frame_width, frame_height))

        battery = tello.get_battery()
        height = tello.get_height()

        # テレメトリ表示
        cv2.putText(frame, f'Battery: {battery}%', (10, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv2.putText(frame, f'Height: {height}cm', (10, 70),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        # 録画中表示
        if recording:
            cv2.putText(frame, '● REC', (800, 30),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

        # 映像表示
        cv2.imshow("Tello Gamepad RC (MP4 Rec)", frame)

        # 録画中なら保存
        if recording and video_writer:
            video_writer.write(frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

        time.sleep(0.03)

    finally:
    tello.send_rc_control(0, 0, 0, 0)
    if flying:
        tello.land()
    tello.streamoff()
    if recording and video_writer:
        video_writer.release()
    cv2.destroyAllWindows()
    pygame.quit()



　その後、実際にやることは、以下の順番
 ①  Telloを起動（多くのDJI製品は、起動、終了とも2度押しだが、Telloの起動は2度押しでなく1度押し。Telloの終了は２度押し）
 ②  ＰＣで、Wi-Fi設定で TELLO-XXXX に接続（今までつないがっていたインターネットからはＰＣは切断される）。
 ③  tello_gamepad_rc.pyをPC上で実行 

　すると、tello_gamepad_rc.pyには、画面表示機能（さらには、録画機能）も含めたので、下記のような画面がPC上に出現。 

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676736/0dd46af2-25d3-4334-ae48-86dbec414033.png)



　ドローン認定試験の実地試験では「ＧＰＳ制御機構のないドローンを使った目視飛行」が行われるので、目視外飛行に使うこの画面表示はおまけの機能である（が、うまくシステムが働いているか？の確認ができる）。
　そして、RadioControlモードにもなっている。

　各ゲームコントローラーのボタンのわりふりは下記のよう。 

🎮【スティック割り当て】
左右移動 右スティック 左右（axis 2）
前後移動 右スティック 上下（axis 3）
上昇・下降 左スティック 上下（axis 1）
左右回転 左スティック 左右（axis 0） 

✅動作チェックメモ操作 入力方法
離陸 Aボタン
着陸 Bボタン
録画開始 Yボタン
録画停止 Xボタン
終了 キーボード q キー押下

　スマホにBluetooth接続した「TELLO専用GameSir T1dコントローラー」よりも、ＰＣにつないだこの「汎用性の普通のゲームコントローラー（任天堂やＸｂｏｘ）」のほうが、スティックコントロールがよりスムーズの印象である。