CAN(controller area network)の実験

category: make

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バス接続しました。

それぞれのCAN High端子と、CAN Low端子を並列接続します。

CAN experiment

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デバイスでも通信できるようにしてみたいです。