#c #communication #can-bus
Вопрос:
Я пытаюсь использовать C/C для связи с шиной CAN. Я использую сокеты для чтения и записи в автобусе. Я создал поток записи и поток чтения. Поток чтения постоянно пытается прочитать и сокет, и когда поступает запрос на запись, поток записи берет под контроль сокет с помощью мьютекса и выполняет запись.
У меня большая проблема со скоростью использования этого метода, так как выполнение запроса на запись иногда может занять 500 мс (что совершенно невозможно для моего приложения). Я попытался установить тайм-аут для команды чтения, чтобы она не блокировалась, когда на шину ничего не поступает, но если тайм-аут слишком короткий, у меня возникают проблемы с надежностью чтения. С другой стороны, если я сделаю это слишком долго, увеличение скорости будет недостаточным.
Это мой первый раз, когда я работаю с КЭНОМ. Не могли бы вы дать несколько советов по реализации быстрого двустороннего узла связи CAN в C/C ? Какую библиотеку следует использовать для взаимодействия с самой шиной ? Какая архитектура обеспечит наименьшую задержку чтения и записи ?
Чтобы дать несколько показателей для приложения, скорость передачи данных по шине составляет 1 Мбит/сек, я использую CAN-Open с 64-битными пакетами данных (каждое сообщение содержит 32 бита для индексов и 32 бита данных). Я хотел бы иметь частоту записи от 300 до 500 Гц, такую же для частоты чтения.
Большое спасибо за вашу помощь !
Редактировать :
Большое спасибо за все ваши комментарии. Вот некоторые разъяснения по моему заявлению и проблемам.
Я работаю над проектом мобильного робота и использую CAN-Open для связи с водителями и датчиками. Код будет выполняться на Raspberry Pi CM4 под управлением ОС Raspbian, установленной на пользовательской плате ввода-вывода, интегрирующей контроллер MCP2515 CAN. Я хочу реализовать быстрый интерфейс связи между архитектурой 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, amp;ifr);
memset(amp;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, amp;err_mask, sizeof(err_mask));
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(*socketIDOut, SOL_SOCKET, SO_RCVTIMEO, (const char*)amp;tv, sizeof tv);
// Binding Socket
if (bind(*socketIDOut, (struct sockaddr *)amp;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::mutexamp; mutex)
{
struct canfd_frame frame;
int err = parseFrame(id, message, amp;frame);
if(err == 0){
ROS_ERROR_STREAM("[Can Utils] Unable to parse frame : " << id << ", " << message);
return 0;
}
mutex.lock();
int res = write(socket, amp;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::mutexamp; mutex)
{
struct can_frame frame;
// Reading on bus
mutex.lock();
int nbytes = read(socketID, amp;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, amp;frame);
return nbytes;
}
Я надеюсь, что это сделает вопрос более ясным и сфокусированным.
Комментарии:
1. Пожалуйста, не используйте термин «C/C «. Такого языка не существует. Это 2 очень разных языка, несмотря на некоторое сходство. Пожалуйста, также отрегулируйте теги вашего вопроса в соответствии с выбранным языком.
2. Рекомендации библиотеки являются оффтопическими на SO. Но если вы покажете код, с которым у вас возникли проблемы, могут быть даны предложения по улучшению.
3. @Gerhardh он не покажет код, так как те, кто работает с Can/Canoe sw/hw, обычно работают в автомобильных компаниях, которые ограничивают их публикацию своих данных за пределами. Это не вопрос для SO… Он должен пойти и отладить некоторые sw, написанные такими компаниями, как Vector, Elektrobit и т. Д. И т. Д.
4. Сокеты означают Linux или что-то в этом роде. Таким образом, у вас не может быть производительности в реальном времени, потому что это не RTOS, точка. Однако задержка в 500 мс звучит как ошибка.
5. @alinsoar Нигде в посте нет упоминания о каноэ или Векторе.
Ответ №1:
Благодаря всем комментариям по этому вопросу я смог решить проблему скорости. Я не знал, что SocketCAN поддерживает несколько сокетов на одной шине. Возможность создания сокетов для каждого процесса для чтения и записи позволила распределенно сократить количество разговоров с шиной, что значительно повысило скорость.