TA的每日心情 | 开心 2017-5-15 14:59 |
---|
签到天数: 8 天 连续签到: 1 天 [LV.3]偶尔看看II
|
概述:
平衡球游戏在手机平台上很常见,玩家操控手机的平衡来控制平衡球运动,到达指定地点。为了实现平衡球游戏,我使用Arduino 101作为游戏手柄,将101的加速度计数据通过串口或BLE发给PC机,在PC机上实现一个平衡球游戏的界面。(因为没学过美工,也没有时间去认真做这个游戏,现在界面很简陋,仅仅作为一个抛砖引玉).
目的: 使用Arduino 101作为手柄,用PC机作为界面,通过串口和BLE两种方式完成101与PC机的交互,实现平衡球游戏。
硬件/软件需求:
硬件需求:CurieNano/Arduino 101、电脑
软件需求(对于串口版本):Arduino 101 1.x+库、 Python、pygame
软件需求(对于蓝牙版本):Arduino 101 1.x+库、Visual Studio2015+
使用串口传输的版本:
这个版本没有使用BLE,需要把101和电脑通过USB连接。我写了一个Python2.7的脚本,调用串口库获取101发来的串口数据,调用pygame显示界面。
需要:Python2.7 、pygame 、Arduino 101 、Arduino 101 1.0.x+库
Arduino 101代码:- #include "CurieIMU.h"
- int ax, ay, az; // accelerometer values
- int gx, gy, gz; // gyrometer values
-
- const int ledPin = 13; // activity LED pin
- boolean blinkState = false; // state of the LED
-
- int calibrateOffsets = 1; // int to determine whether calibration takes place or not
-
- void setup() {
- Serial.begin(9600);
- while (!Serial);
- CurieIMU.begin();
-
- if (calibrateOffsets == 1) {
- delay(1000);
- CurieIMU.autoCalibrateGyroOffset();
- CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
- CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
- CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
- }
- pinMode(ledPin, OUTPUT);
- }
-
- int8_t buf[4];
-
- void loop() {
- while(Serial.read()!='g');
- CurieIMU.readMotionSensor(ax, ay, az, gx, gy, gz);
- *((int16_t*)buf) = ax;
- *((int16_t*)(buf+2)) = ay;
- Serial.write(buf[0]);
- Serial.write(buf[1]);
- Serial.write(buf[2]);
- Serial.write(buf[3]);
-
- blinkState = !blinkState;
- digitalWrite(ledPin, blinkState);
- }
复制代码 Python2.7代码:- #coding: utf-8
- #Version: Python2.7
-
- from time import sleep
- from serial.tools import list_ports
- from serial import Serial
- from struct import unpack
- import pygame,sys
-
- class MySerial():
- def __init__(self):
- port_list = list(list_ports.comports())
- if len(port_list) <= 0:
- self._ser = None
- return
- self._ser = Serial(list(port_list[0])[0],9600)
- sleep(1)
- def opened(self):
- return self._ser!=None
- def GetAngle(self):
- self._ser.write('g')
- s = self._ser.read(size=4)
- return unpack('hh',s)
-
-
- class Ball():
- def __init__(self):
- self.reset()
- self.radius = 20.0
- def reset(self):
- self.x = 100.0
- self.y = 100.0
- self.vx = 0.0
- self.vy = 0.0
- def move(self,a):
- self.vx += a[0]/131072.0
- self.vy += a[1]/131072.0
- self.x -= self.vx
- self.y += self.vy
-
- if self.x<self.radius:
- self.vx = 0.0
- self.x = self.radius
-
- if self.x>600.0-self.radius:
- self.vx = 0.0
- self.x = 600.0-self.radius
-
- if self.y<self.radius:
- self.vy = 0.0
- self.y = self.radius
-
- if self.y>600.0-self.radius:
- self.vy = 0.0
- self.y = 600.0-self.radius
-
- if self.y>200.0-2*self.radius and self.y<200.0 and self.x<400.0:
- self.vy = 0.0
- self.y = 200.0-2*self.radius
-
- if self.y<200.0+2*self.radius and self.y>200.0 and self.x<400.0:
- self.vy = 0.0
- self.y = 200.0+2*self.radius
-
- if self.y>400.0-2*self.radius and self.y<400.0 and self.x>200.0:
- self.vy = 0.0
- self.y = 400.0-2*self.radius
-
- if self.y<400.0+2*self.radius and self.y>400.0 and self.x>200.0:
- self.vy = 0.0
- self.y = 400.0+2*self.radius
-
- if (465-self.x)**2+(465-self.y)**2 < (1.4*self.radius)**2:
- return 1
-
- for i in xrange(0,4):
- for j in xrange(0,4):
- hole_x = 150*i + 15
- hole_y = 150*j + 15
- if (hole_x-self.x)**2+(hole_y-self.y)**2 < (1.4*self.radius)**2:
- return -1
- return 0
-
- def main():
- ser = MySerial()
- if not ser.opened():
- print "No Serial"
- return
- else:
- print "Serial OK"
- ball = Ball()
- pygame.init()
- screencaption = pygame.display.set_caption('Balance Ball')
- screen = pygame.display.set_mode([600,600])
- screen.fill([255,255,255])
- pygame.display.update()
-
- while True:
- for event in pygame.event.get():
- if event.type==pygame.QUIT:
- return
- screen.fill([255,255,192])
- pygame.draw.rect(screen,[0,0,0],[0,200-int(ball.radius),400,int(ball.radius)*2],3)
- pygame.draw.rect(screen,[0,0,0],[200,400-int(ball.radius),600,int(ball.radius)*2],3)
- for i in xrange(0,4):
- for j in xrange(0,4):
- hole_x = 150*i + 15
- hole_y = 150*j + 15
- pygame.draw.circle(screen,[0,0,0],[hole_x,hole_y],int(ball.radius),int(ball.radius))
-
- pygame.draw.circle(screen,[0,0,255],[465,465],int(ball.radius),int(ball.radius))
- pygame.draw.circle(screen,[255,30,60],[int(ball.x),int(ball.y)],int(ball.radius),int(ball.radius))
- pygame.display.update()
-
- result = ball.move(ser.GetAngle())
-
- if result == -1 :
- print "You Lose!"
- ball.reset()
- elif result == 1:
- print "You Win!"
- ball.reset()
-
- if __name__ == '__main__':
- main()
复制代码 运行方式:
上传程序后,确保Arduino 101已连接电脑,且不要使用其它COM口。再运行Python脚本,这个脚本是自动寻找Arduino101的串口的,若找到串口,会在屏幕上显示"Serial Ready",然后弹出游戏界面,就可以玩了:
图:有线连接的平衡球游戏
使用BLE传输的版本:
这个版本使用了BLE,不需要把101和电脑通过USB连接,只需要给101供电就行(比如充电宝)。在PC端我是修改的一个UWP应用,还没有编写墙壁、洞口等场景,仅有空的地图。
需要:Windows10 、Visual Studio 2015+ 、Arduino 101 、Arduino 101 1.0.x+库
代码:
算上UWP工程后,文件极大,因此可前往git库下载:
https://git.ustclug.org/WangXuan.c/101-UWP-balanceball 并按照ReadMe.txt操作。
运行方法:
上传Arduino101代码后,给101上电(不必用电脑供电),在Win10的蓝牙设置里配对Arduino 101。编译运行UWP程序,可以看到以下界面。依次点击“101 Detected! Press to Start”和“{00002A37-0000-1000-8000-00805F9B34FB}” 。晃动101,就能看到黄色的圆球随之运动了。
图:BLE版本的平衡球
|
|