Arduino to Unity3D латентность / задержка

Я строю эту аркадную игру с реальными элементами управления и ПК под управлением Unity3D. В основном люди перемещают физический стержень, а он перемещает цифровой стержень. (это должно быть как можно в реальном времени).

Прямо сейчас стержень вращается поворотным энкодером. Мега Arduino, выполняющий этот код с прерываниями, считывает значения, а затем отправляет их в игру Unity через последовательный порт.

Все очень хорошо оптимизировано, но у меня примерно 500 мс задержки между моментом, когда я перемещаю стержень, и моментом, когда он отображается на экране.

Любые идеи, чтобы уменьшить это отставание? Должен ли я использовать новые кодеры? Новое Arduino? Другая установка?

Спасибо большое:)

2 ответа

Решение

В вашем вопросе не указан код Unity C# или Arduino C/C++, поэтому вы получите только совет.

1 Используйте Thread для чтения из сериала на стороне Unity. Вы должны понимать C# Thread, прежде чем пытаться сделать это в Unity, иначе у вас возникнет множество других проблем.

2 Избегайте выполнения конкатенации строк (oldString+=newString) на стороне Arduino или Unity при получении данных. Если этого не сделать, со временем произойдет замедление.

3 Оптимизируйте, как вы отправляете и получаете данные от Arduino. Используйте байтовый массив на стороне Arduino вместо строки.

Из примера кода кодировщика Arduino, размещенного по ссылке в вашем вопросе, он выглядит примерно так:

Serial.print("Left = ");
Serial.print(newLeft);
Serial.print(", Right = ");
Serial.print(newRight);

Это не хорошо. Допустим, у вас есть 4 кодировщика. Передний левый, передний правый, задний левый и задний правый энкодеры. Получить эти значения от каждого кодера. Если значение положительное, масштабируйте его до 0,127. Если значение отрицательное, масштабируйте его от текущего значения до -1,-127. Масштабирование может быть легко сделано с помощью функции Map.

Создайте массив без знака или используйте байтовый массив и присвойте ему каждое масштабированное значение;

byte encoders[] = {0, 0, 0, 0}; //4 Encoders
encoders[0] = valueOfScaledFrontLeftEncoder;
encoders[1] = valueOfScaledFrontRightEncoder;
encoders[2] = valueOfScaledBackLeftEncoder;
encoders[3] = valueOfScaledBackRightEncoder;

Затем отправьте их в то же время в виде массива байтов

Serial.write(encoders, sizeof(encoders));

Теперь на стороне получателя в Unity 4 байта поступят по порядку. Прочитайте их и извлеките значения в том порядке, в котором они были отправлены. Это экономит время на Arduino и увеличивает скорость приема и отправки. НЕТ больше отправки длинных строк!

4 Если все не удается, переключитесь с Arduino Maega на Arduino Due. Это очень быстро, потому что он использует процессор ARM. Обратите внимание, что он использует 3,3 вольт вместо 5 вольт. Так что не забудьте купить кодер 3,3 В и / или использовать понижающее напряжение от 5 В до 3,3.

Спасибо за ваш ответ!

Я сделал еще несколько оптимизаций, и теперь у меня задержка составляет около 100 мс. Это все еще немного и не дает большого игрового опыта.

Вот код Arduino:

   #include <Encoder.h> 
   // Define GPIO of the rotary encoders 

    Encoder rot0(38,39);
    Encoder rot1(40,41);
    Encoder pos0(6,7);
    Encoder pos1(18,19);
    // and so on...


    // setting default position
    int oldRot0, oldRot1, oldPos0, oldPos1 = -99999;
    int newRot0, newRot1, oldPos0, oldPos1;
    // and so on...

    void setup() 
    {  
      Serial.begin(250000);
    }


    void loop() {

      // Reading constantly the encoders
      newRot0 = rot0.read();
      newRot0 = rot0.read();

      newPos0 = pos0.read();
      newPos1 = pos1.read();
      // and so on...

    // Definying a char buffer to output data
    char buffer[4];

      // IF ROD 1 MOVES : output values
      if (newRot0 != oldRot0 || newPos0 != oldPos0)
       {

        sprintf(buffer,"1%c%c",newRot1,newPos1); // Sending the rod ID and data in char format to save space
        Serial.println(buffer);

        /* BEFORE: (I changed it to the sprintf buffer)
       Serial.print("~1#0#");
        Serial.print(newPos1);      
        Serial.print("#");
        Serial.print(newRot1);
        Serial.println();
        */

        oldRot0 = newRot0;
        oldPos0 = newPos0;
        }

... то же самое для других стержней.

  1. Вы говорите о oldRot0 = newRot0;? Должен ли я избежать этого или использовать его?

  2. Действительно, я читаю значение, использую функцию map для масштабирования, а затем выводю их через буфер. Могу ли я сделать это еще более оптимизированным?

  3. Я думал об использовании Arduino DUE, но я уже купил и собрал все свои кодировщики, и они работают в 5V. Я не хочу, чтобы на 3V3 просыпались новые энкодеры, плюс они кажутся менее распространенными, чем 5V. Вместо этого я думал о замене Arduino на более мощный микроконтроллер. Будет ли это правление? Он работает на частоте 80 МГц по сравнению с 16 МГц у Mega2560.

РЕДАКТИРОВАТЬ:

В конце концов я заменил Arduino Mega на Teensy 3.2, который чрезвычайно быстр, полностью совместим с программным обеспечением и допускает 5V! Это значительно улучшилось. Я не вернусь к 8-битным микроконтроллерам...

Другие вопросы по тегам