CAN通信のロガーをraspberry pi(以下ラズパイ)で実装しようと思います。
第一回 Preparation(リファレンスのシンプル送受信機準備)
第一回ではラズパイは開発環境としてしか使用しません。
まずはCAN通信のリファレンスにする送受信機を作ります。
今回はやっていませんが、本来ならArduinoを2台用意して、この送受信が成立するか確認するべきです。
(比較的ハード問題が難解ではないとおもうので飛ばします)
なぜにラズパイか
これの全体目的は通信ロガー兼その他の汎用データロガーとして、PCを必要とせずにデータ出力がどんどんできる治具ということで、raspberry piが最適です。
CANロガーだけならそれほど大きな負荷はかからないと思うので、Arduinoで専用治具作れば良さそうですが、最終的はネットワーク出力で遠隔監視などなど広げようという目論見です。
Arduinoをリファレンスに?
リファレンスなので、すでにちゃんと動くCAN通信機器を使うというのもありですが、手元の製品(例えば自動車)とかをリファレンスにして間違ってイランエラーログ残したくないので、シンプルに送信・受信だけする治具をつくってラズパイの通信確認のリファレンスとします。
テストに使う機器類
今回は最近入手したraspberry pi 4 を開発環境として、通信テストの相手に、Arduinoを使おうと思います。
(もちろんこの記事もraspiで書く)
余談ですが、raspi4良いです。こういうライトなデスクトップ環境として十二分に動いてくれます。
raspi3でも必要十分ではありましたが、シリアルモニターしながらいろいろやっていると正直怪しくなってました。
使用機材一覧
機材 | 数量 | 備考 |
---|---|---|
raspberry pi 4 | 1 | |
Arduino uno | 1 | |
RS485CANHAT | 1 | raspberry pi にライドオン!で使える安価な便利ボード |
AMAZONで入手した安価なMCP2515CANボード | 1 | 基本的にMCP2515チップに対してSPI通信する共通の流れを使用して通信デモ機を作りたいため |
最終的には業務等のCAN通信機器のモニターとしてこの治具類を活用したいですね。
(自動車のODB2読み取るとか夢が広がります)
諸事上でオシロスコープは省略しています。 できれば揃えて、信号が出ていることを一歩々々確認しながら進めるべきです。
送信側の準備(Arduino)
別に送信側固定ではなく、送受信しますが、とりあえず多くのことをやらせたいのではなく、Arduinoは「通信が成立しているか?」のデバッグ用テスト環境です。
参考:amazon で arduino CANでヒットする安価ボード
MCP2515のライブラリをインストール
Arduino IDEにMCS2515のライブラリが提供されているので、それを入れます。
リンク先:https://github.com/coryjfowler/MCP_CAN_lib
ここで提供されている、mcp_can.hをIDEのライブラリに入れますが、手動ならプログラムのフォルダに入れますが、手堅くIDEメニュー「スケッチ/ライブラリーをインクルード/.ZIP形式のライブラリをインスト・・」でダウンロードした上記ライブラリファイルをインストールします。
通信ボードの接続
通信ボード PIN | Arduino PIN |
---|---|
INT | PIN 2 (変更可) |
SCK | PIN 13(固定) |
SI | PIN 11(固定) |
SO | PIN 12(固定) |
CS | PIN 10(変更可) |
GND | GND(固定) |
VCC | 5V(固定) |
実装CODE
基本的にはライブラリのサンプルコードを使います。
ライブラリリンク:https://github.com/coryjfowler/MCP_CAN_lib/tree/master/examples
CAN_receive.ino : 受信サンプル
CAN_send.ino : 送信サンプル
注意点は、
・確認用IDEのシリアルボーレート
・CAN設定の、種別:MCP_ANY、CAN通信ボーレート:500KBPS、通信ボードの動作クロック(ボード上の水晶)MCP_8MHZ
これがあっていれば、あとは接続の問題か相手側の問題。
サンプルコードをベースにして、少し都合よい内容にします。
まずは送信CODE
# include <mcp_can.h>
# include <SPI.h>
MCP_CAN CAN0(10); // Set CS to pin 10
void setup()
{
Serial.begin(115200);
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
else Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted
}
byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
unsigned long _time;
void loop()
{
_time = millis() / 500; //これはなにか通信内容に変化もたせたいだけのArduinoの動作カウントをいれるだけです。
// send data: ID = 0x123, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
byte sndStat = CAN0.sendMsgBuf(0x123, 0, 8, data);
if(sndStat == CAN_OK){
Serial.println("Message Sent Successfully!");
Serial.println(String(data[5])+String(data[4])+String(data[3])+String(data[2])+String(data[1])+String(data[0]));
} else {
Serial.println("Error Sending Message...");
}
delay(500); // send data per ms
}
次に受信コード
# include <mcp_can.h>
# include <SPI.h>
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128]; // Array to store serial string
# define CAN0_INT 2 // Set INT to pin 2
MCP_CAN CAN0(10); // Set CS to pin 10
void setup()
{
Serial.begin(115200);
// Initialize MCP2515 running at 8MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
Serial.println("MCP2515 Initialized Successfully!");
else
Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.
pinMode(CAN0_INT, INPUT); // Configuring pin for /INT input
Serial.println("MCP2515 Library Receive Example...");
}
void loop()
{
if(!digitalRead(CAN0_INT)) // If CAN0_INT pin is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
if((rxId & 0x80000000) == 0x80000000) // Determine if ID is standard (11 bits) or extended (29 bits)
sprintf(msgString, "Extended ID: 0x%.8lX DLC: %1d Data:", (rxId & 0x1FFFFFFF), len);
else
sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", rxId, len);
Serial.print(msgString);
if((rxId & 0x40000000) == 0x40000000){ // Determine if message is a remote request frame.
sprintf(msgString, " REMOTE REQUEST FRAME");
Serial.print(msgString);
} else {
for(byte i = 0; i<len; i++){
sprintf(msgString, " 0x%.2X", rxBuf[i]);
Serial.print(msgString);
}
}
Serial.println();
}
}
それぞれのCODE(スケッチ)を、送信確認、受信確認として使用する。
今回はここまで。
第2回は Intrduction ラズパイの設定と送受信テスト