基于NVIDIA Jetson AGX Xavier的移动机器人开发(3)——Xavier CAN简介、Socket简介、Socket CAN简介

【摘要】由于大陆ARS408毫米波雷达以及底盘控制均采用CAN通信,Xavier的40-Pin扩展引脚包含两路CAN控制器,因此本篇介绍CAN的相关配置以及使用SoketCAN进行报文的收发。

一、Xavier CAN

  1. Xavier AGX使用两个Bosch的M_TTCAN(时间触发CAN)控制器,支持CAN2.0和CAN FD,采用ISO11898,最高传输速率可达15 Mbps,8位数据传输。具体特性可以参考Xavier的用户手册以及Bosch的手册,另外嵌入式linux官方给了关于xavier can的介绍(网址
  2. 两路CAN位于40pin的扩展引脚上,Xavier本身不带CAN收发器,因此需要外接CAN收发器与T以及R引脚相连
  3. 进行CAN收发报文之前,需要使能Linux对应的CAN驱动,包括以下几个步骤:
  • CAN的相应引脚默认配置为GPIO功能, 需要将其设置为CAN复用模式,通过更改 pinmux 配置文件实现。有两种方式可以修改,首先直接修改 pinmux 文件:
    将pinmux.0x0c303000 和 pinmux.0x0c303008 用于CAN1,而 pinmux.0x0c303010 和 pinmux.0x0c303018 用于CAN0。
    法1:直接修改配置文件,pinmux 配置文件位于 JETPACK_ROOT/Xavier/Linux_for_Tegra/bootloader/t186ref/BCT/
    法2:使用 busybox 中的 devmem 工具配置(推荐)
# 法1
$JETPACK_ROOT/Xavier/Linux_for_Tegra/bootloader/t186ref/BCT/tegra19x-mb1-pinmux-p2888-0000-a04-p2822-0000-b01.cfg

*****************************************************************************************************************
# 法2
# 安装busybox, 需要里面的devmem工具
sudo apt install busybox

# pinmux.0x0c303000 and pinmux.0x0c303008 are for CAN1
# pinmux.0x0c303010 and pinmux.0x0c303018 are for CAN0
# 检查当前的寄存器值
sudo busybox devmem 0x0c303000	# 0x0000C055
sudo busybox devmem 0x0c303008	# 0x0000C055
sudo busybox devmem 0x0c303010	# 0x0000C059
sudo busybox devmem 0x0c303018	# 0x0000C059

# 用devmem修改寄存器
sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458

# 改完后检查
sudo busybox devmem 0x0c303000	# 0x0000C400
sudo busybox devmem 0x0c303008	# 0x0000C458
sudo busybox devmem 0x0c303010	# 0x0000C400
sudo busybox devmem 0x0c303018	# 0x0000C458
  • 挂载 CAN驱动
sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

# 检查挂载
lsmod
  • CAN的基本配置,包括波特率,然后启动CAN
# 配置波特率为500000
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can1 type can bitrate 1000000

# 启动CAN
sudo ip link set up can0
sudo ip link set up can1

# 检查配置
ifconfig

# 关闭CAN
sudo ip link set down can0
sudo ip link set down can1

# 检查
ifconfig	# 关闭的话里面就没有can0, can1了
  • 使用can_utils进行简单的测试
# 安装
sudo apt install can-utils

# 123是十六进制帧ID, 后面是8字节十六进制数, 可以用.相隔也可以不用
cansend can0 123#99.95.42.07.2B.96.66.6E
cansend can1 123#99.95.42.07.2B.96.66.6E

# 随机发送
cangen -v can0
cangen -v can1

# 接收数据
candump can0
candump can1
  • 可以通过sh脚本一次性完成上述工作
echo ">>> Reconfigure the four regs for CAN controllers' pins"

echo ">> ----------original regs data----------"
sudo busybox devmem 0x0c303000
sudo busybox devmem 0x0c303008
sudo busybox devmem 0x0c303010
sudo busybox devmem 0x0c303018
echo ">> ----------Modified regs data----------"
sudo busybox devmem 0x0c303000 32 0x0000C400
sudo busybox devmem 0x0c303008 32 0x0000C458
sudo busybox devmem 0x0c303010 32 0x0000C400
sudo busybox devmem 0x0c303018 32 0x0000C458

sudo busybox devmem 0x0c303000
sudo busybox devmem 0x0c303008
sudo busybox devmem 0x0c303010
sudo busybox devmem 0x0c303018

echo ">>> ----------Mount CAN controllers and load the drivers----------"
sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

echo ">>> ----------Set Baud rate----------"
sudo ip link set can0 type can bitrate 500000 \
	dbitrate 2000000 berr-reporting on fd on
sudo ip link set can1 type can bitrate 500000 \
	dbitrate 2000000 berr-reporting on fd on

echo ">>> ----------Enable CAN----------"
sudo ip link set up can0
sudo ip link set up can1

二、Socket简介

  1. socket就是套接字的意思,用于描述地址和端口。主机通过IP地址确定通信的网络设备,而端口号用于指定具体的进程
  2. TCP(传输控制协议)和UDP(用户数据报协议)是两种常用的网络传输协议,而socket是用于进行网络通信的编程接口
  3. TCP是一种面向连接的协议,它提供可靠的数据传输、流式传输和错误检测机制。TCP在通信之前需要建立一个连接,并确保数据的可靠传输,保证数据的顺序和完整性,同时,收发顺序相同,因此基于数据流(流式套接字)。UDP是一种无连接的协议,它提供了一种简单的、不可靠的数据传输机制。UDP不需要建立连接,每个数据包都是独立发送的,没有数据包顺序和可靠性的保证。UDP适用于那些对实时性要求较高、对数据传输可靠性要求相对较低的应用场景
  4. Socket接口提供了用于创建和管理网络连接的函数,例如socket()函数用于创建一个套接字,bind()函数用于绑定套接字到特定的地址和端口,listen()函数用于监听连接请求,accept()函数用于接受连接,connect()函数用于发起连接等。通过Socket接口,应用程序可以选择使用TCP或UDP协议,并根据需要建立连接、发送和接收数据
  5. socket支持的协议有三种:流式套接字(SOCK_STREAM,对应TCP)、数据报套接字(SOCK_DGRAM,对应UDP)、原始套接字(SOCK_RAW,Socket CAN使用)

三、 Socket CAN介绍与使用

  1. 在Linux中,Socket编程接口是一种通用的接口,它不仅用于网络通信,还可以在本地进行进程间通信(IPC,Inter-Process Communication)。因此,Linux提供了无需网络的Socket,用于在本地进程之间进行通信
  2. UNIX域套接字(Unix Domain Socket):它是Linux提供的一种特殊类型的Socket,用于在同一台机器上的进程间进行通信。UNIX域套接字使用文件系统路径作为套接字的地址,并通过文件系统进行数据交换。它不需要网络协议栈的支持,因此具有较低的延迟和高的性能。UNIX域套接字适用于需要高性能和低延迟的本地进程通信场景
  3. SocketCAN是Linux内核中的一组网络协议和驱动程序,用于支持CAN总线的通信(注意,并非unix域通信,而是与外部CAN总线通信)。Linux 的传统 CAN 驱动程序基于字符设备的模型。通常,它们只允许向CAN控制器发送和从CAN控制器接收。此类设备驱动程序的传统实现仅允许单个进程访问设备,这意味着同时阻止所有其他进程。此外,这些驱动程序通常都与提供给应用程序的界面略有不同,从而扼杀了可移植性。而SocketCAN概念使用网络设备模型,允许多个应用程序同时访问一个CAN设备SocketCAN借用了套接字(socket)的概念和接口风格,但在实现上并不是传统意义上的套接字。它使用了一种特殊的CAN_RAW套接字类型和自定义的接口和驱动程序,以提供对CAN总线的访问和控制
  4. int socket(int domain, int type, int protocol);是socket函数的原型,这是一个通用的网络编程函数,用于创建套接字并指定通信协议,参数分别为:协议集、socket类型、传输协议(0会缺省),返回一个文件描述符。在SocketCAN中,我们使用socket函数创建用于CAN总线通信的套接字,需要指定PF_CAN协议族和CAN_RAW套接字类型。PF_CAN是对于原始socket协议系列的补充,同时,使用了一种特殊的CAN_RAW套接字类型
  5. SOCK_STREAM和SOCK_DGRAM的两个server和client程序是通过网络相互收发数据。而CAN的socket的server和client程序收发数据的对象是CAN总线。server从CAN总线上接收数据,client将数据发到CAN总线上,当CAN总线上有数据时,server才能接收数据,当CAN总线空闲时,client才能将数据发送出去。
  6. AF_CAN代表"CAN Family",即CAN族。它是Linux内核中用于SocketCAN的一种协议族,用于支持CAN总线的通信。在Linux中,SocketCAN提供了一种抽象的接口,使用户空间程序能够通过套接字(Socket)接口与CAN总线进行通信。AF_CAN是SocketCAN的一部分,它定义了CAN总线通信的协议族。AF_CAN支持多种CAN总线类型,包括CAN 2.0和CAN FD(Flexible Data-Rate)。它提供了一组特定的套接字选项和控制命令,用于配置和操作CAN总线。通过使用AF_CAN,用户可以方便地进行CAN数据的发送和接收,以及配置CAN总线的参数
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main()
{
	// 创建Socket,采用AF_CAN协议
	int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
	if (sock == -1) 
    	std::cerr << "Failed to create SocketCAN socket." << std::endl;

	// 设置CAN接口名称,配置CAN地址信息
	struct sockaddr_can addr;
	struct ifreq ifr;
	std::strcpy(ifr.ifr_name, "can0");  // 替换为实际的CAN接口名称
	if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) 
	{
	    std::cerr << "Failed to get CAN interface index." << std::endl;
	    close(sock);
    }
	addr.can_family = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;

	// 绑定CAN地址
	if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) 
	{
	    std::cerr << "Failed to bind SocketCAN socket." << std::endl;
	    close(sock);
    }

	// 发送CAN报文
	struct can_frame frame;
	frame.can_id = 0x123;  // CAN标识符
	frame.can_dlc = 8;     // 数据长度
	std::memset(frame.data, 0, sizeof(frame.data));  // 数据内容
	if (write(sock, &frame, sizeof(frame)) == -1) 
	{
	    std::cerr << "Failed to send CAN frame." << std::endl;
	    close(sock);
	}

	// 接收CAN报文
	struct can_frame frame;
	ssize_t nbytes = read(sock, &frame, sizeof(frame));
	if (nbytes < 0) 
	{
	    std::cerr << "Failed to receive CAN frame." << std::endl;
	    close(sock);
	} 
	else if (nbytes < sizeof(struct can_frame)) 
	{
	    std::cerr << "Incomplete CAN frame received." << std::endl;
	    close(sock);
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值