Дополненная реальность и виртуальные игры стали недавней тенденцией в игровой индустрии. Время использования клавиатуры, джойстика и мыши для игры в компьютерную игру прошло. Теперь каждая игровая консоль поставляется с виртуальным контроллером, который помогает нам играть в игру, используя наши движения тела и жесты, таким образом, игровой опыт значительно увеличился, и пользователь чувствует себя более вовлеченным в игру.
В этом проекте мы сделаем игру в пинг-понг, используя Arduino и акселерометр, чтобы реализовать управление с использованием движения руки.
В наши дни доступно огромное количество программного обеспечения, с помощью которого можно создать графический интерфейс. Одним из очень простых и удобных является среда Processing, которую мы и будем использовать для создания игры в пинг-понг.
Аппаратная часть будет реализована на Arduino Nano (вместо Nano можно использовать Micro, Uno и т.д.), которая будет получать данные от аналогового акселерометра ADXL335 и передавать их на компьютер.
Схема подключения очень простая:
Будьте внимательны, если на Вашем модуле с ADXL335 после вывода Vcc нет понижающего стабилизатора, подключайте вывод Vcc модуля акселерометра к 3,3В выводу Arduino. В противном случае микросхема акселерометра может выйти из строя, т.к. не рассчитана на питание от 5В.
Акселерометр - это устройство, с помощью которого можно измерять ускорение. Если объект движется с постоянной скоростью, его ускорение равно нулю. Если скорость увеличивается, ускорение положительное. Если замедляется, ускорение отрицательное. ADXL335 измеряет ускорения по трём осям, что даёт возможность определять вектор ускорения в трёхмерном пространстве.
Так же следует отличать динамическое и статическое ускорение. Толкнули или резко переместили датчик, возникнет динамическое ускорение. Статическое ускорение возникает под действием гравитационного поля земли. ADXL335 измеряет оба этих ускорения.
Если датчик находится в состоянии покоя, можно определить вектор гравитационного притяжения, т.е. ориентацию акселерометра в трёхмерном пространстве относительно земли.
Что бы при движении определить вектор динамического ускорения, вклад гравитационного ускорения нужно удалить из данных акселерометра. Это можно сделать с помощью простого фильтра. Этот фильтр будет состоять из двух массивов: один используется для хранения значений выборки с датчика, а другой для сортировки значений выборки и поиска наиболее повторяющихся значений.
#define AccelPin A0 // A0 is connected to X-axis of Accel #define Samplesize 13 // filterSample number int Array1 [Samplesize]; // array for holding raw sensor values for sensor int rawData1, smoothData1; // variables for sensor data int toSend; void setup() { Serial.begin(9600); } void loop() { rawData1 = analogRead(AccelPin); // read X-axis of accelerometer smoothData1 = digitalSmooth(rawData1, Array1); toSend = map (smoothData1, 193, 280, 0, 255); // the data from accelerometer mapped to form a byte Serial.write (toSend); delay(100); } int digitalSmooth(int rawIn, int *sensSmoothArray) { // "int *sensSmoothArray" passes an array to the function - the asterisk indicates the array name is a pointer int j, k, temp, top, bottom; long total; static int i; static int sorted[Samplesize]; boolean done; i = (i + 1) % Samplesize; // increment counter and roll over if necc. - % (modulo operator) rolls over variable sensSmoothArray[i] = rawIn; // input new data into the oldest slot for (j = 0; j < Samplesize; j++) { // transfer data array into anther array for sorting and averaging sorted[j] = sensSmoothArray[j]; } done = 0; // flag to know when we're done sorting while (done != 1) { // simple swap sort, sorts numbers from lowest to highest done = 1; for (j = 0; j < (Samplesize - 1); j++) { if (sorted[j] > sorted[j + 1]) { // numbers are out of order - swap temp = sorted[j + 1]; sorted [j + 1] = sorted[j] ; sorted [j] = temp; done = 0; } } } bottom = max(((Samplesize * 15) / 100), 1); top = min((((Samplesize * 85) / 100) + 1 ), (Samplesize - 1)); // the + 1 is to make up for asymmetry caused by integer rounding k = 0; total = 0; for ( j = bottom; j < top; j++) { total += sorted[j]; // total remaining indices k++; } return total / k; // divide by number of samples }
Если у Вас слишком много шумов, в коде увеличьте размер выборки в следующей строке:
#define Samplesize 13 // filterSample numberМой акселерометр по оси X дает 193 в крайнем левом положении и 280 в крайнем правом положении. В строке:
toSend = map (smoothData1, 193, 280, 0, 255);измените 193 и 280 на соответствующие для Вашего акселерометра.
Скетч PingPong.pde:
#define AccelPin A0 // A0 is connected to X-axis of Accel #define Samplesize 13 // filterSample number int Array1 [Samplesize]; // array for holding raw sensor values for sensor int rawData1, smoothData1; // variables for sensor data int toSend; void setup() { Serial.begin(9600); } void loop() { rawData1 = analogRead(AccelPin); // read X-axis of accelerometer smoothData1 = digitalSmooth(rawData1, Array1); toSend = map (smoothData1, 193, 280, 0, 255); // the data from accelerometer mapped to form a byte Serial.write (toSend); delay(100); } int digitalSmooth(int rawIn, int *sensSmoothArray) { // "int *sensSmoothArray" passes an array to the function - the asterisk indicates the array name is a pointer int j, k, temp, top, bottom; long total; static int i; static int sorted[Samplesize]; boolean done; i = (i + 1) % Samplesize; // increment counter and roll over if necc. - % (modulo operator) rolls over variable sensSmoothArray[i] = rawIn; // input new data into the oldest slot for (j = 0; j < Samplesize; j++) { // transfer data array into anther array for sorting and averaging sorted[j] = sensSmoothArray[j]; } done = 0; // flag to know when we're done sorting while (done != 1) { // simple swap sort, sorts numbers from lowest to highest done = 1; for (j = 0; j < (Samplesize - 1); j++) { if (sorted[j] > sorted[j + 1]) { // numbers are out of order - swap temp = sorted[j + 1]; sorted [j + 1] = sorted[j] ; sorted [j] = temp; done = 0; } } } bottom = max(((Samplesize * 15) / 100), 1); top = min((((Samplesize * 85) / 100) + 1 ), (Samplesize - 1)); // the + 1 is to make up for asymmetry caused by integer rounding k = 0; total = 0; for ( j = bottom; j < top; j++) { total += sorted[j]; // total remaining indices k++; } return total / k; // divide by number of samples }
Обратите внимание на строку в функции setup:
port = new Serial(this, Serial.list()[0],9600);В данной строке вместо 0 нужно подставить индекс ком-порта, к которому подключена Arduino. Посмотреть индекс порта можно в консоли после запуска скетча (вверху окна кнопка с зелёным треугольником).
В данном случае в системе два порта:
[0] "COM1"В коде считывание данных настроено с порта "COM1", у которого индекс 0.