相机和毫米波雷达数据融合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卡需要激活,一般厂家会有执行文件,你每次开机然后执行这个文件就好了。也可以把这个文件设置成开机自动执行,这样就不要每次都运行了。
里面的内容没有太大借鉴意义,不同厂家写的不一样。运行成功之后可以通过ifconfig命令查看是否出现了相应的can口。注意这里面的can口命名(can0,can1)很重要,后面的SocketCan代码中的名字和这里的一致
算了还是看看这个**.sh**文件里写了什么吧。
重点就是设置的语句“set up”等等,你会看到参考文章链接中的代码前面会有类似的设置语句,这时你就知道我的**Can_Init()**里面为什么注释掉这几行设置代码了。总结就是别重复激活,一个位置激活了,另外就没必要再次激活了。
Canutils,这是linux下一个查看can报文的软件,你可以在你的linux里下一个,网上教程很多。用candump命令可以很好地查看指定can口传输的报文。
本人对c++基础不好,在编写的时候对相应类的编写可能不合适,希望大家一起交流,指导。
里面的错误可以忽略,因为这是linux下的代码,但是为了方便写文章我在windows下打开了。
箭头所指的两个文件用来实现SocketCan功能。
#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;i s, &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
如果代码这里有问题,可以在评论区提出来,最好先看参考文章的内容,百度之后再问,最后的测试代码是我写文章的时候写的没有测试,不知道有没有问题,但是你可以看到,写成类之后,这几行代码就完成需要的功能。



