在 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正是你所需要的。这是我的例子。
首先,在Linux中从header创建一个pollfd结构。我已决定创建一个 class 成员,但您可以根据自己的喜好创建:
pollfd poll_;
poll_.fd = soc_;
poll_.events = POLLIN;
poll_.revents = 0;
这里,soc_
是套接字,POLLIN
表示要从套接字读取。
然后,在我的 while 循环中,我没有延迟,而是在我的 while 循环开始时使用了这个函数:
poll_int = poll(&poll_, 1, 100);
if (poll_int <= 0) continue;
所以 poll()
函数 returns 值为 1 如果读取成功并且我设置了 100 毫秒的超时(只是一个随机数,我知道数据以更高的速率传输)
这样,只要轮询 returns 一个大于 0 的值,您就只会从套接字中读取数据。
结果? 3% CPU 使用率,如果您想向套接字流中添加更多数据,轮询将为您优化,因此这是一种可扩展的读取方式,例如 CAN 总线。
我有 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正是你所需要的。这是我的例子。
首先,在Linux中从
header创建一个pollfd结构。我已决定创建一个 class 成员,但您可以根据自己的喜好创建: pollfd poll_; poll_.fd = soc_; poll_.events = POLLIN; poll_.revents = 0;
这里,soc_
是套接字,POLLIN
表示要从套接字读取。
然后,在我的 while 循环中,我没有延迟,而是在我的 while 循环开始时使用了这个函数:
poll_int = poll(&poll_, 1, 100); if (poll_int <= 0) continue;
所以 poll()
函数 returns 值为 1 如果读取成功并且我设置了 100 毫秒的超时(只是一个随机数,我知道数据以更高的速率传输)
这样,只要轮询 returns 一个大于 0 的值,您就只会从套接字中读取数据。
结果? 3% CPU 使用率,如果您想向套接字流中添加更多数据,轮询将为您优化,因此这是一种可扩展的读取方式,例如 CAN 总线。