找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3490

积分

0

好友

478

主题
发表于 昨天 18:20 | 查看: 8| 回复: 0

在嵌入式系统、汽车电子和工业自动化领域,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工具包中的cansendcandump是测试CAN通信的利器。

  1. 终端A:发送CAN测试数据
    打开一个终端,发送一帧标准CAN数据:

    cansend vcan0 123#1122334455667788

    这条命令向 vcan0 接口发送了一帧CAN数据,其中123是十六进制的帧ID,#后面是8个字节的数据载荷(0x11至0x88)。

  2. 终端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. 方式1:UDP模式(适合实时性要求高的场景)

    • 电脑A(监听8888端口,转发至B的8889端口):
      ./can_eth_bridge udp can0 8888 192.168.1.101 8889 PC-A
    • 电脑B(监听8889端口,转发至A的8888端口):
      ./can_eth_bridge udp can1 8889 192.168.1.100 8888 PC-B
  2. 方式2:TCP模式(适合可靠性要求高的场景)

    • 电脑A作为TCP服务端(监听8888端口):
      ./can_eth_bridge tcp server can0 8888 PC-Server
    • 电脑B作为TCP客户端(连接A的8888端口):
      ./can_eth_bridge tcp client can1 8889 192.168.1.100 8888 PC-Client
  3. 验证通信

    • 在电脑A上,通过cansendcan0发送一帧数据:
      cansend can0 123#1122334455667788
    • 电脑B上运行的程序会接收到此数据,并将其转发到本地的can1接口。在电脑B上使用candump监听can1即可验证:
      candump can1  # 应能看到ID为0x123的CAN帧
    • 同理,在电脑B上发送数据,在电脑A上也能接收到。

五、高级测试技巧

在基础通信验证通过后,可以进行更深入的测试。

  1. 压力测试
    使用循环发送大量随机CAN帧,测试桥接程序的稳定性和处理能力:

    for i in {1..1000}; do cansend vcan0 $i#$(openssl rand -hex 8); done
  2. 协议转换模拟
    在实际应用中,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))
  3. 延迟测量
    可以在CAN数据中嵌入时间戳,用于粗略测量端到端的传输延迟:

    cansend vcan0 456#$(date +%s | xxd -p)

    接收方解析数据中的时间戳,与当前时间对比即可估算延迟。

参考资料

[1] CAN与以太网协议转换, 微信公众号:mp.weixin.qq.com/s/Il1p3hBIPnZuITMm8z76xQ

版权声明:本文由 云栈社区 整理发布,版权归原作者所有。




上一篇:OpenAI波兰裔工程师:揭秘推动GPT-4与o1模型的关键技术贡献与团队演变
下一篇:RuVector:Rust 构建的自进化向量库,125ms 极速启动实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-25 07:36 , Processed in 0.418027 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表