車のコントローラ間に流れるCAN信号を読み取る装置の作り方 (Processing編)
これまで車両に流れるCAN信号を読み取るために必要なハードの作り方と、車両からCAN信号を読み出すARDUINOのプログラムを説明してきました。
今回はARDUINOで読み出したCAN信号をパソコンに表示させるプログラムについて説明します。
プログラムはProcessingという言語で作成します。
Processingを使う理由は、最終的な目的として、CAN信号をリアルタイムでPC画面上にグラフ表示させたいためです。
私はプログラミングに関して初心者ですので、ネットで検索してProcessing+Arduinoの組み合わせでデータのグラフ化をされている例がいくつか見つかりましたので、そちらを参考に作成してみました。
まずは、ARDUINOから送られてきたCAN信号を、IDごとに並べて表示するというシンプルなプログラムです。
〜 import processing.serial.*; Serial port; int[] id = new int[2]; //シリアル受信生値 id 2byte分 //=============ウィンドサイズ設定================== int WinSize_X = 1000; int WinSize_Y = 700; //=============CAN生値表示位置設定================== float CanValPosi_X = WinSize_X*1/100; float CanValPosi_Y = WinSize_Y*3/100; int ValPosi = 0; //=============ログ表示設定================== int SetFps = 60; //FPS設定 //============= シリアル受信生値 CAN値 8byte分 ================== int[] output_024_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_116_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_119_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_11C_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_120_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_122_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_124_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_130_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_180_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_310_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_314_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_318_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_380_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_3A0_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_3D0_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_3F4_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; int[] output_3F5_Val = new int[]{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //=============通信開始/終了用================== int Comflag; void settings() { size(WinSize_X, WinSize_Y); } void setup() { printArray(Serial.list());//シリアル通信に使用するポートを出力 port = new Serial(this, Serial.list()[1], 115200);//Serial(this, 上で確認したポートを引数に設定, ボーレート) background(0, 0, 0); PFont font = createFont("MS Gothic",50); textFont (font); //noSmooth(); //noSmoothを有効にするとアンチエイリアスOFF frameRate(SetFps);// FPSは画面の更新頻度であるとともに、Processingの場合、draw()が実行される間隔となる。 } void draw() { // 描画エリア設定 fill(0); noStroke(); rect(0, 0, width, height); fill(255); textSize(height/40); textAlign(LEFT); int j = 1; //CAN値の表示---------------------------------------------------------------------------- text("024", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_024_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("116", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_116_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("119", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_119_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("11C", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_11C_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("120", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_120_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("122", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_122_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("124", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_124_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } j++; text("130", CanValPosi_X, CanValPosi_Y*j); for(int i = 0; i < 8; i++){ text(hex(output_130_Val[i],2), width*(0.05+(0.03*i)), CanValPosi_Y*j); } } void serialEvent(Serial port){ // シリアルポートからデータを受け取ったら if (port.available() ==10) { // 10byte分のデータがそろったら処理開始 id[0] = port.read(); id[1] = port.read(); switch(id[0]*256+id[1]){ case 0x024: for(int i =0; i<8; i++){ output_024_Val[i] = port.read(); } break; case 0x116: for(int i =0; i<8; i++){ output_116_Val[i] = port.read(); } break; case 0x119: for(int i =0; i<8; i++){ output_119_Val[i] = port.read(); } break; case 0x11C: for(int i =0; i<8; i++){ output_11C_Val[i] = port.read(); } break; case 0x120: for(int i =0; i<8; i++){ output_120_Val[i] = port.read(); } break; case 0x122: for(int i =0; i<8; i++){ output_122_Val[i] = port.read(); } break; case 0x124: for(int i =0; i<8; i++){ output_124_Val[i] = port.read(); } break; case 0x130: for(int i =0; i<8; i++){ output_130_Val[i] = port.read(); } break; case 0x180: for(int i =0; i<8; i++){ output_180_Val[i] = port.read(); } break; case 0x310: for(int i =0; i<8; i++){ output_310_Val[i] = port.read(); } break; case 0x314: for(int i =0; i<8; i++){ output_314_Val[i] = port.read(); } break; case 0x318: for(int i =0; i<8; i++){ output_318_Val[i] = port.read(); } break; case 0x380: for(int i =0; i<8; i++){ output_380_Val[i] = port.read(); } break; case 0x3A0: for(int i =0; i<8; i++){ output_3A0_Val[i] = port.read(); } break; case 0x3D0: for(int i =0; i<8; i++){ output_3D0_Val[i] = port.read(); } break; case 0x3F4: for(int i =0; i<8; i++){ output_3F4_Val[i] = port.read(); } break; case 0x3F5: for(int i =0; i<8; i++){ output_3F5_Val[i] = port.read(); } break; default: while (port.available()>0)port.read(); // 受信対象外のidの場合はバッファを空にする。データのビットズレに対してもリセットがかかることになる。 break; } } else if (port.available() > 10){ while (port.available()>0)port.read(); // バッファが10byteを超えた場合はバッファを空にし、エラーメッセージを表示 println("エラー:バッファが10byteを超えました"); } } //マウスクリックで通信開始⇔終了 void mouseClicked(){ port.clear(); //バッファ領域を空にする if (Comflag == 0xFF){ Comflag = 0X01; }else{ Comflag = 0xFF; } port.write(Comflag); } 〜
プログラムの中で、以下の部分は、プログラムを実行するとProcessingのメイン画面の下に、COMポートの番号リストが表示されますので、ARDUINOを接続しているCOMポートの番号を確認して、Serial.list()の内に記入してください。
私の環境では”1”だったので、Serial.list()[1]としています。
printArray(Serial.list()); //シリアル通信に使用するポートを出力
port = new Serial(this, Serial.list()[1], 115200); //Serial(this, 上で確認したポートを引数に設定, ボーレート)
CANの読み出しをスタートさせるには、Processingの画面上をクリックする必要があります。(もう一度クリックすると一時停止)
読み出した値は下記のように表示されます。
このプログラムはあくまで、私の車(スズキ SX4)向けのプログラムなので、CAN idの部分は車に合わせて変更する必要があります。
では、車両に流れているCAN idをどうやって知るか、、、?
それを次回説明します。