昨年のNaka Drone Racing 2024以来育ててきたGoogle Sheetによるレース集計システムを紹介します。まだまだ未完成ですが、いくつかのレースを経て役に立つものになりつつあります。またTinyViewPlus v0.9.33 beta6の通知機能を利用しリアルタイムな更新も可能となりました。
その概要とプログラム全てを公開いたします。使い方や細かい動作までは説明しきれないので、勝手に参考にしてもらったり、使える部分は再利用をしてください。という放任主義です、悪しからず。
[ システムの概要 ]
WTW Tokushimaのドローン部長による場内PAおよび配信システムの一部であるTinyViewPlusと集計操作用のMacBook Airを連携して行います。
[ oscrcv.py ]
oscrcv.pyスクリプトはTinyViewPlusからのOSCプロトコルによる通知で受信したデータをGoogle SheetにPOSTします。データの受信を確実にするためにoscrcv.pyはTinyViewPlusが稼働しているWindows PC上で稼働するようにしています。また予選、決勝などのレース毎(あるいはGoogle Sheetの切り替え)にoscrcv.pyの起動パラメータを指定して立ち上げ直す必要がありますので、MacBook AirからsshでTinyViewPlusのPCにログインして行なっています。
# oscrcv.py
import argparse
import math
from pythonosc import dispatcher
from pythonosc import osc_server
import json
import requests
import time
import datetime
url = ""
url1 = "https://script.google.com/macros/s/AKfycbzDg0hHdgDlE_qYEngvYBBqYDummyssJ_sA_fmstVcXgyyx-KMem32_lbSoC8gdAhgg/exec"
url2 = "https://script.google.com/macros/s/AKfycbw7_T9Z4eWVWbybGm2IhXsazDummyRVwOjrQ_OcuowXC2yV-onDk0ppOxefZdZNQHQh/exec"
sheetname = ""
sh1 = "練習"
sh2 = "予選ヒート1,2"
sh3 = "予選ヒート3,4"
sh4 = "勝ち上がり戦入力"
def timeformat(seconds):
td = datetime.timedelta(seconds=seconds)
minutes, seconds = divmod(td.total_seconds(), 60)
return f"{int(minutes):02d}:{seconds:05.2f}"
def oschandle(addr, *args):
global url
global sheetname
print(addr)
print(args[0])
print("")
timestamp = time.strftime('%Y/%m/%d %H:%M:%S')
args3 = args4 = ""
if (len(args) > 3):
if (isinstance(args[3], float)):
args3 = "{:05.2f}".format(args[3])
else:
args3 = args[3]
if (len(args) > 4):
if (isinstance(args[4], float)):
args4 = timeformat(args[4])
else:
args4 = args[4]
data = {
"timestamp" : timestamp,
"addr" : addr,
"arg0" : args[0],
"arg1" : args[1] if (len(args) > 1) else "",
"arg2" : args[2] if (len(args) > 2) else "",
"arg3" : args3,
"arg4" : args4,
"sheetName" : sheetname
}
print(json.dumps(data))
# json.dumpでデータをJSON形式として扱う
r = requests.post(url, data=json.dumps(data))
print(r)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip",
default="", help="The ip to listen on")
parser.add_argument("--port",
type=int, default=4001, help="The port to listen on")
parser.add_argument("--url",
default="1", help="1 = Sprint, 2 = Endurance")
parser.add_argument("--sheet",
default="1", help="1 = 練習, 2 = 予選ヒート1,2, 3 = 予選ヒート3,4, 4 = 勝ち上がり戦入力")
args = parser.parse_args()
if (args.url == "1"):
url = url1
else:
url = url2
if (args.sheet == "1"):
sheetname = sh1
elif (args.sheet == "2"):
sheetname = sh2
elif (args.sheet == "3"):
sheetname = sh3
else:
sheetname = sh4
print("URL: ", args.url)
print("Sheetname: ", sheetname)
dispatcher = dispatcher.Dispatcher()
dispatcher.map("/*", oschandle)
server = osc_server.ThreadingOSCUDPServer(
(args.ip, args.port), dispatcher)
print("Serving on {}".format(server.server_address))
server.serve_forever()
[ Google Sheetでの処理 ]
oscrcv.pyからのPOSTはGASで受信します。送られてくるデータは2種類あります、一つはLapデータでリアルタイムなレース状況の更新に使います。
TinyViewPlus v0.9.33 beta5でラップの削除も通知されるようになったのでテスト。 pic.twitter.com/DRfXIqs2Lr
— コザック KozakFPV 空の自由人 (@nkozawa) February 20, 2025
もう一つはレース結果で、レースの集計に使います。
TinyViewPlus がレース結果を送信してくれるようになりました。UDPなので取りこぼしも考慮して、従来通り結果ファイルを見るかクリップボードを見る準備も必要。 pic.twitter.com/PxdglMhXl3
— コザック KozakFPV 空の自由人 (@nkozawa) March 2, 2025
集計作業は結果入力シートにデータを集積し集計プログラムシートにあるボタンからGASを起動して順位を別のシートに記入します。詳細は書きませんが、勝ち上がり戦の組み合わせまでは自動で行います。勝ち上がり戦の集計以降は手作業で行なっています。
予選の順位は周回数が多い方を上位とします。同一周回数の場合は合計時間が短い方が上位となります。全く同じ成績であった場合の処理は入っていませんのでデータの目視確認が必要となります。
WTWShikokuDroneRaceWorksheet
このワークシートはRead Onlyで共用しています。ご自身のGoogl DriveにコピーするとGASの内容も読めるようになります。
TinyViewPlus->Python Script->Google Sheetへの連携の詳細は別記事「Tiny View Plusの外部通知機能を試す」に書いていますので参照願います。
[ ディスク共用 ]
OSCのデータによる集計に問題があった時のためにTinyViewPlusのResultフォルダーをMacBook Airからアクセスできるように共用しています。Google SheetのGASは集計データのファイルからの読み込みにも対応しています。この部分はninjaMoonLightさんが書かれたものです。
[ TinyView Plusのバイロット名 ]
集計作業とは別ですがWindows上のTinyView Plusのカメララベル(パイロット名)のセットもMacBook Airから行なっています。使用しているプログラムはGithubにて公開しています。
https://github.com/nkozawa/tvpilotnames
以上です。まだ完全自動とは言えませんが、そこそこ役に立つものになりました。また進歩があれば何かの形で公開したいと思います。
no comment untill now