Wiki
CAN通訊
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
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 裝置抽象成類似網路介面的形式,例如 can0、can1。
常見工具和庫包括:
| 方案 | 型別 | 特點 | 適合場景 |
|---|---|---|---|
| SocketCAN | Linux 原生 CAN 介面 | Linux 標準方案,通用、穩定、工程常用 | 推薦作為主線學習 |
| can-utils | SocketCAN 命令列工具集 | 提供 candump、cansend、cangen 等工具 |
除錯 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 波特率 - 使用
candump、cansend除錯 CAN 匯流排 - 理解 CAN ID、標準幀、擴充套件幀、資料區等概念
- 使用 C++ SocketCAN 進行 CAN 幀收發
- 將 CAN 通訊封裝成可複用的 C++ 類
- 為後續接入 ROS 2、ros2_control、電機驅動器控制打基礎