我尝试使用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;
}
我希望这能使问题更清楚,更有针对性。
1条答案
按热度按时间tf7tbtn21#
感谢所有关于这个问题的评论,我能够解决速度问题。我不知道SocketCan支持同一总线上的多个套接字。能够为每个进程创建用于读取和写入的套接字,可以减少分布式方式与总线的对话,大大提高速度。