在 while 循环中读取 CAN 数据的更有效方法

More efficient way for reading CAN data in while loop

我有 3 个设备通过 CAN 接口发送 8 个字节的数据。为了从 CAN 读取缓冲区,我使用了一个 while 循环,它看起来像这样:

void CanServer::ReadFromCAN() {
     data_from_buffer_.clear();
     can_frame frame;
     read_can_port_ = read(soc_, &frame, sizeof(struct can_frame));

     if (read_can_port_ < 0) return;

     id_ = frame.can_id&0x1FFFFFFF;
     dlc_ = frame.can_dlc;

     for (const auto& byte : frame.data) 
          data_from_buffer_.push_back(byte);
}

while (ros::ok()) {
       std_msgs::Int32MultiArray tachometer_array;
       std::vector<__u8> data_from_can;

       /***
        * Read for the Radar1
        */

       this->ReadFromCAN();

       if (read_can_port_ < 0) continue;

       //ROS_INFO("Read from CAN");
       if (id_ == can_id::RadarFrame1)
           for (int i = 0; i < dlc_; i++) {
                radar1_bytes_[i] = data_from_buffer_[i];
                radar1_buffer_.push_back(data_from_buffer_[i]);
           }

           if (IsMagicWord(radar1_bytes_, 0)) {
               frame_id = "radar1_link";
               this->PulbishRadarPCL(frame_id, radar1_pub_, radar1_buffer_, 0);
               radar1_buffer_.clear();
               canFrame_.can_dlc = 0;
           }
}

    if (id_ == can_id::RadarFrame2) {
        for (int i = 0; i < dlc_; i++) {
            radar2_bytes_[i] = data_from_buffer_[i];
            radar2_buffer_.push_back(data_from_buffer_[i]);
        }

        if (IsMagicWord(radar2_bytes_, 1)) {
            frame_id = "radar2_link";
            this->PulbishRadarPCL(frame_id, radar2_pub_, radar2_buffer_, 1);
            radar2_buffer_.clear();
            canFrame_.can_dlc = 0;
        }
    }

    if (id_ == can_id::RadarFrame3) {
        for (int i = 0; i < dlc_; i++) {
            radar3_bytes_[i] = data_from_buffer_[i];
            radar3_buffer_.push_back(data_from_buffer_[i]);
        }

        if (IsMagicWord(radar3_bytes_, 2)) {
            frame_id = "radar3_link";
            this->PulbishRadarPCL(frame_id, radar3_pub_, radar3_buffer_, 2);
            radar3_buffer_.clear();
            canFrame_.can_dlc = 0;
        }
    }

    rate.sleep();
}

其中 rate.sleep() 类似于 C++ 中的 sleep() 函数。

现在,我 运行 这个 while 循环以 5 MHz 但是我认为这是一个矫枉过正,我在 1 个核心上几乎 100% CPU 使用率。

我试过延迟时间,但我认为这是非常低效的,我想知道有没有其他方法可以解决这个问题?

原来poll正是你所需要的。这是我的例子。

  1. 首先,在Linux中从header创建一个pollfd结构。我已决定创建一个 class 成员,但您可以根据自己的喜好创建:

     pollfd poll_;
     poll_.fd = soc_;
     poll_.events = POLLIN;
     poll_.revents = 0;
    

这里,soc_是套接字,POLLIN表示要从套接字读取。

  1. 然后,在我的 while 循环中,我没有延迟,而是在我的 while 循环开始时使用了这个函数:

     poll_int = poll(&poll_, 1, 100);
     if (poll_int <= 0) continue;
    

所以 poll() 函数 returns 值为 1 如果读取成功并且我设置了 100 毫秒的超时(只是一个随机数,我知道数据以更高的速率传输)

这样,只要轮询 returns 一个大于 0 的值,您就只会从套接字中读取数据。

结果? 3% CPU 使用率,如果您想向套接字流中添加更多数据,轮询将为您优化,因此这是一种可扩展的读取方式,例如 CAN 总线。