USB-CAN-FDでRaspberry PiとCAN/CAN-FD通信する
海洋ロボコンをやってた人です。
今回は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: インプット資料
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が焼いてある想定で進めます。
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 "へ追記を行います。
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有効有無、送信バッファサイズを設定します。
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の送信キューの長さを設定します。
sudo ifconfig can0 txqueuelen 65536
2: CAN/CAN-FDのデモンストレーション
2.1: デモプログラムの準備/確認
2-CH-CAN-FD-HATのデモプログラムをRaspberry Pi側でインストールします。
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側からもデータ送信してみましょう。
sudo python3 send0.py
USB_CANFD_TOOL側でのデータ受信が確認できます。
2.2: CAN/CAN-FD定期送受信
wgetしてきたデモプログラムは定期送受信に対応していないので、以下で定期送受信を試してみます。
- CAN定期受診
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を送信するようにしています。
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は以下になります。
+ 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の仕様は以下を参照してください。
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データ送信のデモを記載します。
以上です。
Likeいただけると大変励みになりますので、よろしくお願いいたします。
Reference
- CAN/CAN-FD
Discussion