第 13.2 節

CAN通信

0瀏覽次數0訪問次數--跳出率--平均停留

Linux CAN 通信

CAN 通信是機器人、車輛、工業控制和電機驅動中非常常見的總線通信方式。

相比串口通信,CAN 更適合多個設備掛在同一條總線上進行通信。例如一個機器人底盤中,可能有多個電機驅動器、底盤控制板、傳感器節點共同連接在 CAN 總線上。

在實際項目中,CAN 通信常見於:

  • 控制電機驅動器
  • 讀取電機編碼器反饋
  • 連接底盤控制板
  • 多個控制節點之間通信
  • 車輛總線通信
  • 工業設備和運動控制系統

對於移動機器人底盤、電機控制、自動駕駛線控系統等方向來說,CAN 是非常重要的一類通信方式。

CAN 通信是什麼

CAN,全稱 Controller Area Network,是一種多主機總線通信協議。

和串口點對點通信不同,CAN 總線上可以掛多個節點。每個節點都可以發送消息,其他節點根據 CAN ID 判斷是否需要處理這條消息。

CAN 通信中常見概念包括:

概念說明
CAN ID用來標識一幀 CAN 消息的含義或來源
標準幀11 位 CAN ID
擴展幀29 位 CAN ID
數據區經典 CAN 一幀最多 8 字節數據
CAN FDCAN 的擴展版本,支持更長數據區和更高數據速率
波特率常見有 250K、500K、1M
終端電阻CAN 總線兩端通常需要 120Ω 終端電阻

在 Linux 中,CAN 設備通常不是 /dev/ttyUSB0 這種設備文件,而是被抽象成網絡接口,例如:

can0

可以使用下面的命令查看:

ip link

Linux 下常見 CAN 工具和庫

Linux 下 CAN 通信的核心是 SocketCAN。

SocketCAN 是 Linux 內核提供的 CAN 通信框架,它把 CAN 設備抽象成類似網絡接口的形式,例如 can0can1

常見工具和庫包括:

方案類型特點適合場景
SocketCANLinux 原生 CAN 接口Linux 標準方案,通用、穩定、工程常用推薦作爲主線學習
can-utilsSocketCAN 命令行工具集提供 candumpcansendcangen 等工具調試 CAN 總線
libsocketcanSocketCAN 輔助庫便於配置和管理 CAN 接口需要程序內配置 CAN 參數時使用
ros2_socketcanROS 2 封裝庫將 SocketCAN 封裝進 ROS 2 生態純 ROS 2 項目或參考實現
ros2_canopenROS 2 CANopen 協議棧適合 CANopen 設備電機驅動器使用 CANopen 協議時
廠商 SDK廠商提供的驅動庫和具體硬件綁定使用特定 USB-CAN、PCIe-CAN 設備時

各方案對比

方案優點缺點
SocketCANLinux 原生、通用、穩定、適合長期學習需要理解 socket 編程和 CAN 幀結構
can-utils調試方便,命令簡單主要用於命令行測試,不是完整工程封裝
libsocketcan配置 CAN 接口方便不是主要的數據收發方案
ros2_socketcan和 ROS 2 生態結合方便離開 ROS 2 後複用性較差
ros2_canopen適合 CANopen 設備,協議棧完整只適合 CANopen 場景,學習成本較高
廠商 SDK對特定硬件支持好通用性較差,容易綁定廠商

本教程建議選擇

本教程建議優先選擇:

SocketCAN + can-utils

原因是:

  • SocketCAN 是 Linux 下 CAN 通信的標準方案
  • 不依賴 ROS 2,適合普通 C++、OpenCV、Qt、嵌入式 Linux 項目
  • can-utils 非常適合調試和驗證 CAN 設備
  • 後續可以封裝成普通 C++ driver
  • 可以自然接入 ros2_control hardware_interface

推薦的學習順序是:

1. 使用 ip link 配置 can0
2. 使用 candump 接收 CAN 帧
3. 使用 cansend 发送 CAN 帧
4. 理解 struct can_frame
5. 使用 C++ SocketCAN 进行收发
6. 封装自己的 CanDriver 类
7. 接入 ROS 2 或 ros2_control

推薦的工程結構是:

上层项目:ROS 2 / OpenCV / Qt / 普通 C++ 程序
        ↓
自己封装的 CanDriver 类
        ↓
SocketCAN
        ↓
can0
        ↓
电机驱动器 / STM32 / 底盘控制板

與 ROS 2 的關係

學習 SocketCAN,並不代表不用 ROS 2。

在 ROS 2 項目中,可以將 CAN 通信封裝成一個普通 C++ 類,然後在 ROS 2 節點或 ros2_control hardware_interface 中調用。

例如:

ros2_control controller
        ↓
hardware_interface
        ↓
自己封装的 CanDriver
        ↓
SocketCAN
        ↓
can0
        ↓
电机驱动器

這樣做的好處是,CAN 通信代碼不會和 ROS 2 強綁定。以後即使寫普通 C++ 項目、Qt 上位機或者 OpenCV 控制程序,也可以繼續複用同一套 CAN driver。

什麼時候使用 ros2_socketcan

ros2_socketcan 並不是不能用。

如果項目本身就是純 ROS 2 架構,並且希望快速把 CAN 幀轉換成 ROS 2 topic,那麼 ros2_socketcan 是一個可以考慮的方案。

但是對於底層驅動學習和長期工程複用來說,仍然建議先掌握 SocketCAN。

可以這樣理解:

SocketCAN:底层能力
ros2_socketcan:ROS 2 封装

先學 SocketCAN,再看 ros2_socketcan 會更容易理解。

什麼時候使用 ros2_canopen

如果你的電機驅動器或工業設備使用的是 CANopen 協議,那麼就不能只把它當作普通 CAN 幀通信來看待。

CANopen 是建立在 CAN 之上的高層協議,涉及對象字典、PDO、SDO、NMT 等概念。

這種情況下,可以考慮學習:

ros2_canopen

但如果你的設備只是自定義 CAN 協議,例如自己規定 CAN ID 和數據格式,那麼優先學習 SocketCAN 就足夠了。

本章學習目標

學習完本章後,應該能夠掌握:

  • CAN 通信的基本概念
  • Linux 下 can0 設備的使用方式
  • 使用 ip link 配置 CAN 波特率
  • 使用 candumpcansend 調試 CAN 總線
  • 理解 CAN ID、標準幀、擴展幀、數據區等概念
  • 使用 C++ SocketCAN 進行 CAN 幀收發
  • 將 CAN 通信封裝成可複用的 C++ 類
  • 爲後續接入 ROS 2、ros2_control、電機驅動器控制打基礎
音乐页