CAN(controller area network)の実験
CAN
CAN(controller area network)とは、2線の有線にてシリアル通信を行う通信規格の一つです。CANは、現在の自動車内のネットワークOBD2(on-board diagnostics second generation)としても利用され、1996年以降のアメリカで、2006年以降の日本で、それぞれ販売される自動車と小型トラックにCAN通信を行うOBD2搭載が義務付けられています。
シリアル通信として、I2C(inter-integrated circuit)やSPI(serial parallel interface)と並び、CANも広く使われています。そこで、Raspberry Pi Zero Wと、そのCANアダプタを使って、CAN通信を試しました。
接続
CANは、CSMA/CR(carrier sense multiple access/collision resolution)にて、複数の装置間を2線のバス接続にて通信できるようにする規格です。最大1 Mbit/sの通信速度が定義され、40メートルバス長では1 Mbit/sの通信速度となるそうです。CANでは、最大30台までの機器を接続できます。
ここでは、次の3台の機器をCANバス接続しました。
- Raspberry Pi Zero Wと、WaveShare RS485 CAN HAT を2セット
- Seeeduino Unoと、Longan Labs Serial CAN Bus Module を1セット
それぞれのCAN High端子と、CAN Low端子を並列接続します。
Serial CAN Bus Moduleは、CANをシリアル通信に変換するモジュールです。また、Seeeduino Unoは、Arduino Unoの互換品です。Seeeduino Unoには、Groveコネクタが付いていて、また、通信と電源供給を行うコネクタがUSB microで、便利です。
実験
久しぶりにRaspberry Pi Zero W用のマイクロSDカードを作成しました。今回、利用したRaspberry Pi Zeroは、最新の2Wではなく、Wなので、32ビットOSを利用します。現在のところ、最新のDebian OS “bookworm"ではWi-Fiが利用できなかったため、一昔前の"bullseye"を利用しました。
最初に、CANをデバイスcan0
として利用可能にします。通信速度は1 Mbit/sに設定しました。
sudo ip link set can0 type can bitrate 100000
sudo ifconfig can0 up
次に、2台のRasberry Pi Zero Wの一方を送信側に、他方を受信側に、それぞれ設定します。CANでは、一度に8バイトが伝送され、それらをID番号にて区別されます。ここでは、ID0x123
にてランダムな8バイトを1秒ごとに連続して送信します。送信側のPythonコードsend.py
は次のとおりです。
#!/usr/bin/env python
import os
import can
import random
import time
can0 = can.interface.Bus(channel='can0', bustype='socketcan')
while True:
data = [random.randint(0,255) for _ in range(8)]
print(data)
msg = can.Message(
arbitration_id=0x123,
data = data,
is_extended_id=False)
can0.send(msg)
time.sleep(1)
# EOF
一方、受信側のPythonコードreceive.py
は次のようにしました。
#! /usr/bin/env python
import os
import can
can0 = can.interface.Bus(channel='can0', bustype='socketcan')
while True:
msg = can0.recv(2.0)
if msg:
print (msg)
# EOF
送信側では、ID0x123
にてランダムな8バイトが送信されました。
[217, 203, 250, 65, 193, 222, 223, 133]
[0, 58, 102, 152, 76, 70, 98, 171]
[127, 250, 174, 163, 203, 114, 7, 117]
[205, 167, 208, 195, 198, 60, 67, 84]
[230, 115, 117, 118, 4, 70, 153, 123]
一方、受信側では、その8バイトを受信できました。
Timestamp: 1698198813.890996 ID: 0123 S Rx DL: 8 d9 cb fa 41 c1 de df 85 Channel: can0
Timestamp: 1698198814.894715 ID: 0123 S Rx DL: 8 00 3a 66 98 4c 46 62 ab Channel: can0
Timestamp: 1698198815.897671 ID: 0123 S Rx DL: 8 7f fa ae a3 cb 72 07 75 Channel: can0
Timestamp: 1698198816.901728 ID: 0123 S Rx DL: 8 cd a7 d0 c3 c6 3c 43 54 Channel: can0
Timestamp: 1698198817.905382 ID: 0123 S Rx DL: 8 e6 73 75 76 04 46 99 7b Channel: can0
Serial CAN Bus Moduleについて、Arduino IDE用のライブラリをインストールして、通信速度とIDをあわせてみたのですが、この内容を受信できませんでした。もう少し考えてみます。
なお、Digilent Analog Discovery 2の付属ソフトウェアWaveforms 3.21.3でもCAN通信を表示できるとされていますが、そのままDIO(digital input output)端子に接続してもCAN通信を解釈できませんでした。Digilentのフォーラムによると、PModCANというCANをSPIに変換する方法が紹介されています。グランドラインを接続する方法もあるようです。
おわりに
CANの通信実験をしました。通信距離を伸ばす、Serial CAN Bus Moduleや他のCANデバイスでも通信できるようにしてみたいです。