🌐

USB-CAN-FDでRaspberry PiとCAN/CAN-FD通信する

2024/03/28に公開

海洋ロボコンをやってた人です。
今回はUSB-CAN-FDを入手したので、学んだことを備忘録として記載しておきます。

CANはMyActuator、Direct Drive (SWITCH SCIENCE)の通信プロトコルにも使用されており、一度はどんなものかを知っておくのも良いなと思っていました。
ただ、上記はアクチュエーターなだけあり高価なものが多く、CANをピンポイントで学ぶには少々コストが高めです。
なので、手軽に入手できる WaveshareさんのUSB-CAN-FDを使ってどんなものか触ってみた、というのが経緯になります。

この記事ではCAN,CAN-FD環境の構築と動作確認について記載します。
CAN, CAN-FDについては深く学びたい方はVector社様の資料をはじめ、Referenceを参照してください。

CANを学ぼうとされている方のお力になれれば幸いです。

1: USB-CAN-FDのセットアップ

1.1: 動作環境

動作環境は以下です。
WaveShareさんの公式サイトから購入すれば2-CH CAN HATとUSB CAN-FDを購入しても2万以内に収まります。また発注してから1週間もすれば届きます。
(慣れていない方は英語の発注書はミスないようにしっかり確認しましょう)

Windows 10

RaspberryPi 4 Model B (Ubuntu 22.04)

2-Channel Isolated CAN FD Expansion HAT for Raspberry Pi

Industrial Grade CAN FD Bus Adapter

1.2: インプット資料

USB-CAN-FD Waveshare Wiki

2-CH CAN FD HAT Wiki

1.3: HW Setup

無事、WaveShareさんよりCANデバイスの入手したら、ハードウェアのセットアップとして以下のように配線を行います。

Connection USB-CAN-FD CAN FD Expansion HAT for RPi
Black CAN1 H CAN_0 H
Green CAN1 L CAN_0 L
White CAN2 H CAN_1 H
Red CAN2 L CAN_1 L

1.4: SW Setup

続いて、ソフトウェアのセットアップを行います。

USB-CAN-FD ツール ソフトウェア より"USB-CANFD Tool Setup(V1.02).exe"をインストールします。

※クリックすると.zipのインストールが始まります。


.exeに沿ってインストールを進めます。文字化けしていても、デフォルト設定のままで問題ありません。

Install まで進むと、以下のアイコンでソフトウェアがインストールされます。

デバイスの確認

"Device Manage(O)" -> "Open Device" -> "Device Information"

から、HWやFWのバージョン、S/Nなどを確認することができます。

USB-CAN-FDのLoopback Test

サンプルデモ より"USB-CAN-FD-python-demo"をインストールします。

※クリックすると.zipのインストールが始まります。

docxファイルに従って、動作テストを実施してください。(ここでは略)

RPi4 to USB-CAN-FDの動作確認

適当なOSのラズパイを2-CH CAN FD HATを使用するためのライブラリインストールします。
以下、ラズパイへUbuntuが焼いてある想定で進めます。

terminal
sudo apt-get update
sudo apt-get install python3-pip
sudo apt-get install python3-pil
sudo apt-get install python3-numpy
sudo pip3 install RPi.GPIO
sudo pip3 install spidev 
sudo pip3 install python-can

SPI Mode Settings

デフォルトではSPI0-0、SPI1-0を使用してCAN制御するA(デフォルト)モードになっています。

とあるようにUbuntu OSの場合は"/boot/firmware/config.txt "へ追記を行います。

terminal
sudo nano /boot/firmware/config.txt
dtparam=spi=on
dtoverlay=spi1-3cs
dtoverlay=mcp251xfd,spi0-0,interrupt=25
dtoverlay=mcp251xfd,spi1-0,interrupt=24
dtoverlay=waveshare-can-fd-hat-mode-a

sudo reboot

Configure CAN

CANのボーレート、動作モード、CAN-FD有効有無、送信バッファサイズを設定します。

terminal
sudo ip link set can0 up type can bitrate 1000000 dbitrate 8000000 restart-ms 1000 berr-reporting on fd on

用語は以下です。
bitrate xxxxxx (bps):arbitration bitrate(アービットレーションビットレート:通信調停)
dbitrate xxxxxx (bps):data bitrate(データビットレート:データ転送)

Configuration buffer

CAN0のネットワークIFの送信キューの長さを設定します。

terminal
sudo ifconfig can0 txqueuelen 65536

2: CAN/CAN-FDのデモンストレーション

2.1: デモプログラムの準備/確認

2-CH-CAN-FD-HATのデモプログラムをRaspberry Pi側でインストールします。

termial
sudo apt-get install can-utils
sudo apt install p7zip-full
cd ~
wget https://files.waveshare.com/upload/4/46/2-CH-CAN-FD-HAT-Demo.7z
7z x 2-CH-CAN-FD-HAT-Demo.7z -o./2-CH-CAN-FD-HAT-Demo

cd 2-CH-CAN-FD-HAT-Demo/2-CH-CAN-FD-HAT-Demo/Raspberry_Pi/Python/
sudo python3 receive0.py

USB_CANFD_TOOLから以下を設定しSendをクリックしてデータを送信してみましょう。

CANFDToolPro Value
Type Standard
Format Data
Protocol CAN
Send Type Normal

送信したDataがRaspberry Pi上で確認できると思います。

同様に、Raspberry Pi側からもデータ送信してみましょう。

termial
sudo python3 send0.py

USB_CANFD_TOOL側でのデータ受信が確認できます。

2.2: CAN/CAN-FD定期送受信

wgetしてきたデモプログラムは定期送受信に対応していないので、以下で定期送受信を試してみます。

  • CAN定期受診
rx_can0.py
import can
import os

# CAN bus settings
can_interface = 'can0'
bitrate = 1000000  # Arbitration bitrate
data_bitrate = 8000000  # Data bitrate
restart_ms = 1000  # Restart time in milliseconds

# Execute CAN bus settings
os.system(f'sudo ip link set {can_interface} up type can bitrate {bitrate} dbitrate {data_bitrate} restart-ms {restart_ms} berr-reporting on fd on')

# Create CAN bus interface
can0 = can.interface.Bus(channel=can_interface, bustype='socketcan')

try:
    while True:
        # Receive messages
        msg = can0.recv()
        print(msg)
except KeyboardInterrupt:
    # Perform cleanup on Ctrl+C
    pass
finally:
    # Take CAN bus down
    os.system(f'sudo ifconfig {can_interface} down')

  • CAN定期送信

CANは1フレームのデータ長は最大8byteなので、4byte分は適当なデータを送信し残りは0xffのpaddingを送信するようにしています。

tx_can0.py
import os
import can
import time
import random

# CAN bus settings
can_interface = 'can0'
arbitration_bitrate = 1000000
data_bitrate = 8000000
restart_ms = 1000  # Restart time in milliseconds

# Define meaningful variables for sending data
engine_speed = 0
vehicle_speed = 0
coolant_temperature = 0

# Execute CAN bus settings
os.system(f'sudo ip link set {can_interface} up type can bitrate {arbitration_bitrate} dbitrate {data_bitrate} restart-ms {restart_ms} berr-reporting on fd on')

# Create CAN bus interface
can0 = can.interface.Bus(channel=can_interface, bustype='socketcan')

try:
    while True:
        # Update meaningful variables with random values
        engine_speed = random.randint(0, 7000)              # Random engine speed (rpm)
        vehicle_speed = random.randint(0, 120)              # Random vehicle speed (km/h)
        coolant_temperature = random.randint(50, 120)       # Random coolant temperature (°C)

        # Construct CAN message data
        data = [
            engine_speed & 0xFF,          # Lower byte of engine speed
            (engine_speed >> 8) & 0xFF,   # Upper byte of engine speed
            vehicle_speed,                # Vehicle speed
            coolant_temperature,          # Coolant temperature
            0xFF, 0xFF, 0xFF, 0xFF
        ]
        
        # Construct CAN message
        msg = can.Message(is_extended_id=False, arbitration_id=0x123, data=data)
        
        # Send CAN message
        can0.send(msg)
        
        # Wait for 100 milliseconds
        time.sleep(0.1)

except KeyboardInterrupt:
    # Perform cleanup on Ctrl+C
    pass
finally:
    # Take CAN bus down
    os.system(f'sudo ifconfig {can_interface} down')
  • CAN-FD定期送信

CAN FD(CAN with Flexible Data rate)は0~8、12、16、20、24、32、48、64byteのData Filedで送信ができるため、以下では64byteのランダムなデータを送信しています。

2-CH CAN FD HATのWikiにCAN-FDを使用する場合の設定が記載されているので、データフェーズのサンプリングポイントなどを80%へ設定します。

上記を反映させたCAN定期送信とのdiffは以下になります。

tx_canfd0.py
+ dsample_point = 0.8
+ sample_point = 0.8

# Execute CAN bus settings
+ os.system(f'sudo ip link set {can_interface} up type can bitrate {bitrate} dbitrate {data_bitrate} restart-ms {restart_ms} berr-reporting on sample-point {sample_point} dsample-point {dsample_point} fd on')

また、can.Busの引数にfd=Trueを設定します。

can.Busの仕様は以下を参照してください。

CAN Bus Interface Names

tx_canfd0.py
import os
import can
import time
import random

# CAN bus settings
can_interface = 'can0'
arbitration_bitrate = 1000000
data_bitrate = 8000000
restart_ms = 1000  # Restart time in milliseconds
dsample_point = 0.8
sample_point = 0.8

# Execute CAN bus settings with CAN-FD enabled
os.system(f'sudo ip link set {can_interface} up type can bitrate {arbitration_bitrate} dbitrate {data_bitrate} restart-ms {restart_ms} berr-reporting on sample-point {sample_point} dsample-point {dsample_point} fd on')

# Instantiate the bus with CAN FD support
bus = can.Bus(interface='socketcan', channel=can_interface, bitrate=arbitration_bitrate, fd=True, data_bitrate=data_bitrate)

try:
    while True:
        # Generate 64 random bytes for data
        data = [random.randint(0, 255) for _ in range(64)]
        
        # Construct CAN message
        msg = can.Message(arbitration_id=0x123, data=data, is_extended_id=False, is_fd=True)
        
        # Send the message
        try:
            bus.send(msg)
            print(f"Message sent on {bus.channel_info}")
        except can.CanError:
            print("Message NOT sent")
        
        # Wait for 100 milliseconds before sending the next message
        time.sleep(0.1)

except KeyboardInterrupt:
    # Perform cleanup on Ctrl+C
    pass
finally:
    # Take CAN bus down
    os.system(f'sudo ifconfig {can_interface} down')

2.3: デモの様子

CANでの8byteデータ送信(上)とCAN-FDでの64byteデータ送信のデモを記載します。

https://twitter.com/tasada038/status/1772030534006517786

以上です。
Likeいただけると大変励みになりますので、よろしくお願いいたします。

Reference

  • CAN/CAN-FD

はじめてのCAN / CAN FD

Sunny Giken: CAN FD(CAN with Flexible Data Rate)とは)

python-can document: Message

Discussion