CAN通信
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 FD | CAN 的擴展版本,支持更長數據區和更高數據速率 |
| 波特率 | 常見有 250K、500K、1M |
| 終端電阻 | CAN 總線兩端通常需要 120Ω 終端電阻 |
在 Linux 中,CAN 設備通常不是 /dev/ttyUSB0 這種設備文件,而是被抽象成網絡接口,例如:
can0
可以使用下面的命令查看:
ip link
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 設備時 |
各方案對比
| 方案 | 優點 | 缺點 |
|---|---|---|
| SocketCAN | Linux 原生、通用、穩定、適合長期學習 | 需要理解 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 波特率 - 使用
candump、cansend調試 CAN 總線 - 理解 CAN ID、標準幀、擴展幀、數據區等概念
- 使用 C++ SocketCAN 進行 CAN 幀收發
- 將 CAN 通信封裝成可複用的 C++ 類
- 為後續接入 ROS 2、ros2_control、電機驅動器控制打基礎