Arduinoでヘッドアップディスプレイを自作①OBD2通信テスト

このエントリーをはてなブックマークに追加
2015/04/09 1:05 pm
Blog Category / 制作ログ
 

hudm
憧れのHUD
以前から車載用のヘッドアップディスプレイを作りたいと思っていた。古くはS13シルビア、最近ではレクサスやBMWといった高級車のほか、マツダの各車種にも装備されていて凄く羨ましい。見た目の格好良さもさることながら、実用的にも運転中の視線、焦点をずらさずに時速などを確認できて便利だと思う。実際にHUD装備の車を運転した事があるが、こんな便利な装備がなぜ他の車には用意されていないのか。21世紀をとうに過ぎているというのに未だスタンダードになっていない事態に憤りを感じる。
自作の検討
obd22
最近はスマホ用のHUDアプリがある
自作するには以下の方法が頭に浮かんだ。
①スマホ用のHUDアプリを使い、3Dプリンタ製のマウントと併せて運用
②車のEUCから車速パルスを拾ってArduinoに読み込み、7セグLEDに速度を表示
まず挙げた①のGPSを用いたHUDアプリが一番お手軽だ。スマホのアプリを立ち上げてダッシュボードに置けば画面がフロントガラスに反射してHUDっぽくなってくれる。反射する事を考えて予め表示は反転されており、アプリの種類もデザインも様々。3Dプリンタでスマホを固定するマウントだけ作ればいいだけなのだが、車に乗る度にスマホをいちいちセットするのが面倒臭い。GPSは電池の消耗が激しいので、電源の確保も必要と一見お手軽に見えるも実際にはスマートさに欠ける。
②の方法は自分にとっては少々敷居が高い。車速パルスを拾う事は以前乗っていた軽自動車にナビを自分で取り付けた際に経験済みだが、それをArduino上で速度情報に変換する自信もスキルも無い。ネット上に事例もあるが、色々とややこしそうでたじろいでしまう。
OBD2端子から簡単に信号を取り出せるらしい
obd23
最近の車にはOBD2端子という車両情報通信の為の端子が付いており、ここから簡単に情報を読み込む為の機器が販売されているようだ。ELM327というカナダメーカーのICを使った機器がAmazon等で安価に売られているが、これらはBT通信が基本で、端子から取り出した信号をスマホのアプリと通信して車両情報をスマホディスプレイに映し出す用途を主とする。
僕はスマホと通信させたい訳では無く、自分でも手軽に扱えるArduinoと通信させたい(事例はあるけど、要改造)、ネット上を更に調べていると目的に合致するアイテムが見つかった。
obd2
Freematicsというオーストラリアメーカー?(多分個人運営だと思う)のOBD-II Arduino Adapterが正に自分が求めているものだった。このArduino用アダプタもELM327を使用しているとの事だ。2本のシリアル線と車両経由の電源、アースの計4本の線で簡単にArduinoに車両情報を読み込ませる事ができる。GitHub上にあるArduinoのサンプルスケッチを見たところ、非常に簡単な記述だった。これなら僕でもいけそう。
39.9$のモデルAと59.9$のモデルBがあり、高い方のモデルはArduino互換ボードやGPS、加速度センサー、I2C通信等を内蔵している上位版のようだが自分の場合は車速さえ取り出せればいいのでモデルAを購入。39.9$+EMS送料10$だった。数日後発送したとの連絡があったものの、発送元は中国上海。上海の空港を出発後なかなか荷物追跡のステータスが更新されず焦ったが、発注から1週間程たってから川崎の通関を通過し、程なくして自宅に到着した。
写真 2015-04-03 19 38 21
さすがチャイナクオリティ。緩衝材もなにも無く、この貧弱な紙袋にそのままアダプターが入っていた。しかも袋が臭い。
写真 2015-04-03 19 49 48
目的のブツ
無事荷物が届いたので早速Arduinoに接続してテストしたい。

Arduinoへの接続とライブラリのインストール
写真 2015-04-09 20 55 25
接続はこれだけ。LEDは動作確認用。
アダプタのVccをArduino(サインスマートの安物互換ボード)の5Vへ。GNDはGND。アダプタのTxをArduinoのRxへ、RxをTxと販売元のマニュアル通りに配線。Githubに用意されているライブラリをArduinoIDEに読み込み、サンプルスケッチを書き込んだ。※スケッチ書き込み時にArduinoUnoはシリアル通信を行っているのでRx、Txの配線を外さないとうまく書き込めない。
#include <Wire.h>
#include <OBD.h>

COBD obd; /* for Model A (UART version) */

void setup()
{
  // we'll use the debug LED as output
  pinMode(13, OUTPUT);
  // start communication with OBD-II adapter
  obd.begin();
  // initiate OBD-II connection until success
  while (!obd.init());
}

void loop()
{
  int value;
  // save engine RPM in variable 'value', return true on success
  if (obd.read(PID_RPM, value)) {
    // light on LED on Arduino board when the RPM exceeds 3000
    digitalWrite(13, value > 3000 ? HIGH : LOW);
  }
}
 obd.read(PID_RPM)という記述で車両の回転数をリクエストしている。上記のサンプルコードだと3000回転以上でArduino_13番デジタルピンのLEDが点灯するという内容。回転数やスピードだけでは無く、スロットルポジションや外気温、水温、排気温度等、ありとあらゆる情報が読み取れる。
反応が無い
Arduinoへ配線したアダプタを早速車両のOBD2端子へ接続。自分の車は2015年製ホンダオデッセイRC1で、OBD2端子はアクセルペダルの真上あたりにあった。
端子へアダプターを接続したところエンジン始動前からArduinoの通電LEDが点灯した。どうやら常時通電らしい。
エンジンを始動し、エンジン回転を3000回転以上に上げる。LEDが光れば動作チェックOKだけど………全く反応が無い。光らない。なんでや!配線もスケッチも間違い無いはず。OBD2アダプタは内蔵されているLEDが光って動作しているようだが、ライブラリに問題があるのだろうか。しかし少し古いライブラリを探して入れたりしても結果変わらず。これ、俺の車に対応していないのか。
問題はライブラリにあった
ものは試しとヨメの車(トヨタIQ)へ接続してみたところ、指定回転数で呆気無くLEDが点灯。という事は配線もスケッチにも問題は無い。普通は事前に自分の車が対応しているかどうか調べてから買うものだとは思うが、そこの部分を調べてみた。これで非対応だったら俺ただの馬鹿だ。
調べてみたところ、2010年以降のホンダ車はOBD2の通信プロトコルは殆どがCAN 500kbps/29bitだという事が分かった。このアダプターの対応プロトコルは
  • CAN 500Kbps/11bit
  • CAN 250Kbps/11bit
  • CAN 500Kbps/29bit
  • CAN 250Kbps/29bit
  • KWP2000 Fast
  • KWP2000 5Kbps
との事なので、動く筈なんだ。そして引き続き調べていると、購入先のFreematicsのフォーラムで気になるトピックを見つけた。
フォーラムでは、ISO9141-2というアダプタ対応の通信プロトコルの車なのにサンプルスケッチが動かねえ。的な内容で、Freematics代表のstanleyが「調べるから」と返事したものの放置プレイ。質問主が「進展は?」と聞いてもスルー。結局翌年になって他のユーザーが解決策を公開するという顛末だった。酷えなstanley、ちゃんとサポートしろよ。
解決した方法はライブラリの通信プロトコル指定は通常AUTOのところ、自分の車両プロトコルに該当する記述に置き換えるという事。フォーラムの解決方法はI2C通信を用いるモデルBでの事例だが、ライブラリ内のモデルA用コードを同じように変更してあげれば動くのではないか。希望が見えてきた。
ライブラリ「OBD.h」の内容を変更
class COBDI2C : public COBD {
public:
    void begin();
   void end();
    bool init(OBD_PROTOCOLS protocol = PROTO_CAN_11B_500K);//PROTO_AUTO); //PROTO_CAN_11B_500K <==Works for me
    bool read(byte pid, int& result);
    void write(const char* s);
    // Asynchronized access API
    void setPID(byte pid);
    void applyPIDs();
    void loadData();
    uint16_t getData(byte pid, int& result);
    // GPS API
    bool gpsQuery(GPS_DATA* gpsdata);
    void gpsSetup(uint32_t baudrate, const char* cmds = 0);
protected:
    bool sendCommand(byte cmd, uint8_t data = 0, byte* payload = 0, byte payloadBytes = 0);
    byte receive(char* buffer, int timeout = OBD_TIMEOUT_SHORT);
    byte m_addr;
    PID_INFO obdInfo[MAX_PIDS];
    byte obdPid[MAX_PIDS];
};
赤字の部分はデフォだとPROTO_AUTO。通常だとELM327が通信プロトコルを自動で判断してくれるらしいが、このフォーラムのイケメンや僕のように駄目な場合がある。
typedef enum {
    PROTO_AUTO = 0,
    PROTO_ISO_9141_2 = 3,
    PROTO_KWP2000_5KBPS = 4,
    PROTO_KWP2000_FAST = 5,
    PROTO_CAN_11B_500K = 6,
    PROTO_CAN_29B_500K = 7,
    PROTO_CAN_29B_250K = 8,
    PROTO_CAN_11B_250K = 9,
} OBD_PROTOCOLS;
この箇所がELM327へ渡す通信プロトコルのパラメーター。※ここは触らなくてもいい
上記の変更はモデルB用I2Cの記述なので、今回買ったモデルAのシリアル通信用コード(109行目)を以下のように変更。意味はないかもしれないが、念の為上記のI2C用コードも同様に変更した。
virtual bool init(OBD_PROTOCOLS protocol = PROTO_CAN_29B_500K);
ありがとう…フォーラムのナイスガイ
写真 2015-04-09 18 50 26
通信できて感無量
フォーラムの解法でやっと通信に成功。よかった、、わざわざ個人輸入した物が無駄にならなくて。Arduinoのスケッチで1500回転以上になるとLEDが点灯するコードにしたがその通りに反応してくれた。回転数の他に20km/h以上でLEDが点灯するコードも試したが、それもきちんと動作して問題が無い模様。
初っ端から躓いてしまったが、次は表示部の制作に進みたい。
技術は無いけどがんばるぞ。


  • 人気の記事
  • アーカイブ
  • カテゴリー
  • タグクラウド