GoProは素晴らしいことに、WiFi, BLE, USBからコマンドを送って操作できます。(なんと2021年から!)
言うまでもないことですが、BLEは電波が微弱すぎる、USBは耐水にすることが大変なので、ボート用としてはWiFiを選択します。
結構、ややこしい話なのでユースケースを考えます。
- Fc(フライトコントローラー)の電源投入と初期化、Raspberry PIの電源投入とブート終了、GoProの電源を入れたらスマホのQuikと接続する必要があります。GoProはBluetoothを利用してWiFi利用を開始してアクセスポイントが使用可能となります。
- 接続ができたら、Pythonプログラム(これから作る)を起動します。
- このプログラムはFCからのトリガーをGoProの写真シャッターを起動するコマンドに変換してGoProに送ります。
同時に30秒に一度、KeepAliveを送りGoProが眠り込まないようにします。
この1, 2は現時点ではPCとRASPIをイーサネット経由SSHで接続して操作することとします。
(改善の余地あります!)
Open GoPro
GoproをコントロールするプログラミングインターフェースはOpen Gopro で提供されているパッケージを使います。
インストールにはpipがいります。
sudo apt -y install python3-pip
Open GoProのインストールは
pip install open-gopro
APIをドライブする方法
Pythonを使うことに異論はないのですが、Open Gopro を使うためにSDKとしてOpen Gopro Python SDK があります。
あくまで個人的見解ですが、これがまったくイケていません。サンプルは~/.local/bin にインストールされていますが、どれもすんなり動かないこととasyncioで作られています。
Open Goproのデモは同期型でpythonでhttp処理をする時によく使われるrequestsが採用されています。
Open GoProはhttpリクエストを送り、結果をJSONでもらうというシンプルな構造になっているし、結果を受け取るまで待ってもなにも問題がないのです。非同期である必要はありません。
ただし、やりとりが止まるとスリープするのでKeep Aliveを30秒ごとに送れ、とあります。こちらは非同期でなければ困ります。
Linuxではプロセス、スレッドというものがあります。
区別がついていないと困るので、少しメモをしておきます。プロセスはLinuxの親プロセスからforkで作られる、新しい仮想空間です。その中でスレッドが具体的なプログラムとして動作します。もちろん、ひとつのプロセスの中で複数のスレッドを生成して非同期に動かすことは可能です。Pythonでもthreadingライブラリーを使ってスレッドを生成できます。
この場合、OSレベルではスレッドの切り替えは割り込みにより起きます。外部デバイス、タイマー、プロセッサー間、ハードウェア警告。割り込みが起きると割り込み処理がされ、次にどのスレッドを処理するかOSは考えます。このルーチンをディスパッチャーといいます。
今回、Pythonでスレッドを動かすことにします。
まずは簡単な例から。以下はGoPro Tutorial6のカメラの状況を撮るサンプルを一部、改変して、カメラが写真撮影するものです。
同時に3秒おきにKeepAliveを送っています。
import requests
import time
import json
import threading
GOPRO_BASE_URL = "http://10.5.5.9:8080/"
def request_cmd(cmd):
response = requests.get(GOPRO_BASE_URL+cmd, timeout=10)
response.raise_for_status()
resp = response.json()
print( json.dumps(resp) )
def request_alive():
while True:
resp = requests.get(GOPRO_BASE_URL+"/gopro/camera/keep_alive")
resp = resp.json()
print("Keep Alive")
time.sleep(3)
if __name__ == '__main__':
thread_A = threading.Thread(target=request_alive)
thread_A.start()
# photo mode.
request_cmd("/gopro/camera/presets/set_group?id=1001")
time.sleep(10)
request_cmd("/gopro/camera/shutter/start") # push
time.sleep(3)
# request_cmd("/gopro/camera/shutter/stop") # release
thread_A.join() # wait until thread_A
ピッという音と共にモードが切り替わります!