Description
The initial concept for this game is a back-and-forth match between the player and computer. It starts with dropping a marble into the playfield, and each side earns points by hitting the marble into the opposite end zone. The computer constantly moves its paddle on the far side pseudo-randomly to defend its goal, while the player manually controls the paddle on their end via photosensor. The closer one’s finger gets to the sensor, the further clockwise the paddle spins. Conversely, the farther one’s finger moves to the sensor, the further counterclockwise it spins. By randomizing the way the opposition spins its paddle, the game comes down to reaction time and getting used to controlling the sensor and paddle. The final outcome is a game where players must hone in on fine motor control and be ready to take advantage of any opportunity to shoot the marble into their opponent’s end zone, creating more of a rally spectacle.
# dual_spin.py # # Raspberry Pi Pico - DC motor motion demo # # Demonstrates operating two DC motors driven by a DRV8833. # # This assumes a Pololu DRV8833 dual motor driver has been wired up to the Pico as follows: # Pico pin 24, GPIO18 -> AIN1 # Pico pin 25, GPIO19 -> AIN2 # Pico pin 26, GPIO20 -> BIN2 # Pico pin 27, GPIO21 -> BIN1 # any Pico GND -> GND # DRV8833 carrier board: https://www.pololu.com/product/2130 ################################################################ # CircuitPython module documentation: # time https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/index.html # math https://circuitpython.readthedocs.io/en/latest/shared-bindings/math/index.html # board https://circuitpython.readthedocs.io/en/latest/shared-bindings/board/index.html # pwmio https://circuitpython.readthedocs.io/en/latest/shared-bindings/pwmio/index.html ################################################################################ # print a banner as reminder of what code is loaded print("Starting dual_spin script.") # load standard Python modules import math, time # load the CircuitPython hardware definition module for pin definitions import board # load the CircuitPython pulse-width-modulation module for driving hardware import pwmio from digitalio import DigitalInOut, Direction, Pull import analogio import digitalio import random #-------------------------------------------------------------------------------- # Class to represent a single dual H-bridge driver. class DRV8833(): def __init__(self, AIN1=board.GP18, AIN2=board.GP19, BIN2=board.GP20, BIN1=board.GP21, pwm_rate=20000): # Create a pair of PWMOut objects for each motor channel. self.ain1 = pwmio.PWMOut(AIN1, duty_cycle=0, frequency=pwm_rate) self.ain2 = pwmio.PWMOut(AIN2, duty_cycle=0, frequency=pwm_rate) self.bin1 = pwmio.PWMOut(BIN1, duty_cycle=0, frequency=pwm_rate) self.bin2 = pwmio.PWMOut(BIN2, duty_cycle=0, frequency=pwm_rate) def write(self, channel, rate): """Set the speed and direction on a single motor channel. :param channel: 0 for motor A, 1 for motor B :param rate: modulation value between -1.0 and 1.0, full reverse to full forward.""" # convert the rate into a 16-bit fixed point integer pwm = min(max(int(2**16 * abs(rate)), 0), 65535) if channel == 0: if rate < 0: self.ain1.duty_cycle = pwm self.ain2.duty_cycle = 0 else: self.ain1.duty_cycle = 0 self.ain2.duty_cycle = pwm else: if rate < 0: self.bin1.duty_cycle = pwm self.bin2.duty_cycle = 0 else: self.bin1.duty_cycle = 0 self.bin2.duty_cycle = pwm #-------------------------------------------------------------------------------- # Create an object to represent a dual motor driver. print("Creating driver object.") driver = DRV8833() #-------------------------------------------------------------------------------- # Begin the main processing loop. This is structured as a looping script, since # each movement primitive 'blocks', i.e. doesn't return until the action is # finished. # Set up built-in green LED for output. led = DigitalInOut(board.LED) # GP25 led.direction = Direction.OUTPUT # Set up a digital input on GP15, which is physically pin 20 at one corner of the board. # E.g., this may be attached to a switch or photointerrupter with associated pullup resistor. switch = DigitalInOut(board.GP15) switch.direction = Direction.INPUT # Set up an analog input on ADC0 (GP26), which is physically pin 31. # E.g., this may be attached to photocell or photointerrupter with associated pullup resistor. sensor = analogio.AnalogIn(board.A0) # These may be need to be adjusted for your particular hardware. The Pico has # 12-bit analog-to-digital conversion so the actual conversion has 4096 possible # values, but the results are scaled to a 16-bit unsigned integer with range # from 0 to 65535. lower_threshold = 8000 upper_threshold = 45000 #--------------------------------------------------------------- # Run the main loop: script equivalent to Arduino loop() # The following logic detects input transitions using a state machine with two # possible states. The state index reflects the current estimated state of the # input. The transition rules apply hysteresis in the form of assymmetric # thresholds to reduce switching noise: the sensor value must rise higher than # the upper threshold or lower than the lower threshold to trigger a state # change. state_index = False #--------------------------------------------------------------- # Run the main loop: script equivalent to Arduino loop() # Keep track of the previous switch state in order to detect input changes. last_change_time = time.time() start_time = time.time() print("Starting main script.") change_action_time = 0 while True: # Computer's paddle # Check if curr time > change time # If so, create a new random movement. # print("Time", time.time() - start_time, "change action time", change_action_time) if time.time()-start_time >= change_action_time: action_length = 0.7 * random.random() change_action_time = time.time() - start_time + action_length action_power = random.uniform(0.6, 1.0) if random.random() > 0.5: action_power = action_power * -1.0 driver.write(0, action_power) print("Power:", action_power, "time", action_length) # Read the sensor once per cycle. sensor_level = sensor.value # Player's paddle player_power = 2.0*(float(sensor_level)/float(65535))- 1.0 driver.write(1, player_power) # uncomment the following to print tuples to plot with the mu editor # print((sensor_level,)) # time.sleep(0.02) # slow sampling to avoid flooding
Leave a Reply
You must be logged in to post a comment.