Подключение UART TTL видеокамеры к IskraJS

Тема в разделе "Глядите, что я сделал", создана пользователем Walker2000, 25 сен 2018.

  1. Walker2000

    Walker2000 Нерд

    Всем привет!

    Купил ребёнку Робоняшу. Прошли мы с ним все задания и заскучали. И тут возникла идея оснастить этого робозверька зрением. Ну типа, чтобы он патрулировал территории и мог при необходимости сфотографировать что-нибудь или кого-нибудь.

    После этого была приобретена вот такая камера. Достоинство её в наличии на борту довольно продвинутого контроллера с jpeg компрессором и последовательным портом. Также на плате у неё установлен преобразователь уровней MAX232, пришлось его выпаять и замкнуть Rx и Tx выводы контроллера напрямую на выходной разъем. Кстати, довольно точное описание работы с видеокамеры оказалось на Алиэкспресс (где она, собственно, и была приобретена), поэтому каких-то долгих изысканий по работе с камерой не понадобилось.

    [​IMG]

    Подпаял питание камеры к Тройка Шилду няши, последовательный порт - к P1 и P0, а после изучения протокола обмена (можно скачать вот здесь) написал небольшой код. Управление камерой пока сделал от ИК-пульта. Задействованы 5 кнопок:

    RED - запрос версии прошивки видеокамеры.
    GREEN - захват кадра.
    BLUE - запрос длины кадры.
    SQUARE - передача кадра в IskraJS.
    CROSS - сброс камеры.

    Код следующий:

    Код (Javascript):
    var timeLoop = 0;                               // Время окончания задержки
    var sec = 0;                                    // Продолжительность задержки в минутах
    var ImageLength = Uint8Array(2);                // Длина кадра

    var Command = 0;                                // Код команды в ответе
    var CommandLength = 0;                          // Длина ожидаемого приемного пакета
    var CommandBuf = "";                            // Массив из части кадра побайтно.
    var ImageStr = "";                              // Принятый кадр в виде строки
    var ImageHex = "";                              // Строка кодов с пробелами

    var receiver = require("@amperka/ir-receiver").connect(P3);

    var delay = function(sec) {                        // Функция формирования задержки на sec секунд
    timeLoop = getTime() + sec;
    while(getTime() < timeLoop);
    };

    Serial3.setup(38400);

    Serial3.on("data", function(data) {               // Обработка принятых из COM порта данных
      CommandBuf += data;
      if (CommandBuf.length < CommandLength) return;  // Если посылка пришла не вся, выходим

      Command = Number(CommandBuf.charCodeAt(2)).toString(16);
      print("Command = ", Command, "Command length = ", CommandBuf.length);
      CommandLength = 0;                               // Обнуляем длину возвратной посылки

      if (Command === "11") {                          // Принимаем номер версии
         print("Version is",CommandBuf.substr(5,12));} // Выводим номер версии

      if (Command === "34") {                          // Принимаем длину кадра
         ImageLength[0] = CommandBuf.charCodeAt(CommandBuf.length-2);
         ImageLength[1] = CommandBuf.charCodeAt(CommandBuf.length-1);
         print("Frame lenght is",ImageLength[0]*256+ImageLength[1],"bytes");}

      if (Command === "36") {                          // Отрабатываем захват кадра
      if (CommandBuf === "\x76\x00\x36\x00\x00")
         print("Frame is catched");
      if (CommandBuf === "\x76\x00\x36\x03\x00")
         print("Frame error");}

      if (Command === "32") {                          // Выделяем из принятых данных кадр
         ImageStr = CommandBuf.substr(5,
                    ImageLength[0]*256+ImageLength[1]);// Отделяем кадр из тела команды
         print("Image length is", ImageStr.length);
         for (var j = 0; j < ImageLength[0] + 1; j++){
          ImageHex = "";
          for (var i = 0; i < 256; i++){                // Переводим в символьную форму побайтно
           if (Number(ImageStr.charCodeAt(256*j + i)) < 16)
               ImageHex = ImageHex + "0" + Number(ImageStr.charCodeAt(256*j + i)).toString(16) + " ";
           else ImageHex = ImageHex + Number(ImageStr.charCodeAt(256*j + i)).toString(16) + " ";
           }
          print(ImageHex);
         }
      }
    });

    receiver.on('receive', function(code) {            // Опрос ИК-приемника
      delay(0.25);
      CommandBuf = "";                                 // Если нажата кнопка, обнуляем входной буфер.
      if (code === receiver.keys.RED) {
         CommandLength = 16;                           // Длина возвратной посылки
         Serial3.write("\x56\x00\x11\x00\x00");        // Считываем версию ПО камеры
    }
      if (code === receiver.keys.GREEN) {
         CommandLength = 5;                            // Длина возвратной посылки
         Serial3.write("\x56\x00\x36\x01\x00");        // Захватить кадр
    }
      if (code === receiver.keys.BLUE) {
         CommandLength = 9;
         Serial3.write("\x56\x00\x34\x01\x00");        // Узнать длину кадра
    }
      if (code === receiver.keys.SQUARE) {             // Передать кадр
         CommandLength = ImageLength[0]*256+ImageLength[1] + 10;
         readSBUF = "\x56\x00\x32\x0C\x00\x0A\x00\x00\x00\x00\x00\x00" + ImageLength + "\x00\x00";
         Serial3.write(readSBUF);
    }
      if (code === receiver.keys.CROSS) {
      Serial3.write("\x56\x00\x26\x00");               // Сброс камеры
      delay(0.25);
    }
    });
    Поскольку у Робоняши пока нет WiFi передатчика (хочу поставить в ближайшем будущем), для приема кадра пришлось слегка извратиться. Кадр выведен в консоль в несколько строк длиной 255 байт. Каждый байт представлен 16-ричным числом.

    Собственно именно этот кусок и перегружает интерпретатор, как мне показалось. Иногда вылетают сообщения типа "New interpreter error: FIFO_FULL" и сам кусок кода сильно тормозит. Но принять кадр таким образом все равно удалось.

    Вот как выглядит принимаемый кадр в консоли: )))

    [​IMG]

    Потом осталось только содержимое консоли скопировать, обрезать кусок от FF D8 до FF D9 (это и есть переданный jpg файл) и сохранить с расширением "jpg". В итоге на компе получился искомый кадр в разрешении 320 на 240 (умолчание камеры, можно менять):

    [​IMG]

    Баланс белого сильно завален в желтый (кстати, тоже можно менять в конфигурации камеры), потому что освещение искусственное. Да и сама матрица камеры не особо качественная, конечно.

    Но в целом всё работает. Iskra вполне может работать с изображениями, а Робоняша - обзавестись каким-то подобием зрения )))

    [​IMG]

    Если у кого-то возникнет желание доработать код или предложить какие-то усовершенствования - добро пожаловать в комментарии.
     

    Вложения:

    Последнее редактирование: 4 окт 2018
    RGB-светодиод, Daniil, parovoZZ и ещё 1-му нравится это.