Пульт управления виртуальной камерой

от автора

Практика формирования видеоряда напрямую из 3D программ, созданных на Unity/Unreal/OpenSceneGraph для создания 3D-обучающих видеофильмов показала высокую эффективность такого подхода. Качество синтезируемой модели часто практически не уступает по фотореалистичности видео, созданному “классически”, т.е. традиционным рендерингом из программ 3dMax/Maya/Cinema и т.д.

Пример видеоряда из Unity 3D / Трубопроводный транспорт. КПП СОД.
Пример видеоряда из Unity 3D / Трубопроводный транспорт. КПП СОД.
Пример видеоряда из Unity
Пример видеоряда из Unity
Еще пример
Еще пример
Еще пример
Еще пример

При этом имеется возможность управления камерой в режиме реального времени, используя стандартные средства ввода-вывода / клавиатура-мышь. Для выполнения простых пролетов камеры, например по орбите с равномерным приближением или отдалением такой подход является достаточным и не требует каких либо дополнительных устройств управления. Однако при сложных движениях камеры требуется контролировать большее количество параметров движения и как следствие использование стандартных средств ввода-вывода становится или неудобным или недостаточным. VR также не всегда применим, особенно при больших размерах объекта и/или при быстрых перемещениях камеры.

На основе нашего опыта создания видеоряда из 3D программ было принято решение создать пульт управления виртуальной камерой, для эффективного управления движениями камеры, управлением масштабов времени и реализацией управления сценарием происходящего в 3D.

В качестве базы было выбрано оборудование, имеющееся “в запасе”, а именно:

Arduino Due — плата микроконтроллера на базе процессора Atmel SAM3X8E ARM Cortex-M3 (описание). Это первая плата Arduino на основе 32-битного микроконтроллера с ARM ядром. На ней имеется 54 цифровых вход/выхода (из них 12 можно задействовать под выходы ШИМ), 12 аналоговых входов, 4 UARTа (аппаратных последовательных порта), a генератор тактовой частоты 84 МГц, связь по USB с поддержкой OTG, 2 ЦАП (цифро-аналоговых преобразователя), 2 TWI, разъем питания,  разъем SPI, разъем JTAG. Частота процессора (CPU) 84 МГц. 96 КБ ОЗУ. 512 КБ флеш-памяти для хранения программ. контроллер DMA, который разгружает центральный процессор от выполнения интенсивных операций с памятью.

Да, немного перебор, но она была под рукой.

TFT-дисплей на базе ILI9341 с тачскрином (320*240 65к цветов)

Энкодер с кнопкой, переменные резисторы, два модуля джойстиков, переключатели и кнопки с фиксацией и без фксации.

Фото устройства в процессе монтажа в корпусе.

Код написан в Arduino IDE, с использованием библиотек:

  • include “SPI.h”

  • include “Adafruit_GFX.h”

  • include “Adafruit_ILI9341.h”

  • include “Joystick.h”

Код программы приведен в конце статьи, а пока результат:

Внутренности после монтажа (клавиши еще не смонтированы)

Вот так операционная система определяет устройство (можно поменять конечно)

Ну и собственно тестирование.

Исходный код программы:
#include "SPI.h" #include "Adafruit_GFX.h" #include "Adafruit_ILI9341.h" #include "Joystick.h" #include <EncButton2.h>    Joystick_ Joystick;  /* Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,    JOYSTICK_TYPE_MULTI_AXIS, 32, 0,   true, true, false, false, false, false,   true, true, false, false, false); */  const int analogInPin1 = A0; const int analogInPin2 = A1; const int analogInPin3 = A2; const int analogInPin4 = A3;  const int analogInPin5 = A4; const int analogInPin6 = A5; const int analogInPin7 = A6;    // For the Adafruit shield, these are the default. #define TFT_RST 8 #define TFT_DC 9 #define TFT_CS 10 #define TFT_MISO 50 #define TFT_MOSI 51 #define TFT_SCK 52 // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC //Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); // If using the breakout, change pins as desired  Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO);  EncButton2<EB_ENC> enc(INPUT, 45, 43);        // просто энкодер    // the setup function runs once when you press reset or power the board void setup() {    //Serial.begin(9600);    // Set Range Values   Joystick.setXAxisRange(-127, 127);   Joystick.setYAxisRange(-127, 127);   Joystick.setZAxisRange(0, 255);   Joystick.setRxAxisRange(255, 0);   Joystick.setRyAxisRange(0, 255);   Joystick.setRzAxisRange(255, 0);   Joystick.setThrottleRange(0, 255);   Joystick.setRudderRange(0, 255);    Joystick.setAcceleratorRange(0, 255);   Joystick.setBrakeRange(0, 255);   Joystick.setSteeringRange(0, 255);           Joystick.begin(false);        pinMode(A0, INPUT_PULLUP);   pinMode(A1, INPUT_PULLUP);   pinMode(A2, INPUT_PULLUP);   pinMode(A3, INPUT_PULLUP);   pinMode(A4, INPUT_PULLUP);   pinMode(A5, INPUT_PULLUP);   pinMode(A6, INPUT_PULLUP);   pinMode(A7, INPUT_PULLUP);    pinMode(1, INPUT_PULLUP);   pinMode(2, INPUT_PULLUP);   pinMode(3, INPUT_PULLUP);   pinMode(4, INPUT_PULLUP);   pinMode(5, INPUT_PULLUP);    //pinMode(13, OUTPUT);   pinMode(LED_BUILTIN, OUTPUT);    pinMode(47, INPUT); //butt0 encoder   pinMode(45, INPUT); //encoder1   pinMode(43, INPUT); //encoder2    pinMode(38, INPUT); //butt1   pinMode(40, INPUT); //butt2     tft.begin();    // read diagnostics (optional but can help debug problems)   uint8_t x = tft.readcommand8(ILI9341_RDMODE);   //Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);   x = tft.readcommand8(ILI9341_RDMADCTL);   //Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);   x = tft.readcommand8(ILI9341_RDPIXFMT);  // Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);   x = tft.readcommand8(ILI9341_RDIMGFMT);  // Serial.print("Image Format: 0x"); Serial.println(x, HEX);   x = tft.readcommand8(ILI9341_RDSELFDIAG);  // Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);     tft.setRotation(0); //0 1 2 3     tft.fillScreen(ILI9341_BLACK);   //unsigned long start = micros();   tft.setCursor(0, 0);   tft.setTextColor(ILI9341_WHITE);    tft.setTextSize(2);   tft.println("Lcontent.ru");   tft.setTextColor(ILI9341_BLUE);    tft.println("Joy module v.1.0");   tft.setTextColor(ILI9341_RED);    tft.println("by Maxim Gammer");    }  int OLD_sensorValue1 = 0;  int encoderValue=0; // the loop function runs over and over again forever void loop()  {     int sensorValue1 = 0;      int outputValue1 = 0;       int sensorValue2 = 0;      int outputValue2 = 0;      int sensorValue3 = 0;      int outputValue3 = 0;      int sensorValue4 = 0;      int outputValue4 = 0;       int sensorValue5 = 0;      int outputValue5 = 0;      int sensorValue6 = 0;      int outputValue6 = 0;      int sensorValue7 = 0;      int outputValue7 = 0;       sensorValue1 = analogRead(analogInPin1);     sensorValue2 = analogRead(analogInPin2);     sensorValue3 = analogRead(analogInPin3);     sensorValue4 = analogRead(analogInPin4);      sensorValue5 = analogRead(analogInPin5);     sensorValue6 = analogRead(analogInPin6);     sensorValue7 = analogRead(analogInPin7);          // map it to the range of the analog out:     outputValue1 = map(sensorValue1, 0, 1023, 0, 255);     outputValue2 = map(sensorValue2, 0, 1023, 0, 255);     outputValue3 = map(sensorValue3, 0, 1023, 0, 255);     outputValue4 = map(sensorValue4, 0, 1023, 0, 255);     outputValue5 = map(sensorValue5, 0, 1023, 0, 255);     outputValue6 = map(sensorValue6, 0, 1023, 0, 255);     outputValue7 = map(sensorValue7, 0, 1023, 0, 255);          Joystick.setYAxis(outputValue1 - 128);     Joystick.setXAxis(outputValue2 - 128);     Joystick.setRxAxis(outputValue3);     Joystick.setRyAxis(outputValue4);                    Joystick.setZAxis(outputValue5);     Joystick.setRzAxis(outputValue6);     Joystick.setThrottle(outputValue7);          //Joystick.setRudder(255);     Joystick.setRudder(255);     Joystick.setAccelerator(255);     Joystick.setBrake(255);     Joystick.setSteering(255);          int buttonState0 = digitalRead(47);     Joystick.setButton(0, buttonState0);      int buttonState1 = digitalRead(38);     Joystick.setButton(1, buttonState1);      int buttonState2 = digitalRead(40);     Joystick.setButton(2, buttonState2);            enc.tick();                       // опрос происходит здесь     if (enc.left())      {       encoderValue = encoderValue+45;           }     if (enc.right())      {       encoderValue = encoderValue-45;     }     if (encoderValue<=-45)      {       encoderValue=315;     }     else if (encoderValue>=360)     {       encoderValue=0;     }     int hatSwitch =0;     Joystick.setHatSwitch(hatSwitch, -1);     Joystick.setHatSwitch(hatSwitch, encoderValue); //0 45  90  135 180  225 270 315           Joystick.sendState();           //Serial.print("sensor = ");     //Serial.println(sensorValue);     /*    char TX[20];    //tft.fillRect(0, 0, 40, 10, ILI9341_BLACK); // textbgcolor is protected in Adafruit_GFX.h     tft.setTextSize(1);    tft.setCursor(0, 0);    tft.setTextColor(ILI9341_BLACK);     sprintf(TX,"%4d", OLD_sensorValue1);    tft.println(TX);    OLD_sensorValue1 = sensorValue1;    tft.setCursor(0, 0);    tft.setTextColor(ILI9341_WHITE);     sprintf(TX,"%4d", sensorValue1);    tft.println(TX); //"Hello World!"          delay(2);    */      //digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)   //delay(1000);                       // wait for a second   //digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW   //delay(1000);                       // wait for a second }


ссылка на оригинал статьи https://habr.com/ru/post/656059/


Комментарии

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

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