TECH PLAY

アプトポッド

アプトポッド の技術ブログ

248

はじめに こんにちは、アプトポッドの岩田です。 今回は、当社のCANバス接続用USBデバイスの「 EDGEPLANT CAN-USB Interface 」と、それに付属する自動車計測向けクラウドサービスの「 intdash Automotive Pro 」についてご紹介したいと思います。 はじめに EDGEPLANT CAN-USB Interface とは EDGEPLANT CAN-USB Interface の特長 デイジーチェーン型のSync線共有機構 CANバスへのCANフレームの送出も可能 公開されているファームウェアとデバイスドライバー 本製品を含む自動車計測遠隔化ソリューション "Automotive Pro" とは Automotive Pro の構成 基本構成 拡張性・カスタマイズ性 Automotive Pro でのデータ管理・可視化 おわりに EDGEPLANT CAN-USB Interface とは EDGEPLANT CAN-USB Interface (EP1-CH02A)は、自動車のCAN *1 バスに接続して、CANデータを取得するための小型のUSBデバイスです。 車載したゲートウェイ装置などとUSB接続することで、簡単にCANバスからデータを取得できます。 本製品の特徴は以下の通りです。 Y分岐ケーブルを使用して、 同時に2チャンネルのCANバスに接続 可能 TCXO(温度補償型水晶発振器)搭載 、高い周波数精度とタイマー分解能 CANフレーム受信直後のタイムスタンプを付与 してUSBホストに受け渡し デイジーチェーン方式のSync線共有機構 、複数機器のクロックを同期可能 USB Type-Bコネクタで手軽にゲートウェイ装置へ接続可能 高保持力USBコネクタを採用し、意図しないコネクタ挿抜を防止 USBバスパワーによる駆動で配線を簡略化 別売のアナログ入出力インターフェイス *2 で アナログ信号と同期計測 も可能 ファームウェア・デバイスドライバーを当社Webサイトにて公開 *3 また、より詳細な技術仕様は以下の通りです。 【定格】 5V、100mA、0.5W 【適合規格】 FCC Class A、CE 【ESD】 IEC 61000-4-2, Air ±8kV, Contact ±4kV 【インターフェイス】 CAN 2ch、USB Type-B Full Speed(12Mbps) 【ボーレート】 最大1Mbps(33, 50, 83, 100, 125, 250, 500 kbps 切替え) 【終端抵抗】 なし 【使用温度】 -20℃~+75℃ 【外形寸法】 61mm × 77mm × 26mm(幅 × 奥行き × 高さ) 【質量】 約120g その他の詳細な技術仕様は、当社Webサイトの製品ページからご覧いただけます。 データシート等もご用意がありますので、ご興味をお持ちいただけた方はこちらよりご確認・お問い合わせください。 www.aptpod.co.jp EDGEPLANT CAN-USB Interface の特長 EDGEPLANT CAN-USB Interface も、Vector社やPEAK-System社など自動車計測用機材を扱っているその他企業のUSB/CANインターフェイス製品と同様に、CANバスに接続することで、USB接続したゲートウェイ装置やPCに対して、受信したCANフレームを利用可能とするデバイスです。 デイジーチェーン型のSync線共有機構 本製品で特徴的なのはデイジーチェーン型のSync線共有機構(タイムスタンプの同期機構)です。複数の CAN-USB Interface をデイジーチェーン(いわゆる "数珠つなぎ")で接続することにより、分配器やSyncのための親機を用意することなく複数デバイスを同期できます。 他社製品では、エントリーモデルにはハードウェア同期機構がついていないものも多く、複数デバイスでの正確なタイムスタンプ同期を実現するにはある程度のコネクタ数を備えた上位モデルを採用しなければなりません。一方、当社製品では、単体で使用した場合でも複数で使用した場合でも変わらず、分配器などの追加機器を必要とすることなくハードウェア同期を実現できます。これにより、小規模な構成から大規模な構成まで、柔軟にスケールさせることができ、構成変更があった場合にも既存機器が無駄になりません。 Sync線共有の方式比較: 分配器を用いた方式とデイジーチェーン方式 ゲートウェイPC(当社製 EDGEPLANT T1)へ接続した様子 自動車計測におけるタイムスタンプ同期の重要性とは? 自動車の内部では、エンジン、ブレーキ、ステアリングといった様々な制御システムが互いに連携して動作します。 これらのシステムの全体を検証・評価するには、それぞれがどのように相互作用しているかを厳密な時系列で追跡し、正確なタイミングを理解することが不可欠です。 しかし、各システムが異なるCANバスを通じて通信している状況で同期されていないデバイスによってデータを取得すると、 それぞれのバスから取得されたデータのタイムスタンプの同期が取れなくなってしまいます。 タイムスタンプが同期していないと、各システムがどのような時系列で連携しているのか正確に把握することができません。 例えば、ブレーキシステムの指令がエンジン制御へどのように影響を与えるか、または緊急時におけるステアリングとブレーキの協調動作が適切に動作しているかなどが評価できなくなってしまいます。 CANバスへのCANフレームの送出も可能 本製品は、CANバスからのCANフレームの取得だけでなく、CANフレームの送出にも対応しています。 例えば、セントラルゲートウェイにつながるCANバスに本製品を接続して、診断用のプロトコルに従ってCANフレームを送出することで診断通信を行うことも可能です。標準化された診断通信の規格に則ってフレームをやり取りすることで、DBCファイルをお持ちでない場合でも車両データを取得することができます。 また、CANバスへ予期しない影響を与えないように、本製品はデバイスドライバーから動作モードをListen Onlyに設定できるようになっています。Listen Onlyモードに設定することで、一切のCANフレームやACK信号を送出しなくなるため、安心してCANバスに接続していただけます。 公開されているファームウェアとデバイスドライバー 本製品のファームウェアおよびデバイスドライバーは上記の 当社Webサイトの製品ページ で公開していますので、それらと各種オープンソースツールを組み合わせることで、本製品単体でもご利用いただけます。 以下の記事では、オープンソースのCANドライバー SocketCAN と可視化ツールの SavvyCAN を使用して、本製品を利用する例をご紹介しています。 tech.aptpod.co.jp 一方、本製品は、冒頭でも触れました当社のクラウドサービス「 intdash Automotive Pro 」と組み合わせてご利用いただくことで、より効果的にご活用いただけます。 本記事の後半では、「 intdash Automotive Pro 」についてもう少し掘り下げてご紹介していきます。 本製品を含む自動車計測遠隔化ソリューション "Automotive Pro" とは intdash Automotive Pro は、自動車計測ワークフローの自動化・遠隔化を実現するためのパッケージソリューションです。 これまでにご紹介した EDGEPLANT CAN-USB Interface は、実はもともと、本ソリューションの一部として開発されたデバイスになります。 www.aptpod.co.jp intdash Automotive Pro では、自動車から各種データを取得するための専用の車載装置、クラウドサーバー上に配置したデータの管理・可視化アプリケーションをセットで提供します。 専用車載装置はLTEによるインターネット接続を備えており、自動車から取得したデータを自動的にクラウドサーバーへアップロードします。 クラウドに集められたデータには、ブラウザベースの管理・可視化アプリケーションによって世界中からいつでもどこからでもアクセスが可能です。 www.youtube.com 本ソリューションの目的は、自動車業界における車両計測ワークフローの改善です。 従来のデータロガーを使ったワークフローでは、車両に積んだ計測機器のデータを一旦ハードディスクなどに保存し、各計測地から回収していました。 データを回収した後も、ディスクからデータをコピーする、計測機器間のタイムスタンプを同期させるなど、データを解析に回すまでの後処理工程にも手間がかかります。 intdash Automotive Pro を利用することで、データはLTE回線を使用して随時自動的にクラウドへアップロードされ、リアルタイムに世界中の拠点で共有されます。 独自のタイムスタンプ管理機構も備えており、各機器のタイムスタンプがきちんと揃った状態でクラウドにデータが保存されるため、後処理工程の手間もなく直ぐに解析に取り掛かることができます。 Automotive Proの特長 CAN/CAN-FDに対応(同時取得4~8チャンネル) カメラ映像の取得も可能(同時取得1~2ストリーム) GNSSによる車両位置の取得 取得データは即時クラウドに伝送され、遠隔地でリアルタイム可視化可能 LTE回線による取得データの自動アップロード 自動データリカバリー機能で、LTE回線切断時もデータロストなし Automotive Pro の構成 現在は、 intdash Automotive Pro DAQ Bundle という名称で、ハードウェア、クラウドサーバー、Webアプリケーションすべてオールインワンなバンドルパッケージとして販売しています。 基本構成 本製品の基本的な構成は、以下の通りです。 専用のゲートウェイコンピュータ(当社製 EDGEPLANT T1 ) USB/CANインターフェイス機器(当社製 EDGEPLANT CAN-USB Interface ) 映像取得用USBカメラ(当社製 EDGEPLANT USB Camera ) 当社が運用するクラウドサービス(データ伝送・データ管理機能を提供) データ可視化アプリケーション・データ管理アプリケーション CANデータの取得に対応した専用の車載装置を計測対象の自動車に搭載していただくことで、当社のクラウドサーバーと繋がった車載装置がLTE回線を使用して自動的に取得データをクラウドに格納していく仕組みです。車載装置からのデータ伝送には自動的なデータリカバリー機能が実装されているため、LTE回線の電波状況が悪く断続的に切断を繰り返すような不安定な環境でも、取得したデータをロストすることなく完全にクラウドに回収しきることが可能です。 拡張性・カスタマイズ性 intdash Automotive Pro DAQ Bundle の基本構成は前述したとおりですが、基本構成で満たせない要件がある場合は、本製品をベースとしたカスタマイズにより対応可能です。 例えば、CANバスへのデータ出力が可能な各種機器を利用することで、同期計測可能なデータの種類を拡張できます。CANバスへのデータ出力に対応した機器には、6軸センサー(加速度・ジャイロ)や高精度GPSなど色々なものがありますので、これらを利用することでCANと様々なデータを同時に計測可能です。 また、当社の別製品としてアナログ入出力を行うUSB機器( EDGEPLANT ANALOG-USB Interface )があり、こちらを使用することでアナログ信号とCANデータの同期計測を行うことも可能です。 ANALOG-USB Interface は CAN-USB Interface と同様のデイジーチェーン方式の同期機構を備えており、同じSync線によって接続が可能です。 www.aptpod.co.jp その他、カスタマイズ開発のためのSDKやAPIもご用意がありますので、要件に合わせて様々に拡張してご利用いただくことができます。 Automotive Pro でのデータ管理・可視化 intdash Automotive Pro のさらなる魅力付けのために、付属する可視化アプリケーション「 Visual M2M Data Visualizer 」を最後にご紹介いたします。 Visual M2M Data Visualizer は、 intdash Automotive Pro に付属するデータ可視化用のWebアプリケーションです。 Webアプリケーションとして提供されるため、利用するPCへの追加ソフトウェアのインストールは一切必要なく、 ブラウザと認証情報さえあれば、世界中のどこからでも、どのPCからでもクラウド上のデータにアクセスすることができます。 www.youtube.com データの可視化では、可視化ウィジェットをマウス操作で組み合わせてダッシュボードを作成する、いわゆるノーコードツールとしてご利用いただけます。 データをテキストや数値で表示するだけでなく、ライングラフや散布図などのグラフ表現で直感的に可視化したり、数値データと合わせて映像や音声スペクトログラムを表示したり、 マルチモーダルな様々なデータを一つの画面で一括して表示することが可能になります。 また、ブラウザで使用するWebアプリケーションではありますが、 DBCファイルを用いたCANデータの物理値への変換処理はブラウザ上で行う仕組みとなっており、秘匿情報であるDBCファイルはクライアントPCから外に出ません。 クラウドサーバーに保存されるCANデータも物理値変換前のバイナリ値のままで格納されるため、サーバーを管理する当社からも物理値情報へアクセスすることはできない仕組みとなっています。 お手持ちの解析ツールや独自の解析手法との連携についてもご心配は無用です。 Visual M2M Data Visualizer で表示しているデータはCSVファイルとしてダウンロードすることが可能で、ファイルによってお手持ちの解析ツールに連携していただけます。 また、可視化ウィジェットの拡張用SDKも提供しておりますので、いちいち解析ツールに連携するのが手間であれば、解析手法をまるごと Visual M2M Data Visualizer に埋め込むことも可能です。 より高度な連携を実現するためのAPIの提供もありますので、カスタマイズによりより深く独自のワークフローに適合させること可能です。 可視化アプリケーションの特長 リアルタイムストリーム、蓄積された過去データ双方の可視化に対応 CANのような高頻度データ(秒間数千メッセージ)の可視化にも十分な性能 CANに加え、映像・音声データなど様々なマルチモーダルデータに対応 ライングラフ、映像再生、地図プロットを含む様々な可視化表現 DBCファイルによる物理値変換に対応 API・SDKによる可視化表現の拡張が可能 おわりに 本記事では、CANバスからのデータ取得用デバイス「 EDGEPLANT CAN-USB Interface 」のご紹介からはじめ、本製品を含んだ自動車計測の遠隔化ソリューション「 intdash Automotive Pro 」についてご紹介しました。 intdash Automotive Pro では、LTE接続可能な専用の車載装置、クラウドサービス、可視化アプリケーションをオールインワンでご提供することで、人手がかかっていた自動車計測ワークフローを大幅に改善し、人的コストやリードタイムを削減します。自動車計測ワークフローの効率化やコスト削減をお考えの皆様、導入をご検討いただけますと幸いです。 すこしでも興味をお持ちいただけましたら、当社Webサイトのお問い合わせフォームよりお問い合わせください。 www.aptpod.co.jp *1 : CAN: Controller Area Network *2 : EDGEPLANT ANALOG-USB Interface *3 : ファームウェア・デバイスドライバー: 当社Webサイトの製品ページ より入手してください
アバター
はじめに VPoPの岩田です。本記事は、先日より開始しているMQTT5連載の第4回目になります。 第4回目となる本記事では、MQTTで用いられる認証方式についてご紹介します。 MQTT3.1.1で定義されていた方式について触れた後、MQTT5で追加された方式について解説します。 すでに公開されている連載記事は、末尾のリンクからご覧いただけます。 はじめに 当社プロダクトの簡単なご紹介 MQTT 3.1.1 から継承している認証方式 ユーザー名/パスワードによるBASIC認証 可変ヘッダー内の有効化フラグ ペイロード内の実際のデータ MQTT5で加えられた変更 MQTTの下回りでの認証(TLS、WebSocket等の利用) MQTT 5で追加された新しい認証方式 CONNECTパケットへの変更点 AUTHパケットによる追加情報のやり取り 再認証フローの追加 あとがき: 追加された仕様の有効性は? おわりに 連載記事のご紹介 当社プロダクトの簡単なご紹介 弊社アプトポッドでは、IoTシステムの通信バックエンドとしてデファクトスタンダードとなっているMQTTに代わる選択肢として、独自開発の通信ミドルウェア 「intdash」 を開発・提供しています。 intdashでは、MQTTの旧バージョンであるMQTT 3.1.1が抱えていたスケーラビリティやパフォーマンスに関わる課題を、MQTT5とは異なるアプローチによって解決しています。 intdashについては、連載1日目の記事でももう少し詳しく触れていますので、よろしければこちらの記事もご覧ください。 tech.aptpod.co.jp また、intdashで使用している当社独自の通信プロトコルについても以下の記事で解説していますので、こちらも併せてご覧ください。 tech.aptpod.co.jp また、システム構築の受託やご相談も受け付けておりますので、IoTシステムの構築でなにかお困りのことがあれば、お気軽に弊社までお問い合わせください。 www.aptpod.co.jp それでは、本編に入っていきます。 はじめに 当社プロダクトの簡単なご紹介 MQTT 3.1.1 から継承している認証方式 ユーザー名/パスワードによるBASIC認証 可変ヘッダー内の有効化フラグ ペイロード内の実際のデータ MQTT5で加えられた変更 MQTTの下回りでの認証(TLS、WebSocket等の利用) MQTT 5で追加された新しい認証方式 CONNECTパケットへの変更点 AUTHパケットによる追加情報のやり取り 再認証フローの追加 あとがき: 追加された仕様の有効性は? おわりに 連載記事のご紹介 MQTT 3.1.1 から継承している認証方式 従来のMQTT 3.1.1 では、CONNECTパケットによりユーザー名とパスワードを送信することにより認証を行うことが可能でした。 基本的にはBASIC認証に使用される想定の仕組みでしたが、現在ではパスワードとしてトークンを渡すなど、BASIC認証以外の認証でも活用されるようになっています。 また、MQTTのプロトコルが持つ機能ではありませんが、MQTTの下回りとして使用するプロトコルの認証機能を使用することも可能です。たとえば、MQTT over TLSを使用すれば、TLSレベルでクライアント認証を設定することができます。また、MQTT over WebSocketを使用すれば、WebSocketへアップグレードする前のHTTPのレベルで、Web技術を活用した様々な認証を設定できます。 これらの方式は、MQTT5でも変わらず使用できます。 ユーザー名/パスワードによるBASIC認証 可変ヘッダー内の有効化フラグ CONNECTパケットの可変ヘッダーには、Connect Flags(接続フラグ)というフィールドが存在します。 接続フラグには、Willやセッション初期化に関するフラグの他に、ユーザー名やパスワードを使用するかどうかのフィールドが存在します。 これらを有効にすることによって、ユーザー名とパスワードを使用した認証を有効化できます。 CONNECTパケットの可変ヘッダーに関する仕様の詳細は 「3.1.2 CONNECT Variable Header」 で定義されています。 ペイロード内の実際のデータ 実際のユーザー名やパスワードは、CONNECTパケットのペイロードで送信されます。 CONNECTパケットのペイロードには、ユーザー名やパスワード以外にも、以下のような情報が含まれます。 Client Identifier (クライアント識別子) Will Properties (Willのプロパティ) Will Topic (Willのトピック) Will Payload (Willのペイロード) User Name (ユーザー名) Password (パスワード) このうち、クライアント識別子だけが必須のフィールドで、それ以外のフィールドは可変ヘッダー内の接続フラグで有効化されているもののみが含まれる仕様となっています。 格納のされ方としては、長さと実際のデータをセットで1つとして、有効化されているフィールド分ただ羅列するようなフォーマットになっています(格納順序が決まっており、上に箇条書きで記載した順番になります)。 言葉だけでは若干分かりにくいため、実際の格納例を以下に示します。 可変ヘッダーの接続フラグでユーザー名やパスワードを有効化し、ペイロードに実際のデータを含めることで、CONNECTパケットによる認証情報の送信が可能になります。 MQTT5で加えられた変更 ユーザー名とパスワードによる認証の方法について、基本的な構造はMQTT 3.1.1から変更されていません。 ただし、1点だけ特筆すべき変更点があります。それは、ユーザー名を有効化しないでパスワードだけを有効化することができるようになった点です。 前述のとおりMQTT 3.1.1におけるユーザー名とパスワードのフィールドはBASIC認証を想定した設計になっていたため、ユーザー名なしでパスワードを送信することは許可されていませんでした。 MQTT5では、実際の使われ方としてパスワードフィールドがパスワード以外の認証情報の伝達に広く使用されていることを鑑みて、ユーザー名を設定しないでパスワードフィールドを使用することが許容されました。 この背景については、 「3.1.2.9 Password Flag」 のセクションで Non-normative comment として、わざわざ注記されています。 Non-normative comment This version of the protocol allows the sending of a Password with no User Name, where MQTT v3.1.1 did not. This reflects the common use of Password for credentials other than a password. MQTTの下回りでの認証(TLS、WebSocket等の利用) 前述の通り、MQTT自体のプロトコル仕様による認証方式以外に、MQTTの下回りとして使用するプロトコルの認証方式を利用することもできます。 MQTT自体は経路暗号化などの機能を持たないため、安全でないネットワークでの利用ではMQTT over TLSの形式で使用することが多くあります(いわゆる MQTTS)。 下回りにTLSを使用する場合には、クライアント証明書を使用することでクライアントを認証できます。 また、インターネットを介した情報のやりとりでは一般的にHTTPなどのWeb技術を利用することが多く、MQTTもWeb上での通信技術のひとつであるWebSocket上でのやり取りに対応しています。 WebSocketを使用する場合、まずHTTPで接続したあとにWebSocketのコネクションへアップグレードするというシーケンスを取るため、 HTTPでの接続の際にWeb技術が持っている様々な認証方式を採用することができます。 これらの方式は、MQTT自体の仕様ではなく、MQTTを動かす下回りの仕様を利用したものなので、MQTT5でも変わらず利用できます。 MQTT 5で追加された新しい認証方式 ここまでの認証方式は、MQTT3.1.1から大きく変更されていませんでした。 ここから、MQTT5で新たに追加された方式について解説していきます。 MQTT5で追加された認証方式は、 「4.12 Enhanced authentication」 のセクションで定義されています。 docs.oasis-open.org MQTT 3.1.1で定義されていた、CONNECTパケットによるユーザー名とパスワードの送信による認証では、まずクライアントがCONNECTパケットを送信し、次にサーバーがCONNACKパケットを返却するという、1往復のやり取りによる認証しかサポートできませんでした。 MQTT5では、CONNECTパケットとCONNACKパケットの間にAUTHパケットによるやり取りを定義することで、チャレンジ/レスポンス形式など複雑な認証方法をサポート可能にしています。 MQTT5で追加された認証方式の概要 CONNECTパケットへのプロパティの追加 AUTHパケットの追加(追加情報のやり取り用) 再認証フローの追加 CONNECTパケットへの変更点 CONNECTパケットのVariable Headerに含まれるプロパティに、Authentication Method(認証メソッド)とAuthentication Data(認証データ)が追加されました。 認証メソッドは、その名の通り認証に使用する方法を指定する任意の文字列です。認証メソッドに値を設定することで、Enhanced Authenticationが有効になります。 基本的にはSASL(Simple Authentication and Security Layer、RFC4422)の登録名を使用することが想定されているようですが、それ以外の文字列も使用できるそうです。 Wikipedia - Simple Authentication and Security Layer RFC4422: Simple Authentication and Security Layer (SASL) 認証データは、指定された認証メソッドに固有のデータが格納されるプロパティです。 どのようなデータをどのような形式で格納するかは認証メソッドごとに異なるため、MQTT5の仕様では定義されていません(情報を伝達するための箱としてのプロパティのみが定義されています)。 AUTHパケットによる追加情報のやり取り 前述の通り、CONNECTパケットの認証メソッドプロパティに、認証方式を表す文字列を設定することでEnhanced Authenticationが有効になります。 Enhanced Authenticationが有効になった状態であれば、AUTHパケットによる追加情報のやり取りが可能になります。 使用する認証方式において、クライアントがまずデータを送信する必要がある場合は、CONNECTパケットの認証データプロパティでデータを送信します。 その後、認証を完了するために何らかのデータをサーバーが返却する必要がある場合は、サーバーからAUTHパケットを返送できます。 さらに追加のシーケンスが必要であれば、認証に必要なやり取りが完了するまでクライアント・サーバー間で何度でもAUTHパケットを往復させることができます。 全ての認証シーケンスが完了したら、CONNACKパケットにより認証を完了させます。 再認証フローの追加 MQTT 3.1.1 における認証は、CONNECTパケットとCONNACKパケットによりコネクションの開始時に実施するだけでした。 MQTT5では、CONNACKパケットにより認証が完了したあとのコネクション継続中であっても、再認証を実施できるようになりました。 再認証の要求は、CONNACKパケットによる認証完了後に、クライアントからAUTHパケットを送信することにより開始されます。 一連のシーケンス終了後、サーバーからAUTHパケットにより再認証完了を通知することによって完了します。 あとがき: 追加された仕様の有効性は? これまで解説してきた通り、MQTT5のEnhanced Authenticationによって、様々な拡張認証を採用できるようになりました。確かに、認証方法が拡充され高機能になったようにも感じられます。 しかし、認証が必要なシーン(よくあるケースではインターネット越しの場合)ではWebSocketを使用することが多く、コネクション開始時にWeb技術を挟むことができればだいたいどんな認証でも実装できてしまっていた、というのが実情なのではないかと思います。したがって、Enhanced Authentication自体は実はそれほど大きなインパクトはなく、基本認証使用時のユーザー名のオプショナル化あたりの方が、ユーザー視点では有り難い変更なのではないか、というのが個人的な感想です。 認証方式については、ミドルウェアやサービス事業者がサポートする方式を決めて、ユーザーは提供される方式から選択する流れになると思います。 プロトコルレベルでEnhanced Authenticationがサポートされたことにより、これらのミドルウェア・サービスが新たな認証方式を提供し始めることも考えられますので、 新たな方式がサポートされた際にすぐに利用を検討できるよう、インパクトは小さいにせよ知識としては持っておくことをお勧めします。 おわりに 本記事では、MQTT5ににおいて新たに追加された認証方式について解説しました。 MQTT3.1.1から引き継いだBASIC認証方式が実際の使われ方に沿って使用調整されたことに加えて、新規追加されたEnhanced Authenticationについてもご紹介しました。 今回の解説は以上となります。次回以降の連載にもご期待ください。 連載記事のご紹介 tech.aptpod.co.jp tech.aptpod.co.jp tech.aptpod.co.jp
アバター
はじめに VPoPの岩田です。本記事は、先日より開始しているMQTT5連載の第3回目になります。 今回より、そろそろ本格的な解説に移っていきます。 第3回目となる本記事では、まずMQTT5のプロトコル仕様をざっくりと掴むために、コントロールパケットの構造を解説していきます。 MQTTのコントロールパケットの基本的な構造を知っておくことで、MQTT5で追加されたフィールドがどこに追加されたのかが把握しやすくなります。 すでに公開されている連載記事は、末尾のリンクからご覧いただけます。 はじめに 当社プロダクトの簡単なご紹介 MQTTコントロールパケットの構造 Fixed Header | 固定ヘッダー MQTT Control Packet Type Flags Remaining Length Variable Header | 可変ヘッダー Packet Identifier Properties User Properties Reason Code Payload | ペイロード おわりに 連載記事のご紹介 当社プロダクトの簡単なご紹介 弊社アプトポッドでは、IoTシステムの通信バックエンドとしてデファクトスタンダードとなっているMQTTに代わる選択肢として、独自開発の通信ミドルウェア 「intdash」 を開発・提供しています。 intdashでは、MQTTの旧バージョンであるMQTT 3.1.1が抱えていたスケーラビリティやパフォーマンスに関わる課題を、MQTT5とは異なるアプローチによって解決しています。 intdashについては、連載1日目の記事でももう少し詳しく触れていますので、よろしければこちらの記事もご覧ください。 tech.aptpod.co.jp また、intdashで使用している当社独自の通信プロトコルについても以下の記事で解説していますので、こちらも併せてご覧ください。 tech.aptpod.co.jp また、システム構築の受託やご相談も受け付けておりますので、IoTシステムの構築でなにかお困りのことがあれば、お気軽に弊社までお問い合わせください。 www.aptpod.co.jp それでは、本編に入っていきます。 MQTTコントロールパケットの構造 ★MQTT3.1.1から変更なし MQTTのコントロールパケットは、以下の構造となっています。 Fixed Header (全てのコントロールパケットに含まれる) Variable Header (一部のコントロールパケットのみに含まれる) Payload (一部のコントロールパケットのみに含まれる) コントロールパケットの全体構造は、MQTT 3.1.1から変わっていません。 Fixed Header | 固定ヘッダー ★MQTT3.1.1から変更なし Fixed Headerは全てのコントロールパケットに存在し、以下の構造をとります。 内容は極めて単純で、以下の3つの情報のみを格納します。 MQTT Control Packet Type : どのコントロールパケットか Flags : 各タイプごとに異なるフラグ値を格納する4bitのフィールド Remaining Length : パケットの残りの部分の長さ Fixed Headerの構造についても、MQTT 3.1.1から変わっていません。 MQTT Control Packet Type ★MQTT5で変更あり MQTT Control Packet Typeは以下のような定義になっており、それぞれのパケットごとに数値が割り当てられています。 MQTT 3.1.1との違いは、以下の2点のみです。 15番がReservedからAUTHに変更(新しいメッセージの追加) DISCONNECTのDirection of flowで、サーバーからクライアントへの送信が追加 Flags ★MQTT3.1.1から変更なし フラグ用の4ビットの定義は以下のようになっています。 MQTT 3.1.1から存在するメッセージについては、定義の変更はありません。 PUBLISHメッセージ以外のメッセージでは将来の仕様のためにReserved(固定値)となっており、現時点でこのフィールドを活用しているのはPUBLISHメッセージのみです。 PUBLISHメッセージのFlagsに関する定義は、OASIS仕様書の 「3.3.1 PUBLISH Fixed Header」 から確認できます。 docs.oasis-open.org Remaining Length ★MQTT3.1.1から変更なし Remaining Lengthは、Variable Byte Integerという可変長整数でエンコードされ、可変のフィールド長を持ちます。 Remaining Lengthに格納される長さは、Variable HeaderとPayloadを足した長さになります。 このフィールドについても、MQTT 3.1.1から定義は変わっていません。 Variable Header | 可変ヘッダー ★MQTT3.1.1から変更なし Variable Headerは一部のコントロールパケットに存在し、その中身はコントロールパケットの種類ごとに異なります。 以降では、複数のコントロールパケットに共通して含まれる以下のフィールドについて解説します。 Packet Identifier (パケット識別子) Properties (プロパティ) Reason Code (結果コード) Packet Identifier ★MQTT3.1.1から変更なし 以下のコントロールパケットには、Packet Identifier(パケット識別子)と呼ばれるフィールドが存在します。 PUBLISH (QoS > 0) PUBACK、PUBREC、PUBREL、PUBCOMP SUBSCRIBE、SUBACK UNSUBSCRIBE、UNSUBACK Packet Identifierは、ACKが必要なメッセージに対して元のメッセージとACKメッセージを紐付けるために使用されます。 このフィールドについても、MQTT 3.1.1から定義は変わっていません。 Properties ★MQTT5で追加 PINGREQ、PINGRESP以外のコントロールパケットには、一連のプロパティ(Properties)が含まれるようになりました。 プロパティはその長さと内容をセットで1つとして扱われ、一連のプロパティには複数のプロパティが含まれます。 プロパティの内容には、Variable Byte Integerで表された識別子と実際のデータが含まれます。 言葉での説明では分かりにくいですが、図で表すと以下のような単純な構造であることが分かります。 以下に、仕様書に記載されているプロパティの定義を掲載します。 プロパティは、MQTT 5.0で追加された新しい考え方です。 User Properties ★MQTT5で追加 プロパティに関して特筆すべきは、38番で定義されている User Property(ユーザープロパティ)です。 ユーザープロパティはその他のプロパティのように事前に定義されているものではなく、ユーザーが自由に定義して使用できるプロパティになります。 自由な情報を定義できるため、任意の文字列によるキーバリューペアとして定義されます。 ただし、「ユーザー」の定義については、若干注意が必要です。 PUBLISHメッセージについては、サーバーがメッセージを中継する際にユーザープロパティの内容もそのまま伝達しなければならない旨が仕様に明記されています。 すなわち、PUBLISHのユーザープロパティについては、パブリッシャーとサブスクライバーの間のエンドツーエンドでやり取りができる情報となります。 このため、サーバー機能を提供するミドルウェアやサービスの仕様に関わらず、クライアントアプリケーションで勝手に仕様を決めて使用できます。 この意味で、PUBLISHメッセージにおける「ユーザー」とは、サーバーを利用する「クライアントアプリケーション」であると解釈できます。 PUBLISHメッセージのユーザープロパティについて記載されている 「3.3.2.3.7 ユーザープロパティ」 にも、 Non-normative commentとしてその旨が注記されています。 Non-normative comment This property is intended to provide a means of transferring application layer name-value tags whose meaning and interpretation are known only by the application programs responsible for sending and receiving them. 一方で、PUBLISHメッセージ以外については、基本的にサーバーとクライアントのやり取りに使用するメッセージのため、サーバーとクライアントの間で仕様が合意されている必要があります。 想定される使用方法としては、サーバー機能を提供するミドルウェアやサービス事業者が、MQTT仕様に存在しない拡張仕様を付加価値として提供する場合が考えられます。 ミドルウェアやサービス事業者が拡張機能を実装してユーザープロパティ仕様を公開し、それに従ってクライアントが情報をやり取りすることによって拡張機能を利用できる、といった具合です。 この意味で、PUBLISH以外のメッセージにおける「ユーザー」とは、サーバー利用者としての「クライアントアプリケーション」というよりは、「プロトコルの利用者としての」サーバーやクライアントアプリケーションを指すものであると解釈できます。 Reason Code ★MQTT5で変更あり 以下のコントロールパケットには、Reason Code(理由コード)と呼ばれる1バイトの数値フィールドが含まれます。 CONNACK PUBACK、PUBREC、PUBREL、PUBCOMP DISCONNECT AUTH 少し特殊なケースとして、以下のコントロールパケットでは、Variable HeaderではなくPayloadにResult Codeが格納されます。 これらのパケットでは複数のReason Codeを一度に返却する必要があるため、他のパケットとは異なる定義となっているようです。 SUBACK、UNSUBACK Reason Codeは、先立つコントロールパケット等によって行われた操作の結果を表すために使用されます。 数値ごとに異なる理由や結果が割り当てられていますが、値の範囲によってざっくりと成功か失敗かが分かるようになっています。 0x80未満 : 正常に操作が完了したことを表し、通常は0が使用されます 0x80以上 : 操作が失敗したことを表します MQTT 3.1.1では、Return Codeというフィールドが各コントロールパケットごとにそれぞれ定義されていましたが、 MQTT 5.0ではこれを共通フィールドとして格上げして、より汎用的に扱うようになりました。 Reason Codeは種類が多いためここでのご紹介は割愛します。 詳細は、OASIS仕様書の 「2.4 Reason Code」 を参照してください。 docs.oasis-open.org Payload | ペイロード MQTTのコントロールパケットには、Payloadを含むものと含まないものがあります。 必須/オプショナルの別は以下の通りで、下記以外のメッセージには含まれません。 CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK は必須 PUBLISH はオプショナル それぞれのコントロールパケットにおけるPayloadの中身は、それぞれのコントロールパケットごとに詳細に定義されていてここには書ききれないので、 興味のある方は OASIS仕様書 の各パケットのセクションを参照してください。 おわりに 本記事では、MQTT 5.0の仕様を理解するための基礎となるコントロールパケットの構造と、MQTT5.0での変化についてご紹介しました。 特にPropertiesの追加によってこれまでメッセージごとに定義されていたメタデータの格納方法が統一されたことで、ぐっと理解がしやすくなったと思います。 また、User Propertiesの追加によりサードパーティで仕様の拡張が可能となったのも、今後のMQTTの可能性を広げる素晴らしい拡張のように思います。 今回の解説は以上となります。次回以降の連載にもご期待ください。 連載記事のご紹介 tech.aptpod.co.jp tech.aptpod.co.jp
アバター
はじめに VPoPの岩田です。本記事は、先日開始したMQTT5連載の第2回目になります。 すでに公開されている連載記事は、以下のリンクからご覧いただけます。 tech.aptpod.co.jp 第2回目の本記事では、MQTT Version 5.0での変更点のサマリーをご紹介します。 MQTT Version 5.0でのおもな変更点は、 OASIS標準仕様書 の末尾Appendix Cにまとめられていますので、こちらをひとつずつ日本語に翻訳して紹介したいと思います。 docs.oasis-open.org なお翻訳については、なるべく文意がわかりやすくなるよう直訳ではなく意訳していますので、誤訳等心配な場合は原文もあわせてご確認ください。 それぞれの項目は、次回以降の連載で詳しく解説していきます。 はじめに 当社プロダクトの簡単なご紹介 MQTT Version 5.0 での変更点 Session Expiry | セッションの有効期限 Message Expiry | メッセージの有効期限 Reason Code on All ACKs | 全ACKに付与される理由コード Reason String on All ACKs | 全ACKに付与される理由文字列 Server Disconnect | サーバーからの切断 Payload Format and Content Type | ペイロード形式とコンテンツタイプ Request / Response | リクエスト・レスポンスパターン Shared Subscriptions | 共有サブスクリプション Subscription ID | サブスクリプション識別子 Topic Alias | トピックエイリアス Flow Control | フロー制御 User Properties | ユーザープロパティ Maximum Packet Size | 最大パケットサイズ Optional Server Feature Availability | サーバーのオプション機能の利用可否 Enhanced Authentication | 改良された認証機能 Subscription Options | サブスクリプション用オプションの追加 Will Delay | Willメッセージの発出遅延 Server Keep Alive | サーバーからのKeep Aliveの指定 Assigned ClientID | サーバーからのクライアントIDの付与 Server Reference | 他のサーバーへの誘導 おわりに 著作権等に関するお知らせ 当社プロダクトの簡単なご紹介 弊社アプトポッドでは、IoTシステムの通信バックエンドとしてデファクトスタンダードとなっているMQTTに代わる選択肢として、独自開発の通信ミドルウェア 「intdash」 を開発・提供しています。 intdashでは、MQTTの旧バージョンであるMQTT 3.1.1が抱えていたスケーラビリティやパフォーマンスに関わる課題を、MQTT5とは異なるアプローチによって解決しています。 intdashについては、連載1日目の記事でも簡単に触れていますので、よろしければこちらの記事もご覧ください。 tech.aptpod.co.jp また、intdashで使用している当社独自の通信プロトコルについても以下の記事で解説していますので、こちらも併せてご覧ください。 tech.aptpod.co.jp また、システム構築の受託やご相談も受け付けておりますので、IoTシステムの構築でなにかお困りのことがあれば、お気軽に弊社までお問い合わせください。 www.aptpod.co.jp それでは、本編に入っていきます。 MQTT Version 5.0 での変更点 Session Expiry | セッションの有効期限 Split the Clean Session flag into a Clean Start flag which indicates that the session should start without using an existing session, and a Session Expiry interval which says how long to retain the session after a disconnect. The session expiry interval can be modified at disconnect. Setting of Clean Start to 1 and Session Expiry Interval to 0 is equivalent in MQTT v3.1.1 of setting Clean Session to 1. Clean Session フラグを、既存のセッションを使用せずにセッションを開始することを示すClean Startフラグと、切断後にセッションを保持する期間を示すSession Expiry Intervalに分割しました。Session Expiry Intervalは切断時に変更できます。Clean Startを1に設定し、Session Expiry Intervalを0に設定することは、MQTT v3.1.1でClean Sessionを1に設定することと同等です。 Message Expiry | メッセージの有効期限 Allow an expiry interval to be set when a message is published. メッセージが公開される際に、有効期限を設定できるようになりました。 Reason Code on All ACKs | 全ACKに付与される理由コード Change all response packets to contain a reason code. This include CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT, and AUTH. This allows the invoker to determine whether the requested function succeeded. すべての応答パケットに理由コードを含めるように変更しました。これにはCONNACK、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBACK、UNSUBACK、DISCONNECT、AUTHが含まれます。これにより、要求された機能が成功したかどうかを呼び出し元が判断できます。 Reason String on All ACKs | 全ACKに付与される理由文字列 Change most packets with a reason code to also allow an optional reason string. This is designed for problem determination and is not intended to be parsed by the receiver. 理由コードを含むほとんどのパケットに、オプショナルな理由文字列も追加できるように変更しました。これは問題の切り分けや特定のために設計されており、受信者によってパースされることを意図していません。 Server Disconnect | サーバーからの切断 Allow DISCONNECT to be sent by the Server to indicate the reason the connection is closed. サーバーがDISCONNECTを送信し、接続が閉じられた理由を示すことを可能にしました。 Payload Format and Content Type | ペイロード形式とコンテンツタイプ Allow the payload format (binary, text) and a MIME style content type to be specified when a message is published. These are forwarded on to the receiver of the message. メッセージが公開される際に、ペイロードフォーマット(バイナリまたはテキスト)と、MIME形式のコンテンツタイプを指定できるようにしました。これらはメッセージの受信者に転送されます。 Request / Response | リクエスト・レスポンスパターン Formalize the request/response pattern within MQTT and provide the Response Topic and Correlation Data properties to allow response messages to be routed back to the publisher of a request. Also, add the ability for the Client to get configuration information from the Server about how to construct the response topics. MQTTでのリクエスト/レスポンスパターンを正式仕様とし、Response TopicとCorrelation Dataプロパティを提供して、レスポンスメッセージをリクエストの発行者に返信できるようにします。また、どのようにレスポンストピックを構築すればよいかを、クライアントがサーバーから取得する機能を追加しました。 Shared Subscriptions | 共有サブスクリプション Add shared subscription support allowing for load balanced consumers of a subscription 負荷分散のために1つのサブスクリプションを複数のコンシューマーでサブスクライブすることを可能にする、共有サブスクリプションのサポートを追加しました。 Subscription ID | サブスクリプション識別子 Allow a numeric subscription identifier to be specified on a SUBSCRIBE, and returned on the message when it is delivered. This allows the Client to determine which subscription or subscriptions caused the message to be delivered. サブスクライブの際に数値のサブスクリプション識別子を指定し、メッセージを受信する際にその識別子を受け取ることができます。これにより、クライアントはそのメッセージがどのサブスクリプションのの結果として配信されたのかを判断できます。 Topic Alias | トピックエイリアス Decrease the size of the MQTT packet overhead by allowing the topic name to be abbreviated to a small integer. The Client and Server independently specify how many topic aliases they allow. トピック名に小さな整数値を割り当てて省略することで、MQTTパケットのオーバーヘッドのサイズを減らすことができます。クライアントとサーバーは、それぞれが許可するトピックエイリアスの最大数を独立して指定します。 Flow Control | フロー制御 Allow the Client and Server to independently specify the number of outstanding reliable messages (QoS>0) they allow. The sender pauses sending such messages to stay below this quota. This is used to limit the rate of reliable messages, and to limit how many are in flight at one time. QoSが1以上の信頼性のあるメッセージについて、未処理のメッセージ数をクライアントとサーバーが独立して設定できるようにします。送信者は、この割り当てを下回るようにQoS 1以上のメッセージの送信を止めます。これは、QoSが1以上の信頼性のあるメッセージのレートを制限し、同時にin-flightとなるメッセージ数を制限するために使用されます。 User Properties | ユーザープロパティ Add User Properties to most packets. User properties on PUBLISH are included with the message and are defined by the Client applications. The user properties on PUBLISH and Will Properties are forwarded by the Server to the receiver of the message. User properties on the CONNECT, SUBSCRIBE, and UNSUBSCRIBE packets are defined by the Server implementation. The user properties on CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK and AUTH packets are defined by the sender, and are unique to the sender implementation. The meaning of user properties is not defined by MQTT. ほとんどのパケットにユーザープロパティを追加します。PUBLISHメッセージのユーザープロパティは、クライアント側のアプリケーションによって定義され、メッセージに含められます。PUBLISHメッセージのユーザープロパティとWillのプロパティはサーバーによって転送され、受信者まで届けられます。CONNECT、SUBSCRIBE、UNSUBSCRIBEメッセージのユーザープロパティは、サーバーの実装によって定義されます。CONNACK、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBACK、UNSUBACK、AUTHメッセージのユーザープロパティは、送信者によって定義され、送信者の実装ごとに異なります。ユーザープロパティの意味は、MQTTによっては定義されていません。 Maximum Packet Size | 最大パケットサイズ Allow the Client and Server to independently specify the maximum packet size they support. It is an error for the session partner to send a larger packet. クライアントとサーバーが、それぞれがサポートする最大パケットサイズを独立して指定できるようにします。セッションを張っている相手が最大サイズより大きなパケットを送信することはエラーとして扱われます。 Optional Server Feature Availability | サーバーのオプション機能の利用可否 Define a set of features which the Server does not allow and provide a mechanism for the Server to specify this to the Client. The features which can be specified in this way are: Maximum QoS, Retain Available, Wildcard Subscription Available, Subscription Identifier Available, and Shared Subscription Available. It is an error for the Client to use features that the Server has declared are not available. It is possible in earlier versions of MQTT for a Server to not implement a feature by declaring that the Client is not authorized for that function. This feature allows such optional behavior to be declared and adds specific Reason Codes when the Client uses one of these features anyway. サーバーが許可しない機能セットを定義し、サーバーがクライアントにこれを指定するメカニズムを提供します。このように指定できるのは、最大のQoS、Retainが利用可能か、ワイルドカードサブスクリプションが利用可能か、サブスクリプション識別子が利用可能か、共有サブスクリプションが利用可能か、などの機能です。サーバーが利用不可と宣言した機能を、クライアントが使用することはエラーとして扱われます。 MQTTの以前のバージョンでは、その機能に対してクライアントが認証されていないと宣言することで、サーバーがその機能を実装しない選択肢を取ることができました。この機能は、そのようなオプショナルな動作を宣言することを許可し、クライアントがこれらのいずれかの機能を使用した際に特定の理由コードを追加します。 Enhanced Authentication | 改良された認証機能 Provide a mechanism to enable challenge/response style authentication including mutual authentication. This allows SASL style authentication to be used if supported by both Client and Server, and includes the ability for a Client to re-authenticate within a connection. 相互認証を含むチャレンジ/レスポンス形式の認証を可能にするメカニズムを提供します。これにより、クライアントとサーバーの両方がサポートしている場合、SASL形式の認証を使用できるようになります。また、クライアントがコネクション内で再認証することも可能になります。 Subscription Options | サブスクリプション用オプションの追加 Provide subscription options primarily defined to allow for message bridge applications. These include an option to not send messages originating on this Client (noLocal), and options for handling retained messages on subscribe. 主にメッセージブリッジアプリケーション用に定義された、サブスクリプションオプションを提供します。これには、このクライアントで発生したメッセージを送信しないオプション(noLocal)と、サブスクライブ時のRetainされたメッセージの取り扱いに関するオプションが含まれます。 Will Delay | Willメッセージの発出遅延 Add the ability to specify a delay between the end of the connection and sending the will message. This is designed so that if a connection to the session is re-established then the will message is not sent. This allows for brief interruptions of the connection without notification to others. コネクションが終了してからWillメッセージを送信するまでの間の遅延時間を指定する機能を追加します。これはセッションへの接続が再確立された場合、Willメッセージが送信されないようにするためのものです。これにより、他者に通知することなく、短時間の接続中断が可能になります。 Server Keep Alive | サーバーからのKeep Aliveの指定 Allow the Server to specify the value it wishes the Client to use as a keep alive. This allows the Server to set a maximum allowed keepalive and still have the Client honor it. クライアントに使用させたいKeep Aliveの値を、サーバーから指定できるようにします。これにより、サーバーは許容可能な最大のKeep Alive値を設定し、クライアントにそれを遵守させることができます。 Assigned ClientID | サーバーからのクライアントIDの付与 In cases where the ClientID is assigned by the Server, return the assigned ClientID. This also lifts the restriction that Server assigned ClientIDs can only be used with Clean Session=1 connections. ClientIDがサーバによって割り当てられている場合は、割り当てられたClientIDを返します。これにより、サーバから割り当てられたClientIDはClean Session=1でのコネクションでのみ使用できるという制限も解除されます。 Server Reference | 他のサーバーへの誘導 Allow the Server to specify an alternate Server to use on CONNACK or DISCONNECT. This can be used as a redirect or to do provisioning. CONNACKまたはDISCONNECT時に使用する代替サーバーを、サーバーが指定できるようにします。これはリダイレクトやプロビジョニングに使用できます。 おわりに 本記事では、MQTT Version 5.0での変更点について、OASIS仕様書のAppendix Cの翻訳という形でご紹介しました。 今回ご紹介した各機能は、このあとの連載にて詳細に解説していきます。 次回以降の連載にもご期待ください。 著作権等に関するお知らせ OASIS標準仕様 には、以下の注意書きがあります。標準文書およびその翻訳の提供には、著作権表示と「Notices」セクションの表示が必要とのことですので、こちらにコピーを記載いたします。 Notices Copyright © OASIS Open 2019. All Rights Reserved. All capitalized terms in the following text have the meanings assigned to them in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The full Policy may be found at the OASIS website. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this section are included on all such copies and derivative works. However, this document itself may not be modified in any way, including by removing the copyright notice or references to OASIS, except as needed for the purpose of developing any document or deliverable produced by an OASIS Technical Committee (in which case the rules applicable to copyrights, as set forth in the OASIS IPR Policy, must be followed) or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. OASIS requests that any OASIS Party or any other party that believes it has patent claims that would necessarily be infringed by implementations of this OASIS Committee Specification or OASIS Standard, to notify OASIS TC Administrator and provide an indication of its willingness to grant patent licenses to such patent claims in a manner consistent with the IPR Mode of the OASIS Technical Committee that produced this specification. OASIS invites any party to contact the OASIS TC Administrator if it is aware of a claim of ownership of any patent claims that would necessarily be infringed by implementations of this specification by a patent holder that is not willing to provide a license to such patent claims in a manner consistent with the IPR Mode of the OASIS Technical Committee that produced this specification. OASIS may include such claims on its website, but disclaims any obligation to do so. OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS' procedures with respect to rights in any document or deliverable produced by an OASIS Technical Committee can be found on the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this OASIS Committee Specification or OASIS Standard, can be obtained from the OASIS TC Administrator. OASIS makes no representation that any information or list of intellectual property rights will at any time be complete, or that any claims in such list are, in fact, Essential Claims. The name "OASIS" is a trademark of OASIS , the owner and developer of this specification, and should be used only to refer to the organization and its official outputs. OASIS welcomes reference to, and implementation and use of, specifications, while reserving the right to enforce its marks against misleading uses. Please see https://www.oasis-open.org/policies-guidelines/trademark for above guidance.
アバター
はじめに アプトポッドVPoPの岩田です。 弊社アプトポッドでは、MQTTのようなIoTデータ通信向けの独自ミドルウェア「intdash」を開発・提供しています。 www.aptpod.co.jp 独自のミドルウェアを設計・開発する過程で、近年リリースされたMQTT5や、その前身であるMQTT 3.1.1についての仕様調査・研究を行ってきました。 この調査・研究の過程でMQTTに関する知見も蓄積してきましたので、一度情報を整理して、連載という形で公開することにしました。 本連載では、MQTT5リリースに伴って変更された仕様を中心に、MQTT3.1.1仕様も含めたMQTT全体について解説していきたいと思っています。 また、その過程でMQTTとintdsahの違いについても触れながら、当社の製品についても皆様に知っていただけるような構成を考えております。 連載初回となる本記事では、MQTT登場の背景やなぜ利用されているのか、といったMQTTの概要と、MQTT5のリリースに至る過程についてざっくりとまとめています。 今後も複数回にわたり、MQTT5に関する情報をお届けする予定ですので、次回以降にもご期待ください。 連載の次回以降の記事は、以下のリンクからご覧いただけます。 tech.aptpod.co.jp それでは、本編に移ります。 はじめに MQTTとは MQTTがなぜ利用されるのか MQTT Version 3.1.1の課題とMQTT 5.0への進化 当社ミドルウェア「intdash」のご紹介 まとめ MQTTとは MQTT(Message Queuing Telemetry Transport)は、軽量なメッセージングプロトコルで、特にリソースが限られたデバイスやネットワーク環境での使用に適しています。1999年にIBMによって開発され、その後、オープンスタンダードとして広く採用されました。MQTTは、メッセージのサイズが小さく、ネットワーク帯域の使用を最小限に抑える設計が特徴です。これにより、スマートデバイス、センサー、モバイルデバイスなど、さまざまな環境で効率的に通信が行えます。 MQTTはOASISにより標準化されており、その仕様は MQTT Version 3.1.1 から確認することができます。 MQTTでは、パブリッシュ/サブスクライブ型のメッセージングモデルが採用されています。このモデルでは、メッセージの送信者(パブリッシャー)が特定のトピックにメッセージを公開(パブリッシュ)し、メッセージの受信者(サブスクライバー)がそのトピックを購読(サブスクライブ)します。メッセージは中央のサーバー(MQTTブローカー)を介してルーティングされ、ブローカーが適切なサブスクライバーにメッセージを配信します。この方式により、デバイス間の直接的な通信が不要となり、ネットワークの複雑さを大幅に削減できます。 MQTTのメッセージングモデル MQTTを使用しない場合のメッセージング MQTTがなぜ利用されるのか MQTTの魅力は、その効率性とシンプルさにあります。メッセージのサイズを最小限に抑えることで、帯域幅が限られた環境でも高いパフォーマンスを発揮します。これは、リアルタイムデータ転送が求められるIoTアプリケーションにとって特に重要です。シンプルなプロトコル設計は、開発者が容易に組み込めることを意味し、多様なデバイスやアプリケーションでの採用を加速しています。 MQTT Version 3.1.1の課題とMQTT 5.0への進化 MQTT 3.1.1は、そのシンプルさと効率性で多くのプロジェクトに採用されましたが、採用が進むにつれて大規模なシステムや多様なデバイスを扱う際のスケーラビリティの問題が明らかになりました。メッセージングのルーティングオプションが限られており、大量のデバイスや高頻度のメッセージ交換が必要なシナリオでは、ブローカーの負荷が過大になることがありました。トピックフィルタリングのオプションが限定的で、特定のメッセージを特定のクライアントに効率的に配信することが難しく、大規模なIoTデプロイメントの効率性と柔軟性を制限していました。 これらの課題に対応するため、MQTTはVersion 5.0へと進化しました。MQTT 5.0では、メッセージングプロセスをより細かく制御できる拡張されたプロパティセット、詳細なエラーコードによる改善されたエラーレポーティング、トピックエイリアスによる通信効率の向上、リクエスト/レスポンス型の通信を容易にする応答トピックと相関データ、そしてサブスクリプション識別子によるメッセージの管理と処理の効率化など、新しい機能が追加されました。これらの改善により、MQTT 5.0は特に大規模なシステムや複雑なアプリケーションでの使用に適したプロトコルとなっています。 当社ミドルウェア「intdash」のご紹介 MQTT 3.1.1が抱える課題は、特に大規模で大量のデータを扱うIoTシステムや、複雑なルーティングが必要なシステムにおいて顕著です。当社は、MQTTブローカーのようなIoTデータの伝送・管理向け メッセージングミドルウェア「intdash」 の開発と、これを用いたシステム開発サービスを提供しています。「intdash」は、自動車メーカーのR&D向けに開発された背景を持ち、大量のシーケンシャルメッセージの伝送に対応する高いパフォーマンスを誇ります。 www.aptpod.co.jp また、よくあるパブリッシュ/サブスクライブ型のメッセージルーティングとは若干異なり特定のデバイスのデータのみを効率的にフィルタリングして受信したり、ネットワーク接続の切断等でリアルタイムに送信しきれなかったデータを検知して後回収する機能を備えており、ネットワークが不安定な環境でもデータを取りこぼすことなく伝送できます。 当社のIoTミドルウェア「intdash」の全体像 MQTTもVersion 5.0にアップデートされることで、MQTT 3.1.1が抱える課題はある程度解決されていますが、同一プロトコルの拡張という進化の過程の都合上ドラスティックな仕様変更は難しく、まだまだ秒間数百〜数千メッセージといった大量のシーケンシャルメッセージではパフォーマンス課題に直面するケースがあります。一方で「intdash」は、これらの課題の解決に特化してはじめから設計されており、特に大規模・大量のデータ伝送や複雑なルーティングが求められるシナリオにおいて、MQTTに代わる有力な選択肢となります。 まとめ この記事では、MQTTプロトコルの概要とその進化、および当社のミドルウェア 「intdash」 の特徴について説明しました。MQTTは、その軽量性と効率性により、IoTアプリケーションに広く採用されています。Version 5.0へのアップデートにより、大規模なシステムや複雑なアプリケーションでの使用に適したプロトコルとなりました。一方で、 「intdash」 は、MQTTが抱える課題を解決し、特に大規模なデータ伝送や複雑なルーティングが求められるシナリオにおいて、MQTTに代わる有力な選択肢として提供されています。 さらなる情報が必要な場合は、 当社のウェブサイト をご覧いただくか、直接お問い合わせください。また、MQTTや「intdash」に関する詳細な技術情報やユースケースについては、当社のテックブログや技術資料を参照してください。 当社へのお問い合わせはこちらからお願いいたします。 www.aptpod.co.jp
アバター
アプトポッド 組み込みエンジニアの久保田です。 連載の前回 では、ROSの開発においてDockerをどのように活用するかを紹介しました。その中で触れた通り、Dockerコンテナを使ってホストのハードウェアリソースにアクセスすることが可能です。例えば、当社で販売している車載向けエッジコンピュータ EDGEPLANT T1 はNVIDIA Jetson TX2を搭載しています。NVIDIA Jetsonシリーズは、GPUを搭載しており、AIやディープラーニングのタスクに適しています。このJetsonのGPUをDockerコンテナ内で最大限に活用するために、NVIDIAが提供する公式Dockerイメージの使用が推奨されています。 ROS開発において、この公式Dockerイメージは導入しやすい反面、ROS自体がソースコードからビルドされており、ROS公式に提供されているdebianパッケージを利用することができません。この制限を解消するためには、NVIDIA GPU資源を利用でき、かつROS公式に提供されているdebianパッケージの利用可能なDockerイメージの作成が必要となります。 連載ROS Tips第3回目となる今回は、ROSのDockerコンテナからのNVIDIA GPU利用方法を紹介します。 なお、連載の予定として、以下のようなコンテンツを予定しております。(連載内容は、変更・追加の可能性があります。ご了承ください) そもそもROSとは? ROS開発におけるDocker活用テクニック ROSのDockerコンテナからNVIDIA GPUを利用するには (本記事) 大量伝送シナリオにおけるROS/DDSのチューニング 本連載の投稿済みの記事はこちらからご覧いただけます。 tech.aptpod.co.jp tech.aptpod.co.jp コンテナからNVIDIA GPUを利用するには NVIDIA Container Runtimeの使用方法 GPU状態の確認方法 ROSコンテナからNVIDIA GPUを利用するには(NVIDIA公式イメージの使用) ROS安定版に対して、NVIDIA公式イメージで使用できるタグ 公式イメージではROSパッケージをリポジトリから追加できない NVIDIA公式イメージの仕組み NVIDIA GPUを使用しつつ、ROSパッケージをリポジトリ追加可能にするには 当社リポジトリで提供開始するイメージのご紹介 Jetson TX2搭載エッジコンピュータ EDGEPLANT T1 のご紹介 当社提供イメージの仕組み まとめ 当社プロダクトのご案内 コンテナからNVIDIA GPUを利用するには DockerコンテナからNVIDIA GPUを利用するには、NVIDIA Container Runtimeが必要です。 Enabling GPUs with NVIDIA Docker Container Runtime NVIDIA Container Runtimeは、Dockerなどのコンテナ技術とNVIDIA GPUを統合するためのツールです。これにより、GPUを活用したアプリケーションをコンテナ内で簡単に実行することができます。NVIDIAのGPUドライバと連携して、コンテナ内からGPUリソースにアクセスするために必要なライブラリやバイナリを提供し、ディープラーニングや機械学習、高性能計算などのGPUを活用したタスクを、コンテナ化された環境で効率的に実行することができます。 NVIDIA Container Runtimeの特徴: GPUアクセス: コンテナからNVIDIA GPUへの直接アクセスが可能になります。 互換性: DockerやKubernetesなどの主要なコンテナ技術との互換性があります。 柔軟性: 複数のGPUや異なるGPUアーキテクチャに対応しています。 NVIDIA Container Runtimeの使用方法 NVIDIA公式サイトで示されている手順を紹介します。 NVIDIA Container RuntimeによりDockerコンテナ内でGPUを利用するためには、Dockerコンテナを実行するホストでインストール・設定などの準備が必要です。 なお、JetsonシリーズではJetPackをインストールすることによりNVIDIA Container Runtimeを利用することができますので、ここでご紹介する手順でのインストール・設定は不要です。 docs.nvidia.com まず、リポジトリを設定します。 curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ sed ' s#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g ' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list \ && \ sudo apt-get update 次に、NVIDIA Container Runtimeをインストールします。 sudo apt-get install -y nvidia-container-toolkit さらに、Dockerの設定を変更します。 sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker 最後に、NVIDIA Container Runtimeを実行します。 docker run --rm \ --runtime=nvidia \ --gpus all \ arm64v8/ubuntu:22. 04 \ nvidia-smi 上記で使用するコマンドの引数は以下の情報を参考にしてください。 引数 説明 runtime ランタイムの指定 (nvidia) gpus 使用GPU指定 ( all : すべてのGPU ) docs.nvidia.com GPU状態の確認方法 GPUの状態を確認するために通常はnvidia-smiコマンドが使用されますが、Jetsonシリーズでは使用できません。 JetsonシリーズでGPUの状態を表示するためには、jtopコマンドが便利です。 github.com jtopコマンドを実行するには、json-stats をインストールが必要です。 sudo apt install -y python3-pip sudo pip3 install -U jetson-stats jtopコマンドを実行します。 jtop ROSコンテナからNVIDIA GPUを利用するには(NVIDIA公式イメージの使用) JetsonシリーズでROSのDockerコンテナを起動しコンテナ内からGPUを活用する場合、NVIDIA公式イメージの使用が推奨されています。 公式イメージの提供サイト: GitHub - dusty-nv/jetson-containers dockerhub - dustynv/ros ROS安定版に対して、NVIDIA公式イメージで使用できるタグ 公式イメージでは、ROSの各ディストリビューション用にタグがいくつか公開されています。 ここでは、ROSの最新の安定版ディストリビューション(LTS)に対応するタグを紹介します。 ROS Distro L4T Ubuntu イメージのタグ ROS Noetic R32.7.1 18.04 dustynv/ros:noetic-ros-base-l4t-r32.7.1 R34.1.1 20.04 dustynv/ros:noetic-ros-base-l4t-r34.1.1 R35.4.1 20.04 dustynv/ros:noetic-ros-base-l4t-r35.4.1 ROS2 Humble R32.7.1 18.04 dustynv/ros:humble-ros-base-l4t-r32.7.1 R34.1.1 20.04 dustynv/ros:humble-ros-base-l4t-r34.1.1 R35.4.1 20.04 dustynv/ros:humble-ros-base-l4t-r35.4.1 公式イメージではROSパッケージをリポジトリから追加できない これらの公式イメージは、ベースとするUbuntuのイメージにROSをソースコードビルドでインストールして構成されています。ROSは各ディストリビューションで前提とするUbuntuバージョンがそれぞれ決まっていますが、NVIDIA公式イメージではROSディストリビューションが前提としているUbuntuバージョンとベースイメージのUbuntuバージョンが異なる場合があり、そういった場合にdebパッケージによるROSのインストールが行えなえません。 この影響により、公式イメージに新しいROSパッケージを追加する際、Ubuntuの公式リポジトリを用いてaptコマンドで直接追加することができません。ROSの追加機能やパッケージを導入したい場合は、GitHubなどからソースコードを取得して手動でビルドする必要があります。 NVIDIA公式イメージの仕組み 先のセクションで利用するために、公式イメージがどのように作られているのか、中身を調べていきます。 NVIDIAが提供している公式イメージは、L4T rootファイルシステムに含まれるパッケージのサブセットで構成された l4t-base というイメージをベースにしています。l4t-base は、Jetsonシリーズで実行することを想定しており、NVIDIA Container Runtime を使用してコンテナ内でL4Tアプリケーションを実行できるようにします。 ハードウェア依存性を提供するプラットフォーム固有のライブラリと、特定デバイスのデバイスファイルをNVIDIA Container Runtimeによってコンテナにマウントし、コンテナ内で実行するL4Tアプリケーションに提供します。マウントされるライブラリは /etc/nvidia-container-runtime/host-files-for-container.d/l4t.csv に記載されています。 ベースイメージの提供サイト: GitLab - nvidia/container-images/l4t-base l4t-baseイメージの Dockerfile は次のような構成となっており、以降ではこの Dockerfile について解説します。 ベースイメージの指定 パッケージのインストール NVIDIAの公開鍵の追加 NVIDIAのリポジトリの追加 Tegraライブラリの設定 EGLの設定 GPU関連環境変数の設定 ベースイメージの指定 FROM docker.io/arm64v8/ubuntu:18.04 ARM64アーキテクチャのUbuntuイメージをベースイメージとして指定します。 Ubuntuの安定版(LTS)のイメージとして、以下のようなものがあります。 Ubuntu バージョン Distro イメージのタグ 22.04 Jammy arm64v8/ubuntu:22.04 20.04 Focal arm64v8/ubuntu:20.04 18.04 Bionic arm64v8/ubuntu:18.04 パッケージのインストール RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -qq -y --no-install-recommends \ bc \ bzip2 \ can-utils \ freeglut3-dev \ gstreamer1.0-alsa \ gstreamer1.0-libav \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-ugly \ gstreamer1.0-tools \ i2c-tools \ iw \ kbd \ kmod \ language-pack-en-base \ libapt-inst2.0 \ libcanberra-gtk3-module \ libgles2 \ libglu1-mesa-dev \ libglvnd-dev \ libgtk-3-0 \ libpython2.7 \ libudev1 \ libvulkan1 \ libzmq5 \ mtd-utils \ parted \ pciutils \ python \ python-pexpect \ python3-distutils \ sox \ udev \ vulkan-utils \ wget \ wireless-tools wpasupplicant && \ rm -rf /var/lib/apt/lists/* && apt-get clean GstreamerやOpenGL関連のライブラリ、ワイヤレスツール、PythonなどGPU利用に関連するパッケージをインストールします。L4Tアプリケーションの実行に必要な最低限のパッケージとなっています。 NVIDIAの公開鍵の追加 COPY jetson-ota-public.key /etc/jetson-ota-public.key RUN apt-key add /etc/jetson-ota-public.key NVIDIAの公開鍵をコンテナにコピーし、パッケージ管理ツール apt に鍵を追加します。 NVIDIAのリポジトリの追加 RUN echo "deb https://repo.download.nvidia.com/jetson/common $RELEASE main" >> /etc/apt/sources.list NVIDIAのJetson用リポジトリを追加します。環境変数 RELEASE には r32.7 などリリースバージョンを指定します。 Tegraライブラリの設定 RUN echo "/usr/lib/aarch64-linux-gnu/tegra" >> /etc/ld.so.conf.d/nvidia-tegra.conf && \ echo "/usr/lib/aarch64-linux-gnu/tegra-egl" >> /etc/ld.so.conf.d/nvidia-tegra.conf Tegra関連のライブラリのパスをldconfigの設定に追加します。 EGLの設定 RUN rm /usr/share/glvnd/egl_vendor.d/50_mesa.json RUN mkdir -p /usr/share/glvnd/egl_vendor.d/ && echo '\ {\ "file_format_version" : "1.0.0" ,\ "ICD" : {\ "library_path" : "libEGL_nvidia.so.0" \ }\ }' > /usr/share/glvnd/egl_vendor.d/10_nvidia.json RUN mkdir -p /usr/share/egl/egl_external_platform.d/ && echo '\ {\ "file_format_version" : "1.0.0" ,\ "ICD" : {\ "library_path" : "libnvidia-egl-wayland.so.1" \ }\ }' > /usr/share/egl/egl_external_platform.d/nvidia_wayland.json RUN ldconfig NVIDIAのEGL (Embedded-System Graphics Library)とWaylandの設定を追加します。 GPU関連環境変数の設定 ENV NVIDIA_VISIBLE_DEVICES all ENV NVIDIA_DRIVER_CAPABILITIES all NVIDIA Container Runtimeから使用できるデバイスとドライバの機能をすべて有効にします。 NVIDIA GPUを使用しつつ、ROSパッケージをリポジトリ追加可能にするには 前述した通り、Jetsonシリーズでは、NVIDIAの公式イメージの使用が推奨されています。このイメージでは、ベースとするUbuntuイメージのバージョンとROSディストリビューションが前提とするUbuntuバージョンが異なることが理由でROSをソースコードからビルドしてインストールしているため、本来対応しているUbuntuバージョンの公式リポジトリを用いてaptコマンドでROSパッケージを直接追加することはできません。 この制限を克服する方法として、ホストOSのUbuntuバージョンとは異なるバージョンをベースにした非公式イメージを使用する方法が考えられます。 非公式Ubuntu 20.04ベースイメージの提供サイト GitHub - timongentzsch/Jetson_Ubuntu20_Images 非公式Ubuntu 22.04ベースイメージの提供サイト GitHub - atinfinity/l4t-base-docker これらの非公式イメージは、任意のバージョンのUbuntuイメージをNVIDIA GPUに対応させるために、任意のバージョンのUbuntuイメージをベースとして、NVIDIA Container Runtimeを使用するために必要なツールをインストールしています。これらのNVIDIA GPU対応のUbuntuベースイメージに、さらにROSディストリビューションをインストールすればNVIDIA GPUに対応したROSコンテナができあがります。 当社リポジトリで提供開始するイメージのご紹介 上記で紹介した非公式イメージは、別々の開発者が Ubuntu 20.04、Ubuntu 22.04 それぞれに向けて、各自のリポジトリで提供しているものです。 今回、より汎用的に任意のUbuntuバージョンで利用できるコンテナイメージ用のDockerfileを当社にて作成し、提供を開始いたしますのでご紹介します。 Dockerfileの提供サイト GitHub - aptpod/l4t-ros: NVIDIA L4T (Linux for Tegra) enabled ROS Container Image こちらは、当社が販売している Jetson TX2 を搭載したエッジコンピュータ EDGEPLANT T1 でご利用いただくことを想定して作成したものですが、Jetsonシリーズを搭載したコンピュータであれば同様にご利用いただけるはずです。 GitHubには、ROS 2用だけでなく、ROS 1用のDockerfileも用意しています。GPUを活用したROSコンテナを利用したい場合に是非ご活用ください。 なお、今回GitHubで公開したDockerfileは Apache 2.0 ライセンスにて公開しており、基本的には自己責任にて使用していただく想定です。とはいえ、なるべく当社でメンテナンスしていく予定ですので、もし不具合等ございましたら当社までご連絡ください。 より詳しい技術情報は、リポジトリのREADMEをご覧ください。 Jetson TX2搭載エッジコンピュータ EDGEPLANT T1 のご紹介 上記のDockerfileにて作成したイメージは、Jetsonシリーズを搭載したコンピュータであればご利用いただけるはずですが、基本的には当社が販売している Jetson TX2 を搭載したエッジコンピュータ EDGEPLANT T1 でご利用いただくことを想定したものになります。 EDGEPLANT T1はNVIDIA Jetson TX2を搭載したエッジコンピュータで、映像のエンコードやデコードなどGPUを使用する処理や、デバイスエッジでのAIモデルの実行用途にお使いいただけます。また、SIMスロット、GPSモジュールなど、IoT端末として必要な様々な機能を備えています。車載機器に求められるEMC規格(Eマーク)、信頼性規格(JASO D014)などにも準拠しており、ROSを使用したロボット開発、自動運転システムの開発にもおすすめです。 EDGEPLANT T1は、当社の販売パートナー様または、 Amazon.co.jp からご購入いただけます。詳しくは、製品ページをご覧ください。 www.aptpod.co.jp 今回ご紹介したイメージを EDGEPLANT T1 上でご利用いただく場合であれば当社からの技術サポートも可能です。 コンテナイメージ上でのNVIDIA GPUを活用したROSアプリケーションの開発をご検討の方は、 EDGEPLANT T1 の採用も是非ご検討ください。 当社提供イメージの仕組み 以降では、提供開始するDockerfileの構成について解説します。 ご紹介するコンテナイメージは、これまでにご紹介したUbuntuの任意のバージョンをNVIDIA GPUに対応させる方法に加え、ROSの利用に必要なセットアップを行ったものです。 ROSコンテナの公式イメージの Dockerfile は次のサイトで提供されていますので、こちらを参考にセットアップを行います。 ROSの公式イメージの提供サイト: GitHub - osrf/docker_images このテックブログでは、NVIDIA GPUを利用できる ROS2 Humble - L4T 32.7.1 のコンテナ構成ファイルを紹介します。 L4Tベースイメージ (Container tag: l4t-base:jammy-r32.7) FROM docker.io/arm64v8/ubuntu:22.04 ARG RELEASE= "r32.7" ARG SOC= "t186" ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -qq -y --no-install-recommends \ bc \ bzip2 \ can-utils \ ca-certificates \ freeglut3-dev \ gstreamer1.0-alsa \ gstreamer1.0-libav \ gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good \ gstreamer1.0-plugins-ugly \ gstreamer1.0-tools \ i2c-tools \ iw \ kbd \ kmod \ language-pack-en-base \ libapt-inst2.0 \ libcanberra-gtk3-module \ libgles2 \ libglu1-mesa-dev \ libglvnd-dev \ libgtk-3-0 \ libpython2.7 \ libudev1 \ libvulkan1 \ libzmq5 \ mtd-utils \ parted \ pciutils \ python \ python-pexpect \ python3-distutils \ sox \ udev \ vulkan-utils \ wget \ wireless-tools wpasupplicant && \ rm -rf /var/lib/apt/lists/* && apt-get clean ADD --chown=root:root https://repo.download.nvidia.com/jetson/jetson-ota-public.asc /etc/apt/trusted.gpg.d/jetson-ota-public.asc RUN chmod 644 /etc/apt/trusted.gpg.d/jetson-ota-public.asc && \ echo "deb https://repo.download.nvidia.com/jetson/common $RELEASE main" >> /etc/apt/sources.list && \ echo "deb https://repo.download.nvidia.com/jetson/$SOC $RELEASE main" >> /etc/apt/sources.list RUN echo "/usr/lib/aarch64-linux-gnu/tegra" >> /etc/ld.so.conf.d/nvidia-tegra.conf && \ echo "/usr/lib/aarch64-linux-gnu/tegra-egl" >> /etc/ld.so.conf.d/nvidia-tegra.conf RUN rm /usr/share/glvnd/egl_vendor.d/50_mesa.json RUN mkdir -p /usr/share/glvnd/egl_vendor.d/ && echo '\ {\ "file_format_version" : "1.0.0" ,\ "ICD" : {\ "library_path" : "libEGL_nvidia.so.0" \ }\ }' > /usr/share/glvnd/egl_vendor.d/10_nvidia.json RUN mkdir -p /usr/share/egl/egl_external_platform.d/ && echo '\ {\ "file_format_version" : "1.0.0" ,\ "ICD" : {\ "library_path" : "libnvidia-egl-wayland.so.1" \ }\ }' > /usr/share/egl/egl_external_platform.d/nvidia_wayland.json RUN echo "/usr/local/cuda-10.0/targets/aarch64-linux/lib" >> /etc/ld.so.conf.d/nvidia.conf ARG CUDA=invalid COPY ./dst/bin /usr/local/cuda-$CUDA/bin COPY ./dst/nvvm /usr/local/cuda-$CUDA/nvvm COPY ./dst/nvvmx /usr/local/cuda-$CUDA/nvvmx COPY ./dst/include /usr/local/cuda-$CUDA/targets/aarch64-linux/include COPY ./dst/lib64/stubs /usr/local/cuda-$CUDA/targets/aarch64-linux/lib/stubs COPY ./dst/lib64/libcudadevrt.a /usr/local/cuda-$CUDA/targets/aarch64-linux/lib/ COPY ./dst/lib64/libcudart_static.a /usr/local/cuda-$CUDA/targets/aarch64-linux/lib/ RUN ln -s /usr/local/cuda-$CUDA /usr/local/cuda && \ ln -s /usr/local/cuda-$CUDA/targets/aarch64-linux/include /usr/local/cuda/include && \ ln -s /usr/local/cuda-$CUDA/targets/aarch64-linux/lib /usr/local/cuda/lib64 ENV PATH /usr/local/cuda-$CUDA/bin:/usr/local/cuda/bin:${PATH} ENV LD_LIBRARY_PATH /usr/local/cuda-$CUDA/targets/aarch64-linux/lib:${LD_LIBRARY_PATH} RUN ldconfig ENV NVIDIA_VISIBLE_DEVICES all ENV NVIDIA_DRIVER_CAPABILITIES all CMD [ "/bin/bash" ] ベースイメージを利用したROS2 Humbleイメージ (l4t-ros:humble-ros-core-r32.7) また、L4Tベースイメージを利用して、任意のROSコンテナを作成するためのDockerfileのテンプレートも用意しました。 FROM l4t-base:jammy-r32.7 # setup timezone RUN echo 'Etc/UTC' > /etc/timezone && \ ln -s /usr/share/zoneinfo/Etc/UTC /etc/localtime && \ apt-get update && \ apt-get install -q -y --no-install-recommends tzdata && \ rm -rf /var/lib/apt/lists/* # install packages RUN apt-get update && apt-get install -q -y --no-install-recommends \ dirmngr \ gnupg2 \ && rm -rf /var/lib/apt/lists/* # setup sources.list RUN echo "deb http://packages.ros.org/ros2/ubuntu jammy main" > /etc/apt/sources.list.d/ros2-latest.list # setup keys RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 # setup environment ENV LANG C.UTF-8 ENV LC_ALL C.UTF-8 ENV ROS_DISTRO humble # install ros2 packages RUN apt-get update && apt-get install -y --no-install-recommends \ ros-humble-ros-core=0.10.0-1* \ && rm -rf /var/lib/apt/lists/* # setup entrypoint COPY ./ros_entrypoint.sh / ENTRYPOINT [ "/ros_entrypoint.sh" ] CMD [ "bash" ] ご紹介したイメージは、コンテナ内でGPUを利用するためにNVIDIA Container Runtimeを使用しています。 このため、一部のdebパッケージ・ライブラリはNVIDIA Container Runtimeが想定しているソフトウェアのバージョンとの不整合によりうまく動作しない場合があります。 現時点で、以下のパッケージが正常に動作しないことを確認しております。(今後、こちらのパッケージも使用可能となるよう修正を加えていく予定です) バージョン不整合により動作しないパッケージ(記事公開時点で確認済みのもの) GStreamer OpenCV まとめ 今回は、ROSのDockerコンテナでのNVIDIA GPUの利用方法について解説しました。 NVIDIA は Machine Learning やAI用の公式イメージを提供していますが、このGPU利用の仕組みを理解することで、 まだ提供されていない機能を持つコンテナイメージを作成することもできる用になります。 また、当社によるDockerfileの提供開始についてもお知らせしました。 Ubuntuの公式リポジトリを通じてROSパッケージを追加することが可能になることで、皆様の開発効率向上の手助けになれば幸いです。 連載の次回は ROS 2を利用する上での大容量データ転送シナリオにおけるチューニングについての紹介 を予定しています。 当社プロダクトのご案内 先日行われた ROSConJP 2023 では、ROSの開発ワークフローを効率化するDXソリューションとして、新たなソリューションを発表いたしました。詳細については、ROSConJP 2023の参加報告記事をご覧ください。 tech.aptpod.co.jp また、ROS開発において、当社プロダクトをどの様にご活用いただけるかは、連載1日目にて当社のVPoPがより詳しく紹介しておりますので、こちらもご覧ください。 tech.aptpod.co.jp さらに、当社では、モビリティ・ロボットのフリート管理や遠隔監視、遠隔制御を実現するための管制制御システム向けのソリューションフレームワーク「intdash CONTROL CENTER」を提供しています。 tech.aptpod.co.jp スマートシティにおける自動運転車、工場や物流倉庫における搬送ロボット、建設現場における建設機械など、モビリティ群の統合遠隔監視・管理、遠隔制御システムな どでお困りのことがあれば、ぜひお声掛けください。 お問合せフォームは こちら です。
アバター
Aptpod Advent Calendar 2023 25日目(最終日)の記事です。 CTOの梶田です。 今年もまたまたあっという間(いつも言ってますね💦)でAdvent Calendar もなんとか走りきれそうです。 今年最後の記事として、恒例の年末ネタを取り上げ、2023年を 昨年 と同様にトピック中心に振り返ります! それでは、始めましょう。 はじめに 資本業務提携 パートナー様との展開 新しい試み ROS連載コンテンツ 2024年に向けて はじめに 2023年は、COVID-19が感染症法上5類に移行し、以前のようなイベントや賑わいが戻った年でした。 働き方に関しても、新しいスタイルを維持する企業、出社形態に戻る企業、ハイブリッドを採用する企業など、さまざまでしたね。 (弊社は大きな変更はありませんでしたが😎) 技術トピックとしては、やはり生成AIが世界を席巻したのが強かった! 開発シーンにおいても大きなインパクトがありました。弊社としてもまだまだこれから💦ですが、活用は強めていきたいと思っています。 昨年の予想通り、物価高や為替変動、円安は大きな影響を及ぼし、継続して難しい局面は続いています。 変化に適用し、走り続ける こちらは継続して、心に留めています。 2023年は、やはりいろいろありましたが、パートナー様との展開に注力した1年でした。 製品開発としても長く開発してきた部分もあり、課題や技術負債を解消するような次世代への移行も進み、新しい展開も多くありました。 今回のAdventCalendar2023でも以下でいくつか触れられておりますので是非ご覧ください。 12日目: Webhook用のアプリケーションをAWS SAMで実装してみる 15日目: サクッとIoTシステムを構築する 20日目: MenderとDockerでアプリケーションのOTAを実現した、新しい組込Linuxシステムのご紹介 資本業務提携 2023年の大きなトピックとして、事業会社様との資本業務提携があります。 以前から進めていたマクニカ様や日立建機様、ヨコオ様といった新しいつながりも加え、さまざまな形で事業連携によるシナジーを活かしながら各分野での社会実装の促進、市場拡大を目指す取り組みを開始しております。 アプトポッド、マクニカ及びヨコオと第三者割当増資による資本業務提携を実施 アプトポッド、日立建機と第三者割当増資による資本業務提携を実施 テックブログでも取り組みを紹介できたらしていきたいとは思っています。 パートナー様との展開 最初に触れた通り、2023年はパートナー様との展開に注力した形で進捗した面もありましたが、なかなか難しい面、なかなかうまくいかないことも多くありました。 まだまだ試行錯誤はありますが、地道に進んでいる面もあるので大事にしつつ、パートナー様とともにうまく軌道に乗せていきたいと考えています。 そういったなかでありましたいくつかトピックご紹介します。 マクニカ様との取り組みとして、以下に記載ある 遠隔運行管理システム(FMS: Fleet Management System) の名前が "everfleet" に決まり、新しいアプリケーションの開発も進行して、実証実験から社会実装への展開の兆しも出てきています。 www.macnica.co.jp NTTコミュニケーションズ様との取り組みにおいても、以下の通りintdashを利用したソリューションとしてご提供する発表をしております。 www.aptpod.co.jp この取り組みのなかのリアルタイムデジタルツイン *1 については、技術トレンドになりつつある、メタバース/デジタルツインの世界において仮想空間と現実空間をリアルタイムにつなぐ技術として先行的に取り組んだ分野であり、以下のテックブログでも触れています。 tech.aptpod.co.jp openhub.ntt.com サンプルと同様に、intdashを活用してデジタルツインシステムを実現した例として、以下のような事例もございます。 上記記事の中では、 建設現場の遠隔化/リアルタイムデジタルツイン というテーマで、今回のサンプルをさらにグレードアップしたようなアプリケーションが紹介されています。 (おまけ) NTTコミュニケーションズ様との連携として今回のAdventCalendar2023でも触れています超小型受信端末を活用した高精度位置情報測位サービス「Mobile GNSS」との連携事例は面白いのであらためてご紹介↓ tech.aptpod.co.jp 新しい試み 今年は新しい試みとして開発本部主導でROS Con JP2023に出展し、「Open-RMFを応用したクラウドフリート管理システムの構築」というテーマで講演が採択されました。(昨年も実は申請はしたものの採択されず。。😅) www.aptpod.co.jp Open-RMFという話題はROS界隈ではホットなトピックであり、弊社としても試行錯誤が多く苦労も多かったですが、ROS Con JPで発信できたというのは大変よかったと感じています。 テックブログでも触れていますのでぜひご覧ください。 tech.aptpod.co.jp tech.aptpod.co.jp テックブログでも連載という形式でROSにフォーカスして始めたり、新しい試みもいくつか始めています。 来年はもう少し他にも話題を広げて展開しようとしていますのでご期待ください! ROS連載コンテンツ そもそもROSとは? ROS開発におけるDocker活用テクニック ROSコンテナでホストのGPUを利用するには(予定) 大量伝送シナリオにおけるROS/DDSのチューニング(予定) 2024年に向けて 2023年はパートナー様との展開に注力し、会社としても新しい流れが生まれ、大きな変化の年でした。 昨年同様に難しかった面もあり、課題もまだまだありますが、着実に前に向かって進んでいます。 あらためて振り返ってみると多くの成果も見え、まだまだ成果として伝えきれていないこともありますが改めてメンバーへの感謝の気持ちが出てきました。(今年もお疲れ様でした!) 2024年もさらなる広がりと新しい時代に向けて、お客様およびパートナー様との共創をさらに深く進めて、さらなる前へチーム一丸となって進んでいきたい、進んでいけるチームだと確信しています。 来年もまたアプトポッドにご期待ください!! メリークリスマス!🎄 それでは皆様良いお年を! *1 : リアルタイムデータを使って仮想空間上で現実世界を再現すること
アバター
はじめに aptpod Advent Calendar 2023 12月22日担当の、Automotive Pro Grの小野寺です。 弊社は CAN 計測を中心にした自動車計測の遠隔化ソリューションを提供している会社です。 自動車へデータ収集用のアプライアンスを搭載し、収集したデータをLTE経由で送信することで、計測した自動車データのクラウドへの自動保存や遠隔地からの監視・可視化を実現します。 自動車計測ソリューションについては当社のWebサイトをご覧ください。 www.aptpod.co.jp 最近、自動車だけではなく船舶(ヨットやプレジャーボート)等の海洋電子機器の通信として普及している NMEA 2000 への対応をご要望いただくことが増えてきました。 今回は、この NMEA 2000 のデータを、弊社のデータ通信ミドルウェア製品である intdash を使用して、クラウド経由で遠隔可視化してみたいと思います。 www.aptpod.co.jp はじめに NMEA 2000とは NMEA 2000 のデータ データフォーマットの変更 物理層の変更 single-packet と fast-packet テスト機材を構成する データを取得して可視化する トラフィックスニッファでのバイナリデータ確認 Webダッシュボードでの数値データ確認 おわりに NMEA 2000とは NMEA 2000は NMEA (National Marine ElectronicsAssociation) によってに策定された規格で、主に海洋電子機器での通信に利用されています。 www.nmea.org GPSやGNSSなどを利用する際にNMEAというワードを聞いたことがある方もいらっしゃるかも知れませんが、 このようなところで従来利用されていた NMEA 0183 という規格を新しくしたものが NMEA 2000 です。 詳細については、下記の情報等を参照してみてください。 NMEA2000(wikipedia) NMEA2000の概要について(PDF) 従来の NMEA 0183 との大きな違いとして、物理層に CAN を使用するようになったという点があります。 NMEA 2000 のデータ データフォーマットの変更 NMEA 0183 では、センテンスと呼ばれる、固定文字列($GPGGAや$GPGLLなど)を使用したASCIIコードが使用されていました。 一方 NMEA 2000 では、PGNと呼ばれるデータフォーマットに従ってバイナリフォーマットでデータが格納されます。 物理層の変更 NMEA 0183 と異なり、NMEA 2000 ではCANを使用して通信が行われます。 CANでは、1フレームで送信できる最大サイズが8バイトなので、それ以上のデータが送られてくる場合データの受信時にひと手間必要になります。 single-packet と fast-packet 1フレームにデータが収まりきらない場合への対応として、single-packet と fast-packet という仕様が用意されています。 (multi-packet もありますが、今回は使用しないので割愛します) それぞれ最大のデータサイズは、以下のようになっています。 single-packet: 8バイト fast-packet: 223バイト single-packetは、受信した1つのCANフレームで完結しますが、 fast-packetは、データが複数のCANフレームに分割されて送られてくるので、所定の手順に従って結合させる必要があります。 ただし、fast-packet での通信は、リクエスト/レスポンスなどの面倒なやり取りはなく一方的に送られてくるだけなので、データを順次処理していけば大丈夫です。 ちなみに、single-packet 、fast-packetのどちらで送られてくるかは、PGNの定義によって決まっているので、仕様書で確認する必要があります。 fast - packet の 例 以下の赤い部分のデータを結合すればOK テスト機材を構成する NMEA 2000 のデバイスは、 Garmin GPS 24xd と Garmin ECHOMAP UHD 73sv を使用しました。 ゲートウェイコンピュータには弊社の EDGEPLANT T1 を使用し、 CANフレームを取得してゲートウェイへ中継するペリフェラルデバイスとしてさらに EDGEPLANT CAN-USB Interface を使用しました。 CAN-USB Interface が CANバスからCANフレームを取得してゲートウェイコンピュータへ中継し、 ゲートウェイコンピュータに搭載されているLTE通信機能によってクラウドへデータが送信される構成です。 構成イメージは、下図の様になります。 データを取得して可視化する あいにく、弊社では持ち合わせの船もなく、船舶免許も保有していないので、地上で計測することにします。 トラフィックスニッファでのバイナリデータ確認 弊社のWebベースの可視化サービスで表示するとこのような表示になりました。 Edge Finderでのトラフィックの確認 Data Name Value列の "v1/11/xxxxxx" の "xxxxxx" の部分がCAN IDです(例:2314277376 → 9F11200のCANID) Payload列が実際のデータです。8バイトのデータがsingle-packet、それ以上のサイズのものがfast-packetになります(キャプチャでは長いデータは見切れています) 使用しているのは、 intdash に付属しているトラフィックの可視化アプリケーション(Edge Finderといいます)で、クラウドを経由して伝送されているトラフィックの生のデータを確認することができるツールです。生バイナリが表示されており若干見づらいですがご容赦ください。 intdashに付属するその他のWebアプリケーションは こちら からご確認いただけます。 www.aptpod.co.jp Webダッシュボードでの数値データ確認 さらに、より多彩な表現ができるWebダッシュボードを使用して可視化すると、以下のようになります。 Visualizerで表示 キャプチャでは PGN = 1F805h のデータを可視化しています Longtitude, Latitudeが、日本のそれっぽい位置になっているのがわかります こちらでは、様々な可視化パーツを使用してノーコードで簡単に可視化が行える弊社のWebダッシュボードプロダクト Visual M2M Data Visualizer を使用しています。 今回は準備時間が足りず数値のみでの可視化になってしまいましたが、Visual M2M Data Visualizer では地図上での表示やグラフ表示など様々な可視化表現が可能です。弊社のWebサイトに可視化ダッシュボードの例も掲載しておりますので、ご興味がございましたらぜひご覧ください。 Visual M2M Data Visualizer での可視化の例 www.aptpod.co.jp おわりに 今回は、NMEA 2000のデータを取得して、クラウド経由での伝送・可視化を試してみました。 通信がCANなので、自動車向けの遠隔計測・可視化ソリューションを使用して、比較的簡単に対応することができました。 弊社は自動車の遠隔可視化を中心に事業を進めている会社ではありますが、そこから派生してロボットの遠隔可視化・遠隔操縦や、最近では船舶関連のお問い合わせもいただく様になっております。 最近では、Starlinkがサービスを開始したことで海洋上でのデータ通信環境も整いつつあるため、船舶関連の遠隔可視化などでもなにかお手伝いできればと思っております。 もしなにかデータ通信・管理やシステム構築でお困りごと・ご相談がございましたら、お気軽にお問い合わせください。 www.aptpod.co.jp また、別のメンバーが、Starlinkの検証を行ったブログ記事も投稿していますので、もしご興味があればご覧ください。 tech.aptpod.co.jp
アバター
こんにちは。 aptpod Advent Calendar 2023 12月21日を担当するVisual M2Mグループの白金です。 普段は Visual M2M Data Visualizer (以下 Data Visualizer )の製品開発を担当しています。 当製品において LiDAR で計測した3D点群を可視化するための開発をする機会がありました。3D点群には、ひとつひとつの点について、X、Y、Zの位置情報を含みます。また、LiDARで計測する環境によって、1回の描画で数千個以上の点の情報を含む場合があり、可視化アプリケーションではパフォーマンスを意識し、効率よく可視化する処理が要求されます。 また、3D点群の表示の一例として、原点から距離に応じて色が変化する可視化の方法があります。各点ごとに一つ一つ3Dモデルを作成し色を指定する方法でも実現できますが、点の数に比例してCPUの計算コストが肥大化し、パフォーマンスが低下する課題があります。 そこで、上記課題を解決するため、GPUで計算するGLSLを使用して可視化する方法についてサンプルコードも交えてご紹介します。 サンプルコードの実行結果 GLSLとは 頂点シェーダー フラグメントシェーダー その他の使用するフレームワーク ワークスペースを作成する ソースコードを追加・編集する 実行する Data Visualizerで3D点群を可視化する おわりに GLSLとは 3Dや2Dを描画するために、GPUを直接操作するためのシェーダー言語です。 three.js 標準のGLSLも利用可能ですが、GLSLをカスタマイズしたい場合は、目的に応じてGLSLの処理を追加する必要があります。 ja.wikipedia.org WebGLで3Dを表現するためには、頂点シェーダー、フラグメントシェーダーの2つのシェーダーを使用します。 この2つのシェーダーをGLSLで表現します。 詳しくは下記リンク先に掲載されています。ここではピックアップした情報のみご紹介します。 webglfundamentals.org 頂点シェーダー 頂点ごとの空間座標を生成します。入力データとして、3Dモデルの頂点データを受け取ります。主に3Dモデルや、カメラの位置・姿勢情報から、頂点の空間座標を生成する場合に使用します。 頂点シェーダーを拡張することで、目的に応じて、3Dモデルの頂点データから生成する空間座標をカスタマイズすることができます。 当ページのサンプルでは、3D点群を1つの3Dモデルとして受け取り、各頂点ごとに原点からの距離に応じて色を設定する方法をご紹介します。 フラグメントシェーダー 描画対象となるピクセルに対して色を決定するために呼び出されるシェーダーです。 また、頂点データで計算したデータを受け取ることができます。 当ページのサンプルでは、各点を丸の形状で表現するため、フラグメントシェーダーをカスタマイズしています。 その他の使用するフレームワーク GLSLを除く、使用している他のフレームワークは下記のとおりです。 必要最低限の環境で動作を可能にするためのフレームワークとして使用しました。 Vite Viteのワークスペースを作成する機能を使用します。 当フレームワークを使用することで、最低限のサンプルコードで可視化を実現するための準備が可能です。 three.js Webアプリケーションで3Dを描画するフレームワークです。 WebGL のAPIを直接利用することも可能ですが、three.js を利用することで開発コストかなり削減できます。 @react-three/fiber three.jsをReactのコンポーネントで使いやすくするためのフレームワークです。 Reactのコンポーネント内で、three.jsを利用する場合において、可読性の向上、コードの削減化が期待できます。 @react-three/drei @react-three/fiber用の便利なヘルパーが用意されています。 当ページでは OrbitControls や、 GizmoHelper を使用することで、カメラ操作、ビューヘルパーの可視化を少ないコードで実現しています。 では、サンプルコードの準備を進めていきましょう。 ワークスペースを作成する Viteの公式サイト を参考に、サンプルコード用のワークスペースを作成します。 npm create vite@latest --template react-ts 作成したワークスペースに移動し、依存パッケージをインストールします。 npm install さらに、3Dを可視化するために必要なパッケージをインストールします。 npm install three @react-three/fiber @react-three/drei ソースコードを追加・編集する GLSLを活用し、同心円の点群を一定の距離ごとに色を変えて3D点群を可視化するサンプルコードを準備していきます。 まずは、 src/App.tsx を以下のように書き換えます。 createCirclePoints のFunctionで同心円上の点群のサンプルデータを作成し、距離に応じて高さの表示位置を変えています。 import { useMemo } from 'react' import { Vector3 } from 'three' import { Canvas } from '@react-three/fiber' import { OrbitControls, GizmoHelper, GizmoViewport } from '@react-three/drei' import './App.css' import { vertexShader } from './vertex-shader' import { fragmentShader } from './fragment-shader' function App() { /** * 3D点群のPoint配列をFloat32Arrayで作成します。 * 1つの点は、X、Y、Zの3つの配列要素で構成されます。 */ const positions = useMemo(() => new Float32Array([ ...createCirclePoints({ radius: 0.2, height: 0, divisions: 100 }), ...createCirclePoints({ radius: 0.5, height: 0.1, divisions: 100 }), ...createCirclePoints({ radius: 1.0, height: 0.2, divisions: 100 }), ...createCirclePoints({ radius: 1.5, height: 0.3, divisions: 100 }), ...createCirclePoints({ radius: 2.0, height: 0.4, divisions: 100 }), ...createCirclePoints({ radius: 2.5, height: 0.5, divisions: 100 }), ]), []) /** * 頂点シェーダーへ連携する値を設定します。 */ const uniforms = useMemo(() => { return { /* 距離に応じた色を判定する際に使用する最大値を設定します。 */ uDistanceRangeMax: { value: 3 }, /* 点の大きさを設定します。 */ uPointSize: { value: 5 }, } }, []) /** * ページ表示直後のカメラの位置を設定します。 */ const cameraInitPosition = useMemo(() => { return new Vector3(0, 2.5, 5) }, []) return ( <div className="canvas-area"> <Canvas camera={{ position: cameraInitPosition }}> {/* カメラを操作するためのフレームワーク使用します。 */} <OrbitControls makeDefault enableDamping enablePan enableRotate /> {/* グリッドを表示します。 */} <gridHelper /> {/* 3D点群を表示します。 */} <points> <bufferGeometry attach="geometry"> <bufferAttribute attach="attributes-position" array={positions} itemSize={3} count={positions.length / 3} /> </bufferGeometry> <shaderMaterial vertexShader={vertexShader} fragmentShader={fragmentShader} uniforms={uniforms} /> </points> {/* 画面右上にGizmoを表示します。 */} <GizmoHelper alignment="top-right"> <GizmoViewport/> </GizmoHelper> </Canvas> </div> ) } /** * 水平方向に同心円の点郡データを作成します。 */ const createCirclePoints = (config: { /** 原点からの半径 */ radius: number /** 表示する高さの位置 */ height: number /** 同心円における点群の分割数 */ divisions: number }): Float32Array => { const { radius, height, divisions } = config const points: number[] = [] const degreePerPoint = 360 / divisions for (let i = 0; i < 360; i += degreePerPoint) { const radian = i * Math.PI / 180 const x = radius * Math.cos(radian) const y = height const z = radius * Math.sin(radian) points.push(x, y, z) } return new Float32Array(points) } export default App src/App.css を下記コードに置き換えます。 /* Canvaののエリアは全画面で表示します。 */ .canvas-area { width : 100 vw; height : 100 vh; } 最後に、GPUを直接操作する vertex-shader、fragment-shaderのファイルをsrcディレクトリ以下に追加します。 src/vertex-shader.ts の頂点シェーダーのファイルを追加します。 当シェーダーでは、原点から各頂点までの距離に応じて表示するカラーを判定し、フラグメントシェーダーに連携しています。 export const vertexShader = ` precision highp float; /* フラグメントシェーダーにカラー情報を連携するための変数です。 */ varying lowp vec3 vColor; /* 距離に応じた色を判定する際に使用する最大値が設定された変数です。 */ uniform float uDistanceRangeMax; /* 点の大きさが設定された変数です。 */ uniform float uPointSize; /* レベルに応じたカラーを定義する構造体です。 */ struct ColorLevel { float ratio; vec3 color; }; /* レベルに応じたカラーを定義した配列です。 */ ColorLevel[4] COLOR_LEVELS = ColorLevel[4]( ColorLevel(0.0, vec3(1.0, 0.0, 0.0)), ColorLevel(0.333, vec3(1.0, 1.0, 0.0)), ColorLevel(0.667, vec3(0.0, 1.0, 1.0)), ColorLevel(1.0, vec3(0.0, 0.0, 1.0)) ); /* 原点の座標です。 */ vec3 ZERO_POSITION = vec3(0.0, 0.0, 0.0); /* 原点から指定した位置までの距離を計算します。 */ float calcDistance(vec3 position) { return distance(ZERO_POSITION, position); } /* 0 〜 最大値の範囲で指定した値の割合を計算します。 */ float calcRatio (float value, float rangeMax) { return max(min(value / rangeMax, 1.0), 0.0); } /* 割合からカラー情報を取得します。 */ vec3 calcColor(float ratio) { int levelIndex = 0; for (int i = 0; i < COLOR_LEVELS.length(); i++) { if (ratio <= COLOR_LEVELS[i].ratio) { levelIndex = i; break; } } if (levelIndex == 0) { ColorLevel level = COLOR_LEVELS[levelIndex]; return level.color; } ColorLevel currentLevel = COLOR_LEVELS[levelIndex]; ColorLevel prevLevel = COLOR_LEVELS[levelIndex - 1]; float colorRatioLen = currentLevel.ratio - prevLevel.ratio; if (colorRatioLen <= 0.0) { return currentLevel.color; } float colorRatio = (ratio - prevLevel.ratio) / colorRatioLen; float r = prevLevel.color[0] + (currentLevel.color[0] - prevLevel.color[0]) * colorRatio; float g = prevLevel.color[1] + (currentLevel.color[1] - prevLevel.color[1]) * colorRatio; float b = prevLevel.color[2] + (currentLevel.color[2] - prevLevel.color[2]) * colorRatio; return vec3(r, g, b); } void main() { float distance = calcDistance(position); float ratio = calcRatio(distance, uDistanceRangeMax); vec3 color = calcColor(ratio); /* 点の頂点データを設定します。 */ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); /* 点の大きさを設定します。 */ gl_PointSize = uPointSize; /* フラグメントシェーダーにカラー情報を連携します。 */ vColor = color; } ` src/fragment-shader.ts のフラグメントシェーダーのファイルを追加します。 当シェーダーでは、頂点シェーダーからカラー情報を受け取り、各点を丸の形状で描画します。 export const fragmentShader = ` /* 頂点シェーダーから点のカラー情報を受け取ります。 */ varying lowp vec3 vColor; void main() { /* 点を丸の形状で表示します。丸の外側(中心から半径0.5より大きいエリア)は描画が不要なエリアのためdiscardして描画をスキップします。 */ if (length(gl_PointCoord - vec2(0.5)) > 0.5) { discard; } /* 描画する色を指定します。 */ gl_FragColor = vec4(vColor, 1.0); } ` 実行する ソースコードの追加、及び編集が完了したら、以下コマンドを実行し、表示されたURLにブラウザでアクセスします。 npm run dev 実行結果の例 VITE v5. 0 . 10 ready in 482 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help 上記URLをブラウザで表示した結果です。3D点群の原点から距離が遠くになるほど、赤から青に色が変化する点群を可視化できました。 youtu.be Data Visualizerで3D点群を可視化する 最後に、上記サンプルコードを拡張し、当社製品のVisual M2M Data Visualizerへ実装した例をご紹介します。Data Visualizerは、当社が開発・提供しているWebベースの可視化ダッシュボード製品です。ノーコードなGUI操作だけで、様々なセンサーデータをブラウザでリアルタイムに可視化することができます。Data Visualizerについての詳細は、当社の Webサイト からご確認ください。 youtu.be この例では、Data Visualizerで使用する可視化ウィジェットであるビジュアルパーツに、これまでご紹介した点群可視化処理を実装し、LiDARから取得した3D点群をリアルタイムに可視化しています。製品版での実装方法については説明を割愛しますが、今回のサンプルコードをもとに拡張を行えば、このような可視化機能をWebアプリに組み込むことも可能です。 詳細については、次回以降のブログでご紹介したいと思います。 おわりに 今回はGLSLを使用し、3D点群、及び各点に色を指定する方法をご紹介しました。GLSLで使用したことがない実用的な方法が他にもあると思います。今後も積極的に使用して製品へ取り込むことができるよう推進したいと思います。 製品に関するお問い合わせはこちらへ! www.aptpod.co.jp
アバター
aptpod Advent Calendar 2023 12月20日の記事です。 intdashグループの野本です。組込Linuxソフトウェア開発を担当しています。 aptpodでは、intdashに接続可能な組込Linuxシステムとして「 intdash Terminal System (以降、Terminal System)」を開発しており、このたび大規模アップデートを行いました。 Terminal System 2 として近々リリース予定していますので、アップデート内容について(少し先取りして)ご紹介したいと思います! はじめに Terminal Systemとは Terminal Systemの開発経緯 Terminal Systemの課題 Terminal Systemの課題に対する解決策 Terminal System 2の紹介 Terminal System 2のデモ コンテナを利用したアプリケーション開発 Menderを利用したOTA さいごに おまけ はじめに Terminal Systemをご存じない方向けに、まずTerminal Systemについて解説します。 Terminal Systemとは intdash Terminal System Terminal System は、intdashに接続可能なゲートウェイアプライアンスで、組込Linuxにより構築されたシステムです。 名前に"System"が含まれていることからわかるように、 ハードウェア・ソフトウェアを含んだシステム全体 を対象としており、以下により構成されます。 エッジコンピューター: aptpodが開発した専用LinuxディストリビューションであるTerminal System OSがインストールされたハードウェア アプリケーション: intdashサーバーとの間でデータ送受信を行うエージェントソフトウェア(intdash Edge Agent)、エージェントソフトウェアと外部デバイスとの間でデータを仲介するソフトウェア(デバイスコネクター)、各種サービスなど 外部デバイス: データの送受信を行うために接続されたデバイス。EDGEPLANT USB Camera、EDGEPLANT CAN-USB Interface、EDGEPLANT ANALOG-USB Interfaceなど ポイント Terminal Systemは ハードウェア・ソフトウェアを含んだシステム全体 を対象としています。 OS(カーネル)などを含む低レイヤー領域も開発の対象となっています。 Terminal Systemの開発経緯 aptpodは、「“つながる”を社会のチカラへ」をミッションとして掲げ、「“あらゆるスペースをつなぎ、世界の新体験を創造する”」こをビジョンとして追求しています。 導入事例 をご覧頂くと、 多種多様なものをつないできたこと をご理解いただけると思います。 "つなぐ"ことは簡単ではありません。 単純に物理的に機器を接続するだけでなく、取得したデータをintdashサーバーと送受信するできるように、ソフトウェアの対応が必要です。 あらゆるものを対象とする場合、アプリケーションレベルでの対応ができない場合があり、以下のような OS(カーネル)レベルのカスタマイズ作業が発生する 場合があります。 カーネルイメージのビルド(カーネルコンフィグ変更、パッチ適用など) ドライバのビルド、インストール また組込機器では、動作保証の観点から、 システム全体の構成管理 が非常に重要となります。 以下のようなことが発生しないように、堅牢かつ安定性したシステムを開発する必要があります。 昔のOSでは動いていたのに、最新のOSでは動作しなくなった( apt upgrade などでパッケージを更新したら動作しなくなった) あるデバイスでは動くのに、あるデバイスでは動作しない(デバイスのソフトウェアバージョンの不一致、手動作業の適用漏れなど) また、幅広いユースケースに対応するため、エッジコンピューターの複数機種サポートも必要となる場合があり、 様々なエッジコンピューターに対応したビルドシステム も必要です。 エッジコンピューターによっては、以下のような 高度なカスタマイズ要求 が発生する場合もあります。 不要なサービスやパッケージを削除したい(限られたリソースで動作させたい、セキュリティリスクを低減したい) エッジコンピュータごとにシステム設定を最適化したい 複数のエッジコンピューター向けに同じ方法でOSイメージを構築したい Terminal Systemは、これら 組込システム特有の課題を解決するため に開発されました。 具体的には、組込Linuxディストリビューション開発のデファクトスタンダードである Yocto Project (以降、Yocto)を利用し、 組込Linuxディストリビューションである Termial System OSを開発することで、 カーネルレベルの高度なカスタマイズ、構成管理、複数機種のサポート を実現しています。 疑問 「Yoctoじゃないとだめなの?Ubuntuでいいんじゃないの?」という疑問を持たれる方がいらっしゃるかもしれません。 Ubuntuなどの汎用OSは、以下理由により組込システムの開発に課題があります。 設計方針が異なる Ubuntuはデスクトップやサーバー用途を想定して設計されたOSであり、リソースに制約のある組込システム向けに特化していません。 組込システム向けには、不要なパッケージを削除したり、システムを軽量化する作業が追加で発生します。 プリビルドパッケージの制約 Ubuntuはプリビルドされたパッケージを利用しており、一般的に広範な用途に適合するよう設計されています。 これは、特定のハードウェアや特有の要件に合わせた深いレベルでのカスタマイズが困難であることを意味します。 たとえば、特定のハードウェアサポートやカーネルレベルの変更を必要とする場合、Ubuntuではこれらのカスタマイズが直接的かつ容易には行えません。 構成管理の複雑さ Ubuntuの標準的なアップデート方式は、組込システムで求められる厳密な構成管理には必ずしも適合しません。 組込システムでは、システムの全コンポーネントに対する完全な制御と予測可能な振る舞いが重要ですが、Ubuntuではこれらを達成するために追加作業が必要となることがあります。 これらの理由から、Yoctoと比較すると、Ubuntuなどの汎用OSは組込システムには不向きです。 ただし、 迅速なプロトタイピング開発には最適 なので、用途に合わせて使っていきたいですね。 Terminal Systemの課題 そんなTerminal Systemですが、aptpod社内でしばらく運用したところ、以下の課題があることがわかりました。 アプリケーションの開発がしにくい Yoctoを利用したシステムの場合、アプリケーション開発のために専用のビルド環境が必要です。 また、アプリケーションに依存ライブラリが必要となる場合は新しくパッケージをビルドする必要があることや、 そもそもYocto自体の学習曲線が急でとっつきずらいことなど、 Yoctoでのアプリケーションの開発はやりづらいことがわかってきました。 OTAがしにくい Yoctoで生成したパッケージを利用し、ファイルベースのOTA機構を独自開発することでOTAを実現していました。 ただし、リポジトリ運用の取り回しに課題があったり、 小さな変更であってもYoctoを使わないとパッケージを生成できなかったり、 ファイルベースなので更新の完全性(差分更新による不整合、エラーのリカバリなど)に不安があったりと、 運用・機能面に課題があり、今後も現状の方法を続けていくことは厳しいのではという意見が寄せられておりました。 これらの課題解決は、aptpod社内での開発の問題だけでなく、 パートナープログラム により アプリケーション開発などをパートナー様が推進する際に確実に障害になることが予想され、早期に解決する必要がありました。 ポイント Termial Systemは、 アプリケーション開発やOTAのしにくさに課題 がありました。 Terminal Systemの課題に対する解決策 これらの課題を解決するために、intdashグループでは以下の解決策を考えました。 アプリケーションの実行環境にDocker Composeを採用した Yoctoでアプリケーションが開発しにくいなら、開発しなければいいじゃないかということで、アプリケーションの実行環境をDocker Composeに移行しました。 これにより、Yoctoによる高度なカスタマイズ・構成管理によるメリットを享受しながらも、アプリケーション開発のための専用のビルド環境が不要で、自由度の高いカスタマイズをすることが可能です。 コンテナを利用することでホスト環境からも分離されるため、基本的にはホストの変更影響も受けない *1 ですし、既存のコンテナイメージを活用でき、ソフトウェアの再利用性が高まるというメリットもあります。 Menderを利用したOTAをサポート 独自開発したOTA機構を廃止し、northern.tech社のIoTデバイス向けOTA(Over the Air)ソフトウェアアップデートソリューションである Mender をサポートしました。 Menderは、Yoctoを利用せずにアップデートファイルを作成することができます。また、サーバーはSaaSでの提供もされているため、自社での運用・管理が不要で、コストを抑えながら導入可能です(OSS/オンプレによる自社運用も可能です)。 ファイルベースではなく、ブロックベースのA/Bアップデートを採用しており、堅牢かつ高機能なOTAが実現可能です(エラー時のロールバックも可能)。 また、OTAだけでなく、デバイス管理、各種設定/操作にも活用することができます。 こうした対策を実施し、誕生したのがTermial System 2 となります。 参考: Terminal System 2のシステム構成 ポイント Termial System 2は、 Docker ComposeやMenderを採用することにより、Yocto特有のアプリケーション開発のしずらさやOTAのしにくさを解決 しています。 Terminal System 2の紹介 Terminal System 2は、 旧Terminal System の課題 (以降、従来のTerminal Systemを「旧Terminal System」と表記します。)を解決し、以下のような特徴を持っています。 アプリケーションの実行環境にDocker Composeを採用 Menderを利用したOTAをサポート また、内部のアプリケーションもアップデートされています。 エージェントソフトウェアをintdash Edge Agent 2 にアップデート intdash Edge Agent 2向けに最適化されたデバイスコネクターをプリインストール 現時点では、 EDGEPLANT T1 をエッジコンピューターとしてご利用いただけます。 次のリリースでは、より手軽に試せる・カスタマイズのリファレンスとしてご利用いただけるように Raspberry Pi 4 をサポートしつつ、 任意のエッジコンピューターでTerminal System 2を動作できるようにする準備を進めています。 Terminal System 2のデモ Terminal System 2の特徴はカスタマイズにより真価を発揮するため、標準機能だけではエンドユーザーからは何が新しくなったのか分かりづらいです。 なので、実際にカスタマイズ開発やOTAを実施し、どのように課題が改善されたのをデモンストレーションすることで、改善効果を説明したいと思います。 コンテナを利用したアプリケーション開発 今回はEDGEPLANT T1を利用し、Jetsonの推論サンプル jetson-inference の車載カメラ向け物体検出推論デモアプリケーションを動かして、計測をしてみたいと思います。 Terminal System 2では、アプリケーションの実行環境にDocker Composeを採用したため、 特別なカスタマイズをせずにNVIDIAの公式コンテナイメージをそのまま再利用することができます 。 旧Terminal Systemの場合、ソフトウェアを再利用するためにはYoctoで利用できるようにカスタマイズする必要があり、数日〜数週間のカスタム作業が必要となります(難易度によっては実現できない場合もあるかもしれません)。 実施手順の詳細はこの記事では省略しますが、以下の構成で計測を行います。 詳細については Terminal System 2デベロッパーガイド を参照してください。 推論デモアプリケーションを利用した計測方法 jetson-inferenceコンテナ向けのdocker-compose.ymlファイル *2 version : "3" services : jetson-inference : image : dustynv/jetson-inference:r32.7.1 command : detectnet /dev/video0 rtsp://@:55555/inference_output --input-width=1920 --input-height=1080 --input-rate=30 --output-codec=h264 --output-encoder=omx --bitrate=4000000 --headless --log-level=success --network=dashcamnet runtime : nvidia network_mode : host privileged : true restart : unless-stopped init : true volumes : - /dev:/dev - /tmp/argus_socket:/tmp/argus_socket - /etc/enctune.conf:/etc/enctune.conf - /media/ssd/jetson-inference/data:/jetson-inference/data 準備ができたら、車にEDGEPLANT T1やペリフェラルなどをセットアップします。 今回は簡易計測なので助手席にEDGEPLANT T1を設置 EDGEPLANT USB Cameraを利用して映像を取得します ディスプレイデバイスを使うと手元で各種状態の確認や計測開始・停止操作ができて便利です 実際に計測したデータはこちらになります。 物体検出推論デモアプリケーションが動作し、車載カメラに写った自動車や人物が検出されました! 今回はデモアプリを動作させただけですが、サンプルをカスタマイズすることで、検知時の処理を追加したり、モデルをカスタマイズすることも可能です。 Menderを利用したOTA 次に、Menderを利用したOTAをデモとして、上記サンプルの物体検知モデルの差し替えをしたいと思います。 Terminal System 2では、アップデートファイルをYoctoを利用せずに作成でき、Webブラウザ上から好きなタイミングでOTAを実行することができます。 旧Terminal Systemの場合、アップデートファイルの作成にはYoctoビルドが必要で、OTAのためにはリポジトリの立ち上げ・差し替えなどが必要になります(非常に手間・時間がかかります)。 実施手順の詳細はこの記事では省略しますが、以下の方法でアプリケーションアップデートを行います。 詳細については Terminal System 2デベロッパーガイド を参照してください。 アプリケーションアップデートの方法 モデルはjetson-inferenceコンテナ向けのdocker-compose.ymlファイルの --network オプションで指定することができますので、このファイルをMenderを利用して差し替えます。 事前にトレーニングされたモデル を参照し、モデルを dashcamnet から peoplenet に変更します。 これにより、検知するオブジェクトが人物のみになるはずです。 command: detectnet /dev/video0 rtsp://@:55555/inference_output --input-width=1920 --input-height=1080 --input-rate=30 --output-codec=h264 --output-encoder=omx --bitrate=4000000 --headless --log-level=success - --network=dashcamnet + --network=peoplenet アプリケーションアップデートアーティファクトを生成し、ブラウザを立ち上げMenderからデプロイします。 Menderによるアプリケーションアップデートのデプロイ操作 デプロイが完了したので、再度計測します。 モデルが変更され、車載カメラに写った人物のみが検出されるようになりました! *3 今回はファイルを差し替えただけですが、Menderのアップデートの仕組みは非常に柔軟かつ多機能であり、多くのユースケースに対応できます。 アップデートの仕組みについて詳細に知りたい方は Terminal System 2デベロッパーガイド を参照ください。 補足 Menderはソフトウェアアップデートだけでなく、 デバイス設定 、 モニタリング 、 リモートログイン など、エッジコンピューターの遠隔管理に必要な各種機能を備えています。 さいごに この記事では Terminal System 2のご紹介をさせていただきました。 エッジコンピューターを利用したシステムを開発する場合、今回私達が経験したものと同じような課題にお困りの方もいらっしゃるのではないでしょうか。 Terminal System 2の課題解決アプローチに魅力を感じていただけましたら、ぜひ弊社製品・サービスのご利用をご検討ください!以下よりお問い合わせ頂ければと思います。 www.aptpod.co.jp おまけ aptpodの入社面接で「エッジコンピューター上でDockerアプリケーションを動かしたい」と発言したことを今でも覚えています(実際できて嬉しい)。 単純にYoctoで作ったOS上でDockerを動かす だけ なら簡単です。それをシステムとして利用可能な形に落とし込むところに、aptpodのエンジニアの努力が詰まっています。 aptpodは、会社の方向性とマッチしていれば興味のあることについてわりと自由にやらせてくれる組織風土だと思います。 エンジニアのサポートも手厚く、入社当時(数年前)は、Linuxも不慣れで、YoctoもDockerもあまり使ったことがなかったですが、今ではあたりまえのように使うようになりました! aptpodは、趣味で電子工作を楽しんでいるエンジニアや、Raspberry Pi、Arduino、Jetson、M5Stackなど、IoTデバイスをいじったりすることが好きな人も多く在籍しています(私自身も 自作キーボード を作ったりしています)。 もし、弊社にご興味がありましたら、ぜひ以下よりお問い合わせください。aptpodで一緒に働きましょう。 www.aptpod.co.jp *1 : コンテナとホストを完全に分離することはできず、一部ホストに依存する部分があります( NVIDIA Container Runtime など)。 余談ですが、meta-tegraのkirkstoneブランチでnvidia runtimeを動作させるために色々と苦労しました。その話だけで記事がもう1つ書けるので、また別に機会にお話できればと思います。 *2 : 物体検出はdetectnetを使用します。ビルド済みモデルは--networkで指定でき、車載カメラ向けモデルのdashcamnetを使用します。カメラの解像度やFPSも合わせて指定しています。 *3 : peoplenetは車載カメラ向けのモデルではないので、今回の設定では映像のフレームレートが低くなるようでした。
アバター
はじめに 今回作成するアプリ eguiとは eguiの特徴 GUI画面作成 egui template の利用 アプリ構造体の修正 GUIパーツの追加 データ送信処理の組み込み Cargo.tomlの編集 サービスに接続するためのコード追加 GUIアプリの動作確認 デスクトップアプリとしての利用 まとめ はじめに こんにちは、 aptpod Advent Calendar 2023 12月19日担当のアプトポッドの組み込みソフトエンジニアの影山です。 弊社ではエッジデバイスで動くソフトウェアにRustを採用して、開発を進めております。 私もアプトポッドに入社してからRustを本格的に勉強していくつかの開発にも携わってきました。 一般的に何かのWebサービスを使おうとした場合、開発時ははCLIで利用できるだけで基本的には事足りますが、とっつきやすさだったり、情報の閲覧性を考えるとGUIがあった方がうれしいケースも多々あるかと思います。 これまでの経験でRustも多少使えるようになったので、今回は、Rust SDKを使って自社サービスに接続してみようと思います。 弊社では、コアのサービスであるintdashに接続するためのクライアントライブラリを、 色々な言語で提供 *1 しており、その中にRustも含まれています。 RustでGUIを作ることができるライブラリはいくつか提供されています。今回はその中でもeguiというライブラリを利用して、デスクトップアプリを作ってみたいと思います。 今回作成するアプリ 本記事では、弊社のintdashサーバに接続して、ダミーデータを送信するアプリを作ります。 コマンドラインで実行するアプリケーションの設定値は設定ファイルに書いたりすることが多いかと思いますが、その設定をGUIから編集できるようにしてみます。 今回作成するアプリの画面 今回は、上のキャプチャのような、接続に必要な設定を記入して、送信ボタンを押すと、それが所定の文字列がintdashサーバに届くというとてもシンプルなものです。 開発環境は、Windows11上のWSL2です。あらかじめRustやgitをインストールお願いします。 eguiとは eguiは、Rustで書かれたGUIライブラリです。 クロスプラットフォーム対応で、Windows、MacOS、Linux、ブラウザ上で動作します。 github.com リポジトリのReadmeによれば、 egui aims to be the easiest-to-use Rust GUI library, and the simplest way to make a web app in Rust. とうたっています。一番簡単につかえるRustのGUIライブラリを目指しているそうです。 まさにちょっとGUIがほしいユースケースにぴったりそうです。 eguiの特徴 即時モードUIであることが他の一般的なGUIライブラリとは異なっている点と言われています。 即時モードとは、一定の周期でアプリの全体を描画し直すような動作をすることを指します。パーツごとの書き換えのために必要な状態の管理などが不要になり、構造がシンプルになる代わりに、描画量が増えるので、その分の負荷が高まると言われています。 イメージとしてはゲームのように特定の周期で画面をリフレッシュするようなアプリケーションと同じような仕組みで動いているGUIです。 ゲームエンジンとの相性もよいので、eguiは、 bevy というRustのゲームエンジンにも対応しています。 bevyについては弊社テックブログでも過去に触れておりますので、ご興味があれば参照ください。 tech.aptpod.co.jp GUI画面作成 では実際にeguiを利用して、GUI画面を実装してみましょう。 アプリには、パラメータを入力するためのテキストボックスと、送信ボタンが必要になります。 egui template の利用 今回のアプリのベースには、eguiのテンプレートをgit cloneして使ってみます。 github.com src/ 以下に、 app.rs 、 lib.rs 、 main.rs が入っており、GUIに関わるコードは、app.rsに入っていますので、そちらを改造していきます。 例えばcloneした状態で cargo run で実行すると次のようなウィンドウのアプリが立ち上がります。 egui template を実行した例 アプリ構造体の修正 まず最初に接続に使用するサーバのアドレスとエッジのUUIDとSecretの情報を格納するために TemplateApp 構造体を以下のように修正します。 pub struct TemplateApp { server: String , uuid: String , secret: String , } impl Default for TemplateApp { fn default () -> Self { Self { server: String :: new (), uuid: String :: new (), secret: String :: new (), } } } GUIパーツの追加 次にテキストボックスとボタンを追加していきます。 GUIパーツを編集するには、eframe::Appトレイトのupdate関数を修正する必要があります。 update関数はアプリ画面のリフレッシュ時に毎回呼ばれています。 テンプレートで元々あったサンプルコードに手を加えて試行錯誤してみると、GUIパーツをどのように使えばよいのかすぐ理解できるかと思います。 CentralPanelの部分には元々スライダーなどが入っていますが、それらを削除して、編集可能なテキストボックス( text_edit_singleline )を追加して、 server 、 uuid と secret に紐づけます。 送信開始のボタンは ui.button("Send").clicked() というコードに対応しています。こちらのクリックの条件が真になったときに処理したいコードを挿入します。 今回は、このイベントをトリガーにデータの送信を行う関数( send_indash_message )を呼び出します。 send_indash_message 関数の中身はまだ空にしておきます。 impl eframe :: App for TemplateApp { fn update ( &mut self , ctx: & egui :: Context, _frame: &mut eframe :: Frame) { (中略) egui :: CentralPanel :: default (). show (ctx, | ui | { ui. heading ( "intdash sample" ); ui. horizontal ( | ui | { ui. label ( "Server: " ); ui. text_edit_singleline ( &mut self .server); }); ui. horizontal ( | ui | { ui. label ( "Edge UUID: " ); ui. text_edit_singleline ( &mut self .uuid); }); ui. horizontal ( | ui | { ui. label ( "Edge Secret: " ); ui. text_edit_singleline ( &mut self .secret); }); if ui. button ( "Send" ). clicked () { send_indash_message ( & self .server, & self .uuid, & self .secret); } (中略) fn send_indash_message (server: &String , uuid: &String , secret: &String ) { } 修正した結果の画面は以下のようになります。 修正したあとのアプリ画面 データ送信処理の組み込み それではアプリのスケルトンができたので、こちらをベースに弊社のintdashサーバへ接続してデータを送信するコードを作って行きましょう。 Cargo.tomlの編集 Cargo.tomlの [dependencies] に以下の依存関係を追加します。 [dependencies] iscp-rs = "0.10.2" chrono = "0.4.31" async-trait = "0.1.50" oauth2 = "4.0" tokio-test = "0.4" tokio = { version = "1.17", features = ["full"] } uuid = { version = "1.2", features = ["serde", "v4"] } サービスに接続するためのコード追加 サービス(ここでは弊社のintdash)に接続するために、 iscp-rs のサンプルを参考にして、次のようなコードを追加します。 ほぼサンプルコードをコピーした形になります。 詳細の説明は割愛しますが、intdashサーバへ接続して、 greeting というData IDで、 hello というデータを送信する処理になっています。 非同期処理なので、送信関数を呼び出す際は、TokioのRuntimeを利用しています。 use oauth2 :: basic :: BasicClient; use oauth2 :: reqwest :: async_http_client; use oauth2 :: {AuthType, AuthUrl, ClientId, ClientSecret, TokenResponse, TokenUrl}; use std :: { sync :: Arc, time :: Duration}; fn send_indash_message (server: &String , uuid: &String , secret: &String ) { tokio :: runtime :: Runtime :: new (). unwrap (). block_on (async { let _ = send_msg (server, uuid, secret).await; }); } #[derive( Clone )] struct TokenSource { access_token: String , } #[async_trait::async_trait] impl iscp :: TokenSource for TokenSource { async fn token ( & self ) -> iscp :: error :: Result < String > { Ok ( self .access_token. clone ()) } } async fn get_token (node_id: &String , client_secret: &String , url_api: &String ) -> Result < String , String > { let client = BasicClient :: new ( ClientId :: new (node_id. to_string ()), Some ( ClientSecret :: new (client_secret. to_string ())), AuthUrl :: new ( format! ( "{}/api/auth/oauth2/authorization" , url_api)). unwrap (), Some ( TokenUrl :: new ( format! ( "{}/api/auth/oauth2/token" , url_api)). unwrap ()), ); let client = client. set_auth_type ( AuthType :: RequestBody); let token_result = client . exchange_client_credentials () . request_async (async_http_client) .await; Ok (token_result. unwrap (). access_token (). secret (). clone ()) } async fn send_msg (host: &String , node_id: &String , node_secret: &String ) -> Result < (), String > { let url_api = format! ( "https://{}" ,host); let iscp_addr = format! ( "{}:11443" ,host); //Tokenの取得 let api_token = get_token ( & node_id, & node_secret, & url_api).await. map_err ( | e | e. to_string ()) ? ; let token_source = Arc :: new (TokenSource { access_token: api_token, }); //intdashサーバへ接続 let builder = iscp :: ConnBuilder :: new ( & iscp_addr, iscp :: TransportKind :: Quic) . quic_config ( Some ( iscp :: tr :: QuicConfig { host: host. clone (), mtu: 1000 , .. Default :: default () })) . encoding ( iscp :: enc :: EncodingKind :: Proto) . token_source ( Some (token_source)) . node_id (node_id); let conn = builder. connect ().await. unwrap (); let session_id = uuid :: Uuid :: new_v4 (). to_string (); let base_time = chrono :: Utc :: now (); let up = conn . upstream_builder ( & session_id) . flush_policy ( iscp :: FlushPolicy :: IntervalOnly { interval: std :: time :: Duration :: from_millis ( 5 ), }) . ack_interval ( chrono :: Duration :: milliseconds ( 1000 )) . persist ( true ) . close_timeout ( Some ( Duration :: new ( 1 , 0 ))) . build () .await . unwrap (); // 基準時刻をiSCPサーバーへ送信します。 conn. send_base_time ( iscp :: message :: BaseTime { elapsed_time: chrono :: Duration :: zero (), name: "edge_rtc" . to_string (), base_time, priority: 20 , session_id, }, iscp :: SendMetadataOptions { persist: true }, ) .await . unwrap (); tokio :: time :: sleep ( tokio :: time :: Duration :: from_secs ( 1 )).await; // データポイントをiSCPサーバーへ送信します。 up. write_data_points ( iscp :: DataPointGroup { id: iscp :: DataId :: new ( "greeting" , "string" ), data_points: vec! [ iscp :: DataPoint { payload: "hello" . into (), elapsed_time: chrono :: Utc :: now () - base_time, }], }) .await . unwrap (); up. close ( Some ( iscp :: UpstreamCloseOptions { close_session: true , })) .await . unwrap (); conn. close ().await. unwrap (); Ok (()) } GUIアプリの動作確認 次のコマンドで起動します。 $ cargo run 起動したら接続対象のサーバのアドレス、エッジのUUIDとSecretを入力します。 サーバへの接続情報を入力 そしてSendボタンを押すことで、サーバへの接続、データの送信が行われます。 では、Edge Finderという、デバイスからデータ受信状態を表示する弊社のWebアプリで、実際にデータを受信していることを確認してみます。 Edge Finderの画面 上の図はSendボタンを押して何秒か待ったあとの画面です。このようにアプリ上のボタンを押すことで、実際にサーバに hello というテキストデータが届いていることが確認できました。 デスクトップアプリとしての利用 単体で動作するデスクトップアプリとして配布するためには、まずリリース向けにビルドします。 cargo build --release そして target/release フォルダに生成された実行ファイルが、単体で動作するアプリとして利用できます。 まとめ 本記事ではeguiを使って、お手軽に仕事でつかえるデスクトップアプリを作る方法をご紹介しました。 純粋なRustで、ちょっとコードを書くだけで簡単にGUIアプリが作れることが伝われば幸いです。 綺麗なGUIデザインを作ることは難しいかもしれませんが、特定の用途で使うアプリなどを作る際には適したものだと思います。 Rustに関しては、開発チームによる、日々の開発にも役に立つテックブログもあるのでご興味ある方はぜひご覧ください。 tech.aptpod.co.jp *1 : Python、TypeScript、Swift、C#、Go、Rust
アバター
aptpod Advent Calendar 2023 12月18日 を担当する 組み込みエンジニアの久保田です。 みなさん、ROS(Robot Operating System)開発でGazeboシミュレータを動かす際、どのような環境を使っていますか? GPUを搭載した高性能なPCは社内に限られており、長時間の占有が難しいということも多いのではないでしょうか。以前紹介した Open-RMFシミュレーション のように、試行錯誤しながら環境をフルに活用したいようなことがあるかと思います。 AWS EC2にVNC Clientで接続してOpen-RMFのデモを動かしている様子 本記事では、そのような用途向けに、AWS EC2のGPUインスタンス上にx11vncを使用したリモートデスクトップ環境を構築する方法を紹介します。この環境は、ROS開発だけでなく、Unityや動画生成などのGPUを要求するアプリケーションを使用したい方々にとっても有益です。 はじめに VNCサーバ側 AWS EC2インスタンス構築 NVIDIAドライバインストール Ubuntu Desktopインストール x11vncインストール VNCクライアント側 SSH Port Forwarding接続 VNCクライアント接続 まとめ はじめに 本記事ではGPUリソースをフルに活用できる、リモートデスクトップ環境の構築手順を紹介します。 Remote Desktop AWS EC2インスタンスのデスクトップ環境にリモートアクセスする方法がいくつかありますが本記事ではVNCを使用します。 VNC(Virtual Network Computing)はリモートデスクトップアクセスソフトウェアの一つで、インターネットやネットワーク経由で別のコンピュータのデスクトップにアクセスし、操作することができます。この技術は、デスクトップ画面の画像をリモートコンピュータに転送し、リモートコンピュータからの入力(キーボードやマウス操作)をローカルコンピュータに送り返すことで機能します。 このVNCの機能でリモートデスクトップ環境は構築できますが、セキュアな通信とするため、SSH Port Forwardingを使用します。 SSH Port Forwardingは、安全なSSH(Secure Shell)接続を通じてネットワークポートの転送を行う技術です。この方法は、SSHトンネルを使用して、ローカルマシンとリモートマシン間でデータを安全に転送するために使用します。 VNCとSSH Port Forwardingの設定手順をVNCサーバ側、VNCクライアント側それぞれ説明していきます。 VNCサーバ側 AWS EC2インスタンス構築 AWS EC2のGPUインスタンスを構築していきます。このインスタンスにはssh接続できるように設定します。 OSイメージ インスタンスのOSイメージを選択します。ここでは、Ubuntu Server 22.04 LTS (x86) を指定します。   ここではUbuntu Server Editionですが、後述する手順でDesktop環境をインストールします AWS EC2 OSイメージ選択 インスタンスタイプ インスタンスタイプを選択します。ここではGPUインスタンスでも導入しやすい G4dn を指定します。   インスタンスサイズは xlarge (4 Core) としていますが、必要なCPUリソースによって変更してください AWS EC2 GPUインスタンス選択 ストレージ ストレージ容量を選択します。用途に合わせて調整してください。   デスクトップ利用のため、30GiB 以上を推奨します AWS EC2 ストレージ設定 Ubuntuパッケージ更新 EC2インスタンス起動後、Ubuntuを最新の状態に更新します。 sudo apt update sudo apt upgrade NVIDIAドライバインストール 構築したAWS EC2のGPUインスタンスにNVIDIAドライバをインストールしていきます。 ubuntu-driversコマンド NVIDIAドライバインストールに必要なコマンド ubuntu-drivers をインストールします。 sudo apt install ubuntu-drivers-common NVIDIA推奨ドライバー確認 コマンドubuntu-driversを実行して、インスタンスに最適なドライバを確認します。   最適なドライバは recommended と表示されます ubuntu@ip-203-0-113-129:~$ sudo ubuntu-drivers devices == /sys/devices/pci0000:00/0000:00:1e. 0 == modalias : pci:v000010DEd00001EB8sv000010DEsd000012A2bc03sc02i00 vendor : NVIDIA Corporation model : TU104GL [ Tesla T4 ] driver : nvidia-driver-510 - distro non-free driver : nvidia-driver-470 - distro non-free driver : nvidia-driver-470-server - distro non-free driver : nvidia-driver-450-server - distro non-free driver : nvidia-driver-418-server - distro non-free driver : nvidia-driver-515 - distro non-free driver : nvidia-driver-525 - distro non-free recommended driver : nvidia-driver-525-server - distro non-free driver : nvidia-driver-515-server - distro non-free driver : xserver-xorg-video-nouveau - distro free builtin NVIDIAドライバーをインストール 確認した最適なドライバをインストールします。ここではnvidia-driver-525とします。 sudo apt install nvidia-driver-525 インスタンスを再起動後、NVIDIAドライバーを動作確認 コマンド nvidia-smi はNVIDIAのGPU使用状況を確認することができるコマンドです。GPU名 (GPU Name)や温度 (Temp), 消費電力 (Pwr:Usage/Cap)などが表示できている場合、インストールしたドライバが動作していることを確認できます。 ubuntu@ip-203-0-113-129:~$ nvidia-smi Tue Jan 31 04:45:26 2023 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 525 . 78 . 01 Driver Version: 525 . 78 . 01 CUDA Version: 12 . 0 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | | ===============================+======================+====================== | | 0 Tesla T4 Off | 00000000:00:1E. 0 Off | 0 | | N/A 50C P8 15W / 70W | 2MiB / 15360MiB | 0 % Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | | ============================================================================= | | No running processes found | +-----------------------------------------------------------------------------+ Ubuntu Desktopインストール Ubuntu Server Edition上にDesktop環境を構築していきます。 Xorg サーバ設定ファイル作成 Desktop環境に必要なXorgサーバ設定ファイル (/etc/X11/xorg.conf) をコマンド nvidia-xconfig にて作成します。 sudo nvidia-xconfig Ubuntu Desktop インスタンスのOSイメージがServer Editionのため、Ubuntu Desktopをインストールします。 sudo apt update sudo apt install ubuntu-desktop Wayland無効化 X11を使用するため、Waylandを無効にします。 /etc/gdm3/custom.conf WaylandEnable =false LightDMをインストール x11vncに対応したデスクトップマネージャであるLightDMに切り替えます。 sudo apt install lightdm   インストールの途中で、デフォルトのディスプレイマネージャを選択する画面が表示されるので、LightDMを選択します x11vncインストール リモートからDesktop環境を利用するためにx11vncをインストールします。 x11vncは、X Window SystemのデスクトップをリモートアクセスするためのVNCサーバーソフトウェアです。このソフトウェアは、既存のXセッションをリアルタイムでキャプチャし、それをVNCプロトコルを通じて別のコンピューターに転送します。これにより、ユーザーは遠隔地から現在動作しているデスクトップ環境にアクセスし、操作することができます。 x11vncの主な特徴は以下の通りです: 既存のXセッション共有:現在アクティブなXセッションに接続し、その内容をリモートユーザーと共有します。 クロスプラットフォーム対応:Linux、Windows、Macなど、多様なオペレーティングシステムでVNCビューア(クライアント)を使用してアクセスできます。 セキュリティ機能:パスワード保護やSSHトンネリングを使用して、接続を安全に保ちます。 GPUアクセラレーション:描画性能の向上のために、GPUアクセラレーションを利用することが可能です。これにより、グラフィックス処理が高速化され、特にグラフィック集約型のアプリケーションやデスクトップ環境でのパフォーマンスが向上します。 x11vnc x11vncをインストールします。 sudo apt install x11vnc x11vncパスワードファイル パスワードファイルを作成します。 $ sudo x11vnc -storepasswd /etc/vncpasswd Enter VNC password: ← パスワード入力 Verify password: ← パスワード確認入力 Write password to /etc/vncpasswd? [ y ] /n Password written to: /etc/vncpasswd Xauthorityファイル X11アクセス制御情報を格納するファイル .Xauthority を作成します。 /home/ubuntu/.Xauthority $ touch ~/.Xauthority $ xauth add :0 MIT-MAGIC-COOKIE-1 $( openssl rand -hex 16 ) SSHパスワードログイン SSHパスワードログインを有効にします。 /etc/ssh/sshd_config PasswordAuthentication yes ログインパスワードを設定します。 sudo passwd ubuntu x11vnc自動起動設定 インスタンス起動時にx11vncが自動起動するようにsystemdへ設定ファイルを登録します。設定ファイル (x11vnc.service)を作成し、systemd設定ディレクトリ(/etc/systemd/system)に格納してください。 $ sudo systemctl daemon-reload $ sudo systemctl enable x11vnc /etc/systemd/system/x11vnc.service [Unit] Description = x11vnc (Remote access) After = network-online.target [Service] Type = simple ExecStart = /usr/bin/x11vnc -auth guess -display :0 -rfbauth /etc/vncpasswd -rfbport 5900 -forever -loop -noxdamage -repeat -shared ExecStop = /bin/kill -TERM $MAINPID ExecReload = /bin/kill -HUP $MAINPID KillMode = control-group Restart = on-failure [Install] WantedBy = graphical.target   VNCの使用ポート番号を 5900 とします VNCクライアント側 VNCサーバ側の準備ができたところで、VNCサーバへVNCクライアントを接続していきます。 本記事では、VNCクライアントとしてRealVNCのVNC Viewerを使用します。 SSH Port Forwarding接続 SSH Port Forwarding 別ターミナルで、AWS EC2インスタンスのVNCサーバの通信をSSH port forwardingするためにssh接続します。 ssh -L 5900:ec2-203-0-113-129.ap-northeast-1.compute.amazonaws.com:5900 ubuntu@ec2-203-0-113-129.ap-northeast-1.compute.amazonaws.com VNCクライアント接続 VNCクライアント SSH Port Forwardingのためのssh接続後、VNCクライアントを実行してリモートデスクトップ画面を表示します。 vncviewer 127 . 0 . 0 .1::5900 vncviewer コマンド nvidia-smi はNVIDIAのGPU使用状況を確認することができるコマンドです。プロセス情報 (Processes) に デスクトップ表示プロセス (Xorg) が表示されている場合、デスクトップ表示にGPUを使用していることが確認できます。 ubuntu@ip-203-0-113-129:~$ nvidia-smi Tue Jan 31 08:34:40 2023 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 525 . 78 . 01 Driver Version: 525 . 78 . 01 CUDA Version: 12 . 0 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | | ===============================+======================+====================== | | 0 Tesla T4 Off | 00000000:00:1E. 0 Off | 0 | | N/A 33C P8 14W / 70W | 245MiB / 15360MiB | 1 % Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | | ============================================================================= | | 0 N/A N/A 2409 G /usr/lib/xorg/Xorg 136MiB | | 0 N/A N/A 2911 G /usr/bin/gnome-shell 105MiB | +-----------------------------------------------------------------------------+ まとめ 本記事では、AWS EC2 GPUインスタンスへのリモートデスクトップ環境の構築手順を紹介しました。設定項目は多いですが構築できれば快適な環境を手にいれることができます。本記事の内容がROS開発やGPUを使ったその他のプロジェクトに役立つと嬉しいです。
アバター
こんにちは! aptpod Advent Calendar 2023 12月15日担当サーバーサイドエンジニアの宮内です。 普段はサーバーアプリケーションを実装しているのですが、今日はフロントエンドのUI含んだintdashシステム全体の構築方法について書こうと思います。 どれだけ簡単に構築のできるかという点をお伝えしていきます。 リリース前の情報なので、現状でお伝えできる範囲内での内容となります。 背景編 intdashシステムとは intdashの課題 本記事の主題 構築編 提供物について 構築可能な環境 提供までのワークフロー 構築 docker-compose Kubernetes(AWS EKS) Kubernetes(kind) まとめ 背景編 実際の構築に入る前に今から構築しようとしているIoTシステムである「intdash」について簡単におさらいしていきます。 intdashシステムとは intdashシステムを構築する前に簡単にintdashとその周辺についておさらいしておきます。 IoTシステムを作ろうとすると、考えなければならないことがいろいろあると思います。例えば どうやってデバイスからのデータを伝送するか サーバーソフトウェアはどう構成するか どこにデータを保存するか 保存したデータをどう活用するか デバイスの管理をどうするか etc... などなどです。 一つひとつ検討し、さらに構築していくのは骨の折れる作業です。 大手クラウドベンダのサービスを組み合わせればそれぞれの要求に応じたIoTシステムを構築することが可能ですが、 そのためには高い経験値やそれなりにノウハウが必要で容易なことではありません。 intdashとは前述のような一般的なIoTシステムで必要とされる、データの伝送、収集、連携などのユースケースに対応したワンストップソリューションです。 通常のIoTデータ伝送にももちろん使用可能ですが、intdashが特にその真価を発揮するのは、 一つのデバイスから送信するデータが秒間、数百や数千といった大量データでかつ複数データソース時刻同期が必要なユースケースです。 また、intdashは独自のプロトコルにより帯域の細いモバイル回線でも確実にデータ収集を行い、かつレイテンシを低く抑えリアルタイムにデータ伝送が可能です。 intdashの詳細は是非 https://www.aptpod.co.jp/products/software/intdash/ のページから参照ください。 intdashの課題 2023年12月現在、intdashを利用するには基本的には弊社がクラウド上に構築運用している環境を利用してもらう必要があります。いわゆるサービスとしての利用がメインストリーム *1 です。 これまでのブログでもintdashの紹介はありましたが、実際にintdashを試す場合は弊社と契約を結んだあと、弊社で環境を構築し弊社のクラウドに構築されたintdashを使用するという流れになります。 一方で、クラウドベースのサービス展開のみだと 事業的なスケールが難しく実行環境をより自由にする必要がありました。 これは、intdashがあくまでもミドルウェアであり、独自のIoTプラットフォームの構築やクローズドな社内システム構築などといったユースケースに対応する必要があることに起因します。 一般的なデータベースなどと思想は近く、独自のプラットフォームや社内システムを構築できるようにするには、サービス提供にとどまらず プロダクトのポータビリティよくすることは必要不可欠です。 例えば、独自のデータセンターであったり、もっとカジュアルな自前で用意したサーバーなどにも構築することが想定されます。 時には開発者のローカル環境に構築するユースケースも考えられます。 そこでこれまでのサービス利用に加え、 オンプレミスや手元のローカル環境でも実行できるポータビリティの高いプロダクト提供方法の検討と整備をしていました。 結構前から始めていたのですが、ようやく運用ノウハウも少しずつ溜まってきており、 提供に必要な情報もまとまってきて、近日中に公開できるところまで来ています。 本記事の主題 前述の通りIoTシステムを構築するには容易ではありません。 intdashも単純ではなく、下図のような複数のコンポーネントで構成されています。 intdashのコンポーネント 構成は決まっているので、0から考えるよりはいくらかましですが、 それでも構築は大変な作業であることには変わりありません。 図中の intdashのコア機能を提供するAPI(intdash Core Services) intdash環境管理のためのWebインターフェイス(intdash Web Console) 多彩なデータ可視化を実現するWebダッシュボード(Visual M2M Data Visualizer) に加えて、図では表現されていませんが、データベースなどの各種ミドルウェア群を サクッと構築していきましょう!というのが今回の記事の主旨です。 つまり、この記事を読んだあとには、 手元で簡単にintdashを構築できる! 適当な物理サーバーにintdashを構築できる! 自社AWSアカウント上にintdashを構築できる! といった内容をより具体的にイメージ出来るようになります。 以降、具体的にどんな環境へどんな手順でデプロイができるかという点を少しだけ紹介します。 すごく簡単に構築できる!といったところを体感していただけたら幸いです。 構築編 提供物について 一体どんなものがどういった形態で提供されるのか説明します。 現状は次のようなものを提供する予定です。 ライセンス(システム構築には製品のアクティベーションが必要です) プロダクト(コンテナイメージ/RPMパッケージ) 構築運用ガイド 構築を補助するスクリプト類 プロダクトの提供はコンテナとRPMパッケージの2つの提供を目指しています。 実行環境や要求に合わせていずれかの方法が選択可能です。 構築可能な環境 基本的にはいくつか前提となる条件はありますが、その条件を満たせば任意の環境でintdashシステムを構築することができます。 例えば次のような環境です。 AWS EKS Kubernetes(EKS以外) Docker Compose オンプレミスの物理サーバー IaaS(EC2など) 提供までのワークフロー こちらについては未整備な部分もありますが、基本的には次のような流れになります。 ライセンスを購入します。 構築運用ガイド参照し、任意の場所に構築します。 ライセンス購入し、構築ガイドを参照すれば誰でもどこでも構築が可能というわけですね。 現状、少しだけ利用までの敷居が高いので、将来的にはもっとシンプルに商品を提供できるような販売チャネルも検討中です。 構築 RPMとコンテナによる構築方法がありますが、今回はコンテナによる構築方法をご紹介します。 intdashは複数のAPIサーバーアプリケーションやフロントUI、データベースなどの各種ミドルウェアで構成されています。 ですから、現状は単一イメージの提供ではなく、アプリケーションごとのコンテナイメージとその構成ファイル(docker-composeやHelmチャートなどのことを指しています)を使用して構築する必要があります。 もちろんアプリケーションごとのコンテナイメージを組み合わせて独自にマニフェストなどを作成し、intdashシステムを構築することも可能ですが、かなり面倒なのであまり現実的ではありません。 今回はdocker-composeによる構築とHelmチャートによる構築の大きく2つをご紹介します。 また、今回紹介する内容はintdashシステムに加え、intdashが依存する各種ミドルウェアもコンテナで一緒に構築します *2 。 今回ご紹介する内容はあくまで手軽に立てて簡単に機能を確認したい方向けです。 プロダクション環境など、比較的非機能面の要求が高い場合は、ここで紹介した内容を参考にして要求に応じた構成で構築する必要があります。 その内容の詳細については今回は割愛させていただきます。 各構築方法の説明に入る前に、構築を補助するスクリプト群が格納されたファイル(ここでは deployment.zip とします)をライセンス購入後にダウンロードし、解凍しておきます。 以降はこの解凍されたファイル群を使用します(( deployment.zip は使用しなくても製品購入時に提供される構築運用ガイドに沿って進めれば構築は可能です。その場合は deployment.zip 内のファイルはリファレンスとして参照することができます。))。 # 構成ファイル群を入手して解凍する。 unzip deployment.zip # deploymentに移動します。 以降deploymentがカレントディレクトリという事を前提に説明します。 cd deployment ここで紹介する内容は正式な手順ではありません。製品提供時に同梱する構築運用ガイドの内容が正式なものとなります。ガイドの内容が本記事の記載と異なる可能性があることをご容赦ください。 docker-compose docker-composeを使用して構築します。 わざわざ章立てしましたが、ただ構築するだけであれば deployment.zip に起動スクリプトがあるのでほとんどやることはありません。他の構築方法も同様です。 細かい設定などももちろん可能ですが、ここでは割愛します。 起動に必要なツールがあるのでそれぞれインストールします。 aws cli docker(docker compose) openssl mkcert 次のコマンドを実行します。 export IMAGE_REPOSITORY_BASE=イメージのリポジトリ # AWSへログインしておきます。イメージの取得に必要です(イメージの配布方法は未だ検討中なので変わる場合があります。) aws sso login aws ecr get-login-password | helm registry login --username AWS --password-stdin "$IMAGE_REPOSITORY_BASE" aws ecr get-login-password | docker login --username AWS --password-stdin ${IMAGE_REPOSITORY_BASE} # 起動! ./scripts/quick-start.sh localhost 起動ログが流れ始め、遅くても数分程度でアプリケーションが起動します。 標準出力されたアクセス情報を元に https://localhost へアクセスして確認します。 ちなみに、ここで例えば次のようにLAN内のアドレスなどを指定すれば一瞬でLAN内にintdashを構築することも可能です。 ./scripts/quick-start.sh 192.168.x.x 終了する場合は次のコマンドを実行します。 ./scripts/destroy.sh # または docker compose down docker compose down -v スクリプト内では次の処理を順番に行っています。 アプリケーションで使用する秘密鍵の生成 証明書の作成 アプリケーション郡の起動( docker compose up ) Kubernetes(AWS EKS) AWS EKS(Elastic Kubernetes Service)へ構築する場合も基本的には同じ流れです。起動スクリプトを実行します。 docker-composeの時と同様に起動に必要なツールがあるので、それぞれインストールします。 docker aws-cli eksctl helm helmfile mkcert 次に起動スクリプトを実行します。 # 環境変数の設定 # 必須項目 export AWS_ACCOUNT_ID=<AWS ACCOUNT ID:例 111111111111> export IMAGE_REPOSITORY_BASE=<リポジトリ:例 <アカウントID>.dkr.ecr.<リージョン>.amazonaws.com> # オプショナル export REGION=<リージョン: ap-northeast-1> export CLUSTER_NAME=<クラスタ名: intdash-demo> export NAMESPACE=<ネームスペース: intdash> # AWSへログインしておきます。イメージの取得に必要です(イメージの配布方法は検討中なので今後変更の可能性があります。) aws sso login aws ecr get-login-password | helm registry login --username AWS --password-stdin "$IMAGE_REPOSITORY_BASE" aws ecr get-login-password | docker login --username AWS --password-stdin ${IMAGE_REPOSITORY_BASE} # 起動! ./scripts/quick-start-eks.sh 数分(場合によっては数十分)待つとEKS上にintdashクラスタが構築されます *3 。 起動が成功するとアクセス情報が標準出力されます。 表示されたアクセス方法に従ってintdashのコンソールにアクセスします。 スクリプト内では次の処理を順番に行っています。 一度構築した後は基本的には helm コマンドを通してintdashの更新を行います。 EKSクラスタの作成 EKSのOIDCプロバイダの有効化 ALBロードバランサーコントローラーの有効化 EBS/CSIドライバーのアドオン追加 各種ミドルウェアの追加(Postgres/Nats/InfluxDBなど) Helmチャートを使用したintdashのインストール ドメイン設定 *4 証明書設定 Kubernetes(kind) 最後にkindにintdashを立ててみます。 kindとはKubernetesクラスタをDockerコンテナとしてローカルで実行するためのツールです。 大手クラウドベンダーが展開するマネージドKubernetesサービスに依存しないため、比較的構築しやすい構成 *5 となります。 こちらについても起動スクリプトがあるので実行するだけです。 例によって起動に必要なツールがあるのでそれぞれインストールします。 docker aws-cli kind eksctl helm helmfile mkcert それでは、同様にintdashを構築していきます。 # 環境変数の設定 export IMAGE_REPOSITORY_BASE=イメージのリポジトリ export NAMESPACE=<ネームスペース: intdash> export DOMAIN=<ドメイン: example.127.0.0.1.nip.io> # AWSへログインしておきます。イメージの取得に必要です(イメージの配布方法は検討中なので今後変更の可能性があります。) aws sso login aws ecr get-login-password | helm registry login --username AWS --password-stdin "$IMAGE_REPOSITORY_BASE" aws ecr get-login-password | docker login --username AWS --password-stdin ${IMAGE_REPOSITORY_BASE} # 起動! ./scripts/quick-start-kind.sh EKS同様に数分待つとkind上にintdashクラスタが構築されます。 起動が成功するとアクセス情報が標準出力されます。 スクリプト内では次の処理を順番に行っています。 kindクラスタの作成 各種ミドルウェアの追加(Postgres/Nats/InfluxDBなど) ingress-nginxの追加 イメージプル用のシークレットリソース追加 クラスタに証明書のシークレットリソースの追加 まとめ 今回はコンテナによるintdashの構築方法についてご紹介しました。「簡単に構築できそう!」と思っていただけたら幸いです。 もしintdashをローカルや手元のサーバーに構築することができれば、過去テックブログで紹介された記事なども比較的簡単にに確認することができるのではないでしょうか? ご興味があれば こちら からお気軽にお問い合わせください。 繰り返しになりますが今回紹介した内容はあくまでも起動するまでに必要な最低限の内容に絞ってご紹介しています。 プロダクション環境などに導入する場合は今回紹介した起動方法を参考に堅牢なシステムを構築する必要があります。 *1 : パートナー企業様が独自に構築するケースもありますが主流はサービス利用です。 *2 : 本番稼働などを想定する場合、データベースなどは必ずしもコンテナで構築する必要はありません。例えば、RDBであればAmazon RDSなど大手クラウドベンダのマネージドサービスを 使用することも可能です。 *3 : eksctl のほぼデフォルト設定で起動します。必要に応じてnodegroupやVPCなどの設定は変更します。 *4 : AWSから自動に払い出されたドメイン名に対して、無理やり証明してACMに登録する力技が含まれています。あくまでも確認用です。 *5 : AWSに構築する場合は、DockerがインストールされたEC2でkindを実行します。kindは主に開発やテストの目的で利用されるため、本番環境ではEKSなどクラウドベンダーのマネージドKubernetesを利用いただくことを推奨します。
アバター
はじめに aptpod Advent Calendar 2023 12月14日の記事です。 こんにちは。ハードウェアグループの織江です。 弊社では主に4G/LTEや5Gといったモバイル通信網を利用した移動体からのデータ収集や制御を行っていますが、今回はそれに加えて衛星通信を使って利用できる環境を広くすることに挑戦しました。 Starlinkとは Starlinkの通信速度測定 intdashに使う場合のネットワーク遅延評価 まとめ Starlinkとは biz.kddi.com スペースX社が開発した衛星ブロードバンドインターネットです。特徴としては従来の衛星通信で使われていた静止軌道上(地上約36,000㎞)の衛星と比較して低い軌道(2000㎞以下)で周回する衛星を用いたネットワークで従来の衛星通信よりも帯域が広く、遅延が少ないネットワークです。 今回使ったのは KDDIのStarlinkBusinessプラン です。 今回のプランにはアンテナ設置のためのスタンドが含まれていないのでアンテナを移動させながら計測するために、電源やWiFiルーターをセットにして持ち運びやすいようにアルミフレームに適当に括りつけました。 アルミフレームで持ち運びしやすくしたStarlink 屋外で計測するためにモバイルバッテリーを用意しましたが、Starlinkは消費電力が大きい(ピーク消費電力を実測したところ約190W)ので十分余裕のある電源を用意する必要があります。 今回利用したモバイルバッテリーは JackeryのPORTABLE POWER 1000 です。 Starlinkのセットアップは専用のアプリをインストールしたスマホがあると数分で初期セットアップが完了します。注意点としては屋外でWiFiを利用する場合5GHz帯の周波数を使わないないようにセットアップするのがポイントです。専用アプリで屋外モードとして設定するとよいです。誤って設定してしまった場合電源を6回連続でタイミングよく抜き差しすることで工場出荷状態に戻せるのはちょっと便利な機能でした。 Starlinkの通信速度測定 Starlinkは室内では衛星と通信できないのでアンテナをビルなどの障害物の少ない屋外に設置する必要があり、理想的と思われる広い公園で試験を行いました。(Starlinkにとって通信環境がよい場所がLTEにとって通信環境が良いとは限らないので今回の測定は比較の一例だと考えてください。) 障害物の少ない広場(潮風公園) まずはWindowsPCをWiFi経由でStarlinkまたはLTEに接続した場合の通信帯域を計測します。少しばらつきがあるので今回は3回測定して平均をとることにしました。 google speedtestによる通信帯域の計測 計測結果は下り156.1Mbps上り5.80Mbpsとなり、下りは早いと言えますね。一般的なLTE cat.7の通信モジュールよりも数倍速いです。それに対して上りはLTEの半分くらいです。市街地に居ると恩恵がわからないですが、この通信帯域は洋上や山間部での通信となると超高速と言って良いでしょう。 intdashに使う場合のネットワーク遅延評価 改めて弊社の intdash の標準的なデータ収集のユースケースを紹介します。移動体から発生する計測データをクラウド上にアップストリームし、閲覧者側がクラウドにアクセスする形になっています。Starlinkとintdashが稼働する弊社のエッジコンピューター( EDGEPLANT T1 )はWiFi経由で簡単に接続することが可能です。 intdashを用いたデータ収集 こちらのように移動体から発生した計測データをクラウドにアップロードする無線区間で上り帯域を広く利用しており、この無線区間が通信可能エリアの境界付近だと通信全体のボトルネックになりがちです。クラウドからデータの利用者へは光ファイバー網や無線区間も含むこともありますが下り方向なので上りに比べてボトルネックになるケースは少ないです。今回の遅延評価を行うにあたりネットワークの限界付近の挙動はどうしても不安定になるので今回は軽めに1.5Mbps程度のアップロードを行いました。 負荷をかけた状態でのネットワークの遅延はintdashを使いながら付随する機能で同時に計測を行うことができます。得られた遅延は上記の表の通りでStarlinkのネットワークの遅延(RTT)は約45msとなり、予想していたよりも十分小さくスムーズなストリームが維持されており、intdashとの親和性は良好だと感じました。LTEに比べるとStarlinkのほうが遅延が少し大きめになる傾向が得られましたが、LTEよりも長い経路をたどっているためだと思われました。speedtestだけでは測定できない遅延があるのはStarlinkの地上側のネットワークの経路によっては今回使った東京エリアのサーバーまでの経路が特別短いわけではないという可能性が高いです。帯域内の速度であればLTEとほとんど遜色なく通信できているという感触です。 まとめ Starlinkは消費電力が大きい(最大約190W) 最大190W、アイドル時80W、通信時110W前後で、ポータブルバッテリーで長時間稼働させたりするのは難しそうです。 Starlinkはダウンリンクに特に強い(156.1Mbps) インターネットをブラウジングする程度では衛星通信をしている感覚がないほど高速です。 Starlinkのアップリンクはそれほど速くない(実測5.8Mbps) 一般的なインターネットの通信速度をアピールする宣伝文句はたいていの場合下りの帯域を大きく取り上げる傾向にあります。これは一般消費者のインターネットの利用用途が下りが圧倒的に多いからです。 私たちがこのStarlinkを取り上げる意義としてあまり評価されていないほうの上り帯域のレビューという側面が強いです。今回Starlinkを評価してみて極端にダウンリンクに性能が振ってあるネットワークだと感じました。ただ、それでも通信すべきデータを適切に圧縮したりすることで十分利用価値の高いネットワークだと感じました。 弊社のintdashと簡単に疎通させることができるので合わせてぜひご検討ください。 無料のトライアルも受けつけておりますのでぜひお問い合わせください。 www.aptpod.co.jp
アバター
aptpod Advent Calendar 2023 12月13日を担当するintdashグループの落合です。 みなさんはNVHってご存知ですか?僕は全く知らなかったのですが、 Noise(騒音) Vibration(振動) Harshness(ハーシュネス:路面の凹凸による突き上げや、立て付けの悪さから来るガタピシ感など) の頭文字で、自動車の快適性を推し量る上での一つの基準だそうです( WiKi より)。 この意味を知った時、弊社の intdash を使うと簡単に測定できるかもと思ったので、この記事ではintdashでNVHを簡易的に測定してみます。 やること NoiseとVibrationの測定 Noiseの測定 Vibrationの測定 Harshnessの算出 実車でとってみる 走った場所 測定結果(NoiseとVibration) 算出結果(Harshness) まとめ 付録 加速度センサーのキャリブレーション Harshnessの計算に使用したコード やること Noise、Vibration、Harshnessのデータを弊社の intdash に送ることで、データを可視化して確認してみます。 NoiseとVibrationについては、弊社の EDGEPLANT T1 と専用Linuxディストリビューションである Terminal System 2 を利用しました。Terminal System 2ではEDGEPLANT T1に内蔵されている加速度センサーやマイクジャックを使う機能があらかじめ入っているため簡単に音声と加速度を測定できるので、今回は簡易的この値をNoiseとVibrationとして測定します 1 。 Harshnessは、Vibrationの値から計算します。測定したVibrationの値からHarshnessを計算しintdash保存するには、弊社の intdash SDK for Python というクライアントライブラリを利用しました。 最後に、intdashに上がっているデータは Visual M2M Data Visualizer で可視化して確認してみます。 システム構成図 NoiseとVibrationの測定 NoiseとVibrationの測定は、 EDGEPLANT T1 と専用Linuxディストリビューションである Terminal System 2 を利用します。 データを取得するための設定は ドキュメント に記載してあるので割愛させていただき、ここでは使用したデバイスと取れるデータについて説明します。 Noiseの測定 今回は簡易的にデータが取れれば良いので、マイクは サンワサプライ マイク MM-MC32 と サンワサプライ 変換アダプタ KM-A25-005 を利用しました。 今回測定では車の運転席と助手席の間の床部分に養生テープで固定しています。 マイク 次に、データをとって確認してみます。 確認に使用する Visual M2M Data Visualizer には、あらかじめTerminal System 2で測定した音声に適したデータ設定(Audio)があるので、それを インポートして使用 して、スペクトグラムで表示します。 音声データ スペクトグラムからもカーナビの声、ウインカーの音がわかる状況になっていました。音声を再生するとエンジン音もちゃんと撮れているので問題なさそうです。 Vibrationの測定 こちらも簡易的に取得可能な、EDGEPLANT T1に搭載されている u-blox社の NEO-M8U を使用します。このモジュールはGPSの位置情報以外にも加速度センサーの情報も取得できるので、今回はこの情報を使用します(ただ、キャリブレーションについてちょっとクセがあるので、その点は付録としてこのブログの最後に記載しておきます)。 設置はマイク同様に運転席と助手席の間の床部分に養生テープで固定しています。EDGEPLANT T1は車進行方向左側にLANのポートが来るように設置します。 EDGEPLANT T1 それでは、データをとって確認してみます。 こちらも Visual M2M Data Visualizer に、あらかじめTerminal System 2で測定したGPS/加速度情報などに適したデータ設定(UBX)があるので、それを インポートして使用 して、ライングラフで表示します。 加速度データ 値はそれぞれ以下のようになります。 xAccel:車正面への加速度 yAccel:車側面(右方向)への加速度 zAccel:車下面への加速度 車とIMUの軸( u-blox 8 / u-blox M8 Receiver description Including protocol specification より引用) こちらも必要なデータは取れていそうです。 Harshnessの算出 最後にHarshnessを算出です。 流れとしては、 測定済みのVibrationのデータを取得 Vibrationの値からHarshnessを算出 Harshnessの値をintdashに保存 となります。 1.と3.の手順は、intdash SDK for Pythonの ドキュメント にチュートリアルとしてそれぞれ記載されています。 時系列データを取得する 時系列データをサーバーに保存する そのため、ここでは 2. についてのみ詳細を説明します。 Harshnessの計算方法ですが、僕が調べた限りでは、具体的にこうという計算方法の定義は見つけられませんでした。 そのため今回は「路面の凹凸による突き上げ」と限定して、単純な計算式でやってみようと思います。 路面の凹凸に乗り上げた場合にどうなるかを想像すると、上方向への加速度と後ろ方向の加速度が発生しそうです。そこで「上方向への加速度(マイナス方向のxAccel)」+「後ろ方向の加速度(マイナス方向のzAccel)」 = Harshness として簡易的に計算してみます。 具体的には、逆方向の成分は無視したり、重力加速度を考慮する必要があるので以下の計算式で測定してみます。 min(0, xAccel) + max(0, zAccel + 9.8) = Harshness (後述しますがこの仮説モデルは適切ではないです) 上記仕様で作成したpythonのコード 2 は付録に記載しておきます。 サーバーのアドレス、APIトークン、対象の計測UUIDを指定して実行すると、Harshnessを計算しサーバーに保存します。 # ./upload-harshness.py $SERVER $TOKEN $MEASUREMENT_UUID ...省略... 2023-12-09 23:26:55.502140890+00:00 x_accel -0.21 z_accel -9.79 harshness -0.21 2023-12-09 23:26:55.692299440+00:00 x_accel -0.27 z_accel -9.89 harshness -0.36 2023-12-09 23:26:55.909226218+00:00 x_accel -0.22 z_accel -9.81 harshness -0.23 2023-12-09 23:26:56.100891502+00:00 x_accel -0.19 z_accel -9.82 harshness -0.21 実車でとってみる それではデータを測定して確認してみましょう。 今回は私用でレンタカーを借りて移動する機会があったので、そこで測定してみました。 車はダイハツ・ムーヴです 走った場所 道路上にある段差(段差①)と、橋のつなぎ目(段差②)を走行してみました。 段差① 段差② 測定結果(NoiseとVibration) 測定データ 段差①、段差②ともに、音声も加速度センサーも段差によって発生した値が出ています。 また、今回の説明では省略しましたが、y軸に対する角加速度 y AngRate も段差で顕著に反応しているようです。 算出結果(Harshness) 上記データに対してpythonのコードを実行してHarshnessもあわせて表示していみます。 Harshness 一応、段差で反応していますが、段差以外のブレーキをかけたところでも同程度に反応してしまってますね。。。 これは仮説のモデルが適切ではなかったということになります。 仮説では、 「後ろ方向の加速度(マイナス方向のxAccel)」+「上方向への加速度(マイナス方向のzAccel)」 = Harshness としたため、段差に乗り上げると、「後ろ方向の加速度」と「上方向の加速度」に同等に影響があるという想定になっていたのですが、 実際には「上方向の加速度」への影響がほとんどのようです。 また、測定データの結果から、段差に乗り上げた際には 衝突音は声や電子音に比べて、広い周波数で音が発生する y軸方向の角加速度が発生する といった傾向が見られているので、この辺りも利用するとHarshnessの算出に役立ちそうです。 今回はここまでしか行いませんが、一度測定したデータはサーバーに上がっているので、Harshnessの計算式を変えて新たにデータを上げることももちろん可能です。 まとめ Noise、Vibration、Harshnessのデータを弊社の intdash に送ることで、データを可視化しました。 簡易的なセンサーで Noise、Vibrationのデータ測定を行いましたが、段差に応じたデータを測定できました。 Harshnessの算出には仮説のモデルが適切ではなかったため、期待とは異なる結果でした。 ただ、intdashを利用してデータを集め・解析を行い・モデルを検証するという作業を、簡単に構築できるということは示せているのではないかと思います。 今回は、音声とGPS(加速度センサー込み)しか取得していませんが、弊社のシステムではあわせて、動画、CAN、アナログデータなども同時に簡単に取得できる仕組みも入っていますので、これらのデータもHarshnessの算出に利用していただくことも可能です。 付録 加速度センサーのキャリブレーション NEO-M8Uの加速度センサーは、キャリブレーションが行われた後でないと値は出力されません。 キャリブレーションはGPSを捕捉してから、左右に曲がることでキャリブレーションが完了するようです。 u-blox 8 / u-blox M8 Receiver description Including protocol specification には以下のように記載があります。 Drive curves and straight segments during a few minutes by including a few stops lasting at least 30 seconds each. This drive should also include some periods with higher speed (at least 50 km/h) and can typically be carried out on normal open-sky roads with good GNSS signal reception conditions. 僕の感覚ですと、GPSを捕捉した状態で、狭い以下のように、右折→右折→右折→左折や左折→左折→左折→右折という動きを行うとキャリブレーションされやすいようです。 キャリブレーション 一度キャリブレーションが完了した後ですが、EDGEPLANT T1の場合は電源ケーブルを抜かなければ、IG Off 状態でも保持されており、次回 IG On 時はキャリブレーションは不要になります。 Harshnessの計算に使用したコード 本文中に記載してありますが、このHarshnessの仮説モデルは適切ではないので、使用する場合はモデルとなる式の部分を適宜変更してください。 #!/usr/bin/env python3 # coding: utf-8 import argparse import struct import intdash from intdash import timeutils def harshness_generator(x_accel, z_accel): # 前後方向加速度 x_accel と 上下方向加速度 z_accel からハーシュネスを計算する # x_accel, z_accel は 100倍された値が入ってくる # 前後方向は後方向の値のみ使用する x_accel_positive = -1 * min(x_accel, 0) # 上下方向は上方向の値のみ使用し、重力加速度成分を除去する z_accel_positive = max(980 + z_accel, 0) # ハーシュネスは 後方向加速度 * 上方向加速度とする。倍率も補正する。 return (x_accel_positive + z_accel_positive) / 100 def generate_and_upload(measurement, data_points, generator): it = data_points.list( measurement_uuid=measurement.uuid, # 計測の全てのデータポイントを取得したいので、時間はによる取得制限はしない start=timeutils.str2timestamp("2000-01-01T00:00:00.000000Z"), end=timeutils.str2timestamp("2100-01-01T00:00:00.000000Z"), id_queries=[ intdash.IdQuery( data_type=intdash.DataType.bytes, data_id="UBX-HNR-INS", ) ], iterator=True, ) # 取得したデータポイントのペイロードは、iSCP v1のデータ型 bytes のフォーマットになっている # # 7 6 5 4 3 2 1 0 # +---+---+---+---+---+---+---+---+ # 000 | ID Length (11) | # +---+---+---+---+---+---+---+---+ - - - - # 001 | ID (U) | ^ # + + | ID Length # | (B) | | # + + | # | (X) | | # + + | # | (-) | | # + + | # | (H) | | # + + | # | (N) | | # + + | # | (R) | | # + + | # | (-) | | # + + | # | (I) | | # + + | # | (N) | | # + + | # | (S) | v # +---+---+---+---+---+---+---+---+ - - - - # 012 | Data | # + + # : : # # データ型 bytes のDataの部分には、u-blox M8 のUBX-HNR-INSのバイナリデータが入っている # (u-blox M8 に仕様書 https://content.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_UBX-13003221.pdf) # # 7 6 5 4 3 2 1 0 # +---+---+---+---+---+---+---+---+ # 012 | Header (0xB5) | # + + # | (0x62) | # +---+---+---+---+---+---+---+---+ # 014 | Class (0x28) | # +---+---+---+---+---+---+---+---+ # 015 | ID (0x28) | # +---+---+---+---+---+---+---+---+ # 016 | Length (36) | # + + # | (0) | # +---+---+---+---+---+---+---+---+ # 018 | bitfield0 | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 022 | reserved1 | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 026 | iTOW | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 030 | xAngRate [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 034 | yAngRate [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 038 | zAngRate [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 042 | xAccel [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 046 | yAccel [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 050 | zAccel [Scaling 1e-3] | # + + # | | # + + # | | # + + # | | # + + # +---+---+---+---+---+---+---+---+ # 054 | Checksum | # + + # | | # +---+---+---+---+---+---+---+---+ # # 上記バイナリデータをstructで定義し、 # xAngRate, yAngRate, zAngRate, xAccel, yAccel, zAccel が取り出せるようにする ubx_hnr_ins = struct.Struct("<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiixx") harshness_dps = [] for lst in it: for dp in lst: _, _, _, x_accel, _, z_accel = ubx_hnr_ins.unpack(dp.data_payload) # if z_accel >= 0: # continue # 加速度データからharshnessを計算 harshness = generator(x_accel, z_accel) # 値をログ print( dp.time, "x_accel", x_accel / 100, "z_accel", z_accel / 100, "harshness", harshness, ) # intdash Serverへアップロードするのデータポイントを作成 harshness_dps.append( intdash.DataPoint( elapsed_time=dp.time - measurement.basetime, data_type=intdash.DataType.float, channel=1, data_payload=intdash.data.Float( data_id="Harshness", value=harshness ).to_payload(), ) ) # intdash Serverへアップロード data_points.store( measurement_uuid=measurement.uuid, data_points=harshness_dps, ) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate and upload harshness") parser.add_argument( "server", type=str, help="Server URL (e.g. https://xxxx.intdash.jp)", ) parser.add_argument( "token", type=str, help="API token", ) parser.add_argument( "measurement_uuid", type=str, help="Measurement UUID", ) args = parser.parse_args() print(args) client = intdash.Client(url=args.server, edge_token=args.token) measurement = client.measurements.get(uuid=args.measurement_uuid) data_points = client.data_points generate_and_upload(measurement, data_points, harshness_generator) device-connector-intdash v2.0.0 以降を利用することでEDGEPLANT T1に内蔵されているIMUを簡単に使用できます。Terminal System 2ではdevice-connector-intdash v2.0.0以降がインストールされています。 ↩ データポイントをパースするには、バイナリがどのようなフォーマットなのかを確認する必要があります。今回のように Visual M2M Data Visualizer にあらかじめデータ設定の定義がある場合は、そちらの内容を確認することで必要な値を取得するためのフォーマットを知ることができます。 ↩
アバター
aptpod Advent Calendar 2023 12月12日を担当するintdashグループの呉羽です。 弊社が提供する intdash は、Webhook機能の実装を予定しています。Webhookとは、何らかのイベントの発生時、intdashのサーバーから指定のエンドポイントにHTTPリクエストを送信する機能です。この機能によってイベントを起点としたプログラムをHTTP通信で実行できるため、ポーリングやメッセージングシステムの利用は不要です。 そこで今回は、WebhookのHTTPリクエストを受け付けるアプリケーションをAWS上に実装し、実際に動作させるまでの手順をご紹介します。 1. AWS SAMを使ったアプリケーションの構築 sam init コマンドによるテンプレート生成 sam deployでデプロイ Amazon SNSをCloudFormationに追加する 2. Go言語を用いたアプリケーションの実装 HTTPリクエストのBodyの検証 データの取得と集計 3. Webhookのテスト実行 まとめ アプリケーション例として、イベントを起点にデータをAmazon Lambda上で集計し、集計結果をAmazon SNSを通じてメール通知するものを作ります。アプリケーションのフローは以下のようになります。 Webhookの流れ これらの内、intdashが提供するのは2つのサービスです。 Measurement_Service(計測データを保存するサービス) Webhook_Service(イベントに応じてHTTPリクエストを行うサービス) intdashにおける計測とは、時系列データをまとめ、識別するためのリソースのようなものです。計測の作成時や終了時にイベントが発行され、それらをWebhookで通知します。今回のアプリケーションは計測の終了時に実行されることを想定します。 それでは、おおまかに以下のように開発を進めていきます。 AWS SAMを使ったアプリケーションの構築 Go言語を用いたアプリケーションの実装 Webhookのテスト実行 1. AWS SAMを使ったアプリケーションの構築 AWS Serverless Application Model (以下、AWS SAM) は、AWS 上でサーバーレスアプリケーションをコマンドラインから構築できるツールです。以下のような手順で、お手軽に構築できます。 AWS SAM CLIをインストールする sam init コマンドでガイドに従いながらテンプレートを生成する sam build && sam deploy コマンドでAWS上にデプロイする それでは実際に試してみます。今回用いるAWS SAM CLIのバージョンは 1.103.0 です。 sam init コマンドによるテンプレート生成 sam init コマンドを実行するといくつかの質問がなされるので、以下のように回答します。 $ sam init You can preselect a particular runtime or package type when using the `sam init` experience. Call `sam init --help` to learn more. Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Choose an AWS Quick Start application template 1 - Hello World Example 2 - Data processing 3 - Hello World Example with Powertools for AWS Lambda 4 - Multi-step workflow 5 - Scheduled task 6 - Standalone function 7 - Serverless API 8 - Infrastructure event management 9 - Lambda Response Streaming 10 - Serverless Connector Hello World Example 11 - Multi-step workflow with Connectors 12 - GraphQLApi Hello World Example 13 - Full Stack 14 - Lambda EFS example 15 - Hello World Example With Powertools for AWS Lambda 16 - DynamoDB Example 17 - Machine Learning Template: 1 Use the most popular runtime and package type ? ( Python and zip ) [ y/N ] : N Which runtime would you like to use? 1 - aot.dotnet7 ( provided.al2 ) 2 - dotnet6 3 - go1.x 4 - go ( provided.al2 ) 5 - go ( provided.al2023 ) 6 - graalvm.java11 ( provided.al2 ) 7 - graalvm.java17 ( provided.al2 ) 8 - java21 9 - java17 10 - java11 11 - java8.al2 12 - java8 13 - nodejs20.x 14 - nodejs18.x 15 - nodejs16.x 16 - nodejs14.x 17 - python3. 9 18 - python3. 8 19 - python3. 7 20 - python3. 12 21 - python3. 11 22 - python3. 10 23 - ruby3. 2 24 - ruby2. 7 25 - rust ( provided.al2 ) 26 - rust ( provided.al2023 ) Runtime: 3 What package type would you like to use? 1 - Zip 2 - Image Package type: 1 ... すると以下のようなディレクトリが生成されます。 % tree sam-app sam-app ├── Makefile ├── README.md ├── events │ └── event.json ├── hello-world │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── main_test.go ├── samconfig.toml └── template.yaml hello-world/main.go がLambdaで実行されるファイルとなります。 package main import ( "fmt" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ) func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error ) { var greeting string sourceIP := request.RequestContext.Identity.SourceIP if sourceIP == "" { greeting = "Hello, world! \n " } else { greeting = fmt.Sprintf( "Hello, %s! \n " , sourceIP) } return events.APIGatewayProxyResponse{ Body: greeting, StatusCode: 200 , }, nil } func main() { lambda.Start(handler) } sam deploy でデプロイ まずはそのままデプロイしてみましょう。 sam build && sam deploy コマンドを実行すると、AWS上にCloudFormationのスタックが1つ生成され、その中でAPI GatewayやLambda、IAM Roleなどが追加されています。 CloudFormation stack changeset ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Add ApplicationInsightsMonitoring AWS::ApplicationInsights::Application N/A + Add ApplicationResourceGroup AWS::ResourceGroups::Group N/A + Add HelloWorldFunctionCatchAllPermissionProd AWS::Lambda::Permission N/A + Add HelloWorldFunctionRole AWS::IAM::Role N/A + Add HelloWorldFunction AWS::Lambda::Function N/A + Add ServerlessRestApiDeployment47fc2d5f9d AWS::ApiGateway::Deployment N/A + Add ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A + Add ServerlessRestApi AWS::ApiGateway::RestApi N/A ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- コマンド実行後、API Gatewayのエンドポイントが出力されます。このエンドポイントは後ほど利用します。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Outputs ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Key HelloWorldAPI Description API Gateway endpoint URL for Prod environment for First Function Value https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ Amazon SNSをCloudFormationに追加する 今回はメール通知を行うため、以下の対応が必要です。 Amazon SNSのTopic・Subscriptionの作成 LambdaのIAM Roleに、SNSのPublish権限を付与 AWS SAMでは、それらも簡単に行えます。 sam init で生成された template.yaml がCloudFormationのテンプレートです。SNSのTopicとSubscriptionを追加するには、 Resources 配下に以下を追加します。 Resources : ReportingTopic : Type : AWS::SNS::Topic ReportingTopicSubscription : Type : AWS::SNS::Subscription Properties : Endpoint : your-address@example.com Protocol : email TopicArn : !Ref ReportingTopic 次に Resources.HelloWorldFunction.Properties に以下の Environment と Policies を追記します。 Resources : HelloWorldFunction : Properties : Environment : Variables : SNS_TOPIC_ARN : !GetAtt ReportingTopic.TopicArn Policies : - Version : "2012-10-17" Statement : - Effect : Allow Action : - sns:Publish Resource : !Ref ReportingTopic Environment にSNS TopicのARNを渡し、Lambda側でSNSに通知する際に利用します。また Policies で LambdaのIAM Roleに、SNSのPublish権限を付与しています。 そして sam build && sam deploy --guided コマンドを実行すると、AWS上にリソースが作成されます。Amazon SNSからメールを受け取るためにはメールの認証が必要のため、デプロイ後に届いた認証用リンクにアクセスしておきましょう。 2. Go言語を用いたアプリケーションの実装 アプリケーションの実装に入ります。以下の手順で実際のコード例と共に解説します。 HTTPリクエストのBodyの検証 データの取得と集計 SNSへの通知 HTTPリクエストのBodyの検証 WebhookのHTTPリクエストがintdashから送信されたものであることを検証するために、 x-intdash-signature-256 Headerを利用します。このHeaderには、SHA-256アルゴリズムでHTTPリクエストのBodyをHash化した値が入っています。Hash化する際に秘密鍵を利用しており、この秘密鍵をお客様とintdash側で共有することで、第三者がHTTPリクエストを偽造できないようになっています。 以下はGo言語でHash値の検証を行う例です。Headerにはbase64でエンコードされた値が入っているため、デコードしてからハッシュ値を比較します。 func (h *Handler) validateSignature(ctx context.Context, request events.APIGatewayProxyRequest) error { const IntdashSignatureHeader = "x-intdash-signature-256" signature := request.Headers[IntdashSignatureHeader] if signature == "" { return fmt.Errorf( "signature header %q is empty" , IntdashSignatureHeader) } wantSum, err := base64.StdEncoding.DecodeString(signature) if err != nil { return fmt.Errorf( "decode signature: %w" , err) } hasher := hmac.New(sha256.New, h.SHA256Key) hasher.Write([] byte (request.Body)) sum := hasher.Sum( nil ) if !hmac.Equal(wantSum, sum) { return fmt.Errorf( "signature mismatch, want %x, got %x" , wantSum, sum) } return nil } 検証完了後、Bodyをパースします。intdashのWebhookではJSONの resource_type と action プロパティに、「どのリソースで」「何のイベントがあったか」を格納します。 今回の例では以下のように resource_type に measurement 、 action に finished が格納されています。 { " resource_type ": " measurement ", " action ": " finished ", " measurement_uuid ": " xxxxxxx " } またイベントの種類によって measurement_uuid のようなプロパティも追加で格納され、アプリケーションで利用できます。 データの取得と集計 簡略化のため、今回は実際にデータ取得をする代わりに「平均100、標準偏差15の正規分布から抽出した1000個の値を返す」実装をスタブとして利用します。 type IntdashAPIStub struct {} func (s *IntdashAPIStub) FetchFloat64DataPoints(ctx context.Context, measurementUUID string ) ([] float64 , error ) { r := rand.New(rand.NewSource( 0 )) res := make ([] float64 , 1000 ) for i := range res { res[i] = r.NormFloat64()* 15 + 100 } return res, nil } あとはデータを集計し、メールの本文を生成します。今回は得られたデータの平均と不偏分散を集計して通知してみましょう。 func (h *Handler) makeNotificationBody(dataPoints [] float64 ) string { var sum float64 for _, v := range dataPoints { sum += v } avg := sum / float64 ( len (dataPoints)) var variance float64 if len (dataPoints) > 1 { var dss float64 // deviation sum of squares for _, v := range dataPoints { dss += (v - avg) * (v - avg) } variance = dss / float64 ( len (dataPoints)- 1 ) } return fmt.Sprintf( "Average: %f \n " + "Unbiased Variance: %f \n " , avg, variance) } 最後にSNS Topicへ先ほど生成した本文をPublishすれば、メールが送信されます。 func (h *Handler) PublishSNS(ctx context.Context, body string ) error { out, err := h.SNSPublishAPI.Publish(ctx, &sns.PublishInput{ TopicArn: aws.String(h.SNSTopicArn), Message: &body, }) if err != nil { return fmt.Errorf( "publish SNS: %w" , err) } return nil } 以上が大まかな実装方針です。実装後も sam build && sam deploy コマンドを実行すれば、自動でAWS上のリソースを更新してくれます。 ここでは重要なコードのみを紹介しましたが、全体のコードを見たい場合はGitHubに公開している aptpod/intdash-webhook-example をご参照下さい。 3. Webhookのテスト実行 それでは実際にWebhookの動作をテストしてみます。intdashでは以下のようにAPIを通じてWebhookを登録し、HTTPのエンドポイントと、 x-intdash-signature-256 Headerで利用する秘密鍵を指定します。 curl -X POST " https://intdash.example.com/api/hooks " \ -H " Content-Type: application/json " \ -d ' {"url": "https://your-api-gateway-endpoint.example.com/hello/", "secret": "your-secret-here", "measurement_events": true} ' 次にintdashのMeasurement_Serviceにデータをアップロードし、計測を終了します。今回はWebhookとそのアプリケーション実装法のご紹介が目的のため、intdashへの実際のアップロード手順は割愛しますが、おおまかには以下のような手順となります。 計測を作成する 計測にデータを送信する 計測を終了させる 計測の終了後、intdashのWebhook_ServiceがAPI GatewayにHTTPリクエストを送信します。しばらくするとSNSに登録したメールアドレスに集計結果が届きました。 Amazon SNSからの集計結果メール これで一連の動作確認が出来ました。またintdashでは、以下のようにテスト実行用のAPIを叩くことで、実際のイベントが起きていなくとも架空のイベントが発行でき、テストが可能となっています。 curl -v -X PUT " https://intdash.example.com/api/hooks/:id/test " \ -H " Content-Type: application/json " \ -d ' {"resource_type": "measurement", "action": "finished"} ' その他にも x-intdash-signature-256 Headerと共に、手元から直接API Gatewayにリクエストして検証する方法もあります。 まとめ WebhookのアプリケーションをAWSに実装し、intdashのWebhook機能を利用する例をご紹介しました。AWS SAMでは以下のような特徴があります。 サーバーレスな構成となっているため、サーバーの費用は主にLambdaのみで安価に運用できる。 アプリケーションを削除する場合は、CloudFormationのスタックの削除ボタンを押せば一括で削除できる。 AWS SAM CLIによってローカルでもサーバーを立ち上げられる。 また今回は x-intdash-signature-256 HeaderによってHTTPリクエストを検証しましたが、API Gatewayに認証をかける事も可能です。 このようなWebhookを利用したアプリケーションの構築はAWS SAMで手軽に構築できます。ぜひ利用してみてはいかがでしょうか。
アバター
2023 Advent Calendar 12月11日を担当します、コーポレート・マーケティング室、デザインチームの高森です。アプトポッドのデザインチームでは、2022年からメインのUIデザインツールとしてFigmaを使用しています。 デザインチームでは実証実験向けにプロトタイプを作成することがあるのですが、今回カーナビアプリの機能検証をウィザード法(製品やシステムを人間が完成しているように動かすプロトタイプ技法)で行う実証実験にて、Figmaでプロトタイプを作成する機会がありました。(その他のプロトタイプ事例は 過去のAdvent Calendar でも紹介させていただきました) 今回やや苦労したのが、 音声再生が必要 という点でした。現在Figmaには動画ファイルを再生できる機能はありますが音声ファイルを埋め込める機能がありません。プラグインを使って他のアプリと連携等で作成することは可能でしたが、お客さんへ納品するためなるべく複数のアプリケーションを使用せず、かつ安定した挙動で実施できる方法を模索していました。結果、Figmaのみで実現することができたためその内容を簡単に紹介したいと思います。 プロトタイプの概要 ツールの検討 Figmaファイルへの音声取り込み方法 プロトタイプの作成方法 スマートフォンに表示するバナーとタイミングをPCから制御 スマートフォンにバナーが表示されるときに、音声ガイドも再生される スマートフォンに表示されたバナーから外部リンクへの遷移はスマートフォンから操作する まとめ プロトタイプの概要 プロトタイプの条件は以下です デバイス ノートPC(Windows)、スマートフォン(iOS) 実験手順 被験者にプロトタイプを見ながら(実際にはカーナビと並べて配置、ナビ機能はカーナビを利用)運転してもらう 任意のタイミングで後部座席に同乗している実験者がプロトタイプ画面にバナーを表示する 被験者がバナーに反応しなければバナーは一定時間経過で非表示、被験者が停車中にバナーをタップすると外部リンク(モバイルサイト)が表示される 必要な挙動 スマートフォンに表示するバナーとタイミングをPCから制御 スマートフォンにバナーが表示されるときに、音声ガイドも再生される スマートフォンに表示されたバナーから外部リンクへの遷移はスマートフォンから操作可能にする プロトタイプの構成 ツールの検討 ツールの選定軸として、日常的に使っているAdobe系のツールやデザインツールの範囲で、 必要な時だけ、学習コストをかけずに 作成できる点をベースに検討を始めました。さらに今回は音声再生、異なるデバイス間での画面制御が行える方法として、Figma以外にも以下のツールを検討しました。 メリット 懸念点 Figma 通常業務で使っているアプリのためツールに慣れている 今後も管理しやすい 音声ファイルそのままではプロトタイプに埋め込めない オフライン環境で利用できない Adobe XD 音声ファイルが扱いやすい ファイルをローカルに保存しておくことでオフライン環境でも利用可能 Figmaにくらべてツールを習熟していない すでに販売終了してアップデートもされていないため今後の管理を考えると不安がある Proto Pie Proto Pie Connect という拡張機能を使うことで、異なるデバイス間でプロトタイプの実施が可能 ミラーリングではないためより実体験に近いプロトタイプを作成できる。(送信レスポンスを送り、別のデバイスで受け取ってアクションを実行) FIgmaのデザインファイルを取り込み可能 音声ファイルが扱いやすい Proto Pie Connectの機能は有料(Proアカウント以上で利用可能)のためお客さん側にも追加費用が発生する 通常業務で使っていないためツールの習得に時間がかかる Figma + Vysor パソコンとスマホを有線/無線でミラーリングできるツール 使い慣れたツールでデザインを作成できる ドングルを利用することでBluetoothでパソコンとスマホを接続可能 iPhoneへのミラーリングはドングルが必要 Figmaの起動自体がネットワーク環境を前提にしているため今回のモックではあまりメリットがない ネットワークが繋がらない場合でも使える様にしておく必要があるかという点も大きな検討要素となりますが、今回はポケットwi-fi等で常にネット環境下であるとのことでした。 音声ファイルを問題なく扱えるAdobe XDがもっとも手軽ではあったのですが、すでに販売終了してアップデートもされていないため今後の管理に不安が残る点から、Figmaで作成を進める判断になりました。 Figmaファイルへの音声取り込み方法 音声ファイルの取り込みについては、音声ファイルを動画ファイルに変換する作業を挟むというシンプルですがやや力技な方法で対応しました。 音声ファイルを動画ファイルへ変換(今回はmp4に変換しましたが、.mov、.webm形式にも対応しています) 動画ファイルを再生したいフレームに配置 音声ファイルが画面上に表示されないように調整する(透明度0では音声再生されないため背面のレイヤーに配置する等で調整する) ポイントとしては自動変換できるファイルコンバーターを使用して作成した動画ファイルはエラーが発生して取り込むことができなかったため、Premiere等の動画編集アプリを利用して音声ファイルを取り込み、適当な画面サイズにして書き出した動画ファイルを使用するという点です。この時、ファイルサイズを軽くするため、画面サイズは可能な限り小さくしておくと、ファイルサイズを圧迫せず扱いやすいです。 プロトタイプの作成方法 プロトタイプの作成方法については、Figmaのプロトタイプ機能の範囲でできるため簡単に記載しておきます。 スマートフォンに表示するバナーとタイミングをPCから制御 → Figmaのミラーリング機能で実施。任意のタイミングで実験者がスマートフォンにミラーリングするFigmaのフレームをクリック スマートフォンにバナーが表示されるときに、音声ガイドも再生される → 表示と同時に再生されるように設定しておく スマートフォンに表示されたバナーから外部リンクへの遷移はスマートフォンから操作する → バナーをタップすると外部ページが開くようにリンクを作成 まとめ 以上、Figma単体で音声ファイルを再生するプロトタイプ作成例の紹介でした。 ネットワーク環境によって動作の安定性に不安がありましたが、地下5階程度の駐車場ではややディレイがあったものの、それ以外では問題なく安定して稼働したとのことでした。 日常的にFigmaを使用している方には簡単に作成できるプロトタイプのため、音声再生が必要になった際の参考事例になれば嬉しいです。
アバター
aptpod Advent Calendar 2023 12月8日の記事です 入社1ヶ月目のソリューションアーキテクトの奥山です。まだまだペーペーの私ですが、よろしくお願いいたします。 毎日がキャッチアップの連続で頑張っています。この記事では、intdashとはなんぞやから、実際に家にあるものでintdashを変に試しつつ、覚えたての知識をOutputしてみようというものです。 僕はいろんなガジェットを試しては壊し、試しては壊しを繰り返して遊んでいるせいか、最近どうやら物価高の影響で(先月のブラックフライデーもあり)引き落とし額がえらいことになっていました。そんな僕に優しく微笑んでくれたのが格安高性能カメラATOM Cam2です。さぁ、壊して学ぶ時間です。(注:壊したりはしません) ATOM Cam2とは ATOM Cam2 はAIカメラです。なんとこのカメラ、単体クローズドでモーション検知やらいろいろ機能がついていて、IP67で、それでいて4000円弱という素晴らしいカメラなんですね。(下記の写真左側です) お財布事情が寂しい僕としては、とてもありがたいガジェットです。玄関に監視カメラ用途でつけておくという使い方もできそうです。 そしてふと思いました。このATOM Cam2をintdashに接続できないかと、、、 ってことでやってみることにしました。 intdashとは おそらく、この記事を見ている方はintdashはすでに知っているという人の方が多いかもしれませんが、僕のお勉強にお付き合いください。 intdash 低遅延、高スループット 完全性(データ回収率100%) データフォーマットの多様性 時系列データ スケーラビリティ 開発部品のパッケージ化による開発容易性 簡単に言うと、取説を見て取説通りにやればIoT化ができ、しかもデータ完全性など独自検討しなければならない部分もすでに実装済みで至れり尽くせりという素敵仕様なIoTプラットフォームです。 AWS IoTなどで構築すると、カメラをクラウドアップロードするだけでも学習コストが発生する上、よく性質を理解した上で取り扱わなければなりません。intdashを使うとUSBカメラからのアップロードと可視化が学習コストほぼ無く作れてしまうという優れものです。 UIのセンスが無い僕としてはありがたい存在です。 実際にやってみた 全体像 まずは、全体像です。 ATOM Cam2側の設定 最初にATOM Cam2を ユーザーマニュアル の通りにセッティングします。 Atomアプリの対象カメラの<設定>-><その他>-><PCで再生>をONにします。 表示される"rtsp://~"のURLをコピーしておきます。 ラズパイ側の設定 ラズパイには、ubuntu:22.04をインストールしました。rasbianOSでも良いのですが、dockerの設定などの手間暇があるので、 intdashのシステム要件 に合わせました。 intdashのインストールは、 ここ を参照してインストール作業を行います。 ATOM Cam2から動画をintdashへ出力してみる まずは、仮想カメラデバイスを作成するために、v4l2loopbackをインストールします。そして、RTSP送信データを仮想カメラデバイスに転送するためのffmpegも同時にインストールします。 sudo apt-get install -y v4l2loopback-dkms ffmpeg ターミナルを2つひらいて、一つは以下のコマンドを実行します。 sudo modprobe v4l2loopback video_nr=0 ffmpeg -rtsp_transport tcp -r 20 -i <ATOM Cam2のRTSP URL> -vf "scale=640:360" -f v4l2 -vcodec mjpeg /dev/video0 v4l2loopbackで/dev/video0という仮想カメラデバイスを作成します。 その後、ffmpegでRTSPをこの仮想カメラデバイスに動画を転送します。 この時、RTSPを送信しているATOM Cam2が非力であるため、うまくデータが送られて来ない可能性があります。そのため、できる限りスケールを下げておくことをお勧めします。 もう一つのターミナルではconf.yamlファイルを作成し、intdashを起動します。 tasks : - id : 1 element : v4l2-src conf : path : /dev/video0 type : jpeg width : 640 height : 360 fps : 20 - id : 2 element : jpeg-split-filter from : [[ 1 ]] - id : 3 element : iscp-v2-compat-filter from : [[ 2 ]] conf : timestamp : stamp : clock_id : CLOCK_MONOTONIC convert_rule : jpeg : name : "jpeg" - id : 4 element : print-log-filter from : [[ 3 ]] conf : interval_ms : 1000 tag : video0 output : stderr - id : 5 element : file-sink from : [[ 4 ]] conf : path : /var/run/intdash/up-hello.fifo create : true flush_size : 100 sudo intdash-agentctl config connection --modify ' server_url: https://XXXXXX.intdash.jp project_uuid: XXXXXXXXXXXXXXXX edge_uuid: XXXXXXXXXXXXXXXXXXXX client_secret: XXXXXXXXXXXXXXXXXXXXXXXXX ' sudo intdash-agentctl config upstream -c ' id: sample-upstream ' sudo intdash-agentctl config device-connector upstream --create ' id: up-hello data_name_prefix: v1/1/ dest_ids: - sample-upstream format: iscp-v2-compat ipc: type: fifo path: /var/run/intdash/up-hello.fifo launch: cmd: device-connector-intdash args: - --config - <conf.yamlのfull path> ' sudo intdash-agentctl run XXXXは、それぞれの環境に合わせて設定します。 これにより、以下のようにintdashに動画がアップロードされていることを確認することができました。 ちなみにATOM Cam2は、Edge側でモーションを検知し、画像として出力しているため、下記のようにモーションを検知したところに緑枠が入ります。 まとめ ATOM Cam2とintdashは頑張れば接続できる。(やろうと思えばカメラはなんでも繋がる) ATOM Cam2はRTSP機能はおまけ機能なので、速度は期待しない方がいい。タイムラグはかなり発生する。 画像を小さくリサイズすればなんとか動く。(画像サイズが大きいとffmpegが停止する。おそらくバッファサイズ大きくすれば良いのかも) モーション検知してもRTSPだとクライアントになにか通知されるわけではない。
アバター
aptpod Advent Calendar 2023 12月7日の記事です。 intdash Edge Agentを使ってみたいけどMacしか持ってないみなさん、 こんにちは。ソリューションアーキテクトの伊勢です。 intdash Edge Agentは Linuxで動きます が、試しに手元のPCで動かしてみたいときがあります。 そんな人のために今回はMacからカメラ映像をUpstreamしてみました。 これは以前、当ブログでご紹介した WSL2でintdash Edge Agentを動かしてみました のMac版です。 tech.aptpod.co.jp おことわり intdash Edge Agent とは Dockerを建てればいいじゃない Parallels Desktop とは 全体図 手順 必要物品を用意する Parallels DesktopでLinux環境を作成する USBカメラを接続する Agentをインストールする カメラ映像をUpstreamする 補足 おことわり 当記事は安定的なデータストリーミングを保証するものではありません。 intdash Edge Agent とは intdash Edge Agent(以下、Agent)は、intdash Edgeの基本機能を提供するエッジデバイス用のエージェントソフトウェアです。ユーザーは、接続するデバイスに応じたプラグインであるDevice Connectorを実装するだけで、様々なデバイスをintdashに接続することができます。このソフトウェアを使用すれば、intdash Edge が提供する自動再送、データ流量の制御といった、エッジ側の基本機能を利用したクライアントアプリケーションを、最小限の追加実装で開発することが可能となります。 Dockerを建てればいいじゃない Agentを動かすだけなら、仮想環境構築ソフトウェアのDocker DesktopでLinuxコンテナを建てれば実現できます。 しかし、この構成だとMacに接続したUSBカメラは利用できません。 MacとLinuxコンテナでデバイスを取り扱う方法が異なり、LinuxコンテナがUSB機器を認識できないからです。 /dev/video*がMacには存在しない そこで Parallels Desktop を使うことにします。 Parallels Desktop とは Parallels Desktop とは、M シリーズチップ搭載Mac向けの仮想環境構築ソフトウェアで、Mac上で異なるOSのアプリケーションを動かすことができます。14日間のトライアル期間は無料で使えます。 なお、intel チップのMacの場合は代わりにVirtual Boxで同様のことが実現できます。 全体図 Parallels Desktopでカメラデバイスを仮想Linuxに /dev/video* として渡すことで、物理Linux機同様にAgentがカメラ映像を収集できます。 カメラデバイスを/dev/video*として認識させる 手順 ざっくりやり方です。 必要物品を用意する Macbook USBカメラ USB Type-A/Type-C変換アダプタ(必要に応じて) 被写体 Logicool C920 Parallels DesktopでLinux環境を作成する MacbookにParallels DesktopをインストールしてUbuntu環境を建てます。 こちらの記事を参考にさせていただきました。 oopsoop.com Ubuntu Linuxを選択 USBカメラを接続する MacbookにUSBカメラを接続します。 被写体はまだ待機 Parallels DesktopウィンドウのUSBアイコンをクリックすると接続したカメラデバイスが認識されていますので、クリックします。 カメラアタッチ前(Macbookのカメラのみが認識されている) カメラアタッチ後( /dev/video6 が増えた) これでカメラデバイスがUbuntuに認識されました。簡単ですね。 Agentをインストールする 今回は最新版のAgent 2( intdash Edge Agent 2 )を利用します。 インストール・設定手順はデベロッパーズガイドの通りです。 docs.intdash.jp docs.intdash.jp カメラデバイスに /dev/video6 を設定 カメラ映像をUpstreamする ストリームを開始します。 MJPEGをストリーム Data Visualizerで確認 Parallels Desktopでカメラデバイスの映像をintdashに送信できました。 これでAgentの動作や、可視化されたデータの確認を進めることができます。実運用ではMacを使うことは少ないと思いますが、手軽にAgentを試せるのは魅力です。 それではメリークリスマス。よい年の瀬を。 補足 残念ながら安定運用には向いていないようで、長時間の利用だと映像が乱れることがありました。 クリスマス向けホラー映画予告編の冒頭風
アバター
aptpod Advent Calendar 2023 12月6日の記事です。 Automotive Pro Grの新崎です。REMOTE CAL開発チームでプロダクトオーナーをしています。 現在リリースされているREMOTE CALにおいてはエッジ端末として EDGEPLANT T1 を前提としていますが、いくつかのお客様から小型端末への対応というご要望をいただいています。 そこで本記事ではその導入として Raspberry Pi を利用したREMOTE CALの疎通実験をした際の様子をご紹介したいと思います。 REMOTE CAL is 何? 実験 事前準備 計測設定を作成 計測スタート まとめ REMOTE CAL is 何? REMOTE CALとは、aptpodのコア製品である低遅延、ハイスループットのIoTミドルウェアintdashを活用し、汎用計測適合プロトコルであるXCP/CCPによるECUの遠隔計測適合を実現するソリューションです。 こちらの記事 や下記のコーポレートサイトでも詳しく紹介されていますので、ぜひご覧ください。 www.aptpod.co.jp 実験 事前準備 今回エッジ端末として自宅で眠っていたRaspberry Pi 3Bに Terminal System とREMOTE CALパッケージをインストールして利用しました。また、同じく自宅で眠っていたRaspberry Pi 4に XCPlite をインストールして対向機のXCP Slaveとして動作させました。 サーバー環境は社内の開発環境を利用しました。 システム構成 計測設定を作成 今回の計測ではXCP SlaveであるXCPliteが一定間隔で出力しているデータを収集し、可視化するところまでをゴールとしたいと思います。 まず、REMOTE CALのWeb ConsoleからA2Lファイルをアップロードします。A2LファイルとはECU 内部の変数の情報や、XCP/CCPなどの通信に必要なパラメータが定義されているファイルで、XCPliteでは起動時に生成されます。 A2Lファイルアップロード 次に、アップロードしたA2Lファイルから計測対象のラベルを選択しDAQ Label Selectionを作成します。 プルダウンよりDAQ Label Selectionを選択 DAQ Label Selection一覧画面 DAQ Label Selectionを作成 今回は上図のように3つのラベルを選択しました。 DAQ Label Selectionが作成されました 最後に、作成したDAQ Label Selectionをエッジに割り当てます。 エッジ端末の一覧画面 計測設定作成画面 A2L Moduleの一覧より選択 チャンネルを指定してApply 今回は1台でしたが、複数のチャンネルを利用して2台以上の対向機を接続し同時に計測することも可能です。 作成した計測設定が表示される これで計測設定が作成できました。 計測スタート エッジ端末を起動すると自動的に計測が開始されます。Edge Finderで見るとデータが流れていることが確認できます。 Edge Finderのトラフィック画面 また、REMOTE CALのWeb Consoleでは Visual M2M Data Visualizer で計測データを変換するための定義ファイルであるdatファイルを計測設定の元になったA2Lファイル内の定義を元に生成することができます。 右上のDownload Datボタンよりダウンロード ダウンロードしたdatファイルをVisual M2M Data Visualizerに設定することで計測データの可視化もできました。 Visual M2M Data Visualizerで計測データを可視化 今回はLine Graphを使用しましたが、Visual M2M Data Visualizerにはこの他にも様々なパーツが用意されていますので、ご希望に合わせたダッシュボードを作成しデータを可視化していただくことが可能です。 ダッシュボードの例 まとめ 今回の実験で、Raspberry Piをエッジ端末として利用したREMOTE CALによる遠隔計測の疎通確認をすることができました。 ただし、Raspberry Pi向けのパッケージをビルドする必要があるなど課題も見つかり、正式に小型端末への対応をリリースするためにはまだまだ検証や対応が必要ですが、引き続き推進していきたいと考えています。 REMOTE CALではトライアル環境のご用意もございますので、導入のご相談、製品に関するご質問や追加機能のご要望等ございましたら、お気軽に こちらのリンク までご連絡ください。
アバター