Can-Utils 工具集详解

can-utils 是 Linux 上最常用的 CAN 调试工具集,包含多个实用工具,几乎涵盖所有基础 CAN 调试需求。

1. can-utils 安装

1.1 Ubuntu/Debian

sudo apt-get update
sudo apt-get install can-utils

1.2 从源码编译(推荐获取最新版本)

git clone https://github.com/linux-can/can-utils.git
cd can-utils
./autogen.sh
./configure
make
sudo make install

1.3 验证安装

# 查看所有可用工具
candump --help
cansend --help
canplayer --help

2. 核心工具详解

2.1 candump - CAN 帧捕获工具

candump 是最常用的工具,用于捕获和显示 CAN 总线上的所有帧。

基本用法

# 捕获 vcan0 上的所有帧
candump vcan0

# 输出示例:
vcan0  123#DEADBEEF              # 标准帧,ID=0x123,数据=0xDEADBEEF
vcan0  123#DEADBEEF             # 时间戳格式
vcan0  180#01.00.00.00.00.00.00.00  # 扩展帧
vcan0  200#8 byte data with spaces

高级过滤

# 只捕获特定 ID 的帧
candump vcan0,123:7ff  # 掩码 0x7ff 只匹配低 11 位

# 捕获 ID 范围
candump vcan0,100:780  # 匹配 0x100-0x17F

# 捕获多个 ID
candump vcan0,123:7ff vcan0,456:7ff

# 使用过滤器文件
cat > filter.txt << 'EOF'
vcan0,580:7ff
vcan0,600:7ff
vcan0,700:7ff
EOF
candump -F filter.txt vcan0

日志记录

# 记录到文件
candump -l vcan0

# 指定日志文件名
candump -l -L can_log_ vcan0  # 生成 can_log_<timestamp>.log

# 同时显示和记录
candump -l -d vcan0

# 日志文件格式示例 (cat can_log_20240520_143022.log)
(000.000000) vcan0 580#01100580
(000.000501) vcan0 580#01100580
(000.001002) vcan0 600#01

时间戳选项

# 使用硬件时间戳(如果支持)
candump -H vcan0

# 使用相对时间戳
candump -t vcan0  # 默认

# 使用绝对时间戳
candump -T vcan0

# 使用 ISO 8601 时间戳
candump -tz vcan0

2.2 cansend - CAN 帧发送工具

用于向 CAN 总线发送单帧数据。

基本用法

# 发送标准帧
cansend vcan0 123#DEADBEEF

# 发送扩展帧
cansend vcan0 123#DEADBEEF

# 发送 8 字节数据
cansend vcan0 123#0102030405060708

# 发送较少字节数据(自动填充 00)
cansend vcan0 123#11  # 只发送 1 字节

CANopen 示例发送

# NMT 命令:启动节点 2
# 功能码=0x000, 节点ID=0x002, 命令=0x01 (Start Remote Node)
cansend vcan0 000#0102

# 心跳报文(节点 1,状态=5 Operational)
# 功能码=0x700, 节点ID=0x001
cansend vcan0 701#05

# SDO 读取请求(从节点 2 读取 0x1000:00)
# 功能码=0x600, 节点ID=0x002
# CCS=0x40 (Initiate Upload), Index=0x1000, SubIndex=0x00
cansend vcan0 602#40100000

# SDO 写入请求(向节点 2 的 0x1000:01 写入 0x12345678)
# CCS=0x23 (Initiate Download), Index=0x1000, SubIndex=0x01
# Data=0x12345678 (4字节 Expedited)
cansend vcan0 602#2310000112345678

批量发送(Shell 脚本)

#!/bin/bash
# send_nmt_start.sh - 启动所有节点

INTERFACE="vcan0"
MAX_NODES=10

for i in $(seq 1 $MAX_NODES); do
    printf "Starting node %d\n" $i
    cansend $INTERFACE 000#01$(printf "%02X" $i)
    sleep 0.1
done

# 发送心跳
for i in $(seq 1 $MAX_NODES); do
    cansend $INTERFACE $(printf "7%02X" $i)#05
done

2.3 cangen - CAN 帧生成工具

用于持续生成 CAN 帧,常用于压力测试或模拟设备。

基本用法

# 生成随机帧,默认 100 帧/秒
cangen vcan0

# 指定 ID 和数据模式
cangen -v vcan0 -g 100 -D 1122334455667788 -I 123

# 参数说明:
# -v: 详细模式
# -g 100: 100 帧/秒
# -D: 固定数据
# -I: 固定 ID

数据模式选项

# 使用递增数据
cangen vcan0 -L i  # increment

# 使用递减数据
cangen vcan0 -L d  # decrement

# 使用随机数据
cangen vcan0 -L r  # random(默认)

# 使用自定义模式
cangen vcan0 -m 1122334455667788  # 模式数据

ID 生成选项

# 固定 ID
cangen vcan0 -I 123

# 随机 ID(11-bit 范围)
cangen vcan0 -i

# 扩展帧 ID
cangen vcan0 -I 12345678 -e

# ID 递增
cangen vcan0 -L i -I 100

CANopen 模拟示例

# 模拟节点 1 的 PDO 发送(RPDO 0x200)
cangen vcan0 -I 200 -e -g 10 -v -D "11 22 33 44 55 66 77 88"

# 模拟心跳报文
while true; do
    cansend vcan0 701#05
    sleep 1
done

# 模拟节点 2 的 NMT 状态变化
for state in 0 4 5; do  # Initial -> Pre-Operational -> Operational
    cansend vcan0 702#$state
    sleep 1
done

2.4 canplayer - CAN 帧回放工具

用于回放之前记录的 CAN 日志,适用于复现问题或测试。

基本用法

# 回放日志文件(保持原始时间间隔)
canplayer -I can_log.log vcan0=vcan0

# 加速回放(2 倍速)
canplayer -I can_log.log vcan0=vcan0=2x

# 无延迟回放(用于快速测试)
canplayer -I can_log.log vcan0=vcan0=0x

# 慢速回放(0.5 倍速)
canplayer -I can_log.log vcan0=vcan0=0.5x

接口映射

# 将日志中的 vcan0 映射到 can0
canplayer -I can_log.log vcan0=can0

# 回放多个日志
canplayer -I log1.log -I log2.log vcan0=vcan0

2.5 cansequence - CAN 帧序列工具

用于发送一系列预定义的 CAN 帧,支持间隔控制。

# 创建序列文件
cat > sequence.txt << 'EOF'
# ID Data Delay(ms)
123 01020304 100
456 AABBCCDD 200
789 11223344 50
EOF

# 播放序列
cansequence -i sequence.txt vcan0

# 循环播放
cansequence -i sequence.txt -l vcan0

# 指定次数播放
cansequence -i sequence.txt -c 10 vcan0

3. 其他实用工具

3.1 cansniffer - CAN 流量分析

实时分析 CAN 总线流量,显示每条消息的更新间隔。

cansniffer vcan0

# 输出格式:
#   vcan0  123  DEADBEEF   0.010s  ↑  ← 数据变化
#   vcan0  456  00112233   0.050s  -  ← 无变化
#   vcan0  789  AABBCCDD   0.100s  ↓  ← 超时

3.2 candecoder - CAN 帧解码

使用 DBC 文件解码 CAN 帧。

# 需要先安装 libcanberra-dev
candecoder -c signals.dbc vcan0

3.3 cantool - CANopen 工具

专门用于 CANopen 调试的命令行工具。

# 读取对象字典值
cantool read -n 2 -i 0x1000 -s 0

# 写入对象字典
cantool write -n 2 -i 0x1400 -s 0 -d 0x02

4. 实用调试技巧

4.1 实时监控特定节点

# 只监控节点 2 的所有通信
candump vcan0,200:700  # RPDO+TPDO 范围
candump vcan0,500:700  # SDO+SDO 响应范围
candump vcan0,700:7ff  # NMT+心跳范围

4.2 查找特定数据模式

# 查找包含特定数据的帧
candump vcan0 | grep "DEADBEEF"

# 实时统计帧频率
candump vcan0 | awk '{print $3}' | sort | uniq -c

4.3 压力测试脚本

#!/bin/bash
# stress_test.sh - CAN 总线压力测试

INTERFACE="vcan0"
DURATION=60  # 秒

echo "开始压力测试,持续 $DURATION 秒..."

# 启动监控(后台)
candump -l -d $INTERFACE &

# 生成高负载流量
end_time=$(($(date +%s) + $DURATION))
while [ $(date +%s) -lt $end_time ]; do
    cansend $INTERFACE $(printf "%03X" $((RANDOM % 2048)))#$(printf "%016X" $RANDOM)
done

# 检查错误统计
ip -details -statistics link show $INTERFACE

4.4 自动化心跳检测

#!/bin/bash
# heartbeat_monitor.sh - 心跳监控

INTERFACE="vcan0"
NODE_IDS=(1 2 3 4 5)
TIMEOUT_MS=3000

echo "监控心跳超时 ($TIMEOUT_MS ms)..."

candump -l -d $INTERFACE &
CANDUMP_PID=$!

# 监控进程
declare -A last_seen
for node in "${NODE_IDS[@]}"; do
    last_seen[$node]=$(date +%s%3N)
done

check_timeouts() {
    local now=$(date +%s%3N)
    for node in "${NODE_IDS[@]}"; do
        local elapsed=$((now - last_seen[$node]))
        if [ $elapsed -gt $TIMEOUT_MS ]; then
            echo "[$(date)] 警告: 节点 $node 心跳超时 (${elapsed}ms)"
        fi
    done
}

trap "kill $CANDUMP_PID; exit" SIGINT

while true; do
    check_timeouts
    sleep 0.5
done

5. 故障排查速查

问题命令解释
检查接口是否启动ip link show vcan0UP 状态表示已启动
查看总线负载ip -details -statistics link show vcan0查看 RX/TX 统计
测试发送功能cansend vcan0 123#DEADBEEF无报错则正常
检查接收功能candump vcan0 &; cansend vcan0 123#DEADBEEF能看到自己发的帧
查找错误帧candump vcan0 | grep -i error搜索错误关键字

★ Insight ─────────────────────────────────────

  • candump -l 是最常用的调试命令——所有真实环境调试都应该先记录日志,遇到问题时可以回放分析。
  • can-utils 的过滤功能强大但容易出错:掩码 0x7ff 只匹配低 11 位,扩展帧需要用 0x1fffffff。
  • 压力测试时注意不要使用物理 CAN 接口——高负载的随机帧可能导致实际设备进入错误状态。 ─────────────────────────────────────────────────

下一步

→ 03-wireshark-analysis.md —— 学习 Wireshark 协议分析

如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
Cygnus Yang 支付宝支付宝
Cygnus Yang 微信微信