CAN数据转ROS格式的订阅和发布

CAN数据转ROS格式的订阅和发布(C++)

一、环境安装

  1. 安装ROS包:
    确保你的ROS环境已经设置好,然后安装ROS中与CAN相关的包,比如ros_canopenros_canopen_chain_node等。
  2. 安装SocketCAN:
    安装并配置SocketCAN以便与CAN总线通信。

二、ROS环境

1、创建工作空间

mkdir catkin_ws
cd catkin_ws
mkdir src

2、初始化工作空间

cd src
catkin_init_workspace

3、编译(这里我们是空文件编译成功即可)

cd catkin_ws
catkin_make

在这里插入图片描述
编译成功后会生成build和devel这两个目录
4、创建一个功能包

cd src
catkin_create_pkg mytest roscpp std_msgs
mytest是我的功能包名字,一个依赖于std::msgs和 roscpp的mytest功能包

在这里插入图片描述
mytest下就会存在这几个目录和文件
5、创建msg文件

cd src/mytest
mkdir msg
touch Can.h
创建一个msg文件,并将数据格式添加进去

msg文件是根据它里面的数据格式来生一个包含这些数据格式的结构体。
Can总线的数据个数如下:

#can_frame.msg

uint32 can_id
uint8 can_dlc
uint8 can_pad
uint8 can_res0
uint8 can_res1
uint8[8] data

在src下的package.xml文件中进行如下修改
在这里插入图片描述
在src下的CMakeLists.txt文件中
添加message_generation
在这里插入图片描述
添加你的msg文件名(可一次加多个)
在这里插入图片描述
取消注释,并添加message_runtime
在这里插入图片描述
做完以上步骤,返回到catkin_ws目录进行catkin_make编译,编译成功会在devel下的include文件中产生你msg所对应的头文件。

三、订阅和发布的代码

1、 在mytest包中添加两个节点,一个是发布者一个是订阅者

cd catkin_ws/src/mytest/src
touch can_date_pub.cpp
touch can_date_sub.cpp

2、can_date_pub.cpp

#include "ros/ros.h"
#include "mytest/Can.h"   //对应自己的包和生成的头文件
#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <cstring>

int main(int argc, char **argv) {
    ros::init(argc, argv, "can_publisher");
    ros::NodeHandle nh;

    // 创建一个socket用于CAN通信
    int can_socket = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    if(can_socket < 0)
    {
         ROS_ERROR("failed to create  CAN sicket");
         return -1;
    }
     指定CAN网络接口
        struct ifreq ifr;
    std::strcpy(ifr.ifr_name, "can0");   //对应采集CAN总线的接口名
    ioctl(can_socket, SIOCGIFINDEX, &ifr);

    // 将socket绑定到CAN接口
    struct sockaddr_can addr;
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    if (bind(can_socket, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
        ROS_ERROR("Failed to bind CAN socket to interface");
        close(can_socket);
        return -1;
    }

    ros::Publisher can_pub = nh.advertise<mytest::Can>("can0_topic", 10);  

    ros::Rate rate(10); // 调整速率

   while (ros::ok()) {
    // 将CAN数据发布到ROS
    mytest::Can can_data;
    ssize_t bytes = recv(can_socket, &can_data, sizeof(mytest::Can), 0);
    if (bytes > 0) {
        // 创建一个CAN消息
        mytest::Can can_msg;
        can_msg.can_id = can_data.can_id;
        can_msg.can_dlc = can_data.can_dlc;  
        can_msg.can_pad = can_data.can_pad;
        can_msg.can_res0 = can_data.can_res0;  
        can_msg.can_res1 = can_data.can_res1;    
        can_msg.data = can_data.data;

        can_pub.publish(can_msg);
    }
}

    // 延时以确保消息被发布
     ros::spinOnce();
        rate.sleep();
    close(can_socket);
    return 0;
}

3、can_date_sub.cpp

#include "ros/ros.h"
#include "mytest/Can.h"  

void canCallback(const mytest::Can::ConstPtr& can_msg) {  
    // 打印接收到的 CAN 消息数据
    ROS_INFO("Received CAN message:");
    ROS_INFO("can_id: %u", can_msg->can_id);
    ROS_INFO("can_dlc: %u", can_msg->can_dlc);
    ROS_INFO("can_pad: %u", can_msg->can_pad);
    ROS_INFO("can_res0: %u", can_msg->can_res0);
    ROS_INFO("can_res1: %u", can_msg->can_res1);
    ROS_INFO("Data: %u %u %u %u %u %u %u %u",
         can_msg->data[0], can_msg->data[1], can_msg->data[2], can_msg->data[3],
         can_msg->data[4], can_msg->data[5], can_msg->data[6], can_msg->data[7]);
    // ROS_INFO("Data:"can_msg->data);
    //  for (uint8_t data_byte : can_msg->data) {
    //     ROS_INFO(" %u", data_byte);
    //  }
}

int main(int argc, char **argv) {
    ros::init(argc, argv, "can_subscriber");
    ros::NodeHandle nh;

    ros::Subscriber can_sub = nh.subscribe("can0_topic", 10, canCallback);  // 替换成你的话题名

    // 循环等待消息
    ros::spin();

    return 0;
}

4、在CMakeLists.txt文件中加上这两句话

add_executable(can_date_pub src/can_date_pub.cpp)
add_executable(can_date_sub src/can_date_sub.cpp)
target_link_libraries(can_date_pub ${catkin_LIBRARIES})
target_link_libraries(can_date_sub ${catkin_LIBRARIES})

5、添加完成后返回catkin_ws目录下进行编译

注意事项:如果编译时,报头文件错误(这个头文件是指msg数据格式生成的头文件),这个头文件格式是 #include “mytest/Can.h”.
Mytest  是你自己创建的消息包,Can.h是Can.msg生成的一个头文件。