Компания

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

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

При этом имеется возможность управления камерой в режиме реального времени, используя стандартные средства ввода-вывода / клавиатура-мышь. Для выполнения простых пролетов камеры, например по орбите с равномерным приближением или отдалением такой подход является достаточным и не требует каких либо дополнительных устройств управления. Однако при сложных движениях камеры требуется контролировать большее количество параметров движения и как следствие использование стандартных средств ввода-вывода становится или неудобным или недостаточным. 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
}

Author

Максим Гаммер

Инженер по специальности «Машины и оборудование нефтяных и газовых промыслов». Кандидат технических наук.

Оставить комментарий

Ваш адрес email не будет опубликован.

    Заказать прайс

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