跳到正文

Wiki

CAN通訊

約 5 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

1.Linux CAN 通訊

CAN 通訊是機器人、車輛、工業控制和電機驅動中非常常見的匯流排通訊方式。

相比序列埠通訊,CAN 更適合多個裝置掛在同一條總線上進行通訊。例如一個機器人底盤中,可能有多個電機驅動器、底盤控制板、感測器節點共同連線在 CAN 總線上。

在實際專案中,CAN 通訊常見於:

  • 控制電機驅動器
  • 讀取電機編碼器反饋
  • 連線底盤控制板
  • 多個控制節點之間通訊
  • 車輛匯流排通訊
  • 工業裝置和運動控制系統

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

1.1.CAN 通訊是什麼

CAN,全稱 Controller Area Network,是一種多主機匯流排通訊協議。

和序列埠點對點通訊不同,CAN 總線上可以掛多個節點。每個節點都可以傳送訊息,其他節點根據 CAN ID 判斷是否需要處理這條訊息。

CAN 通訊中常見概念包括:

概念 說明
CAN ID 用來標識一幀 CAN 訊息的含義或來源
標準幀 11 位 CAN ID
擴充套件幀 29 位 CAN ID
資料區 經典 CAN 一幀最多 8 位元組資料
CAN FD CAN 的擴充套件版本,支援更長資料區和更高資料速率
波特率 常見有 250K、500K、1M
終端電阻 CAN 匯流排兩端通常需要 120Ω 終端電阻

在 Linux 中,CAN 裝置通常不是 /dev/ttyUSB0 這種裝置檔案,而是被抽象成網路介面,例如:

can0

可以使用下面的命令檢視:

ip link

1.2.Linux 下常見 CAN 工具和庫

Linux 下 CAN 通訊的核心是 SocketCAN。

SocketCAN 是 Linux 核心提供的 CAN 通訊框架,它把 CAN 裝置抽象成類似網路介面的形式,例如 can0can1

常見工具和庫包括:

方案 型別 特點 適合場景
SocketCAN Linux 原生 CAN 介面 Linux 標準方案,通用、穩定、工程常用 推薦作為主線學習
can-utils SocketCAN 命令列工具集 提供 candumpcansendcangen 等工具 除錯 CAN 匯流排
libsocketcan SocketCAN 輔助庫 便於配置和管理 CAN 介面 需要程式內配置 CAN 引數時使用
ros2_socketcan ROS 2 封裝庫 將 SocketCAN 封裝進 ROS 2 生態 純 ROS 2 專案或參考實現
ros2_canopen ROS 2 CANopen 協議棧 適合 CANopen 裝置 電機驅動器使用 CANopen 協議時
廠商 SDK 廠商提供的驅動庫 和具體硬體繫結 使用特定 USB-CAN、PCIe-CAN 裝置時

1.3.各方案對比

方案 優點 缺點
SocketCAN Linux 原生、通用、穩定、適合長期學習 需要理解 socket 程式設計和 CAN 幀結構
can-utils 除錯方便,命令簡單 主要用於命令列測試,不是完整工程封裝
libsocketcan 配置 CAN 介面方便 不是主要的資料收發方案
ros2_socketcan 和 ROS 2 生態結合方便 離開 ROS 2 後複用性較差
ros2_canopen 適合 CANopen 裝置,協議棧完整 只適合 CANopen 場景,學習成本較高
廠商 SDK 對特定硬體支援好 通用性較差,容易繫結廠商

1.4.本教程建議選擇

本教程建議優先選擇:

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 / 底盘控制板

1.5.與 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。

1.6.什麼時候使用 ros2_socketcan

ros2_socketcan 並不是不能用。

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

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

可以這樣理解:

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

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

1.7.什麼時候使用 ros2_canopen

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

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

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

ros2_canopen

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

1.8.本章學習目標

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

  • CAN 通訊的基本概念
  • Linux 下 can0 裝置的使用方式
  • 使用 ip link 配置 CAN 波特率
  • 使用 candumpcansend 除錯 CAN 匯流排
  • 理解 CAN ID、標準幀、擴充套件幀、資料區等概念
  • 使用 C++ SocketCAN 進行 CAN 幀收發
  • 將 CAN 通訊封裝成可複用的 C++ 類
  • 為後續接入 ROS 2、ros2_control、電機驅動器控制打基礎