栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

相机和毫米波雷达数据融合2--SocketCan编写

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

相机和毫米波雷达数据融合2--SocketCan编写

相机和毫米波雷达数据融合1–流程框架

相机和毫米波雷达数据融合2–SocketCan编写

相机和毫米波雷达数据融合2--SocketCan编写

参考文章工控机Can接口激活项目SocketCan编写

头文件 can_vehicle_class.h源文件 can_vehicle_class.cpp

构造函数Can_Init()CAN_Receive_Msg(parameters)Can_Send_Msg(parameters) 总结

参考文章

linux下的SocketCan编写
Linux socket CAN编程示例

工控机Can接口激活

工控机的can卡需要激活,一般厂家会有执行文件,你每次开机然后执行这个文件就好了。也可以把这个文件设置成开机自动执行,这样就不要每次都运行了。


里面的内容没有太大借鉴意义,不同厂家写的不一样。运行成功之后可以通过ifconfig命令查看是否出现了相应的can口。注意这里面的can口命名(can0,can1)很重要,后面的SocketCan代码中的名字和这里的一致

算了还是看看这个**.sh**文件里写了什么吧。


重点就是设置的语句“set up”等等,你会看到参考文章链接中的代码前面会有类似的设置语句,这时你就知道我的**Can_Init()**里面为什么注释掉这几行设置代码了。总结就是别重复激活,一个位置激活了,另外就没必要再次激活了。


Canutils,这是linux下一个查看can报文的软件,你可以在你的linux里下一个,网上教程很多。用candump命令可以很好地查看指定can口传输的报文。

项目SocketCan编写

本人对c++基础不好,在编写的时候对相应类的编写可能不合适,希望大家一起交流,指导。

里面的错误可以忽略,因为这是linux下的代码,但是为了方便写文章我在windows下打开了。
箭头所指的两个文件用来实现SocketCan功能。

头文件 can_vehicle_class.h
#ifndef CAN_VEHICLE_CLASS_H
#define CAN_VEHICLE_CLASS_H

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

using namespace std;

class CanVehicleClass
{
private:
    int Can_Init();


public:
    CanVehicleClass(char* name);
    char* can_name;//绑定的can口
    int s;//socketcan套接字

    unsigned char CAN_Receive_Msg(can_frame& receive_msg,vector &receive_id);
    int Can_Send_Msg(vector& send_msg_vec);

    vector send_msg_vec;//打算发送的报文
    vector receive_id_vec;//接受过滤的报文id
    can_frame receive_msg;//接收到的报文
};


#endif

这个头文件声明了一个CanVehicleClass类,类中声明了构造函数,can初始化函数,can报文发送函数,can报文接收函数,指定的can口名称,想要过滤的报文id,想要发送的报文本身,接收到的报文本身。

源文件 can_vehicle_class.cpp


源文件中对四个函数进行定义,最上面的是CanvehicleClass类的构造函数。
下面来看看这几个函数。

构造函数
CanVehicleClass::CanVehicleClass(char* name)
{
    can_name=name;
    printf("%s","In class constructor of CanVehicleClass.");
    Can_Init();
}

构造函数在创建类的时候会自己运行,所以我把can口名字定义,和Can_Init()函数都写在里面了。

Can_Init()
int CanVehicleClass::Can_Init()
{
    int ret;
    struct sockaddr_can addr;
    struct ifreq ifr;
    // system("sudo ip link set can0 type vcan bitrate 100000");
    // system("sudo ifconfig can0 up");
    // printf("this is a can send demorn");
//1.Create socket
    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0)
    {
        perror("socket PF_CAN failed");
        return -1;
    }
//2.Specify can0 device
    strcpy(ifr.ifr_name, can_name);//这里写入can口名字,我的是can_name
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if (ret < 0) 
    {
        perror("ioctl failed");
        return -1;
    }
//3.Bind the socket to can0
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) 
    {
        perror("bind failed");
        return -1;
    }
//4.Disable filtering rules, do not receive packets, only send
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);  
//5.return socket
    return s;
}

这个代码我也不太懂,但是不需要怎么改,注意在里面指定can口就好了。想要了解相关知识可以自己去查或者看文章开头的参考文章。

CAN_Receive_Msg(parameters)
unsigned char CanVehicleClass::CAN_Receive_Msg(can_frame &receive_msg,vector &receive_id_vec)
{
    //Define receive rules
	struct can_filter rfilter[receive_id_vec.size()];
    for(int i=0;i 0)
    {
        return receive_msg.can_id;
    }
    if(nbytes == -1)
    {
        printf("%s","receive error msg");
        close(s);
        return -1;
    }
}

传入的参数:receive_msg用来存储read函数在总线上读到的can报文。receive_id_vec是你打算获取的报文id列表。这个函数运行之后,receive_msg就被赋值了,这是CanVehicleClass类的成员数据。

Can_Send_Msg(parameters)
int CanVehicleClass::Can_Send_Msg(vector& send_msg_vec)
{
    int nbytes;
    //  struct can_frame frame;
    //  frame.can_id  = send_id;
    //  frame.can_dlc = send_len;
    //  for(int i=0;is, &send_msg_vec[i], sizeof(send_msg_vec[i]));
        if(nbytes != sizeof(send_msg_vec[i]))
        {
        printf("%s,%s","send error frame ",strerror(errno));
        close(this->s);
        return -1;
        }
    }
    return nbytes;
}

传入的参数:你想要发送的报文列表,send_msg_vec是一个存储了很多你这个周期想要发送的报文的vector,这个函数的关键在于用write函数将vector中的can_frame们发送出去。

总结

至此,SocketCan的编写内容就讲完了,代码中有一些不太需要的我没有删除,遇到不懂的可以百度,或者查看参考文章链接。这篇文章主要是完成了具有SocketCan功能类的编写,这样可以方便在之后的程序进行调用。 写完这些文件之后你可以在can_vehicle_class.cpp中继续编写一个main()函数来测试编写的代码是否正确,或者是重新写一个文件,但是需要注意头文件的包含,还有多源文件编译的命令。(去百度linux的编译命令行)

大概就是这样的一段代码吧,我没跑过如果编译有错看看是不是多源文件编译没弄好,头文件没弄好之类的。如果生成了可执行文件,你可有如下选择进行测试:

利用canutils,这是最简单的测试方式。首先利用candump can0,来监听can0口的报文,然后运行可执行文件,会发现窗口出现相应的报文,说明发送报文没问题。然后用cansend 发送0x17 0x18的报文,代码窗口如果只显示0x17的id说明接收没问题。用usbcan,用usbcan连接你的电脑和工控机的can口,然后用相应的测试软件TSmaster来发送和接收can,与上文类似。

int main()
{

    CanVehicleClass test_can("can0");
    for (int i = 0; i < 10; ++i)
    {
        can_frame temp;
        temp.can_id=0x16;

        temp.can_dlc=8;
        for(int j=0;j 

如果代码这里有问题,可以在评论区提出来,最好先看参考文章的内容,百度之后再问,最后的测试代码是我写文章的时候写的没有测试,不知道有没有问题,但是你可以看到,写成类之后,这几行代码就完成需要的功能。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768290.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号