12.1. なぜプロトコルライブラリが必要なのか

ケーブル一対とボーレートさえあれば、カメラからホストPCへバイトを送ることはできます。USB-CDCとUARTはどちらも、write で一方の端にバイトを入れ、read でもう一方の端から取り出すストリームをカメラのプログラムに提供します。では、その上にプロトコルライブラリが加えるものは何でしょうか。

本格的なカメラ・ホスト間チャネルを生のバイト上に直接構築しようとすると、毎回自分で書かなければならない3つの要素があります。

フレーミング。 バイトストリームには本来の構造がありません。カメラが temp=42 を書き込むと、ホストは temp= を読み、その後に割り込みが入り、続いて 42 を読み、さらに次のメッセージ humid=... の先頭がすでにそこへ流れ込んでいる、といったことが起こります。バイトには境界がありません。重要なホストリンクは必ず何らかのマーカーを考案することになります。メッセージ間の \n、長さプレフィックスのヘッダー、バイナリペイロード用のエスケープシーケンスなどです。これにより受信側は1つのメッセージがどこで終わり、次がどこで始まるかを知ることができます。プロトコルライブラリは、同期ワードと長さフィールドを備えた統一的なパケット形式を提供するため、受信側が推測する必要は一切ありません。

信頼性。 USB-CDCは通常動作で静かにバイトを取りこぼすことはありませんが、UARTは取りこぼします(ホストがポートを十分に速く処理しなくなった場合)。また、シリアルケーブルを抜き差しすると、一方の側に不完全なパケットが残ることがあります。正しい対処は、破損を検出し、相手側に再送を要求し、無傷で到着したメッセージだけをアプリケーションコードに渡すことです。プロトコルライブラリはCRCとパケットごとの確認応答により、すべてのパケットに対してこれを行います。これはデフォルトで有効であり、アプリケーションは再送を意識しません。

多重化。 カメラとホストの間にはUSB-CDCポートが正確に1つだけ存在します。カメラが画像をストリーミングし、同時にホストが設定を送信し、さらにIDEが print 出力のために stdout を読んでいる場合、これら3つのやり取りはすべてその単一のバイトストリームを共有しなければなりません。プロトコルライブラリは、独立した各ストリームにチャネル番号を与え、カメラ側でそれぞれにPythonクラスを登録できるようにし、各チャネルでのホストの読み取りが他のチャネルに干渉しないようにします。アプリケーションコードから見ると、各チャネルはそれぞれ専用のリンクのように見えます。

12.1.1. なぜ自分で書かないのか

もちろん書くことはできます。シリアルラインで3つすべてを正しく動かすには数週間かかり、さらにフレーミングがホットプラグからの復旧をきれいに処理し、再送がラウンドトリップでエネルギーを浪費せずに機能し、多重化が部分読み取りに耐えてあるチャネルのバイトを別のチャネルへ混入させないようにするには、さらに数週間かかります。

プロトコルライブラリはすでにその作業を終えており、サポートされているすべてのカメラで検証済みで、同じワイヤ形式を話すホスト側の対応ライブラリも備えています。これを使えば、カメラ側のコードはチャネルごとに小さなクラス1つで済み、ホスト側のコードは channel_readchannel_write メソッドを持つ Camera オブジェクトで済みます。そうして節約できた頭のスペースは、アプリケーションが実際に行うべきことへ振り向けられます。

この章ではプロトコルを基礎から解説します。ワイヤ形式、フレーミング規則、信頼性の仕組み、チャネルモデル、そして最後に両端のPythonクラスです。読み終える頃には、カメラと通信するホストGUI、カメラからノートPCへセンサーデータをストリーミングするスクリプト、そして openmv-projects/tools/ に同梱されているようなインタラクティブな校正ツールを構築できるようになります。