C++中使用套接字实现快速CAN通信

bfrts1fy  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(239)

我尝试使用C/C与CAN总线通信。我使用套接字在总线上进行读写。我创建了一个写线程和一个读线程。读线程不断尝试读取套接字,当写请求到达时,写线程使用互斥锁控制套接字并执行写操作。
我有一个很大的问题与速度使用这种方法,作为一个写请求有时可能需要500毫秒才能完成(这对我的应用程序来说是完全不可行的)。我曾经尝试过在read命令上设置一个超时,使其在总线上没有任何东西到来时不阻塞,但如果超时太短,我会对read产生可靠性问题。另一方面,如果我让它太长速度增加是不够的。
这是我第一次使用CAN。您对用C/C
实现快速双向CAN通信节点有什么建议吗?我应该使用哪个库来与总线本身接口?哪种架构可以产生最低的读写延迟?
为了给予应用程序的一些指标,总线比特率为1 MBits/sec,我使用CAN-Open与64位数据包(每个消息包含32位索引和32位数据)。我希望写入频率从300到500 hz,读取频率相同。
非常感谢你的帮助!
编辑:
非常感谢您的评论。以下是我对申请和问题的一些澄清。
我正在做一个移动的机器人项目,我正在使用CAN-Open与电机驱动器和传感器进行通信。代码将在Raspberry Pi CM 4上运行,运行Raspbian OS,安装在集成MCP 2515 CAN控制器的自定义IO板上。我想在ROS架构和CAN总线之间实现快速通信接口。使用的语言可以是C或C++。
我目前正在使用一个围绕标准C套接字构建的自制接口,但速度非常低,是机器人性能的一大瓶颈。所以我正在寻找更好的解决方案,要么:

  • 一个为此目的而构建的开源库
  • 实现此类程序的体系结构建议
  • 两者的结合

下面是我使用的socket创建、read和write函数,Read和write分别在不同线程的while循环中调用(我使用的是pthread):

bool connectCanBus(int* socketIDOut, std::string canInterfaceName){
  // Socket and can variables
  struct sockaddr_can addr;
  struct ifreq ifr;

  // Openning the socket to send commands over the can bus
  if ((*socketIDOut = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
    perror("[Can Controler] Unable to create socket.");
    return false;
  }

  strcpy(ifr.ifr_name, canInterfaceName.c_str());
  ioctl(*socketIDOut, SIOCGIFINDEX, &ifr);
  memset(&addr, 0, sizeof(addr));
  addr.can_family = AF_CAN;
  addr.can_ifindex = ifr.ifr_ifindex;

  // Setting option to gte errors as frames
  can_err_mask_t err_mask = 0xFFFFFFFF;
  setsockopt(*socketIDOut, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask));

  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = 10000;
  setsockopt(*socketIDOut, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

  // Binding Socket
  if (bind(*socketIDOut, (struct sockaddr *)&addr, sizeof(addr)) < 0)       
{
    perror("[Can Controler] Unable to bind socket.");
    close(*socketIDOut);
    return false;
  }

  ROS_INFO("CAN bus connected.");
  return true;
}

int sendCommand(const char* id, const char* message, int socket, std::mutex& mutex)
{
  struct canfd_frame frame;
  int err = parseFrame(id, message, &frame);
  if(err == 0){
    ROS_ERROR_STREAM("[Can Utils] Unable to parse frame : " << id << ", " <<  message);
        return 0;
  }

    mutex.lock();
    int res = write(socket, &frame, sizeof(struct can_frame));
    mutex.unlock();
  if (res != sizeof(struct can_frame)) {
    perror("[Can Utils] CAN bus Write error");
    return 0;
  }
  return 1;
}

int readBus(CanFrame *outFrame, int socketID, std::mutex& mutex)
{
    struct can_frame frame;

    // Reading on bus
    mutex.lock();
    int nbytes = read(socketID, &frame, sizeof(struct can_frame));
    mutex.unlock();
    if (nbytes < 0) {
        perror("[Can Utils] CAN bus Read error");
        return 0;
    }

  // Converting frame to strings
  sprint_canframe(outFrame, &frame);
  return nbytes;
}

我希望这能使问题更清楚,更有针对性。

tf7tbtn2

tf7tbtn21#

感谢所有关于这个问题的评论,我能够解决速度问题。我不知道SocketCan支持同一总线上的多个套接字。能够为每个进程创建用于读取和写入的套接字,可以减少分布式方式与总线的对话,大大提高速度。

相关问题