質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

4061閲覧

Pythonのasyncで複数のBLEデバイスのデータが均等にアップロードされない

inugami.mamoru

総合スコア20

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/06/23 00:02

編集2021/06/23 00:04

Pythonのbleakライブラリを使って2個のM5StickCをBLE接続してM5StickC内蔵センサの値をPCに取り込もうとしています。

bleakライブラリのtwo devices exampleを使って2個のM5StickCからデータがアップロードできることが確認できたのですが、データが一方のデバイスから主にアップロードされ、もう一つのデバイスからはまばらにしかアップロードされない状況です。

一方のデバイスがデータをアップロードしている間、他のデバイスのアップロードをブロックしているように見えるのですが、均等にアップロードされるようにするには下のスクリプトをどう書き換えればよいでしょうか。

python

1from bleak import BleakClient 2import asyncio 3 4address1 = "D8:A0:1D:55:EE:8A" 5UUID1 = "beb5483e-36e1-4688-b7f5-ea07361b26a8" 6 7address2 = "94:B9:7E:93:21:76" 8UUID2 = "beb5483e-36e1-4688-b7f5-ea07361b26a2" 9 10adresses = [address1, address2] 11UUIDs = [UUID1, UUID2] 12 13def run(addresses, UUIDs): 14 loop = asyncio.get_event_loop() 15 task = asyncio.gather(*(connect_to_device(address, UUID) for address, UUID in zip(addresses, UUIDs))) 16 loop.run_until_complete(task) 17 18async def connect_to_device(address, UUID): 19 print("starting", address, "loop") 20 async with BleakClient(address, timeout=5) as client: 21 print("connected to", address) 22 while(True): 23 tasks = {client.read_gatt_char(UUID)} 24 done, not_done = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 25 for tasks in done: 26 try: 27 print(await tasks) 28 except Exception as e: 29 print(e) 30 not_done.add(tasks) 31 tasks = not_done 32 33if __name__ == "__main__": 34 run(adresses, UUIDs)

出力:(AとBが各M5StickCのID)
starting D8:A0:1D:55:EE:8A loop
starting 94:B9:7E:93:21:76 loop
connected to 94:B9:7E:93:21:76
connected to D8:A0:1D:55:EE:8A
bytearray(b'A,-0.03,-0.98,10.33,20.79,-7.34,49.20')
bytearray(b'B,-3.55,-4.01,8.56,-55.33,35.50,415.26')
bytearray(b'A,-0.06,-1.00,10.32,21.30,-7.37,50.00')
bytearray(b'A,-0.03,-1.01,10.32,21.74,-7.47,50.74')
bytearray(b'A,-0.09,-1.00,10.31,22.17,-7.52,51.54')
bytearray(b'A,-0.01,-0.96,10.31,22.64,-7.55,52.37')
bytearray(b'A,-0.06,-0.99,10.31,23.39,-7.53,53.97')
bytearray(b'A,-0.03,-1.01,10.27,23.85,-7.60,54.75')
bytearray(b'A,-0.06,-0.96,10.27,24.32,-7.60,55.54')
bytearray(b'B,-3.69,-4.10,8.50,-53.77,33.41,72.30')
bytearray(b'A,-0.03,-1.02,10.27,24.84,-7.68,56.30')
bytearray(b'A,-0.05,-1.01,10.32,25.35,-7.77,57.04')
bytearray(b'A,0.02,-0.99,10.29,25.76,-7.85,57.80')
bytearray(b'A,-0.09,-1.00,10.27,26.28,-7.86,58.53')
bytearray(b'A,-0.04,-0.94,10.27,26.92,-7.92,59.27')
bytearray(b'A,-0.08,-0.95,10.28,27.39,-7.94,60.03')
bytearray(b'A,0.03,-0.96,10.31,28.47,-8.03,61.52')
bytearray(b'A,-0.06,-0.99,10.30,29.09,-8.09,62.23')
bytearray(b'B,-3.55,-4.05,8.46,-51.99,30.52,95.55')
bytearray(b'A,-0.02,-0.96,10.31,29.50,-8.11,63.00')

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

タスクの辺りのコードは意図が解らないのですが、問題点のみ指摘すると

問題点1: タスクの操作

python

1 while(True): 2 3 tasks = {client.read_gatt_char(UUID)} # 前のループの not_done は上書きされる。 4 5 for tasks in done: # ループ変数による tasks の上書き 6 7 not_done.add(tasks) # 消化済みのタスクを not_done を追加する理由は? 8 9 tasks = not_done # 恐らく、次のループでの実行を期待してるのでしょうが 10 # 次のループの最初で、新しいコルーチンに上書き。

どのように書き換えれば良いかは、コードの意図が不明なので解りません。
while ループ内の asyncio.wait() ~ task_done 辺りの説明をお願いします。

ブロックされるのが問題の場合は、

python

1 while(True): 2 result = await conn.read_gatt_char(UUID) 3 print(result)

でダメな理由はありますか?

ライブラリを使わずに、問題の挙動は発生しますか?
まずは、問題点を切り分けましょう。


問題点2: asyncio.wait({coro})

asyncio.wait に直接コルーチンを渡すのは、誤動作の原因になる為
将来のバージョンで廃止されます。

→ create_task が解決策ですが、wait() の利用自体に疑問があります。

  • Deprecated since version 3.8, will be removed in version 3.11:
    Passing coroutine objects to wait() directly is deprecated.
  • Deprecated since version 3.8:
    If any awaitable in aws is a coroutine, it is automatically scheduled as a Task.
    Passing coroutines objects to wait() directly is deprecated as it leads to confusing behavior.

問題点3: wait に timeout を設定せずに使っている目的が解りません。

必ずひとつのコルーチンが実行されるので、質問のコードでは役目がないはずですが、
done, not_done を表示して期待通りの戻り値になっているか、確認して見て下さい。

多分、未完了のタスクを次のループで処理する、タイムアウトで次の処理に移りたい、
といった意図だと思いますが、目的の挙動次第では、wait_foras_completed の検討が候補。

投稿2021/06/25 22:57

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

inugami.mamoru

2021/06/26 11:19

コメントありがとうございます。 ```python while(True): result = await client.read_gatt_char(UUID) print(result) ``` でもデータ受信が一方のM5StickCに偏り、もう一方のM5StickCのデータがまばらにしか受信されない、という挙動は同じままです。
teamikl

2021/06/26 11:54

ライブラリを用いずに試して、while 以下のロジックは期待通りに動いてますか? ライブラリ側の問題だとしたら、この辺り Problem with connecting to a few devices https://github.com/hbldh/bleak/issues/105 検証方法: 複数のターミナルから同時に接続を実行する。 プラットフォーム側のバックエンドの問題が懸念。 → OS, bleak ライブラリのバージョンの確認
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問