1. はじめに
まず、大前提としてPython3でシリアル通信をする場合、pip install pyserial
コマンドでpyserial
ライブラリを導入でき、何の問題もなくシリアル通信が可能です。そちらの方がはるかに簡単で安定しています。
でーすーが!Pybricksではpyserial
が使えません。そのため、本記事で紹介するようなOSのファイルI/Oを直接操作する、黒魔術的な解決策を行います。
結論から言うと、この方法は多くの問題を抱えており、実用的な利用は推奨されません。
2. 通信の仕組み
ev3dev
では、USB経由で接続されたArduinoなどのシリアルデバイスが、/dev/ttyUSB0
のようなファイルとして認識されます。この「ファイル」を読み取り、シリアル通信を試みます。
3. 実装
以下は、Arduinoからデータを受信することのみを想定した関数です。(もともとクラスだったものからAIを使って抽出舌コードです。ご了承ください。)
制約により、安定した送受信は不可能なため、受信に特化しています。
#!/usr/bin/env pybricks-micropython
import time
def receive_latest(device_path="/dev/ttyUSB0", debug=True):
try:
# シリアルポートを開く (バッファリングなし)
serial_port = open(device_path, "rb+", buffering=0)
if debug:
print("シリアルポート {} に接続しました。".format(device_path))
except Exception as e:
if debug:
print("ポート {} への接続エラー: {}".format(device_path, e))
return None
try:
# 最新のデータを受信するまで古いデータを破棄
latest_data = None
while True:
line = serial_port.readline()
if not line:
break
# タイムアウト回避のため、新しいデータが来るまで古いデータを読み飛ばす
latest_data = line
if not latest_data:
return None
# 読み取った最新データをデコードして処理
line = latest_data.decode('utf-8').strip()
return line
except Exception as e:
if debug:
print("データ受信エラー: {}".format(e))
return None
finally:
# ポートを閉じる
if 'serial_port' in locals() and not serial_port.closed:
serial_port.close()
# スクリプトの実行例
if __name__ == "__main__":
device_path = "/dev/ttyUSB0"
print("データ受信を開始します。")
while True:
data = receive_latest(device_path, debug=True)
if data:
print("受信データ:", data)
else:
print("データを受信できませんでした。")
time.sleep(1)
4. 注意点
この通信方式には、実用性を著しく損なうほどの厳しい制約があります。
-
この方法は非常に不安定で、データの取りこぼしが発生します。安定した動作は全く見込めません。EV3につながっているデバイスからドッジボールのように送りまくる環境になります。
-
EV3からの送信ができていない。もしかしたらできるかもしれません。
-
ライブラリが制限されているため9600bpsでしか通信できません。遅いです。
-
USBポートが気まぐれです。
ttyUSB0
だったり、突然ttyUSB1
になったり、はたまたttyACM0
のときもありました。起動したときに割り当てられる順番?が問題だと考えられます。
結論
もしEV3で安定したシリアル通信が必要な場合は、Pybricksの使用を諦め、ev3devのPython3が動作する環境へ移行することを強くおすすめします。
もっといいやり方がわかる方がいれば教えて下さい。osライブラリでコマンド実行するとか???