はじめに
私は普段、AWSでバックエンドやWebアプリを開発しているITエンジニアです。
業務の一環として車両のデータをクラウドへ収集するプロジェクトを担当することになり、その過程で「CAN」や「J1939」といった、これまで馴染みのなかった物理的な技術領域に触れる機会を得ました。
顧客との打ち合わせの中で当然のように出てくるこれらの単語について、ググった程度の知識で挑んではいましたが、流石にこのままではいけないと危機感を覚え、今回の記事作成に至ります。
CAN (Controller Area Network) の基本概念
J1939を理解するには、まずその土台となっている「CAN(キャン)」を知る必要があります。
ITのイメージで言えば、TCP/IPのさらに下、物理的なネットワークケーブルやハブのルールに近い存在です。一番しっくりきたのは「全ノード(ECU)で共有された、超シンプルなメッセージキュー」というイメージでした。
CANの登場背景
昔のクルマでは、センサーやアクチュエーターといった「機能」が、ECU(車載コンピュータ)と個別の電線で直接つながっていました。これは、各機能が密結合したモノリシックなアーキテクチャのようなもののイメージです。そのため、機能が増えるたびに配線が指数関数的に増え、重く、複雑で、高コストという課題がありました。それを解決するために生まれたのがCANであり、よりシンプルな方式でのデータ通信を可能にしました。
CANの通信方式
CANは、たくさんのECUをたった2本の通信線でリング状につなぎます。
そして、あるECUがメッセージを送信すると、それはネットワーク上の全ECUに届きます(ブロードキャスト)。
この仕組みは、AWS IoT Coreなどで利用されるMQTT通信のモデルに似ています。MQTTでは、ブローカーを介して特定の「トピック」にメッセージを送受信(Publish/Subscribe)しますが、CANの場合はネットワークバス自体がブローカーのような役割を果たします。各ECUは、特定のCAN IDをトピックとしてメッセージをPublishし、また他のECUがPublishしたメッセージをSubscribeしている、と捉えることができます。
データが必要なECUだけが、流れてきたメッセージを「購読」して処理します。
似たような通信プロトコルにModbusがあり、こちらについては少しだけ知見があったりします。
CAN IDによるメッセージ識別
では、大量に流れるメッセージの中から、どうやって必要なものを見分けるのか?
そこで使われるのが「CAN ID」です。これはメッセージのヘッダーに付与される名札のようなもの。「ID:123はエンジン回転数」「ID:456は車速」といったルールが決められています。
Consumer(ECU)側は、このIDを見て自分に必要なメッセージかどうかをフィルタリングします。
J1939プロトコルの概要
さて、ここからが本題です。
J1939とは、先ほどのCAN(特に29bit IDの拡張フォーマット)というインフラの上で動く、より具体的な「アプリケーション層のプロトコル(API仕様)」のようなものです。
主にトラックやバス、建設機械といった「働くクルマ」で使われる、業界標準のAPI仕様と考えると分かりやすいです。
1. PGNによるデータ構造化
CANのIDだけでは「どんな種類のデータか」しか分かりませんでした。J1939では、よりリッチな情報を扱うために「パラメーターグループナンバー(PGN)」という概念を導入します。
これは、構造化されたデータフォーマットの定義、いわば「JSONスキーマ」のようなものです。
例えば「PGN:61444」は「電子制御エンジンコントローラー#1からの情報」というスキーマで、その中には「エンジン回転数」「ドライバーが要求したエンジントルク率」などの複数のデータフィールド(信号)が含まれる、と定義されています。
我々がクラウドで車両データを扱う際は、まさにこのPGNの定義書(API仕様書)を片手に、送られてくるバイナリデータを意味のあるJSONオブジェクトに変換(デコード)していくことになります。
2. アドレスクレームによるネットワーク管理
J1939ネットワークでは、各ECUは0から253までのユニークなアドレスを持ちます。
ECUがネットワークに接続されると、まず「アドレスクレーム」という手続きを行います。これは「私、エンジンECUは、アドレス『0』を使いたいのですが、誰か使っていますか?」と宣言し、重複がなければ自分のアドレスとして確定させる仕組みです。
これはネットワークの世界におけるDHCPや、マイクロサービスにおけるサービスディスカバリの仕組みに非常に似ています。これにより、動的に接続される機器があってもアドレスの競合を避けられます。
3. J1939におけるCAN IDの構造
J1939がすごいのは、CANの29bit IDを単なる識別子ではなく、意味のある複数のフィールドに分割して利用している点です。これは、TCP/IPのパケットヘッダーにソース/宛先ポート番号やフラグが詰め込まれているのと同じ考え方です。
| フィールド | ビット数 | イメージ |
|---|---|---|
| Priority | 3 | QoS(メッセージの優先度) |
| Data Page | 2 | PGNの名前空間を拡張するフラグ |
| PDU Format (PF) | 8 | APIでいうところのエンドポイントの一部 |
| PDU Specific (PS) | 8 | PFの値により宛先アドレス or エンドポイントの一部 |
| Source Address (SA) | 8 | 送信元IPアドレス |
この29bitをパースするだけで、「どのECUが(SA)」「どのECUに(PS)」「どんな種類のデータを(PF+PS)」「どれくらいの優先度で」送っているのかが分かる仕組みです。
4. トランスポートプロトコルによる大容量データ転送
CANのメッセージペイロードは最大8バイトと非常に小さいです。診断情報など、もっと大きなデータを送りたい場合はどうするのか?
そのために「トランスポートプロトコル(TP)」という仕組みが用意されています。これは、大きなデータを8バイトずつに分割(チャンク化)して送信するためのルールです。
全員に一方的に送りつけるBAM方式(UDPのストリーミングに似ている)と、相手の受信確認を取りながら確実におくるCMDT方式(TCPのハンドシェイクに似ている)があります。
まとめ
ここまで、CANとJ1939についてITエンジニアの視点に当てはめて説明してみました。
まだまだ浅い知識ではありますが、案外と普段利用している知識に当てはめて考えることができると分かり現在では以下のような認識です。
CAN: 物理層に近いシンプルなメッセージバス。MQTTのようなPub/Subモデルで理解できる。
J1939: CANの上で動作する、商用車向けの標準的なアプリケーションプロトコル(API仕様)。
また、クラウド視点でのデータ取得の要点としては、CANデータとして送信されてくる29bitのIDと8バイトのペイロードを、J1939の仕様に基づいてパースし、Json形式のような意味のあるデータに変換することです。
この後、デコードされたデータはDynamoDBをはじめとするデータベースに蓄積され、その後の処理やデータ分析へ活用されていきます。
ここで基礎を理解したことで、まずは入口である「CANデータのJ1939の基づいたデコード」という壁を乗り越えることができそうです。
参考文献
Vector Japan Co., Ltd. 「はじめてのJ1939」 [PDF 全体]