If you are new to CircuitPython, be sure to check out the Welcome guide for an overview. And if you want to know even more, check out the Essentials guide.
Let's see how we can create our Hunter and Treasures using CircuitPython. This is a little more complex than using MakeCode, so you if you would rather just play the game, skip this and move on to the Playing The Game section.
import time import board import pulseio import adafruit_irremote import neopixel # Configure treasure information TREASURE_ID = 1 TRANSMIT_DELAY = 15 # Create NeoPixel object to indicate status pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) # Create a 'pulseio' output, to send infrared signals on the IR transmitter @ 38KHz pwm = pulseio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15) pulseout = pulseio.PulseOut(pwm) # Create an encoder that will take numbers and turn them into IR pulses encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], one=[550, 550], zero=[550, 1700], trail=0) while True: pixels.fill(0xFF0000) encoder.transmit(pulseout, [TREASURE_ID]*4) time.sleep(0.25) pixels.fill(0) time.sleep(TRANSMIT_DELAY)
After importing all the goodies we need, we set the ID for the Treasure as well as the time to wait between transmissions.
# Configure treasure information TREASURE_ID = 1 TRANSMIT_DELAY = 15
You'll want to change TREASURE_ID
to a unique value for each Treasure. Just use simple numbers like 1, 2, 3, etc. The value of TRANSMIT_DELAY
determines how often (in seconds) to send out the ID.
Then we create various items needed for using NeoPixels, the IR receiver, as well as an encoder for creating the transmitted signal.
After all that, we just loop forever sending out the ID:
while True: pixels.fill(0xFF0000) encoder.transmit(pulseout, [TREASURE_ID]*4) time.sleep(0.25) pixels.fill(0) time.sleep(TRANSMIT_DELAY)
Currently, the CircuitPython IR Remote library works with 4 byte NEC codes only. We create this in place with the syntax [TREASURE_ID]*4
. If that looks too magical, you can try it out in the REPL to see what it does.
Adafruit CircuitPython 3.0.0 on 2018-07-09; Adafruit CircuitPlayground Express with samd21g18
>>> [1]*4
[1, 1, 1, 1]
>>> ["hello"]*4
['hello', 'hello', 'hello', 'hello']
>>>
It's just a simple syntax for creating a list with all the same content. In this case, 4 of the same thing.
import time import board import pulseio import adafruit_irremote import neopixel # Configure treasure information # ID PIXEL COLOR TREASURE_INFO = { (1,)*4 : ( 0 , 0xFF0000) , (2,)*4 : ( 1 , 0x00FF00) , (3,)*4 : ( 2 , 0x0000FF) } treasures_found = dict.fromkeys(TREASURE_INFO.keys(), False) # Create NeoPixel object to indicate status pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) # Sanity check setup if len(TREASURE_INFO) > pixels.n: raise ValueError("More treasures than pixels.") # Create a 'pulseio' input, to listen to infrared signals on the IR receiver pulsein = pulseio.PulseIn(board.IR_RX, maxlen=120, idle_state=True) # Create a decoder that will take pulses and turn them into numbers decoder = adafruit_irremote.GenericDecode() while True: # Listen for incoming IR pulses pulses = decoder.read_pulses(pulsein) # Try and decode them try: # Attempt to convert received pulses into numbers received_code = tuple(decoder.decode_bits(pulses, debug=False)) except adafruit_irremote.IRNECRepeatException: # We got an unusual short code, probably a 'repeat' signal # print("NEC repeat!") continue except adafruit_irremote.IRDecodeException as e: # Something got distorted or maybe its not an NEC-type remote? # print("Failed to decode: ", e.args) continue # See if received code matches any of the treasures if received_code in TREASURE_INFO.keys(): treasures_found[received_code] = True p, c = TREASURE_INFO[received_code] pixels[p] = c # Check to see if all treasures have been found if False not in treasures_found.values(): pixels.auto_write = False while True: # Round and round we go pixels.buf = pixels.buf[-3:] + pixels.buf[:-3] pixels.show() time.sleep(0.1)
After the necessary import, we configure things using a dictionary.
# Configure treasure information # ID PIXEL COLOR TREASURE_INFO = { (1,)*4: ( 0 , 0xFF0000) , (2,)*4: ( 1 , 0x00FF00) , (3,)*4: ( 2 , 0x0000FF) }
The key is Treasure ID, in the form of the expected decoded IR signal - we use the same trick as above to create the necessary 4 byte value expected by the irremote library. The values of the dictionary are tuples which contain the location and color of the NeoPixel to use to indicate the Treasure has been found.
If you wanted to increase the number of Treasures in the game, just add an entry to the dictionary. Keep in mind that you'll have to modify a copy of the Treasure code to create a corresponding CPX Treasure to match the new entry.
A second dictionary is created to keep track of whether the Treasures have been found or not:
treasures_found = dict.fromkeys(TREASURE_INFO.keys(), False)
This is created using the same keys as the previous dictionary. The values are just booleans to indicate found state. Initially they are all False, since nothing has been found yet.
After some other setup, we just loop forever getting raw pulses:
# Listen for incoming IR pulses pulses = decoder.read_pulses(pulsein)
Which we then try and decode:
# Attempt to convert received pulses into numbers received_code = tuple(decoder.decode_bits(pulses, debug=False))
If anything happens, exceptions are thrown, which are currently just silently ignored.
Once we get a valid signal, we check the code against the ones we setup in the dictionary. If it matches an entry, then we update the dictionary of found Treasures and turn on the corresponding NeoPixel.
# See if received code matches any of the treasures if received_code in TREASURE_INFO.keys(): treasures_found[received_code] = True p, c = TREASURE_INFO[received_code] pixels[p] = c
Once all of the Treasures have been found, there will no longer be any False entries in the dictionary of found Treasures. So it's a simple check to see if they have all been found. If they have, then we just spin the NeoPixels round and round forever.
# Check to see if all treasures have been found if False not in treasures_found.values(): pixels.auto_write = False while True: # Round and round we go pixels.buf = pixels.buf[-3:] + pixels.buf[:-3] pixels.show() time.sleep(0.1)
Page last edited March 08, 2024
Text editor powered by tinymce.