前回に引きつづきOBDIIの複数PID同時通信についてです。
前回はPCからELM327経由→ECUへ複数のPIDを問い合わせる方法を書きましたが、今回はECU側の実装について書きます。
もちろん実際にECUを作るわけではないのですが、Arduinoを使ったECUシミュレータとか、
これみたいなOBDII対応ECUのふりをするプログラムを作っている関係で、ECU側の実装もトライしてみようとしたわけです。
さて、ECU側がELM327から要求されたPIDに対するセンサ情報を返すとき、
1. ECUはELM327から届いたCANメッセージを解読して、要求されたPIDを抽出する
2. ECUは要求されたPID情報に対応するデータをELM327に返信する
という流れになるわけです。
1ではELM327から送られたメッセージを解析するわけですが、
ここはそんなに難しくなく、PID問い合わせが一つの場合と複数同時の場合でそれほどプロトコルに変更があるわけではありません。
PID問い合わせが一つの場合では、
このWikipediaの"CAN (11-bit) bus format"->"Query"->"SAE Standard"にある通り、ELM327から送られるCANメッセージは
ss 01 aa xx xx xx xx xx
(ssは後続のデータバイトの数。この例では後続データは01 (サービス番号) + PIDの2バイトになることが確定しているのでss=02となる。01はサービス番号で「現在のセンサ値を要求」に対応する。aaが要求するPID)
となります。
PID問い合わせが複数の場合はこれの拡張で下記のようになります。
ss 01 aa bb cc dd ee ff
(ssは後続のデータバイトの数。いくつPIDを問い合わせているかで変わる。01はサービス番号、aa~ffが要求するPID)
となるわけですが、規格上同時に問い合わせるPIDの数は最大6となっておりますので8バイトを超えることはありません。
さて、問題は2のECU→ELM327への返信です。
フォーマット自体は単純で、下のようにただ「PID」+「対応するデータ」を繰り返し列挙するだけです。
41 aa xx bb yy cc zz zz dd uu ee vv ff ww ww
(41は返信用サービス番号。問い合わせのサービス番号+40hなので、01の問い合わせに対しては41を設定する。
aa~ffは問い合わせたPID, xx~zz, uu ~ wwはPIDに対応したデータ。
上の例ではccとffに対応したデータが2バイトであるとしてzzとwwは2バイトになっている(ほかは1バイト)。)
しかしここで問題になるのは、
「CANが1回で送信できるのは最大8バイトまで」
という制約があるということです。Arduino用CANトランシーバ (MCP2515)のライブラリも送信メソッドは8バイトまでしか対応してなく、
上の例では8バイトを余裕で越しているので、そのままでは送ることができません。
そのため、8バイト以上のデータを送信するために複数回に分割して送信するわけですが、送信の手順には決まりがあり、
ISO-TP(ISO15765-2)に従わなくてはならないそうです。
こちらにも説明があります
(送信側が勝手にデータをガンガン送るのではなく、一旦受信側から受信準備ができたのを確認してから(更には受信側が最大何フレーム連続で受信できるかとかも確認しつつ)、送らなくてはならないというわけです)
このような分割処理を一から実装るするのは大変なので、ここは先人の知恵、すなわちライブラリを参照させていただきます。
GithubにArduino用ライブラリを公開されている方がいますので、これを利用させていただくこととします。
これを利用すれば、MCP2515のオブジェクトをラップする形で、任意の長さのバイト配列をISO-TPに則った形で送信することができます。
ブログ一覧 | 日記
Posted at
2023/03/07 00:00:56