Протокол CanOpen

Недавно перед нами встала необходимость объединить несколько устройств в CAN сеть. Одно из устройств было реализовано на базе чипа от Beck и программировалось из CodeSys, другое на базе ARM контроллера, а главным устройством в сети должен был быть персональный компьютер с UNIX подобной ОС на борту. После изучения существующих промышленных протоколов я остановился на CanOpen. Этот протокол оказался очень гибким, он позволяет настроить различные режимы работы сети. Но главное CanOpen поддерживается в CodeSys и существует реализация на C под персональные компьютеры и контроллеры. В этой статье я расскажу, что такое CanOpen и как его запустить на персональном компьютере, используя библиотеку от http://www.canfestival.org.

 

CanOpen

Главным элементом CANopen стандарта является описание функциональности устройства через словарь объектов. Каждая точка входа словаря объектов обозначается через 16-ти битный индекс и 8-ми битный субиндекс. В объектах хранится информация об узле: описание информации, которую может передать узел, режимы передачи информации узлом, текущее состояние узла.

CANopen имеет два базовых механизма передачи данных:

  • Высокоскоростной обмен небольшими объемами данных процесса через так называемые Process Data Objects - PDO
  • Доступ к точкам входа в словаре объектов через Service Data Objects – SDO

Различают следующие PDO:

  • Инициализируемые событием
  • Циклические
  • Запрашиваемые как широковещательные без дополнительной служебной информации протокола

PDO могут использоваться для передачи до 8 байтов данных. Передача и прием PDO может быть синхронизированной по всей сети с помощью синхронизирующих сообщений.

Передача SDO выполняется с подтверждением посредством двух CAN объектов, аналогично логическому соединению точка-точка между двумя устройствами сети. Передаваемые данные имеют произвольную длину. Передача SDO сообщений содержит дополнительные служебные данные протокола.

Для отчета о неисправностях устройства зарезервированы стандартизированные инициируемые событием «аварийные сообщения», которые имеют высокий приоритет.

Функциональность управления, например, контроль и мониторинг статуса связи узлов, выполняется с помощью протокола управления сетью (NMT), который основан на логическом взаимодействии master-slave. Для реализации функций мониторинга предназначено два механизма: Node-Guarding (защита узла) и Heartbeat (сердцебиение).

 

CanOpen PDO

Используются для обмена данными между узлами в реальном времени. Могут содержать не более 8 байт данных. У каждого PDO сообщения есть свой уникальный идентификатор COB-ID длинной в 11 бит, по нему определяется, какие именно данные находятся в пришедшем  PDO сообщении. Этот идентификатор как имя структуры в языке C.

PDO могут передаваться несколькими способами:

  1. По запросу на передачу от удалённого узла. Удалённый компьютер шлёт пустое PDO с требуемым COB-ID и выставленным битом RTR (Remote Transmition Request). Узел, получив такое сообщение, высылает требуемое PDO.
  2. После получения SYNC сообщения. Главный узел в сети периодически шлёт всем остальным узлам SYNC сообщения, таким образом отсчитывая такты времени. Удалённые узлы знают какие PDO и на каких тактах они должны послать.
  3. Асинхронная передача. Удалённый узел сам решает, когда он должен послать PDO.

В canfestival пользователь не должен слать и получать PDO сообщения напрямую. Необходимо в словаре объектов определить переменные, которые находятся в передаваемых и принимаемых PDO, а также указать способ передачи PDO. В пользовательском приложение нужно просто читать и писать значения этих переменных. Все операции с сетью будут делаться автоматически.

 

CanOpen SYNC протокол

Предназначен для синхронизации всех удалённых узлов в сети. Главный узел в сети с постоянным периодом шлёт SYNC сообщения. Удалённые узлы, получив такое сообщение, фиксируют информацию, которую нужно передать и при первой же возможности передают.

По умолчанию COB-ID SYNC сообщения 0x80 и оно не содержит данных. Параметры SYNC протокола находятся в объектах 0x1005 – COB-ID SYNC сообщения, 0x1006 – период цикла в микросекундах, 0x1007 – длина синхронного окна в микросекундах. Длина синхронного окна – время, за которое должны передаться все PDO. В CanFestival в объекте 0x1005 необходимо указывать 0x80000000 + (желаемое COB_ID).

CanOpen Heartbeat протокол

Предназначен для мониторинга состояния узлов. Удалённый узел с постоянным периодом шлёт определённые сообщения в сеть. По этим сообщениям главный компьютер понимает, что удалённый узел работает корректно (нет разрыва сети, удалённый узел не завис). Настраивается протокол при помощи объектов 0x1016 и 0x1017. Объект 0x1016 должен быть создан на главном компьютере, в нём указан период, с которым необходимо ожидать прихода сердцебиения, в миллисекундах. Объект 0x1017 должен быть создан на удалённом узле, в нём указан период в миллисекундах, с которым необходимо генерировать сердцебиение. Данный протокол имеет смысл использовать только, если PDO передаются в синхронном режиме, иначе он будет просто загружать сеть, а контроль удалённых узлов будет вестись по ответам на запросы RTR.

 

CanOpen NMT протокол

Позволяет управлять удалёнными узлами: запускать, останавливать, перезагружать, изменять состояние удалённого узла.

CanOpen узел может находиться в четырёх состояниях. Ниже приведена диаграмма состояний, стрелочками обозначены возможные переходы между состояниями. Полностью функционирует узел в Operational состоянии. В Pre-Operational состоянии узел может конфигурироваться при помощи SDO сообщений, PDO не работают.

CanOpen SDO протокол

Позволяет передавать данные произвольной длины. Сообщение делится на телеграммы по семь байт и последовательно передаётся через CAN. SDO сообщения имеют самый низкий приоритет, поэтому передаются довольно медленно.

CanOpen EDS файлы

Словарь объектов CanOpen узла может сохраняться в стандартизованном EDS файле. С такими EDS файлами умеют работать многие программы, их понимает CodeSys, утилита objdictedit из библиотеки CanFestival по этим файлам генерирует код на C.

 
Библиотека CanFestival под UNIX подобной ОС
В библиотеке реализована поддержка достаточно большого количества CAN плат, вам нужно лишь правильно собрать библиотеку, но, если вашей платы там нет, вам необходимо самому реализовать функции:

UNS8 canReceive(CAN_HANDLE, Message *);
UNS8 canSend(CAN_HANDLE, Message const *);
CAN_HANDLE canOpen(s_BOARD *);
int canClose(CAN_HANDLE);
UNS8 canChangeBaudRate(CAN_HANDLE, char *);

Как это сделать можете посмотреть в файле unix.c в папке drivers/unix.

После того как библиотека собрана и установлена запускаем утилиту objdictedit из папки objdictgen. В ней создаём новый файл, выбираем, что мы будем создавать: master или slave, указываем будем ли использовать SYNC и Heartbeat протоколы. После всего этого перед нами появляется словарь объектов.

В Communication Parameters можно настроить SYNC и Heartbeat протоколы. В Receive PDO Parameters и Transmit PDO Parameters можно создать и настроить отправляемые и получаемые PDO. В Manufacturer Specific можно создать переменные, которые будут спроецированы на PDO сообщения. В Receive PDO Mapping и Transmit PDO Mapping эти переменные можно спроецировать на PDO.

После того как словарь объектов создан жмём Build Dictionary – будут сгенерированы заголовочный файл и файл реализации на C.

В сгенерированном файле будут глобальные переменные на подобии моих:

/* Master node data struct */
extern CO_Data PC_Data;
extern UNS8 IN_1;              /* Mapped at index 0x2000, subindex 0x00*/
extern UNS8 OUT_1;             /* Mapped at index 0x2001, subindex 0x00*/

CO_Data – это структура, описывающая CanOpen узел. UNS8 – переменные, спроецированные на PDO.

 

В моём коде я использую указатель на CO_Data из сгенерированного заголовочного файла.

CO_Data *m_nodeData = & PC_Data;

Инициализация CanOpen:

// Open the Peak CANOpen device
if(! canOpen( & m_board, m_nodeData ) )
    return false;
// Defining the node Id
setNodeId( m_nodeData, ID );
// Start Timer thread
StartTimerLoop( & init );
// Put the master in operational mode
setState( m_nodeData, Initialisation );
setState( m_nodeData, Operational );

Остановка CanOpen стека:

// Stop timer thread
StopTimerLoop( & exit );
// Close CAN board
canClose( m_nodeData );
TimerCleanup( );

 

Запуск удалённого узла с ID равным nodeID.

masterSendNMTstateChange( m_nodeData, nodeID, NMT_Start_Node );

Останов удалённого узла с ID равным nodeID.

masterSendNMTstateChange( m_nodeData, nodeID, NMT_Stop_Node );

Перезагрузка удалённого узла с ID равным nodeID.

masterSendNMTstateChange( m_nodeData, nodeID, NMT_Reset_Node );

Запрос на передачу PDO из словаря объектов, расположенного под индексом RPDOIndex. Полученное значение может быть считано позже из соответствующей спроецированной переменной.

sendPDOrequest( m_nodeData, RPDOIndex );

Мы не впервые используем промышленные сети. Для сетей RS-485 мы используем протокол Modbus RTU.

Leave a Reply

You must be logged in to post a comment.