+7-960-0655211 (Билайн)
+7-987-4207734 (МТС)

интернет-магазин
доставка по России и СНГ
работаем с 2010 года

Игра в пинг-понг с использованием Arduino и акселерометра

Игра в пинг-понг с использованием Arduino и акселерометра

01.jpg
 

Дополненная реальность и виртуальные игры стали недавней тенденцией в игровой индустрии. Время использования клавиатуры, джойстика и мыши для игры в компьютерную игру прошло. Теперь каждая игровая консоль поставляется с виртуальным контроллером, который помогает нам играть в игру, используя наши движения тела и жесты, таким образом, игровой опыт значительно увеличился, и пользователь чувствует себя более вовлеченным в игру.

В этом проекте мы сделаем игру в пинг-понг, используя Arduino и акселерометр, чтобы реализовать управление с использованием движения руки.

В наши дни доступно огромное количество программного обеспечения, с помощью которого можно создать графический интерфейс. Одним из очень простых и удобных является среда Processing, которую мы и будем использовать для создания игры в пинг-понг. 

Аппаратная часть будет реализована на Arduino Nano (вместо Nano можно использовать Micro, Uno и т.д.), которая будет получать данные от аналогового акселерометра ADXL335 и передавать их на компьютер.

Схема подключения очень простая:

02.png

Будьте внимательны, если на Вашем модуле с ADXL335 после вывода Vcc нет понижающего стабилизатора, подключайте вывод Vcc модуля акселерометра к 3,3В выводу Arduino. В противном случае микросхема акселерометра может выйти из строя, т.к. не рассчитана на питание от 5В.

Принцип работы ADXL335

Акселерометр - это устройство, с помощью которого можно измерять ускорение. Если объект движется с постоянной скоростью, его ускорение равно нулю. Если скорость увеличивается, ускорение положительное. Если замедляется, ускорение отрицательное. ADXL335 измеряет ускорения по трём осям, что даёт возможность определять вектор ускорения в трёхмерном пространстве.

Так же следует отличать динамическое и статическое ускорение. Толкнули или резко переместили датчик, возникнет динамическое ускорение. Статическое ускорение возникает под действием гравитационного поля земли. ADXL335 измеряет оба этих ускорения.

Если датчик находится в состоянии покоя, можно определить вектор гравитационного притяжения, т.е. ориентацию акселерометра в трёхмерном пространстве относительно земли.

03.png


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

Код для Arduino

Скетч PingPong.ino:

#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 на соответствующие для Вашего акселерометра.

Код для Processing

Processing - это программное обеспечение, с помощью которого очень легко создавать графический интерфейс, анимацию, визуализацию данных и т.д. Скачать среду разработки можно по этой ссылке

Скетч 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. Посмотреть индекс порта можно в консоли после запуска скетча (вверху окна кнопка с зелёным треугольником).

04.jpg

В данном случае в системе два порта:

[0] "COM1"
[1] "COM3"

В коде считывание данных настроено с порта "COM1", у которого индекс 0.


3cbujc.gif


Автор: Aswinth Raj
Перевод и адаптация: RobotoTehnika.ru