wip applying GPIO to the game
This commit is contained in:
parent
f68fb897c5
commit
d122f66af4
65
NS.py
65
NS.py
|
@ -32,6 +32,7 @@ from pygame.draw import aalines, lines
|
||||||
from pygame.gfxdraw import aapolygon, arc, polygon, aaellipse, ellipse, filled_ellipse, filled_circle
|
from pygame.gfxdraw import aapolygon, arc, polygon, aaellipse, ellipse, filled_ellipse, filled_circle
|
||||||
from pygame.locals import *
|
from pygame.locals import *
|
||||||
|
|
||||||
|
import gpio
|
||||||
from lib.pgfw.pgfw.Game import Game
|
from lib.pgfw.pgfw.Game import Game
|
||||||
from lib.pgfw.pgfw.GameChild import GameChild
|
from lib.pgfw.pgfw.GameChild import GameChild
|
||||||
from lib.pgfw.pgfw.Sprite import Sprite, RainbowSprite, BlinkingSprite
|
from lib.pgfw.pgfw.Sprite import Sprite, RainbowSprite, BlinkingSprite
|
||||||
|
@ -146,11 +147,14 @@ class NS(Game, Animation):
|
||||||
# Specify possible arguments and parse the command line. If the -h flag is passed, the argparse library will print a
|
# Specify possible arguments and parse the command line. If the -h flag is passed, the argparse library will print a
|
||||||
# help message and end the program.
|
# help message and end the program.
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--minimize-load-time", action="store_true")
|
parser.add_argument("--minimize-load-time", action="store_true", help="Disable some graphics loading and effects generation")
|
||||||
parser.add_argument("--serial-port")
|
parser.add_argument("--serial-port")
|
||||||
parser.add_argument("--audio-buffer-size", type=int, default=1024)
|
parser.add_argument("--audio-buffer-size", type=int, default=1024)
|
||||||
parser.add_argument("--list-serial-ports", action="store_true")
|
parser.add_argument("--list-serial-ports", action="store_true")
|
||||||
parser.add_argument("--no-serial", action="store_true")
|
parser.add_argument("--no-serial", action="store_true", help="Force serial (Arduino) mode off.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--pi", action="store_true",
|
||||||
|
help="Force to read input from the GPIO pins of a Raspberry Pi. Must be running on Raspberry Pi. Forces --no-serial.")
|
||||||
parser.add_argument("--show-config", action="store_true")
|
parser.add_argument("--show-config", action="store_true")
|
||||||
arguments = parser.parse_known_args()[0]
|
arguments = parser.parse_known_args()[0]
|
||||||
|
|
||||||
|
@ -221,19 +225,37 @@ class NS(Game, Animation):
|
||||||
if arguments.no_serial:
|
if arguments.no_serial:
|
||||||
self.get_configuration().set("input", "serial", False)
|
self.get_configuration().set("input", "serial", False)
|
||||||
|
|
||||||
|
# Apply the pi flag from the command line if requested. This takes precedence over Arduino, so even if serial is enabled,
|
||||||
|
# force to no serial mode.
|
||||||
|
if arguments.pi:
|
||||||
|
self.get_configuration().set("input", "pi", True)
|
||||||
|
if get_configuration("input", "serial"):
|
||||||
|
print("Pi mode was requested, so forcing serial (Arduino) mode to off")
|
||||||
|
self.get_configuration().set("input", "serial", False)
|
||||||
|
|
||||||
# Print the configuration if requested on the command line
|
# Print the configuration if requested on the command line
|
||||||
if arguments.show_config:
|
if arguments.show_config:
|
||||||
print(self.get_configuration())
|
print(self.get_configuration())
|
||||||
|
|
||||||
# Initialize the serial reader and launch a thread for reading from the serial port
|
# init Pi
|
||||||
if self.serial_enabled():
|
if self.pi_enabled():
|
||||||
|
|
||||||
|
# Initialize GPIO interface
|
||||||
|
gpio.initialize_gpio()
|
||||||
|
|
||||||
|
# init Arduino
|
||||||
|
elif self.serial_enabled():
|
||||||
|
|
||||||
|
# Initialize the serial reader and launch a thread for reading from the serial port
|
||||||
from serial import Serial, SerialException
|
from serial import Serial, SerialException
|
||||||
from serial.tools import list_ports
|
from serial.tools import list_ports
|
||||||
|
|
||||||
# If a list of serial ports was requested, print detected ports and exit.
|
# If a list of serial ports was requested, print detected ports and exit.
|
||||||
if arguments.list_serial_ports:
|
if arguments.list_serial_ports:
|
||||||
for port in list_ports.comports():
|
for port in list_ports.comports():
|
||||||
print(f"Detected serial port: {port.device}")
|
print(f"Detected serial port: {port.device}")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# Open the port specified by the configuration or command line if it is found. If the specified port is not
|
# Open the port specified by the configuration or command line if it is found. If the specified port is not
|
||||||
# found, open the first found serial port. If no serial ports are found, raise an exception.
|
# found, open the first found serial port. If no serial ports are found, raise an exception.
|
||||||
requested_port = self.get_configuration("input", "arduino-port")
|
requested_port = self.get_configuration("input", "arduino-port")
|
||||||
|
@ -247,6 +269,8 @@ class NS(Game, Animation):
|
||||||
self.serial_kill = False
|
self.serial_kill = False
|
||||||
self.serial_data = 0
|
self.serial_data = 0
|
||||||
self.reset_arduino()
|
self.reset_arduino()
|
||||||
|
|
||||||
|
# Launch a separate thread for reading serial data
|
||||||
self.serial_thread = Thread(target=self.read_serial)
|
self.serial_thread = Thread(target=self.read_serial)
|
||||||
self.serial_thread.start()
|
self.serial_thread.start()
|
||||||
|
|
||||||
|
@ -299,6 +323,9 @@ class NS(Game, Animation):
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
|
|
||||||
|
def pi_enabled(self):
|
||||||
|
return self.get_configuration("input", "pi")
|
||||||
|
|
||||||
def serial_enabled(self):
|
def serial_enabled(self):
|
||||||
return self.get_configuration("input", "serial")
|
return self.get_configuration("input", "serial")
|
||||||
|
|
||||||
|
@ -351,6 +378,21 @@ class NS(Game, Animation):
|
||||||
if light.pressed:
|
if light.pressed:
|
||||||
self.idle_elapsed = 0
|
self.idle_elapsed = 0
|
||||||
|
|
||||||
|
def apply_gpio(self):
|
||||||
|
"""
|
||||||
|
Check the connection status of the GPIO pins and turn on the appropriate light objects (the pads).
|
||||||
|
"""
|
||||||
|
# Get the active (a.k.a. pressed) state of each GPIO pin (a.k.a. pad)
|
||||||
|
activity = gpio.activity()
|
||||||
|
|
||||||
|
for light_id in activity.keys():
|
||||||
|
# The pressed state is set to the activity state
|
||||||
|
self.platform.lights[light_id].pressed = activity[light_id]
|
||||||
|
|
||||||
|
# Reset idle timer if a light is detected as pressed
|
||||||
|
if activity[light_id]:
|
||||||
|
self.idle_elapsed = 0
|
||||||
|
|
||||||
def reset(self, leave_wipe_running=False):
|
def reset(self, leave_wipe_running=False):
|
||||||
self.idle_elapsed = 0
|
self.idle_elapsed = 0
|
||||||
self.suppressing_input = False
|
self.suppressing_input = False
|
||||||
|
@ -450,10 +492,22 @@ class NS(Game, Animation):
|
||||||
def update(self):
|
def update(self):
|
||||||
Animation.update(self)
|
Animation.update(self)
|
||||||
last_frame_duration = self.time_filter.get_last_frame_duration()
|
last_frame_duration = self.time_filter.get_last_frame_duration()
|
||||||
if self.serial_enabled():
|
|
||||||
|
# Apply controller input to light (pad) states from either Pi or Arduino if applicable
|
||||||
|
if self.pi_enabled():
|
||||||
|
|
||||||
|
# Translate Raspberry Pi GPIO state into pad states
|
||||||
|
self.apply_gpio()
|
||||||
|
|
||||||
|
elif self.serial_enabled():
|
||||||
|
|
||||||
|
# Translate the most recent serial data, being provided by serial/serial2/serial2.ino, into pad states
|
||||||
self.apply_serial()
|
self.apply_serial()
|
||||||
|
|
||||||
|
# Handle auto reset of the Arduino for stablizing serial data
|
||||||
if self.title.active or self.ending.active or self.dialogue.active:
|
if self.title.active or self.ending.active or self.dialogue.active:
|
||||||
self.no_reset_elapsed += last_frame_duration
|
self.no_reset_elapsed += last_frame_duration
|
||||||
|
|
||||||
# If we received good input, reset the auto reset timer
|
# If we received good input, reset the auto reset timer
|
||||||
if 0b11 <= self.serial_data <= 0b1100:
|
if 0b11 <= self.serial_data <= 0b1100:
|
||||||
self.no_reset_elapsed = 0
|
self.no_reset_elapsed = 0
|
||||||
|
@ -461,6 +515,7 @@ class NS(Game, Animation):
|
||||||
print("auto arduino reset triggered")
|
print("auto arduino reset triggered")
|
||||||
self.reset_arduino()
|
self.reset_arduino()
|
||||||
self.no_reset_elapsed = 0
|
self.no_reset_elapsed = 0
|
||||||
|
|
||||||
self.title.update()
|
self.title.update()
|
||||||
self.level_select.update()
|
self.level_select.update()
|
||||||
self.ending.update()
|
self.ending.update()
|
||||||
|
|
3
config
3
config
|
@ -60,7 +60,8 @@ volume = 1.0
|
||||||
[input]
|
[input]
|
||||||
buffer = 0
|
buffer = 0
|
||||||
arduino-port = /dev/ttyACM0
|
arduino-port = /dev/ttyACM0
|
||||||
serial = True
|
serial = False
|
||||||
|
pi = True
|
||||||
confirm-quit = False
|
confirm-quit = False
|
||||||
|
|
||||||
[time]
|
[time]
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
#
|
#
|
||||||
# Full open source code is available at <https://git.nugget.fun/scrape/scrapeboard>.
|
# Full open source code is available at <https://git.nugget.fun/scrape/scrapeboard>.
|
||||||
#
|
#
|
||||||
# This is a utility script for testing if the GPIO interface of a Raspberry Pi is working
|
# This module can be imported and used to check on the status of connections between four GPIO
|
||||||
# with the four input wires, which correspond to the four metal floor pads in the standard
|
# inputs on the Raspberry Pi for detecting the pads in Scrapeboard.
|
||||||
# Scrapeboard build.
|
#
|
||||||
|
# When run as a script, it prints connections detected between the input GPIO pins.
|
||||||
|
|
||||||
import time, itertools
|
import time, itertools
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
@ -22,6 +23,17 @@ pins = {
|
||||||
LSW: 23
|
LSW: 23
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def initialize_gpio():
|
||||||
|
"""
|
||||||
|
Set pin numbering mode to GPIO and initialize all pins to input pullup.
|
||||||
|
"""
|
||||||
|
# Use GPIO numbering
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
|
||||||
|
# Set all pins to pullup
|
||||||
|
for pin_id, pin in pins.items():
|
||||||
|
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
|
|
||||||
def connection2(pin_a, pin_b):
|
def connection2(pin_a, pin_b):
|
||||||
"""
|
"""
|
||||||
Set `pin_a` to output a low signal, and set every other pin to pullup. If `pin_b` reads a low signal even though
|
Set `pin_a` to output a low signal, and set every other pin to pullup. If `pin_b` reads a low signal even though
|
||||||
|
@ -55,21 +67,46 @@ def connection(pin_a, pin_b):
|
||||||
|
|
||||||
def connections():
|
def connections():
|
||||||
"""
|
"""
|
||||||
Look at all six possible connections between the four pins and print a message if one is found connected.
|
Look at all six possible connections between the four pins and return the state of each as a single dict.
|
||||||
|
|
||||||
|
@return A dict with one entry per combination of pins, the key is a tuple of pin IDs, and the value is the state of connection
|
||||||
"""
|
"""
|
||||||
|
state = {}
|
||||||
for pin_id_a, pin_id_b in itertools.combinations(pins, 2):
|
for pin_id_a, pin_id_b in itertools.combinations(pins, 2):
|
||||||
if connection(pins[pin_id_a], pins[pin_id_b]):
|
if connection(pins[pin_id_a], pins[pin_id_b]):
|
||||||
print(f"{pin_id_a} ({pins[pin_id_a]}) <-> {pin_id_b} ({pins[pin_id_b]})")
|
state[(pin_id_a, pin_id_b)] = True
|
||||||
|
else:
|
||||||
|
state[(pin_id_a, pin_id_b)] = False
|
||||||
|
return state
|
||||||
|
|
||||||
|
def activity():
|
||||||
|
"""
|
||||||
|
Look at all six possible connections between the four pins, and if a pin appears in any active connection, consider it active.
|
||||||
|
Return the active state of all four pins as a dict.
|
||||||
|
|
||||||
|
@return A dict with one entry per pin. The key is the pin ID, and the value is the state of whether it's active (a.k.a. pressed)
|
||||||
|
"""
|
||||||
|
# Create a dict of pins all at False
|
||||||
|
state = pins.copy()
|
||||||
|
for pin in state.keys():
|
||||||
|
state[pin] = False
|
||||||
|
|
||||||
|
# Check all six combinations. If a pin appears in a connection, update its state to True.
|
||||||
|
for pin_id_a, pin_id_b in itertools.combinations(pins, 2):
|
||||||
|
if connection(pins[pin_id_a], pins[pin_id_b]):
|
||||||
|
state[pin_id_a] = True
|
||||||
|
state[pin_id_b] = True
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Use GPIO numbering
|
initialize_gpio()
|
||||||
GPIO.setmode(GPIO.BCM)
|
|
||||||
|
|
||||||
# Set all pins to pullup
|
|
||||||
for pin_id, pin in pins.items():
|
|
||||||
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# Try all connections once each frame
|
# Try all connections once each frame
|
||||||
connections()
|
for connection_ids, connection_state in connections():
|
||||||
|
# Only print connected combinations of pins
|
||||||
|
if connection_state:
|
||||||
|
pin_id_a, pin_id_b = connection_ids
|
||||||
|
print(f"{pin_id_a} ({pins[pin_id_a]}) <-> {pin_id_b} ({pins[pin_id_b]})")
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
Loading…
Reference in New Issue