[Đề tài TN C5] Gamepad và Nỏ bắn Angry birds

bigboy061293

Thành Viên PIF
Cách đây khá lâu, mình có hứa sẽ đăng bài hướng dẫn chi tiết cái đề tài tốt nghiệp C5 lên để chia sẻ cùng mọi người, nhưng do bận nhiều thứ quá nên đến bây giờ mới có dịp chia sẻ, hy vọng mọi người ủng hộ :D

Sơ lược vài đề tài
Nó gồm 2 hạng mục chính:

+ Gamepad:
Được điều khiển bằng 8 nút nhấn và 1 cảm biến gia tốc, giao tiếp với máy tính. Người sử dụng có thể dùng nó để chơi rất nhiều thể loại game (nếu không muốn nói là hầu hết :3cool_adore: ). Vì các nút có thể được thiết lập bằng phần mềm. Ưu điểm để đưa cái gamepad này ngang tầm, thậm chí cao hơn ( :1cool_byebye: ) tay cầm xbox hay ps là vì nó được trang bị 1 cái cảm biến gia tốc (dùng để đo trục nghiêng), rất thích hợp cho các game fps, và được thiết lập tùy theo ý thích người dùng.

Bản chất của nó là giả lập các nút trên bàn phím và chuột để điều khiển thay cho chuột và bàn phím cố định. Vì thế, gamepad này có thể ứng dụng để điều khiến máy tính từ xa khi kết hợp với các module thu phát (rf, bluetooth, ...).

Tóm lại, gamepad này là bá đạo :D, là đỉnh của "đinh" , xứng đáng để các ông trùm như Playstation và Microsoft hay Nitendo dòm ngó :D

+ Nỏ Angrybird
Vượt tầm bá đạo của gamepad trên, tác giả đã lao lực, tốn rất nhiều noron, nhiều đêm mất ngủ và để cho ra 1 sản phẩm cực kì độc đáo, đó là 1 thiết bị chơi game angry birds.
Theo như các truyền thống thì mình bấm vào con chim, giữ chuột rồi kéo để bắn nó đi, dựa vào đó, chiếc nó này mô phỏng lại 1 loạt hành động đó bằng một chuỗi hành động khác, đó là: kéo cần, chỉnh góc nghiêng cho nỏ, và buông tay để bắn chim đi.

Trên thế giới hiện nay có 2 thiết tương tự là Angry Birds Slingshot và Angry Birds Controller, cái thứ nhất ra đời trước sản phầm của mình còn cái thứ 2 thì ra đời sau, mặc dù có sau nhưng nó được đăng báo, quảng cáo rùm ben :( (buồn ghê)

vài dòng tâm sự ...

Thật ra mà nói thì Angry Birds Slingshot là nguồn gốc ý tưởng của mình, ban đầu dự định sẽ làm 1 cái ý như vậy nhưng do sợ phải "ăn mì gói" cả tháng do cái cảm biến lực (stretch sensor) quá mắc và không có bán ở đây nên trong cái khó, ló cái ... khác, đó là sử dụng 1 phương thức khác để bắn nên sau nhiều lần lòng vòng và đi qua đi lại các tiệm linh kiện để tìm ý tưởng thì tìm thấy cái biến trở thanh này :1cool_byebye:


Nguyên lí hoạt động:
+ Gamepad:

Gồm 8 nút nhấn 2 trạng thái, mạch rất đơn giản, nên chắc cũng không cần vẽ ra :D Mọi người xem cái hình là hiểu liền :). Module ảm biến gia tốc MMA8452 giao tiếp I2C được gắn trực tiếp lên board.

Mỗi nút nhấn và trạng thái của cảm biến được giả lập 1 phím trên bàn phím hay chuột, cứ theo đó, người sử dụng có thể chỉnh sửa để xài bất kì thứ gì liên quan tới chuột và bàn phím.

+ Nỏ:

Được cấu tạo từ các thành phần:
+Board khoan lỗ ---> dùng để gắn biến trở lên;
+Biến trở trượt ---> như cái chỉnh volume kéo lên kéo xuống, mua ở trong chợ, giá khá khó chịu, từ 30 -> 50 ngàn 1 cây, tùy loại dài, ngắn, trở khác nhau;
+Mica ----> mua ở tiệm mica , dùng để tăng độ đàn hồi;
+Module MMA8452 ---> để tính góc nghiêng cho nỏ;

và một thứ không thể thiếu, cực kì khó tìm và chính nó thể hiện sự đoàn kết xuyên châu lục của chiếc nỏ này :6cool_boss:, đó chính là ... cọng thun trong sample của TI ... để quấn qua mica và cần điện trở tạo đàn hồi ...:5cool_sweat:

Nỏ hoạt động như sau: đầu tiên con trỏ chuột ở vị trí con chim, khi kéo cần (tức là thay đổi trạng thái trở -> thay đổi ADC đọc về) thì sự kiện click chuột và kéo chuột về được thực hiện cho đến khi hết sự thay đổi này, cũng là lúc dừng việc kéo cần lại ---> chỉnh độ căng của cái ná trong game. Sau đó là chỉnh góc nghiêng cho nỏ để chim được chỉnh lên hay xuống ---> chỉnh góc bắn của chim. Khi buông tay ra (tức là có sự thay đổi ADC theo hướng ngược lại) thì sự kiện buông chuột ra được thực hiện ---> chim bắn đi :D


Điều khiển:

Được điều khiển bằng Arduino bản Leonardo, có thể giả lập chuột và bàn phím không cần qua C#, đây là giải pháp khá tiện lợi cho người sử dụng khi làm biếng viết code cho C# :D (dùng con atmega32u4, hiện tại có 1 con có tính năng tương tự là lpc11u24 dùng trên board mbed)

và đây là code để mọi người tham khảo, trong code có yêu cần thư viện I2C để giao tiếp với 8452, nếu ai có nhu cầu, mình sẽ đăng lên để tham khảo :D [ code được post ở #2 ]


Và sau đây là vài hình ảnh về sản phẩm










bài viết mang tính chém gió khá cao và được viết vào lúc đêm khuya nên mọi người thông cảm :D =))
 

bigboy061293

Thành Viên PIF
do ở trên hơn 1000 kí tự rồi nên post cái code ở đây :)


Code:
/*
no A0
keypad A1
ct 8
cp 9
buten 10
butes 11
 
butu 4
butd 5
butl 6
butr 7
 
MODE 0 -- RESET
MODE 1 -- KEY UP, DOWN, LEFT RIGHT, ENTER, ESC
MODE 2 -- ACC CONTROLS MOUSE
MODE 3 -- KEYPAD + MOUSE --> PLAY SERIOUS SAM
MODE 4 -- KEYPAD + MOUSE --> PLAY ROADRASH
MODE 5 -- ANGRY BIRD
*/
 
 
#include <I2C.h>
#define ACC 0x1D
#define bientro A0
#define keypad A1
const int kb[8] = {863, 853, 816, 756, 783, 775, 744, 694};
const int ct=8;
const int cp=9;
const int buten=10;
const int butes=11;
 
const int butu=4;
const int butd=5;
const int butl=6;
const int butr=7;
 
int mode = -1;
void setup()
{
    Serial.begin(9600);
//  Mouse.begin();
    I2c.begin();
    Keyboard.begin();
 
 
}
 
 
 
    int xc=0;
    int x=0;
    int y=0;
    int yc=1024;
    int ax=1;      //acc of X
    int ay=1;      //acc of Y
    int u=0;
    int d=0;
    int r=0;
    int l=0;
    int en=0;
    int es=0;
    int i=0;
void setasgamepad()
  {
 
    pinMode(butu, INPUT);
    pinMode(butd, INPUT);
    pinMode(butl, INPUT);
    pinMode(butr, INPUT);
    pinMode(buten, INPUT);
    pinMode(butes, INPUT);
  }
 
void setasmouse()
{
    pinMode(ct, INPUT);
    pinMode(cp, INPUT);
}
 
  int yt=0;
  int j=0;
void angrybird()
{
    I2c.read(ACC,0x0B,1);
  if(I2c.receive() == 0x00) I2c.write(ACC,0x2A,0x01);
  // lay truc X
  I2c.read(ACC,0x01,1);
  int Z1 = I2c.receive();
 
  I2c.read(ACC,0x02,1);
  int Z2 = I2c.receive();
 
  Z1 = Z1 << 4;
  Z2 = Z2 >> 4;
  Z1 = Z1 | Z2;
 
//Y direction
  i++;
  y=y+Z1;
  if (i>15)
    {
      i=0;
      ay=abs(y-yc);
      y=y/16;
    constrain(y,30,1024);
      if (y<yc-25) Mouse.move(0,-0.001*(ay));
 
 
 
      else if (y>yc+25) Mouse.move(0,0.001*(ay));
      else Mouse.move(0,0);
 
      yc=y;
 
      y=0;
 
    }
 
    //X direction
    x = analogRead(bientro);
    ax=abs(xc-x);
    if (xc>x) Mouse.move(-0.5*ax,0);
    else if (xc<x)  Mouse.move(0.5*ax,0);
    else Mouse.move(0,0);
 
    if (xc>x+3)
    {
 
    if (j<50)
    {
      if (!Mouse.isPressed(MOUSE_LEFT)) Mouse.press(MOUSE_LEFT);
      j++;
    }
 
    }
    else if(xc<x-3)
    {
    if (Mouse.isPressed(MOUSE_LEFT)) Mouse.release(MOUSE_LEFT);
    j=0;
    }
    xc = x;
 
}
 
void araskey()
{
    I2c.read(ACC,0x0B,1) ;
  if(I2c.receive() == 0x00) I2c.write(ACC,0x2A,0x01);
 
  I2c.read(ACC,0x01,1);
  int X1 = I2c.receive();
  /*I2c.read(ACC,0x02,1);
  int X2 = I2c.receive();
 
  X1 = X1 << 4;
  X2 = X2 >> 4;
  X1 = X1 | X2;
  */
  I2c.read(ACC,0x03,1);
  int Y1 = I2c.receive();
  /*I2c.read(ACC,0x04,1);
  int Y2 = I2c.receive();
 
  Y1 = Y1 << 4;
  Y2 = Y2 >> 4;
  Y1 = Y1 | Z2;
  */
    if ((X1>=212)&&(X1<=244))
    {
        u=1;
        if (d=1)
          {
              d=0;
              Keyboard.release(KEY_DOWN_ARROW);
          }
        Keyboard.press(KEY_UP_ARROW);
 
    }
    else
  if ((X1>=15)&&(X1<=47))
    {
        d=1;
        if (u=1)
        {
            u=0;
          Keyboard.release(KEY_UP_ARROW);
        }
 
        Keyboard.press(KEY_DOWN_ARROW);
 
    }
    else
 
if ((Y1>=15)&&(Y1<=47))
  {
      if (l=1)
        {
            l=0;
            Keyboard.release(KEY_LEFT_ARROW);
        }
 
        Keyboard.press(KEY_RIGHT_ARROW);
        r=1;
    }
    else
if ((Y1>=212)&&(Y1<=244))
      {
        if (r=1)
          {
              r=0;
              Keyboard.release(KEY_RIGHT_ARROW);
          }
        Keyboard.press(KEY_LEFT_ARROW);
        l=1;
    }
    else Keyboard.releaseAll();
 
}
void roadrash()
{
 
    I2c.read(ACC,0x0B,1) ;
  if(I2c.receive() == 0x00) I2c.write(ACC,0x2A,0x01);
 
  I2c.read(ACC,0x01,1);
  int X1 = I2c.receive();
  /*I2c.read(ACC,0x02,1);
  int X2 = I2c.receive();
 
  X1 = X1 << 4;
  X2 = X2 >> 4;
  X1 = X1 | X2;
  */
  I2c.read(ACC,0x03,1);
  int Y1 = I2c.receive();
  /*I2c.read(ACC,0x04,1);
  int Y2 = I2c.receive();
 
  Y1 = Y1 << 4;
  Y2 = Y2 >> 4;
  Y1 = Y1 | Z2;
  */
    if ((X1>=212)&&(X1<=244))
    {
        u=1;
        if (d=1)
          {
              d=0;
              Keyboard.release(KEY_DOWN_ARROW);
          }
        Keyboard.press(KEY_UP_ARROW);
 
    }
    else
  if ((X1>=15)&&(X1<=47))
    {
        d=1;
        if (u=1)
        {
            u=0;
          Keyboard.release(KEY_UP_ARROW);
        }
 
        Keyboard.press(KEY_DOWN_ARROW);
 
    }
    else
 
if ((Y1>=15)&&(Y1<=47))
  {
      if (l=1)
        {
            l=0;
            Keyboard.release(KEY_LEFT_ARROW);
        }
 
        Keyboard.press(KEY_RIGHT_ARROW);
        r=1;
    }
    else
if ((Y1>=212)&&(Y1<=244))
      {
        if (r=1)
          {
              r=0;
              Keyboard.release(KEY_RIGHT_ARROW);
          }
        Keyboard.press(KEY_LEFT_ARROW);
        l=1;
    }
    else Keyboard.releaseAll();
}
 
void keybybut() //controll up down left right enter escape
{
    setasgamepad();
    u = digitalRead(butu);
    d = digitalRead(butd);
    l = digitalRead(butl);
    r = digitalRead(butr);
    en = digitalRead(buten);
    es = digitalRead(butes);
 
    if (u == HIGH)
      {
          Keyboard.release(KEY_DOWN_ARROW);
          Keyboard.press(KEY_UP_ARROW);
      }
      else
      if (d == HIGH)
      {
          Keyboard.release(KEY_UP_ARROW);
          Keyboard.press(KEY_DOWN_ARROW);
      }
      else
 
    if (l == HIGH)
      {
          Keyboard.release(KEY_RIGHT_ARROW);
          Keyboard.press(KEY_LEFT_ARROW);
      }
      else
      if (r == HIGH)
      {
          Keyboard.release(KEY_LEFT_ARROW);
          Keyboard.press(KEY_RIGHT_ARROW);
      }
      else
      Keyboard.releaseAll();
        if  (es == HIGH)
        {
          Keyboard.write(177);
          delay(100);
        }
      if (en == HIGH)
        {
        Keyboard.write(10);
        delay(100);
        }
 
}
 
 
 
void mousebyacc() // up down l right click
{
  setasmouse();
  I2c.read(ACC,0x0B,1) ;//
  if(I2c.receive() == 0x00) I2c.write(ACC,0x2A,0x01);
 
 
  I2c.read(ACC,0x01,1);
  byte X1 = I2c.receive();
 
 
 
  I2c.read(ACC,0x03,1);
  byte Y1 = I2c.receive();
 
 
  int us=LOW;
  int ds=LOW;
  int rs=LOW;
  int ls=LOW;
 
  if ((X1>=212)&&(X1<=244)) ds=HIGH;
  if ((X1>=15)&&(X1<=47)) us=HIGH;
  if ((Y1>=15)&&(Y1<=47)) ls=HIGH;
  if ((Y1>=212)&&(Y1<=244)) rs=HIGH;
 
  int  xDistance = (ls - rs)*3;
  int  yDistance = (us - ds)*3;
 
  if ((xDistance != 0) || (yDistance != 0))  Mouse.move(xDistance, yDistance, 0);
 
  if (digitalRead(ct) == HIGH)
    {
        Mouse.click(MOUSE_LEFT);
        delay(100);
    }
  if (digitalRead(cp) == HIGH)
    {
        Mouse.click(MOUSE_RIGHT);
        delay(100);
    }
  delay(10);
}
void resetall()
{
    Mouse.release(MOUSE_LEFT);
    Mouse.release(MOUSE_RIGHT);
    Keyboard.releaseAll();
 
}
 
 
 
void loop()
{
  //0 -> reset all mode
  //1 -> cu noi gian
  //
  //keybybut();
    for (int i=0; i<8; i++)
      {
          if (kb[i] == analogRead(keypad))
          mode=i;
      }
    switch (mode)
    {
      case 0: //reset
        {
          resetall();
            mode=0;
            break;
 
        }
        case 1: // key by button
          {
              keybybut();
                mode=1;
              break;
     
          }
      case 2: // mouse by acc
        {
          mousebyacc();
          mode=2;
            break;
        }
        case 3: // Key + Mousr ---> play serious sam
        {
            keybybut();
            mousebyacc();
            mode=3;
            break;
        }
        case 4: // Key + mouse -----> play roadrash
        {
          araskey();
        //  keybybut();
          mode=4;
          break;
        }
        case 5:
          {
              angrybird();
              mode=5;
              break;
          }
 
    }
    //araskey();
  //  setasgamepad();
 
  //  mousebyacc();
}
đây là code mình viết để giả lập theo từng loại game khác khác nhau: ví dụ game Roadrash thì nút khác với game Snake. Các mode được chọn qua bàn phím ADC, mọi người tham khảo ở đây http://www.payitforward.edu.vn/forum/threads/623/

một số link tham khảo khác :

Arduino leonardo : http://arduino.cc/en/Main/ArduinoBoardLeonardo
Angry birds slingshot : http://mbed.org/cookbook/Slingshot
Bàn phím 1 dây : http://www.payitforward.edu.vn/forum/threads/623/
 
Top