Ubuntu 22.04でUSB to CAN モジュールを使ってCAN通信をリアルタイムモニタリングする

# USB to CAN モジュールをの使い方

この記事では、[USB to CAN モジュール](https://amzn.asia/d/3sDpjkA)（Amazonで購入）を使用して、Ubuntu 22.04環境でCAN通信を監視する方法を紹介します．

![20250308_165244.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336552/07521e2e-1009-4073-b1bc-39c1b64ee69c.jpeg)


## 動作環境

- **OS:** Ubuntu 22.04
- **CANアダプタ:** USB to CAN モジュール　CANable2  
  購入した商品はこちら → [Amazonリンク](https://amzn.asia/d/3sDpjkA)
- **CANツール:** can-utils、python-can
- **Pythonバージョン:** 3.12

## 必要なツールのインストール

まずは、CAN通信に必要なパッケージをインストールします．

### 1. can-utilsのインストール

ターミナルで以下のコマンドを実行してください．

```bash
sudo apt-get update
sudo apt-get install can-utils
```

### 2. python-canのインストール

Pythonライブラリ`python-can`をインストールします．

```bash
pip3 install python-can
```

（※ pipを利用できない場合は、`apt-get install python3-can`などで）

## USB-CANアダプタの接続と初期確認

CANable2をUSBポートに接続すると、以下のようにシリアルデバイスとして認識されます．

```bash
ls /dev/ttyACM*
# 出力例:
# /dev/ttyACM0
```

この結果から、CANable2はSLcanモードで動作していると判断できます．

## SLcanモードでのCANインターフェース作成

SLcanモードの場合、`slcand`コマンドを用いてシリアルデバイスからCANネットワークインターフェース（通常はcan0）を作成します．以下の手順で進めます．

1 . **カーネルモジュールのロード**

```bash
sudo modprobe slcan
sudo modprobe can
sudo modprobe can_raw
```

2 . **CANインターフェースの作成と起動**

ここでは1000 kbps（1 Mbps）を想定し、`-s8`オプションで設定します．

```bash
sudo slcand -o -c -s8 /dev/ttyACM0 can0
sudo ip link set can0 up
```

3 . **通信の確認**

CAN通信が流れていれば、`candump`コマンドで確認できます．

```bash
candump can0
```

![20250308_165210.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336552/bcd898f0-4b6b-4a0f-a988-2ba1a9026cc3.jpeg)


※ 何も表示されない場合は、CANバス上にメッセージが流れていない可能性があります．テストでメッセージを送信するなどして動作を確認してください．

## Pythonとcursesによるリアルタイムモニタリング

CANバス上のメッセージは非常に多く流れるため、`candump`では見づらくなりがちです．そこで、Pythonを使って各CAN IDごとに最新の情報を表形式で表示するモニタリングツールを作成しました．

以下は、Pythonとcursesを用いたサンプルコードです．

```python
#!/usr/bin/env python3
import curses
import can
import time

def main(stdscr):
    # カーソルを非表示にし、入力待ちをしない設定
    curses.curs_set(0)
    stdscr.nodelay(True)

    # SocketCANを利用してcan0から受信（必要に応じてbitrate指定）
    bus = can.interface.Bus(channel='can0', bustype='socketcan')

    # 各CAN IDの最新メッセージと受信回数を記録する辞書
    messages = {}
    counts = {}

    while True:
        try:
            # タイムアウト付きでメッセージを受信（0.1秒待機）
            msg = bus.recv(timeout=0.1)
            if msg is not None:
                # 受信したCAN IDをキーに最新メッセージを保存し、受信回数を更新
                messages[msg.arbitration_id] = msg
                counts[msg.arbitration_id] = counts.get(msg.arbitration_id, 0) + 1

            # 画面をクリアして再描画
            stdscr.clear()
            stdscr.addstr(0, 0, "CAN Bus Monitor - Real Time Table")
            stdscr.addstr(1, 0, "Press Ctrl+C to exit")
            header = "ID        Count   DLC   Data"
            stdscr.addstr(3, 0, header)
            stdscr.hline(4, 0, '-', len(header)+4)

            row = 5
            # 受信したCAN IDを昇順に表示
            for can_id in sorted(messages.keys()):
                m = messages[can_id]
                count = counts[can_id]
                # IDは16進数表記に変換
                id_str = f"0x{can_id:X}"
                dlc = m.dlc
                # データバイトを2桁の16進数で表示
                data_str = " ".join(f"{byte:02X}" for byte in m.data)
                line = f"{id_str:8} {count:6} {dlc:5} {data_str}"
                stdscr.addstr(row, 0, line)
                row += 1

            stdscr.refresh()
            time.sleep(0.01) #安定化のため.なくても可能
        except KeyboardInterrupt:
            break

if __name__ == "__main__":
    curses.wrapper(main)
```
- **CAN受信:**  
  `bus.recv(timeout=0.1)`により、タイムアウト付きでCANメッセージを受信し、各IDごとに最新のメッセージと受信回数を辞書に保存します．

- **画面表示:**  
  `curses`ライブラリを用いて、画面全体をクリアした後、ヘッダーと各CAN IDの最新情報（ID、受信回数、DLC、データ）をリアルタイムに再描画します．

- **実行方法:**  
  このコードを例えば`can_monitor.py`として保存し、以下のコマンドで実行します．
  ```bash
  python3 can_monitor.py
  ```
>実行前にカーネルモジュールのロードとCANインターフェースの作成と起動をしている必要があります

  終了はCtrl+Cで行います．
  
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="und" dir="ltr">CAN <a href="https://t.co/adoC47S545">pic.twitter.com/adoC47S545</a></p>&mdash; -Altair- (@Flying___eagle) <a href="https://twitter.com/Flying___eagle/status/1898661974692765933?ref_src=twsrc%5Etfw">March 9, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
  

## まとめ

- **CANable2の動作確認:**  
  USB接続後、SLcanモードで認識されるので、`/dev/ttyACM0`として確認できます．

- **CANインターフェースの作成:**  
  `slcand`コマンドを用い、1000 kbpsに設定して`can0`インターフェースを作成しました．

- **リアルタイムモニタリング:**  
  Pythonの`python-can`と`curses`を組み合わせ、各CAN IDごとに最新メッセージを表形式で表示するツールを作成。流れる大量のメッセージから必要な情報を効率的に監視できます．

また，送信もできるようなのでロボマスモーターをPCから直接動かせたりするのは面白そうですね．

続編

https://qiita.com/_Altair_/items/b336bdfb97dfda55da80