【问题标题】:Fast CAN communication using sockets in C++使用 C++ 中的套接字进行快速 CAN 通信
【发布时间】:2021-11-26 12:46:22
【问题描述】:

我正在尝试使用 C/C++ 与 CAN 总线进行通信。我正在使用套接字在总线上进行读写。我创建了一个写线程和一个读线程。读取线程不断尝试读取和套接字,当写入请求到达时,写入线程使用互斥锁控制套接字并进行写入。

我在使用这种方法的速度方面遇到了一个大问题,因为写入请求有时可能需要 500 毫秒才能完成(这对我的应用程序来说完全不可行)。我试图在读取命令上设置一个超时,以使其在总线上没有任何内容时使其非阻塞,但如果超时太短,我会遇到读取的可靠性问题。另一方面,如果我把它做得太长,速度提升是不够的。

这是我第一次使用 CAN。您对在 C/C++ 中实现快速的双向 CAN 通信节点有什么建议吗?我应该使用哪个库来与总线本身交互?哪种架构会产生最低的读写延迟?

为了给应用程序提供一些指标,总线比特率为 1MBits/sec,我正在使用带有 64 位数据包的 CAN-Open(每条消息包含 32 位索引和 32 位数据)。我想要一个从 300 到 500hz 的写入频率,与读取频率相同。

非常感谢您的帮助!

编辑:

非常感谢您的所有 cmets。以下是对我的申请和问题的一些说明。

我正在开发一个移动机器人项目,我正在使用 CAN-Open 与电机驱动器和传感器进行通信。该代码将在运行 Raspbian OS 的 Raspberry Pi CM4 上运行,该操作系统安装在集成了 MCP2515 CAN 控制器的定制 IO 板上。我想在 ROS 架构和 CAN 总线之间实现快速通信接口。使用的语言可以是 C 或 C++。

我目前正在使用围绕标准 C 套接字构建的自制接口,但速度非常低,并且是机器人性能的一大瓶颈。所以我正在寻找更好的解决方案:

  • 为此目的构建的开源库
  • 实施此类程序的架构建议
  • 两者的结合

这是我使用的套接字创建、读取和写入函数。读写分别在不同线程的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;
}

我希望这能让问题更清晰、更集中。

【问题讨论】:

  • 请不要使用术语“C/C++”。没有这样的语言。尽管有一些相似之处,但它们是两种截然不同的语言。还请调整您问题的标签以匹配所选语言。
  • 图书馆推荐与 SO 无关。但是如果你展示你有问题的代码,可以给出改进建议。
  • @Gerhardh 他不会显示代码,因为那些使用 Can/Canoe sw/hw 的人通常在汽车公司工作,这限制了他们在外部发布数据。这不是 SO 的问题……他应该去调试一些由 Vector、Elektrobit 等公司编写的软件。
  • Sockets 表示 Linux 之类的。因此,您无法获得实时性能,因为它不是 RTOS,时期。但是,500 毫秒的延迟听起来像是一个错误。
  • @alinsoar 帖子中没有提到独木舟或 Vector。

标签: c++ communication can-bus


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多