Реализация протокола PELCO-D на Arduino

Когда-то давно передо мной стояла интересная задача. Необходимо было реализовать управление PTZ-камерой PTD-208z по протоколу PELCO-D причем сделать это надо было именно на Arduino. Коротко зачем все это нужно: камера крепится на специального робота, который катается внутри большой трубы и рассматривает дефекты, пишется все видео на DVR и плюс есть оператор, который управляет роботом (управление роботом, механика и драйверы двигателей тоже были сделаны, но это тема для другой статьи). С этого проекта, который я закончил буквально на днях и началось мое знакомство с Arduino.

Небольшое описание самого протокола и зачем он нужен.

Pelco-D очень популярный PTZ (Pan/Tilt/Zoom) протокол? используемый в CCTV индустрии. Собственно он используется для управления поворотными камерами, т.е. поворотов и зуммирования. В качестве среды передачи для протокола наиболее часто выступает 485-й интерфейс, т.к. в основном его поддерживают все производимые аналоговые камеры.

Формат Pelco-D посылки выглядит следующим образом:

Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7
Sync Camera Address Command 1 Command 2 Data 1 Data 2 Checksum
  • Byte 1 (Sync) — байт синхронизации, по умолчанию имеет значение 0xFF, не изменяем;
  • Byte 2 (Camera Address) — логический адрес управляемой камеры (например камера 1 имеет адрес 0x01);
  • Byte 3 и 4 (Command 1 и 2) — описаны ниже;
  • Byte 5 (Data 1) — байт задает скорость поворота камеры влево/вправо, 0x00 — скорость равна 0, 0x3F — максимально возможная скорость поворота. Некоторые камеры поддерживают «турбо» скорость 0xFF;
  • Byte 6 (Data 2) — байт задает скорость движения камеры вниз/вверх, со скоростями все аналогично байту 5;
  • Byte 7 (Checksum) — байт контрольной суммы, байт синхронизации не учитывается в контрольной сумме.

Разберем байты 3 и 4 (Command 1 и 2)

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
Command 1 Sense Reserved Reserved Auto / Manual Scan Camera On/Off Iris Close Iris Open Focus Near
Command 2 Focus Far Zoom Wide Zoom Tele Tilt Down Tilt Up Pan Left Pan Right Fixed to 0

НАПРИМЕР:
Pan Left (поворот налево) — 0b00000100 или 0x04 в шестнадцатиричном представлении записываем в байт 4 (Command 2).

Так с протоколом разобрались, едем дальше.

Как же все это сделано на Arduino.

Для начала мы определились с органом управления, он достался нам от другой аналогичной машинки и управляет не только камерой, но и движением робота, а также светом:

Пульт управления роботом Arduino

Джойстики на пульте управления подключены к плате Arduino UNO к аналоговым входам от A0 до A2. Далее для передачи посылки камере реализовано программное последовательное соединение с помощью библиотеки SoftwareSerial.h, это единственная библиотека, которая используется в этом проекте. Использование ее обусловлено тем, что необходимо иметь связь с ПК и одновременно передавать данные камере.

Для реализации интерфейса RS-485 использовалась микросхема SP485EE. Накидаю небольшую схемку ее расключения:

SP485EE

SP485EE схема подключения

Далее приведу листинг программы:

/*Программа для управления камерой*/
#include <SoftwareSerial.h>

int sensorPan = A0;     // канал вправо/влево 
int sensorTilt = A1;    // канал вверх/вниз 
int sensorFocus = A2;   // канал фокус

int xVal = 0;           // переменная для хранения значения с потенциометра вправо/влево
int yVal = 0;           // переменная для хранения значения с потенциометра вниз/вверх
int focus = 0;          // переменная для хранения значения с потенциометра фокуса камеры

const byte tiltDown = 0x10;
const byte tiltUp = 0x08;
const byte panRight = 0x02;
const byte panLeft = 0x04;
const byte focusNull = 0x00;  // Зума нет
const byte focusNear = 0x20;  // Зум +  0x01
const byte focusFar = 0x40;   // Зум -  0x80

SoftwareSerial newSerial = SoftwareSerial(7, 8);

void setup()
{
   pinMode(7, INPUT);
   pinMode(8, OUTPUT);
   newSerial.begin(2400); // включаем uart 
}

// отправка данных камере
// структура посылки Pelco-D
/*

|  byte 1  |   byte 2   |  byte 3  |  byte 4  | byte 5 | byte 6 | byte 7 |
 ---------- ------------ ---------- ---------- -------- -------- --------
|Sync 0xFF | Cam Adress | Command1 | Command2 | Data 1 | Data 2 |Checksum|

*/

void sendData(byte camNum, byte command_1, byte command_2, byte panSpeed, byte tiltSpeed) 
{
   int modSum = 0;                 // начальное нулевое значение контрольной суммы 
   byte dataVal[6] = {0xFF, camNum, command_1, command_2, panSpeed, tiltSpeed}; // вектор формата комманды Pelco-D
   for (int i=0; i<6; i++)         // цикл отправки посылки камере
   {
      newSerial.write(dataVal[i]);  // отправить байт в UART
      if (i > 0)                   // контрольная сумма начинает считаться со второго байта, поэтому первый 0xFF пропускаем
         modSum += dataVal[i];     // суммируем байты контрольной суммы
   }
   modSum %= 100;                  // контрольная сумма делиться по модуля на 256 в dec или по другому на 100 в hex
   newSerial.write(modSum);         // отправить контрольную сумму
}

void halt()
{
   byte dataVal[7] = {0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01};
   for (int i=0; i<7; i++)
   {
      newSerial.write(dataVal[i]);  // отправить байт в UART   
   } 
}

void loop() 
{
   xVal = analogRead(sensorPan);     // считывание значения потенциометра вправо/влево в соответствующую переменную
   yVal = analogRead(sensorTilt);    // считывание значения потенциометра вниз/вверх в соответствующую переменную
   focus = analogRead(sensorFocus);  // считывание значения потенциометра фокуса камеры в соответствующую переменную
   
   if (xVal > 600)  
   { 
      sendData(0x01, focusNull, panRight, 0x3F, 0x00);      // вызывается функция отправки байта
      while (xVal > 600) 
      {
         xVal = analogRead(sensorPan);   
      }
   }
   if (xVal < 450)
   {
      sendData(0x01, focusNull, panLeft, 0x3F, 0x00);      // вызывается функция отправки байта  
      while (xVal < 450) 
      {
         xVal = analogRead(sensorPan);   
      }
   }
 
   if (yVal > 600)
   {
      sendData(0x01, focusNull, tiltUp, 0x00, 0x3F);      // вызывается функция отправки байта
      while (yVal > 600) 
      {
         yVal = analogRead(sensorTilt);   
      }
   } 
   if (yVal < 450)
   {
      sendData(0x01, focusNull, tiltDown, 0x00, 0x3F);      // вызывается функция отправки байта  
      while (yVal < 450) 
      {
         yVal = analogRead(sensorTilt);   
      }
   }  
   
   if (focus > 600)
   {
      sendData(0x01, focusNull, focusNear, 0x00, 0x00);      // вызывается функция отправки байта
      while (focus > 600) 
      {
         focus = analogRead(sensorFocus);   
      }
   } 
   if (focus < 450)
   {
      sendData(0x01, focusNull, focusFar, 0x00, 0x00);      // вызывается функция отправки байта  
      while (focus < 450) 
      {
         focus = analogRead(sensorFocus);   
      }
   } 
   halt();
}

Программа максимально проста и не вызовет затруднений даже у новичков. В функции loop() происходит опрос состояний джойстиков, а также вызов функции sendData() с аргументами вида байтов протокола. Функция sendData() посылает посылку камере на лету подсчитывая контрольную сумму. Функция halt() срабатывает когда нету реакции ни одного из джойстиков. Вот и все.

Испытания системы управления камерой прошли успешно) Полностью робот в сборе уже бегает по трубам и снимает камерой все дефекты)))

15 Ответов в “Реализация протокола PELCO-D на Arduino

  1. Очень интересно. Пока что нихрена не понятно, но интересно)) Хочу тоже разобраться с похожим проектом. Нужно сделать ptz камеру на базе arduino. По всей видимости, это будет мой курсач). Спасибо за информацию. Будемс разбираться.

  2. у меня не заработало. подключил ардуинку через max к камере, джостики подключил.
    вроде переключил на самой камере все переключатели. камера на как не реагирует на мои команды. может кто подскажет что делать? в какое положение переключатели на камере поставить? может я что напортачил?

      1. ACUMEN ai-sd27 купольная поворотная pzt камера

      2. Не могу по ней найти никакой технической информации, снята с производства и сайт производителя молчит.

      3. на микросхему SP485EE точно 5 вольт на 2 и 3 ножку?

  3. Точно, это высокий уровень для разрешения на передачу данных через интерфейс RS485.

  4. Адрес установлен 0x01? Совпадает с адресом в программе? 4-секционный переключатель должен быть в положении off off on off для режима Pelco-D со скоростью 2400 бит/с.

  5. Здравствуйте, я немного не понял, Вы вот используете библиотеку SoftwareSerial.h для того, чтобы одновременно передавать сигнал и видеокамере и получать сигнал с пк. С передачей сигнала камере, вроде, понятно, а вот с пк не очень. 8 пин Вы в программе определили как передатчик и сделали его выходом, затем этот выход пошел на микросхему для преобразования UART в RS-485. Затем этот сигнал пошел к камере и это все позволит нам ей управлять. 7 пин у Вас сделан приемником, но он нигде не используется. Так и надо? И как эту систему можно подружить с ПК? И вообще, нужна ли была библиотека, которая дублирует UART на цифровые пины, если UART есть на 0 и 1 пине, а мы используем только два пина? (7 и 8).. Предостерегу себя от фейспалмов и скажу, что я полный новичек в этом всем, и если то, что я написал – полнейший бред, то не серчайте. Просто мне нужно в этом разобраться. Спасибо)

    1. Привет, согласен, в статье не совсем очевидно, что и как работает. SoftwareSerial используется для связи с камерой, 8 пин для передачи команд камере, 7 пин по идее для приема, но от камеры мы ничего не получаем, в данном случае протокол однонаправленный, поэтому не используется, но класс SoftwareSerial требует инициализации обоих пинов. Аппаратный Serial интерфейс может использоваться для отладки в данном случае и он так и использовался, потом из кода отладочные строки были убраны мною, а по идее компьютер здесь особо не нужен и можно не заводить SoftwareSerial, а использовать Serial класс для передачи команд. Код старый и я уже не помню всех тонкостей почему именно используется у меня SoftwareSerial. Удачи, если будут вопросы пишите, постараюсь помочь.

  6. ЗДРАВСТВУЙТЕ, достал схему SP485EEN все подключил как вы, скопировал прогу, в установках камеры задал протокол Pelco-D, скорость 2400, данные 8 бит, четности нет, стоп бит -1, но не работает ;/ (камера Wisenet SNZ6320)

    1. Не могу точно сказать, что в вашем случае не работает. Эта камера не PTZ, в ней только зум моторизированный. Попробуйте на другой скорости протестировать отправку данных. Схема подключения есть у вас?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *