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;
}
... то же самое для других стержней.
Вы говорите о oldRot0 = newRot0;? Должен ли я избежать этого или использовать его?
Действительно, я читаю значение, использую функцию map для масштабирования, а затем выводю их через буфер. Могу ли я сделать это еще более оптимизированным?
Я думал об использовании Arduino DUE, но я уже купил и собрал все свои кодировщики, и они работают в 5V. Я не хочу, чтобы на 3V3 просыпались новые энкодеры, плюс они кажутся менее распространенными, чем 5V. Вместо этого я думал о замене Arduino на более мощный микроконтроллер. Будет ли это правление? Он работает на частоте 80 МГц по сравнению с 16 МГц у Mega2560.
РЕДАКТИРОВАТЬ:
В конце концов я заменил Arduino Mega на Teensy 3.2, который чрезвычайно быстр, полностью совместим с программным обеспечением и допускает 5V! Это значительно улучшилось. Я не вернусь к 8-битным микроконтроллерам...