Быстрая связь CAN с использованием сокетов в C

#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 поддерживает несколько сокетов на одной шине. Возможность создания сокетов для каждого процесса для чтения и записи позволила распределенно сократить количество разговоров с шиной, что значительно повысило скорость.