在嵌入式系统、汽车电子和工业自动化领域,CAN(Controller Area Network)总线是一种广泛应用的可靠通信标准。然而,随着系统复杂度提升和网络/系统集成需求,将分布在不同物理位置的CAN网络通过以太网互联,进行协议转换和数据透传,成为一种常见且高效的解决方案。本文将以Linux环境为例,从零开始,详细介绍搭建一个虚拟的CAN与以太网协议转换测试环境的完整流程。
一、搭建虚拟测试环境
1. 创建Linux虚拟机
首先,我们需要一个标准的Linux环境。
- 推荐系统:Ubuntu 22.04 LTS。此版本长期支持,且通常预装了GCC和Python,方便后续开发。
- 网络配置:将虚拟机网络适配器设置为桥接模式。这能确保虚拟机获得一个与物理主机在同一局域网的独立IP地址,是后续进行跨设备通信测试的基础。
2. 安装必备工具
在Ubuntu终端中,执行以下命令安装CAN总线工具及网络工具包:
sudo apt update
sudo apt install can-utils net-tools socat libsocketcan-dev build-essential
其中,can-utils是后续进行CAN数据收发的核心工具集。
二、创建虚拟CAN与网络接口
为了在没有真实硬件的情况下进行测试,我们将创建虚拟接口。
1. 加载内核模块并创建虚拟CAN接口
按顺序执行以下命令:
sudo modprobe can
sudo modprobe can_raw
sudo modprobe can_bcm # 加载BCM(广播管理器)模块
sudo modprobe vcan # 加载虚拟CAN模块
sudo ip link add dev vcan0 type vcan # 创建名为vcan0的虚拟CAN接口
sudo ip link set up vcan0 # 启用该接口
2. 验证虚拟CAN接口
使用ip命令查看接口状态:
ip -d link show vcan0
命令执行后,若看到类似<NOARP,UP,LOWER_UP> mtu 16 ...的输出,表明虚拟CAN接口 vcan0 已创建并启动成功。
3. (单机验证场景)创建虚拟以太网对
为了模拟两个网络节点,我们可以在一台机器上创建一对虚拟以太网接口:
sudo ip link add veth0 type veth peer name veth1 # 创建一对接口veth0和veth1
sudo ip link set up veth0
sudo ip link set up veth1
4. (单机验证场景)为虚拟以太网接口分配IP
为这对接口分配属于同一网段的IP地址,使其能够通信:
sudo ip addr add 127.0.1.1/24 dev veth0
sudo ip addr add 127.0.1.2/24 dev veth1
三、模拟CAN数据收发测试
can-utils工具包中的cansend和candump是测试CAN通信的利器。
-
终端A:发送CAN测试数据
打开一个终端,发送一帧标准CAN数据:
cansend vcan0 123#1122334455667788
这条命令向 vcan0 接口发送了一帧CAN数据,其中123是十六进制的帧ID,#后面是8个字节的数据载荷(0x11至0x88)。
-
终端B:接收并查看CAN数据
打开另一个终端,使用candump监听vcan0接口:
candump vcan0
你将看到类似输出:
vcan0 123 [8] 11 22 33 44 55 66 77 88
candump功能强大,支持多种参数以不同格式显示信息,便于调试分析:
| 参数 |
说明 |
示例 |
-t 系列 |
显示时间戳:<br>-ta:绝对时间<br>-td:相对时间间隔<br>-tz:时间戳归零<br>-tA:带日期的绝对时间 |
candump -ta -x can0 |
-c |
为不同接口的数据着色,便于区分 |
candump -x -c can0 can1 |
-l |
将数据记录到文件(方便后续用文本工具分析) |
candump -l can0 |
例如,使用-x参数可以显示数据方向(TX发送/RX接收):
candump -x vcan0
发送数据后,你会看到类似 vcan0 TX - - 123 [8] 11 22 33 44 55 66 77 88 的输出。
4. 环境清理
测试完成后,可以删除虚拟接口:
sudo ip link delete vcan0 2>/dev/null
对于更复杂的测试环境,可以创建一个清理脚本,用于重置CAN接口、卸载模块等操作。以下脚本是一个参考示例,使用时请根据实际情况(如ROS版本)调整路径:
#!/bin/bash
echo "正在清理虚拟CAN和ROS配置..."
# 清理CAN接口
sudo ip link set down can0 2>/dev/null || true
sudo ip link set down can1 2>/dev/null || true
sudo ip link delete can0 2>/dev/null || true
sudo ip link delete can1 2>/dev/null || true
# 卸载模块
sudo modprobe -r can_raw 2>/dev/null || true
sudo modprobe -r can 2>/dev/null || true
sudo modprobe -r vcan 2>/dev/null || true
# 清理ROS
killall -9 roscore roslaunch rosmaster 2>/dev/null || true
rm -rf ~/.ros/log/*
# 重置环境
unset ROS_MASTER_URI
unset ROS_HOSTNAME
unset ROS_IP
source /opt/ros/noetic/setup.bash # 根据您的ROS版本调整
echo "清理完成!现在尝试启动roscore..."
roscore
四、分布式部署示例(两台电脑互联)
这是更贴近真实场景的测试:电脑A和电脑B通过以太网连接,各自连接一条独立的CAN总线,目标是实现两条CAN总线之间的跨设备数据透传。
假设网络规划如下:
| 设备 |
IP地址 |
CAN接口 |
角色 |
| 电脑A |
192.168.1.100 |
can0 |
发送/接收CAN数据 |
| 电脑B |
192.168.1.101 |
can1 |
发送/接收CAN数据 |
你需要一个桥接程序(例如 can_eth_bridge)来转发数据。该程序通常支持UDP和TCP两种模式。
-
方式1:UDP模式(适合实时性要求高的场景)
-
方式2:TCP模式(适合可靠性要求高的场景)
-
验证通信
五、高级测试技巧
在基础通信验证通过后,可以进行更深入的测试。
-
压力测试
使用循环发送大量随机CAN帧,测试桥接程序的稳定性和处理能力:
for i in {1..1000}; do cansend vcan0 $i#$(openssl rand -hex 8); done
-
协议转换模拟
在实际应用中,CAN帧可能需要封装为特定的网络协议格式(如JSON)进行传输。以下是一个简单的Python示例,展示如何将CAN帧转换为JSON并通过UDP发送:
import json
import socket
# 假设msg是一个包含CAN ID和data的对象
can_frame = {"id": hex(msg.arbitration_id), "data": list(msg.data)}
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.sendto(json.dumps(can_frame).encode(), ("192.168.1.100", 8888))
-
延迟测量
可以在CAN数据中嵌入时间戳,用于粗略测量端到端的传输延迟:
cansend vcan0 456#$(date +%s | xxd -p)
接收方解析数据中的时间戳,与当前时间对比即可估算延迟。
参考资料
[1] CAN与以太网协议转换, 微信公众号:mp.weixin.qq.com/s/Il1p3hBIPnZuITMm8z76xQ
版权声明:本文由 云栈社区 整理发布,版权归原作者所有。