NVIDIA Jetson Xavier CAN 开机启动及应用编程

目录

    • NVIDIA XAVIER CAN 配置及开机启动
      • 1、CAN配置
      • 2、CAN开机自启
      • 3、SocketCan应用编程基础知识
      • 4、NVIDIA Jetson Xavier CAN 发送数据
      • 4、NVIDIA Jetson Xavier CAN 接收数据

NVIDIA XAVIER CAN 配置及开机启动

NVIDIA Jetson Xavier CAN 开机启动及应用编程_第1张图片

1、CAN配置

1.1、使用modprobe 工具 加载CAN设备

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

1.2、配置CAN参数

//①、关闭CAN
sudo ip link set down can0  
sudo ip link set down can1

//②、设备CAN波特率
sudo ip link set can0 type can bitrate 500000
sudo ip link set can1 type can bitrate 500000

//③、打开CAN
sudo ip link set up can0
sudo ip link set up can1

1.3、使用 ifconfig -a 命令查看CAN驱动是否加载成功

2、CAN开机自启

2.1、编写脚本 enable_CAN.sh

touch enable_CAN.sh  // 创建脚本文件
sudo chmod 777 enable_CAN.sh  //给脚本文件赋权限

2.2、编写脚本

sudo vi enable_CAN.sh
#!/bin/sh

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

sudo ip link set down can0
sudo ip link set down can1

sudo ip link set can0 type can bitrate 500000
sudo ip link set can1 type can bitrate 500000

sudo ip link set up can0
sudo ip link set up can1

NVIDIA Jetson Xavier CAN 开机启动及应用编程_第2张图片

2.3、配置开机启动

①、将enable.sh脚本文件拷贝到/usr/locak/ 目录下

sudo cp enable_CAN.sh /usr/local/

②、配置 service 文件

cd /etc/systemd/system   //进入文件目录下
sudo touch enable_CAN.service  //新建 enable_CAN.service
sudo vi enable_CAN.service     //配置文件如下
[Unit]
Description=Can

[Service]
ExecStart=/usr/local/enable_CAN.sh start

[Install]
WantBy=multi-user.target

③、设置服务

sudo systemctl daemon-reload
sudo systemctl enable enable_CAN.service
sudo systemctl start enable_CAN.service

④、重启XAVIER 后 使用 ifconfig -a 查看 CAN设备是否启动成功

NVIDIA Jetson Xavier CAN 开机启动及应用编程_第3张图片

3、SocketCan应用编程基础知识

3.1、创建socket套接字

CAN总线套接字采用标准的网络套接字操作完成,网络套接字在头文件中有定义。创建CAN套接字方式如下:

int s = -1;

/* 创建套接字 */
s = socket(PF_CAN,SOCK_RAW,CAN_RAW);
if(0 > s)
{
	perror("socket error");
	exit(EXIT_FAILURE);
    
}

3.2、将套接字与CAN设备进行绑定

struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
int ret;


strcpy(ifr.ifr_name,"can0");//指定名字
//灵活设置CAN口
sprintf(ifr.ifr_name,"can%d",1);

ioctl(s,SIOCGIFINDEX,&ifr);

can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;

/* 将套接字与 can0 进行绑定 */
ret = bind(s,(struct sockaddr *)&can_addr,sizeof(can_addr));
if(0 > ret)
{
	perror("bind error");
	close(s);
	exit(EXIT_FAILURE);
}

3.3、设置过滤规则

struct can_filter rfilter[2]; // 定义一个can_filter 结构体对象

// 填充过滤规则,只接收ID为(can_id&can_mask)的报文
rfilter[0].can_id = 0x60A;
rfilter[0].can_mask = 0x7FF;
rfilter[1].can_id = 0x60B;
rfilter[1].can_mask = 0x7FF;

// 调用 setsockopt 设置过滤规则
setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,&rfilter,sizeof(rfilter));

如果应用程序功能仅是发送数据,则可省去接收队列,setsockopt()函数的第4个参数设为NULL,第五个参数设置为0:

setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,NULL,0);

3.4、数据发送

CAN总线每一次通信使用struct can_frame 结构体将数据封装成帧,struct can_frame定义如下:

struct can_frame {
 canid_t can_id; /* CAN 标识符 */
 __u8 can_dlc; /* 数据长度(最长为 8 个字节) */
 __u8 __pad; /* padding */
 __u8 __res0; /* reserved / padding */
 __u8 __res1; /* reserved / padding */
 __u8 data[8]; /* 数据 */
};

can_id 为帧的标识符,如果是标准帧,就使用 can_id 的低 11 位;如果为扩展帧,就使用 0~28 位。can_id 的第 29、30、31 位是帧的标志位,用来定义帧的类型,定义如下:

#define CAN_EFF_FLAG 0x80000000U /* 扩展帧的标识 */
#define CAN_RTR_FLAG 0x40000000U /* 远程帧的标识 */
#define CAN_ERR_FLAG 0x20000000U /* 错误帧的标识,用于错误检查 */
/* mask */
#define CAN_SFF_MASK 0x000007FFU /* 获取标准帧 ID */
#define CAN_EFF_MASK 0x1FFFFFFFU /* 获取标准帧 ID */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */

数据发送使用write()函数实现,发送报文ID为0x123,数据为:0xA0、0xB0、0xC0;定义如下:

struct can_frame frame; //定义一个 can_frame 变量
int ret;
frame.can_id = 123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 123;
frame.can_dlc = 3; //数据长度为 3
frame.data[0] = 0xA0; //数据内容为 0xA0
frame.data[1] = 0xB0; //数据内容为 0xB0
frame.data[2] = 0xC0; //数据内容为 0xC0
ret = write(sockfd, &frame, sizeof(frame)); //发送数据
if(sizeof(frame) != ret) //如果 ret 不等于帧长度,就说明发送失败
 perror("write error");

要发送远程帧(帧 ID 为 123),可采用如下方法进行发送:

struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | 123;
write(sockfd, &frame, sizeof(frame));

3.5、数据接收

使用read()函数实现:

struct can_frame frame;
int ret = read(sockfd, &frame, sizeof(frame));

4、NVIDIA Jetson Xavier CAN 发送数据

4.1、can_send.cCAN发送数据具体实现如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int s;

int main(int argc, char *argv[])
{
    int cannum = atoi(argv[1]);
    char buf[60];
	sprintf(buf,"ifconfig can%d down",cannum);// 关闭CAN
	system(buf);
	sprintf(buf,"ip link set can%d type can bitrate 500000",cannum);// 设置CAN 波特率500000
	system(buf);
	sprintf(buf,"ifconfig can%d up",cannum);//开启CAN
	system(buf);
    
    struct can_frame frame1[2] = {{0}};
	struct sockaddr_can addr;
	struct ifreq ifr;

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字
    if(0 > s)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    sprintf(ifr.ifr_name, "can%d",cannum);
    ioctl(s, SIOCGIFINDEX, &ifr); //指定can设备--can0 can1...
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    int ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与can%d 绑定
    if(0 > ret)
    {
        perror("bind error");
        close(s);
        exit(EXIT_FAILURE);
    }

    //待发送的数据
    struct can_frame frame = {0};
    frame.data[0] = 0xA0;
    frame.data[1] = 0xB0;
    frame.data[2] = 0xC0;
    frame.data[3] = 0xD0;
    frame.data[4] = 0xE0;
    frame.data[5] = 0xF0;
    frame.can_dlc = 6;  // 数据字节数
    frame.can_id = 0x123;  // 报文ID

    //设置过滤规则: 仅发送数据 不接收报文*/
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &frame, sizeof(frame)); 

    for(;;)
    {
        //发送数据
        ret = write(s,&frame,sizeof(frame));
        if(sizeof(frame) != ret) //如果ret不等于报文长度 说明发送失败
        {
            perror("write error");
            goto out;
        }

        sleep(1); //发送时延 1s发一次
    }

out:
    close(s);
    exit(EXIT_SUCCESS);

    return 0;
}

4.2、使用aarch64-linux-gnu-gcc 交叉编译器编译程序

aarch64-linux-gnu-gcc -o can_send can_send.c

如果没有ARM 交叉编译环境,则使用如下命令安装:

sudo apt-get install gcc-9-aarch64-linux-gnu
sudo apt-get install gcc-aarch64-linux-gnu

查看aarch64-linux-gnu-gcc版本号

aarch64-linux-gnu-gcc -v

4.3、将生成的可执行文件can_send 拷贝到/home/root/目录下;使用如下命令运行can_send`

./can_updata 1 // 1是对应的CAN 设备号 Xavier 可以引出两路CAN

4.4、把CANCAN_HMPSOC 5EV CAN4_HCANCAN_LMPSOC 5EV CAN4_L

4.5、设置CAN卡参数,打开对应通道,启用终端电阻;

NVIDIA Jetson Xavier CAN 开机启动及应用编程_第4张图片

CAN卡会收到Xavier 发送过来的如下报文

NVIDIA Jetson Xavier CAN 开机启动及应用编程_第5张图片

4、NVIDIA Jetson Xavier CAN 接收数据

4.1、can_read.cCAN接收数据源码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main(int argc, char *argv[])
{
    int cannum = atoi(argv[1]);
    char buf[60];
	sprintf(buf,"ifconfig can%d down",cannum);// 关闭CAN
	system(buf);
	sprintf(buf,"ip link set can%d type can bitrate 500000",cannum);// 设置CAN 波特率500000
	system(buf);
	sprintf(buf,"ifconfig can%d up",cannum);//开启CAN
	system(buf);
    
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    int sockfd = -1;
    int i;
    int ret;

    sockfd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    if(0 > sockfd)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    sprintf(ifr.ifr_name, "can%d",cannum);
    //strcpy(ifr.ifr_name, "can4");
    ioctl(sockfd, SIOCGIFINDEX, &ifr); //指定can设备--can0 can1...
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr)); //将套接字与can%d 绑定
    if(0 > ret)
    {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }


    for(;;)
    {
        if(0 > read(sockfd,&frame,sizeof(struct can_frame)))
        {
            perror("read error");
            break;
        }

        if(frame.can_id & CAN_ERR_FLAG)
        {
            printf("Error frame!\n");
            break;
        }


        if(frame.can_id & CAN_EFF_FLAG)
        {
            printf("扩展帧 <0x%08x>",frame.can_id & CAN_EFF_MASK);
        }
        else
        {
            printf("标准帧 <0x%03x>",frame.can_id & CAN_SFF_MASK);
        }

        if(frame.can_id & CAN_RTR_FLAG)
        {
            printf("remote request\n");
            continue;
        }


        printf("[%d]",frame.can_dlc);

        for(int i = 0; i < frame.can_dlc; i++)
        {
            printf("%02x",frame.data[i]);
        }
        printf("\n");
        
    }
    
    close(sockfd);
    exit(EXIT_SUCCESS);

}

使用aarch64-linux-gnu-gcc 交叉编译器编译程序

aarch64-linux-gnu-gcc -o can_read can_read.c

将生成的可执行文件can_read 拷贝到/home/root/目录下;使用如下命令运行can_read

Welcome to follow my weixingongzhonghao "Kevin的学习站"

你可能感兴趣的:(无人驾驶学习笔记,#,NVIDIA,Jeston,学习笔记,#,自动驾驶智能车实战,自动驾驶,linux,人工智能)