linux 中在命令行中使用 SocketCAN(以 PCAN
1 什么是 SocketCAN
根据 维基百科 的介绍,SocketCAN 是一个开源的 CAN 驱动以及网络堆栈。在 linux 中,传统的 CAN 驱动是基于字符设备(character device)模型的。一个典型的设备驱动实现,只允许一个进程访问一个设备,其他进程的访问会被阻塞。而且不同设备之间的驱动往往略有不同,这也给移植带来了不便。而 SocketCAN 使用了网络设备模型,允许多个应用同时访问同一个 CAN 设备,而一个应用也可以同时访问多个 CAN 总线。
Linux 内核中在 2.6.25 版本中加入了 CAN 的补丁,同时也添加了一些 CAN 设备的驱动。这里所用到的 PCAN 驱动基本上主流的 linux 发布版也都支持。
2 什么是 PCAN
PCAN 是一个 CAN 转 USB 的设备,由德国 PEAK-System 公司生产。一般一端用来连接 CAN 总线另一端用来连接 USB 主机(工控机、ECU、PC等)。这个东西还是比较贵的,差不多要 2k 多 RMB。有人可能就有疑问了,不就是一个 CAN 转 USB 吗?某宝上随便一搜也就是2百多块。为啥这个这么贵?下面我就简单的总结一下 PCAN 的优势:
- PCAN 广泛运用到汽车领域,应该是车规级的产品(我没有查到相关的资料,只是凭感觉推断)。
- PCAN 支持 windows、linux 系统、以及 linux 实时扩展 Xenomai,RTAI (对应为“实时驱动模式”)。
- PCAN 支持 C++、Java、Python 3.x 等编程语言甚至可以直接将数据输入到 matlab/simulink 车辆网络工具箱。
- Qt 也自带对该设备的支持(通过 Qt CAN Bus)。
- 支持 CAN 2.0 a/b 协议以及 CAN FD 协议[1]。
- 读取数据支持事件触发[2]。
- 各种各样的软件以及成熟的生态。尤其是在汽车通信领域。
- 等等。
[1] CAN FD 协议:全称为 Controller Area Network Flexible Data-Rate. 是对原有 CAN 协议的一种扩展。在 2011 年开发并于 2012 年由博世(Bosch)公司发布。和传统 CAN 协议不同,主要体现在了灵活数据(Flexible Data)。主控单元可以动态的切换不同的数据频率(允许高达传统 CAN 传输速率5倍的速度传输),而且每一帧的数据负载大小由最多8字节提升到64字节。
[2] 这一点很容易被其他的 USB-CAN 设备厂商忽略。我在某宝上买过2百多块的 USB-CAN 设备。当时我问老板支不支持事件触发,老板说:“不支持,而且目前国内所有的厂商都不支持。”(这篇文章写于2020年6月5日)。也就是说,使用这些设备你只能使用查询的方式读取数据,这就基本不可能保证实时性。专门使用一个线程开启事件循环来查询接收缓冲区也会浪费大量的 CPU 资源。因此这些设备配套的软件基本无法打到工业级标准,即使他们的硬件达到了标准。
需要注意的是如果你使用的 PCAN 已经安装了对应的字符设备驱动(chardev),那么是无法使用 SocketCAN 的,如果需要使用 SocketCAN(即网络驱动 aka netdev),需要你根据 PCAN 用户手册重新安装网络驱动。如果你的电脑上没有安装任何关于 PCAN 的驱动,那么默认是可以使用下面的 SocketCAN 的。
3 如何在 Linux 命令行中使用 SocketCAN
终于进入正题了。这部分内容主要来自于 How To Use SocketCAN With The Command-Line In Linux。我的环境如下:
- USB-CAN 设备为 PCAN。
- 系统为状态 VMware 中的 Ubuntu 16.04。
3.1 SocketCAN 提供了哪些 CAN 接口类型?
-
Native interfaces: 本地接口对应了真实的硬件(如 USB-CAN 适配器),这些接口命名为
canX
,如can0
,can1
,... -
Virtual interfaces: 虚拟接口并没有对应实际的硬件,它们被命名为
vcanX
,如vcan0
,vcan1
,... -
SLCAN based interfaces: 基于 SLCAN 的接口提供了串行接口,它们被命名为
slcanX
,如slcan0
,slcan1
,等等。
3.2 列出 SocketCAN 接口
在连接好设备之后,我们首先可能想做的就是查看本地都有哪些 CAN 接口(设备是否被正确识别):
$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:97:9a:46 brd ff:ff:ff:ff:ff:ff
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
link/can
这里的最后一个接口 can0
就是 SocketCAN 接口。此时你可能还希望打印本地支持 SocketCAN 的 CAN 设备信息:
$ ip addr ls dev can0
3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN group default qlen 10
link/can
$ ip addr ls dev can1 # 尝试不存在的设备
Device "can1" does not exist.
另一种显示 CAN 接口信息的方法是使用 ifconfig <canx>
:
$ ifconfig can0
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
3.3 配置并且使能 SocketCAN 接口
对于实际存在的 CAN 设备(连上设备时自动创建的 can0
),可以使用如下的方法设定波特率(这里为 1M):
sudo ip link set can0 type can bitrate 1000000
如果你使用的是虚拟 CAN 接口,会略有不同:
$ sudo modprobe vcan
$ sudo ip link add dev vcan0 type vcan
使能 SocketCAN 接口使用如下的命令:
$ sudo ip link set up can0
如果出现
RTNETLINK answers: Operation not supported
错误,去先尝试执行sudo modprobe can
或者sudo modprobe vcan
。
3.4 使用 SocketCAN 发送或者接受数据
首先需要安装 can-utils
:
$ sudo apt install can-utils
如果你的设备连接到了其他的 CAN 设备,你可以使用如下的命令来发送数据到该设备:
$ cansend can0 123#1122334455667788
其中 123
为 id 表示 0x123
,数据为 [ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 ]
。注意值总是被认为是16进制。
如果希望显示所有接收到的消息,可以使用如下命令:
$ candump can0
相关文章: