使用PyGame

时间:2016-06-03 07:47:03

标签: python linux arduino pygame pyserial

我正在使用Arduino作为输入使用PyGame编写的心率监测器,其想法是游戏允许您通过放松练习尝试控制心率,而不管其中的内容是什么屏幕。

我希望能够在游戏中运行视频/鼠标/键盘按钮捕捉等内容,同时在左上角显示心率,并在更改时从arduino更新。

arduino读取心率监视器,然后发布格式如下的JSON字符串:

{'heart_rate': 65,'state': 'running'}

"状态"可以是“初始化”,“跑步”,“失败”和“失败”之一。或者'停止'。

虽然我不熟悉Python,但我已经从http://www.akeric.com/blog/?p=1237获取代码,让我开始使用PyGame,因为我之前没有在这里冒险过。

我遇到的问题是,当我尝试从串口读取时,它会锁定游戏。

我已经阅读了线程,我认为我已经正确实现了它,但是下面的代码仍会阻止:

"""
default.py
www.akeric.com - 2010-09-07
Default, base, initial setup for a pygame program.
In this case, black background, white circle follows mouse position, and
framerate is shown in the title-bar.
"""

#-------------------------------------------------------------------------------
# Imports & Inits
import sys
import serial
import json
import threading

import pygame
from pygame.locals import *
pygame.init()
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0)


#-------------------------------------------------------------------------------
# Constants
VERSION = '1.0'
WIDTH = 800
HEIGHT = 600
FRAMERATE = 60
CURRENT_MESSAGE = {'heart_rate': 0}

#-------------------------------------------------------------------------------
# Screen Setup
screen = pygame.display.set_mode((WIDTH, HEIGHT))
bgCol = Color('black')
clock = pygame.time.Clock()
moduleName = __file__.split('\\')[-1]

#-------------------------------------------------------------------------------
# Define helper functions, classes, etc...
def text_objects(text, font):
    textSurface = font.render(text, True, (255,255,255))
    return textSurface, textSurface.get_rect()

def message_display(text,x_pos=(WIDTH/2),y_pos=(HEIGHT/2)):
    largeText = pygame.font.Font('freesansbold.ttf',25)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = (x_pos,y_pos)
    screen.blit(TextSurf, TextRect)

def spam():
    pos = pygame.mouse.get_pos()
    pygame.draw.circle(screen, Color('white'), pos, 32)

def handle_data(data):
    CURRENT_MESSAGE = json.loads(data)
    message_display("HR: %s" % CURRENT_MESSAGE['heart_rate'],50,20)

def read_from_port(ser):
        while True:
           reading = ser.readline().decode()
           if len(reading) > 0:
               print "Data Recieved"
               handle_data(reading)



#-------------------------------------------------------------------------------
# Main Program
def main():
    print "Running Python version: %s"%sys.version
    print "Running PyGame version: %s"%pygame.ver
    print "Running %s version: %s"%(moduleName, VERSION)
    looping = True

    # Main Loop-----------------------
    while looping:
        # Maintain our framerate, set caption, clear background:
        clock.tick(FRAMERATE)
        pygame.display.set_caption("%s - FPS: %.2f" %(moduleName,clock.get_fps()) )
        screen.fill(bgCol)
        spam()


        # Update our display:---------
        pygame.display.flip()

#-------------------------------------------------------------------------------
# Execution from shell\icon:
if __name__ == "__main__":
    # Make running from IDE work better:
    thread = threading.Thread(target=read_from_port, args=(ser,))
    thread.start()
    sys.exit(main())

任何人都可以帮我理解我在哪里出错吗?

2 个答案:

答案 0 :(得分:0)

我对Python知之甚少,但我会测试是否有任何字符等待读取,只读取该数字而不是使用readline。我想你想使用in_waiting和read( size )。

Readline将一直阻止,直到收到回车符。

所以,我认为如下:

def read_from_port(ser):
    while True:           
       if in_waiting > 0:
           reading = read(in_waiting)
           print "Data Recieved"
           handle_data(reading)

现在,您需要在分隔符处连接并解析字符串,以确保已收到整个字符串。

答案 1 :(得分:0)

我修好了! :)

#!/usr/bin/env python

import pygame
from threading import Thread
import serial
import json
from pygame.color import Color
from pygame.locals import *

CURHR = 0

ser = serial.Serial('/dev/pts/3', 9600, timeout=0)
def worker():

   global CURHR
   while True:
     msg = ser.readline()
     if len(msg) > 0:
       print "Message Received: %s" % msg
       current_message = json.loads(msg)
       if current_message["state"] == "running":
         CURHR=current_message['heart_rate']

t = Thread(target=worker)
t.daemon = True
t.start()

pygame.init()

#-------------------------------------------------------------------------------
# Constants
VERSION = '1.0'
WIDTH = 800
HEIGHT = 600
FRAMERATE = 60

#-------------------------------------------------------------------------------
# Define helper functions, classes, etc...
def text_objects(text, font):
    textSurface = font.render(text, True, (255,255,255))
    return textSurface, textSurface.get_rect()

def message_display(text,x_pos=(WIDTH/2),y_pos=(HEIGHT/2)):
    largeText = pygame.font.Font('freesansbold.ttf',25)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = (x_pos,y_pos)
    screen.blit(TextSurf, TextRect)

def spam():
    pos = pygame.mouse.get_pos()
    pygame.draw.circle(screen, Color('white'), pos, 32)

screen = pygame.display.set_mode((WIDTH,HEIGHT))
clock  = pygame.time.Clock()
font   = pygame.font.SysFont("consolas", 25, True)
count  = 0
pygame.display.set_caption("Test")

done = False
while not done:
    screen.fill(Color('black'))
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done = True
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                  done = True

    spam()
    hr_string = "HR: %s"  % CURHR
    hr_text = font.render(hr_string, True, Color('red'))
    screen.blit(hr_text, [25,10])
    clock.tick(20)
    pygame.display.flip()

诀窍是设置一个Global,然后让线程设置该全局值。

当屏幕“blitted”(那是什么东西?!)时会呈现全局,并且实时更新值而不影响光标的移动。