# Circuit Playground Bluefruit Quick Draw Duo

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/086/939/medium800/circuitpython_cpb-quick-draw-blueflash-woodentable-2000x1500-iii.jpg?1579134063 Quick Draw Duo played on two Circuit Playground Bluefruits with external audio.)

This project is a variant of the [Circuit Playground Quick Draw](https://learn.adafruit.com/circuit-playground-quick-draw "Adafruit Learn: Circuit Playground Quick Draw") game for a _pair_ of [Circuit Playground Bluefruit](https://learn.adafruit.com/adafruit-circuit-playground-bluefruit "Adafruit Learn: Circuit Playground Bluefruit") (CPB) boards using CircuitPython. [Bluetooth Low Energy (LE)](https://en.wikipedia.org/wiki/Bluetooth_Low_Energy "Wikipedia: Bluetooth Low Energy") is used to exchange information between the boards. This means you can play the game wirelessly!

An additional CircuitPython program can be used to measure and compare visual and auditory reaction times. This can run on either a [Circuit Playground Express](https://learn.adafruit.com/adafruit-circuit-playground-express/overview "Adafruit Learn: Circuit Playground Express") (CPX) or CPB board.

Thank-you to [Carter Nelson](https://learn.adafruit.com/users/caternuson "Adafruit Learn: Carter Nelson") for the original game and Megan, Izzy, Elsa and Matilda for help in testing the new game.

The **_two_** CPB boards require the latest 5.x version of CircuitPython.

## Parts

You will need two each of the following parts:

Featured
### Circuit Playground Bluefruit - Bluetooth® Low Energy

[Circuit Playground Bluefruit - Bluetooth® Low Energy](https://www.adafruit.com/product/4333)
 **Circuit Playground Bluefruit** is our third board in the Circuit Playground series, another step towards a perfect introduction to electronics and programming. We've taken the popular Circuit Playground Express and made it even better! Now the main chip is an nRF52840...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4333)
[Related Guides to the Product](https://learn.adafruit.com/products/4333/guides)
![shot of a Black woman's neon-green manicured hand holding up a Circuit Playground Bluefruit glowing rainbow LEDs.](https://cdn-shop.adafruit.com/640x480/4333-11.jpg)

Featured
### 3 x AAA Battery Holder with On/Off Switch and 2-Pin JST

[3 x AAA Battery Holder with On/Off Switch and 2-Pin JST](https://www.adafruit.com/product/727)
This battery holder connects 3 AAA batteries together in series for powering all kinds of projects. We spec'd these out because the box is slim, and 3 AAA's add up to about 3.3-4.5V, a very similar range to Lithium Ion/polymer (Li-Ion) batteries and have an on-off switch. That makes...

Out of Stock
[Buy Now](https://www.adafruit.com/product/727)
[Related Guides to the Product](https://learn.adafruit.com/products/727/guides)
![Front angled shot of 3 x AAA battery holder with on-off switch and 2-pin JST PH connector.](https://cdn-shop.adafruit.com/640x480/727-07.jpg)

You will need a good USB data + power cable to program things:

Featured
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

# Circuit Playground Bluefruit Quick Draw Duo

## Game Design

![](https://cdn-learn.adafruit.com/assets/assets/000/086/570/medium800/circuitpython_1280px-Duel_between_Aaron_Burr_and_Alexander_Hamilton.jpg?1578056845 Duel between Vice President Aaron Burr and Alexander Hamilton in 1804. Engraving from the book "Our Greater Country being a Standard History of the United States".)

The design of the game is very similar to the [original](https://learn.adafruit.com/circuit-playground-quick-draw/game-design "Adafruit Learn: Circuit Playground Quick Draw: Game Design") with a few additions below marked with the † symbol. The additions are needed to synchronise the two CPB boards and exchange reaction times between them. There are also ten rounds to make this more fun although this doesn't strictly make sense for a duelling game!

The communication protocol between the two boards requires a different role is assigned to each board. This is set using the [two-position switch](https://learn.adafruit.com/circuitpython-made-easy-on-circuit-playground-express/slide-switch "Adafruit Learn: CircuitPython Made Easy on Circuit Playground Express and Bluefruit: Slide Switch") on the board, i.e. the two boards _must_ have the switch in _different_ positions. The player's "draw" button is set to the button on the side the switch is set to.

## Game Logic

1. Turn off all of the NeoPixels.
2. Determine the communication delay between the boards.
3. Synchronise the boards.†
4. Wait the determined (random) countdown time.
5. If a player presses a button during this time, they drew too soon (misdraw).
6. Once the countdown time has elapsed, turn on all of the NeoPixels (white).
7. Wait for the button presses and exchange reaction time data between boards.†
8. Look for the first (quickest) button press.
9. Whichever button was pressed first is the Quick Draw winner.
10. Repeat to step 3 until ten rounds have been completed.†
11. Display a personalised summary of wins/misdraws on the NeoPixels.†

The exchange of data at step 7 can cause a delay compared to the original single board game. The winner cannot be determined until each board has received the data from the other board.

The winner at step 9 introduces a new colour (amber) to represent the unlikely outcome of both players simultaneously pressing their buttons.

## Delay Calculation and Synchronisation Protocol

Sending data from one board to another takes a certain amount of time. If one board sends a "go now" command to another then the sender does not know when the receiver has received and processed that command. The receiver could send a reply but the same problem exists whereby the sender of the reply does not know when it has been received and processed. Measuring the transmission time including the time to receive and parse the data facilitates good synchronisation between the boards. This is one element of the [Network Time Protocol (NTP)](https://en.wikipedia.org/wiki/Network_Time_Protocol "Wikipedia: Network Time Protocol") which can be used to distribute accurate time from reference clocks to computers and devices across the globe.

The send time on its own cannot be measured by the sender but the time to _send and receive an immediate reply_ can be measured by the sender. If the network propagation and processing are symmetric then exactly half of this [round-trip time (rtt)](https://en.wikipedia.org/wiki/Round-trip_delay_time "Wikipedia: round-trip delay time") represents the time for the sender's data to propagate and be processed with the the other half representing the time for the receiver's reply to propagate and be processed.

The diagram below shows how the rtt measurement operates. Time progresses downwards in the diagram.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/685/medium800/circuitpython_cpx-quick-draw-ping_for_rtt-protocol-v3.png?1578362087 Sequence diagram showing how round-trip time is measured between CPBs.)

For comparison, the approach is the similar to how [ping](https://en.wikipedia.org/wiki/Ping_(networking_utility) "Wikipedia: ping (networking utility)") works using the [ICMP](https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol "WikiPedia: Internet Control Message Protocol") echo service. The traditional [TCP/UDP echo service](https://en.wikipedia.org/wiki/Echo_Protocol "Wikipedia: echo protocol") is another similar, higher-level service.

The asymmetric roles for the two boards in the measuring process are commonly referred to in computing and electronics as [main and secondary](https://en.wikipedia.org/wiki/Master/slave_(technology) "Wikipedia: master/slave (technology)"). In this example only the main is measuring the rtt but it then passes the value to the secondary in subsequent packets. A simple way to set the role (or any [boolean](https://en.wikipedia.org/wiki/Boolean_data_type "Wikipedia: boolean data type") quantity) is to use the [two-position switch](https://learn.adafruit.com/circuitpython-made-easy-on-circuit-playground-express/slide-switch "Adafruit Learn: CircuitPython Made Easy on Circuit Playground Express and Bluefruit: Slide Switch") on the CPB board.

In [Bluetooth LE terminology](https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt#connected-network-topology-3-2 "Adafriot Learn: Introduction to Bluetooth Low Energy: GATT"), the two devices are a central device which connects to a peripheral device. This also gives the boards different roles in terms of a [client/server model](https://en.wikipedia.org/wiki/Client%E2%80%93server_model "Wikipedia: client-server model").

An approximate, but reasonably accurate, send time can be calculated from the measured round-trip times. This duration can then be used by one board to compensate for the send time and this allows the two boards to be synchronised, enabling the game to start on each board at the same time.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/686/medium800/circuitpython_cpx-quick-draw-barrier-protocol-v2.png?1578362104 Sequence diagram showing how CPBs are synchronised before each game round.)

The procedure name used in the design is `barrier`, a reference to a [type of synchronisation](https://en.wikipedia.org/wiki/Barrier_(computer_science) "Wikipedia: barrier (computer science)") used for multi-threaded applications. This procedure aims to _complete at the same time_ on each CPB board causing the subsequent code on each to execute near simultaneously. In this case, the aim is to be within a few milliseconds of each other. If the player is reacting to their own white NeoPixel flash then they do not have to be perfectly synchronised.

The staccato nature of Bluetooth LE communication (see diagram in [GATT Transactions](https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt#gatt-transactions-3-4 "Adafruit Learn: Introduction to Bluetooth Low Energy: GATT")) is not accounted for in the synchronisation technique and this is one factor reducing its accuracy.

In this design, the same type of messages are used by the request and the response for simplicity.

A [message](https://en.wikipedia.org/wiki/Message_passing "Wikipedia: message passing") which always elicits a reply message is often referred to as a _request_ and _response_. This style of interaction in this protocol could also be regarded as a [remote procedure call (RPC)](https://en.wikipedia.org/wiki/Remote_procedure_call "Wikipieda: remote procedure call").

# Circuit Playground Bluefruit Quick Draw Duo

## CircuitPython on Circuit Playground Bluefruit

# Install or Update CircuitPython

Follow this quick step-by-step to install or update CircuitPython on your Circuit Playground Bluefruit.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/circuitplayground_bluefruit/)
 **Click the link above and download the latest UF2 file**

Download and save it to your Desktop (or wherever is handy)

![adafruit_products_CPB_Download_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/080/530/medium640/adafruit_products_CPB_Download_UF2.png?1567715178)

Plug your Circuit Playground Bluefruit into your computer using a known-good data-capable USB cable.

**A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.**

Double-click the small **Reset** button in the middle of the CPB (indicated by the red arrow in the image). The ten NeoPixel LEDs will all turn red, and then will all turn green. If they turn all red and stay red, check the USB cable, try another USB port, etc. The little red LED next to the USB connector will pulse red - this is ok!

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

(If double-clicking doesn't do it, try a single-click!)

![adafruit_products_CPB_Front_Reset_Button_Arrow.jpg](https://cdn-learn.adafruit.com/assets/assets/000/080/532/medium640/adafruit_products_CPB_Front_Reset_Button_Arrow.jpg?1567715535)

You will see a new disk drive appear called **CPLAYBTBOOT**.

&nbsp;

&nbsp;

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **CPLAYBTBOOT.**

![adafruit_products_CPB_CPLAYBTBOOT.png](https://cdn-learn.adafruit.com/assets/assets/000/080/533/medium640/adafruit_products_CPB_CPLAYBTBOOT.png?1567715858)

![adafruit_products_CBP_drag_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/080/534/medium640/adafruit_products_CBP_drag_UF2.png?1567715871)

The LEDs will turn red. Then, the **CPLAYBTBOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![adafruit_products_CBP_CIRCUITPY.png](https://cdn-learn.adafruit.com/assets/assets/000/080/535/medium640/adafruit_products_CBP_CIRCUITPY.png?1567716034)

# Circuit Playground Bluefruit Quick Draw Duo

## CircuitPython

## Libraries

Once you've gotten CircuitPython onto your Circuit Playground Bluefruit boards, it's time to add some libraries. You can&nbsp;[follow this guide page](https://learn.adafruit.com/adafruit-circuit-playground-bluefruit/circuitpython-libraries)&nbsp;for the basics of downloading and transferring libraries to the board.

[Download the latest library bundle from circuitpython.org](https://circuitpython.org/libraries)
### Libraries for Quick Draw Duo

From the library bundle you downloaded in that guide page, transfer the following libraries onto the _two_ CPB boards'&nbsp; **/lib** &nbsp;directories:

- **adafruit\_ble**
- **adafruit\_bluefruit\_connect**
- **adafruit\_circuitplayground**
- **neopixel.mpy**

### Libraries for Reaction Timer

From the library bundle you downloaded in that guide page, transfer the following libraries onto the CPB (or CPX) board's&nbsp; **/lib** &nbsp;directories:

- **neopixel.mpy**

## Development Testing

During development, the **Quick Draw Duo** application was tested on CPBs using CircuitPython 5.0.0-beta.2 with libraries from the adafruit-circuitpython-bundle-5.x-mpy-20200107.zip bundle. It should work on subsequent versions, [the latest version is recommended](https://circuitpython.org/board/circuitplayground_bluefruit/).

The **Reaction Timer** code was tested on a CPX using CircuitPython 4.1.2 and on a CPB using CircuitPython 5.0.0-beta.2. The libraries were from the adafruit-circuitpython-bundle-4.x-mpy-20200107.zip and adafruit-circuitpython-bundle-5.x-mpy-20200107.zip bundles, respectively. It should work on subsequent versions, the latest version is recommended.

# Circuit Playground Bluefruit Quick Draw Duo

## Quick Draw Duo

![](https://cdn-learn.adafruit.com/assets/assets/000/086/853/medium800/circuitpython_sf-cpb-quick-draw-duo.jpg?1578851493 Quick Draw Duo played on two Circuit Playground Bluefruits with external audio at Sticky Fingers restaurant.)

## Installing Project Code

To use with CircuitPython, you need to first install a few libraries, into the lib folder on your **CIRCUITPY** drive. Then you need to update **code.py** with the example script.

Thankfully, we can do this in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **CPB\_Quick\_Draw\_Duo/quick\_draw\_duo/** and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to both of the&nbsp; **CIRCUITPY** drives.

Your **CIRCUITPY** drives should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/CPB_Quick_Draw_Duo_quick_draw_duo.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CPB_Quick_Draw_Duo/quick_draw_duo/code.py

Info: 

## Playing the Game

When the code starts on both boards the NeoPixels should indicate:

1. Eight brief blue flashes - measurement of round-trip time (rtt).
2. One longer blue flash - successful conclusion of rtt measurements.
3. White - start of round one, time to press the button!

The player's button is the left button, if the switch is set to the left, and the right button if the [switch is set to the right](https://learn.adafruit.com/circuitpython-made-easy-on-circuit-playground-express/slide-switch "Adafruit Learn: CircuitPython Made Easy on Circuit Playground Express and Bluefruit: Slide Switch"). The winner of each round is indicated by a green flash, which is on the _finger side_ for the winner. At the end of the ten rounds, the player's board will indicate their score.

- Green - win.
- No colour - opponent won.
- Red - misdraw.
- Faint red - opponent misdrew.
- Amber - a draw, same reaction time for both players, very rare!

If one board is reset during the game, then the other must also be reset to start the game again.

The maximum Bluetooth range between two CPB boards is approximately 5m (17ft). The range will decrease if obstacles are in the path.

## Example Video
The video below shows both boards being reset and the code starting with the blue flashing for synchronisation. A tense ten round game follows. As per the original game, green on the finger side indicates the winner and at the end the local summary gradually appears on the NeoPixels.

https://www.youtube.com/watch?v=LANz-SWKjv8

## Code Discussion

For this application the core game code is the same for both boards therefore it's reasonable for the implementation to be a single program which contains the communication code for both the Bluetooth LE central device and peripheral device. There are conditionals in the code based on a `master_device` variable for when the code needs to behave differently.

The first significant part of the communication code is creating the connection and then measuring the round-trip time, as per the design, to calculate the send time.

```python
ble = BLERadio()

(conn, uart) = connect()

ble_send_time = ping_for_rtt()
```

For each round of the game the following code runs.

```python
# Code from the main for loop with most comments removed
    gc.collect()
    random_pause()
    try:
        barrier(ble_send_time)
        pixels.fill(white)
        start_t = time.monotonic()
        while not player_button():
            pass
        finish_t = time.monotonic()

        pixels.fill(black)

        cp.play_file("PistolRicochet.wav")

        player_reaction_dur = finish_t - start_t
        opponent_reaction_dur = get_opponent_reactiontime(player_reaction_dur)

        # Show green for winner and red for any misdraws
        (win, misdraw, draw, colour) = show_winner(player_reaction_dur,
                                                   opponent_reaction_dur)
        my_results.append(colour)
        if misdraw:
            misdraw += 1
        elif draw:
            draws += 1
        elif win:
            wins += 1
        else:
            losses += 1

        # Output reaction times to serial console in Mu friendly format
        print("({:d}, {:d}, {:f}, {:f})".format(wins, misdraws,
                                                player_reaction_dur,
                                                opponent_reaction_dur))

        time.sleep(5)
    except Exception as err:  # pylint: disable=broad-except
        print("Caught exception", err)
        if conn is not None:
            conn.disconnect()
            conn = None
        uart = None

    pixels.fill(black)
```

The code is a unusual in requesting that the memory is tidied up before the player reacts to the NeoPixels - this is an attempt to prevent it from occurring during the reaction timing. Generally, scheduling a [garbage collection](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science) "Wikipedia: garbage collection (computer\_science)") (GC) is best left to the interpreter or runtime system. In this specific case, the program is designed to be _idle_ for a period of time and then needs to _accurately_ time a _small_ critical section of the code. These three factors are a reasonable justification for the programmer using a carefully placed `gc.collect()`. In some languages, like [Java](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/System.html#gc() "Java 13: Classes: System.gc()"), the programmer can only request a GC, it's not guaranteed to immediately occur.

The code between the `time.monotonic()` calls is kept to a minimum to try to ensure only the reaction time is measured. The player is reacting to the prior execution of `pixels.fill(white)`. All statements take a certain amount of time to execute and in the case of the `fill` [method](https://en.wikipedia.org/wiki/Method_(computer_programming) "Wikipedia: method (computer programming)") it's not documented precisely when the RGB LEDs change. In this case any small advantage the player gets in reaction time is the same for each player so it makes no competitive difference.

The `cp.play_file("PistolRicochet.wav")` is playing a shooting sound immediately after the player has pressed the button. This statement returns when the sound has completed playing which isn't ideal here but it's the only option from the convenient `cp` object. This is a new combined object from the [adafruit\_circuitplayground library](https://learn.adafruit.com/circuitpython-made-easy-on-circuit-playground-express/first-things-first#using-the-circuit-playground-library-2-11 "Adafruit Learn: CircuitPython Made Easy on Circuit Playground Express and Bluefruit: First Things First") that can be used interchangeably on the CPB and CPX boards.

The `get_opponent_reactiontime``()` function exchanges reaction times between the boards. The boards _trust_ the reaction time is a genuine, accurate measurement. There's clearly scope here for the remote code being altered to cheat!

The [boolean](https://en.wikipedia.org/wiki/Boolean_data_type "Wikipedia: boolean") variable `draw` is used to represent the unlikely outcome of both players pressing their button at the same time. This will become more likely if the boards have been powered on for several hours. Python and CircuitPython's `time.monotonic()` returns time as a float variable. This return value increases over time reducing the resolution available to represent the fractional part of the value. The effect is far more significant for the [30bit storage representation used by CircuitPython](https://github.com/adafruit/circuitpython/issues/342#issuecomment-337228427 "GitHub: adafruit/circuitpython: Avoid double precision floats in time.monotonic() computation to further increase flash space #342") (based on [single precision floating point](https://en.wikipedia.org/wiki/IEEE_754 "Wikipedia: IEEE 754")) in combination with the [epoch](https://en.wikipedia.org/wiki/Epoch_(computing) "Wikipedia: epoch (computing)") time of 0.0 at power-up. This lowers the precision and granularity of the millisecond portion as time passes making draws more likely.

# Circuit Playground Bluefruit Quick Draw Duo

## Reaction Timer

![](https://cdn-learn.adafruit.com/assets/assets/000/086/851/medium800/circuitpython_cpx-reaction-timer-with-mu-editor-videograb-crop43-1.jpg?1578758484 Reaction Timer running on a Circuit Playground Express with Mu editor plotter.)

Only one board is needed for the reaction timer. A Circuit Playground Bluefruit (CPB) or a Circuit Playground Express (CPX) can be used.

## Installing Project Code

To use with CircuitPython, you need to first install a few libraries, into the lib folder on your **CIRCUITPY** drive. Then you need to update **code.py** with the example script.

Thankfully, we can do this in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **CPB\_Quick\_Draw\_Duo/reaction/** and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to both of the&nbsp; **CIRCUITPY** drives.

Your **CIRCUITPY** drives should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/CPB_Quick_Draw_Duo_reaction.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CPB_Quick_Draw_Duo/reaction/code.py

## Reaction Timer with Mu Editor Video

The video below shows the reaction timer being used on a CPX board with the [Mu editor](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor "Adafruit Learn: Welcome to CircuitPython! Installing Mu Editor") in the background. The serial console output can be seen and the numerical output is plotted. The tests alternate between **visual** and **auditory** stimulus. Since these are output on separate lines they unfortunately get plotted together by Mu.

https://www.youtube.com/watch?v=s-jxE07qos0

## Code Discussion

The libraries are loaded in a way that allows the same code to be used on both the CPX or CPB. The exception handling mechanism is used to load one library and if that fails, presumably due to absence, then the other will be attempted. The example below also caters for later versions of the libraries where `RawSample` has migrated to `audiocore`.

```python
try:
    from audiocore import RawSample
except ImportError:
    from audioio import RawSample
```

The other conditional `import` is more interesting as it reveals the CPB's implementation of audio relies on [pulse width modulation (PWM)](https://en.wikipedia.org/wiki/Pulse-width_modulation "Wikipedia: pulse-width modulation (PWM)") , i.e. the audio output is digital unlike the CPX's analogue output from its [DAC](https://en.wikipedia.org/wiki/Digital-to-analog_converter "Wikipieda: digital-to-analog converter"). The `as` syntax is useful here to rename the library's class at import time, allowing the application code to refer to a single class, `AudioOut`.

```python
try:
    from audioio import AudioOut
except ImportError:
    from audiopwmio import PWMAudioOut as AudioOut
```

The CPB board uses an nRF52840 processor which includes a hardware random number generator accessible using the function `os.urandom()`. The random library uses this to seed its [pseudo-random number generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator "Wikipedia: pseudorandom number generator"). The CPX's ATSAMD21 processor does not have this feature which can cause the random library to generate the same sequence each time the board is powered up. The `os.urandom()` function is always present so it must be executed to look for the exception indicating the absence of the hardware feature.

The code below uses the same seeding technique as the original Quick Draw code for the CPX. The function `seed_with_noise()` reads some analogue values from pads and uses these to seed the PRNG. These values randomly fluctuate to some degree if the pads are not connected. This will prevent a user from intentionally or unintentionally learning the sequence of pause intervals in the program.

```python
try:
    os.urandom(4)
except NotImplementedError:
    seed_with_noise()
```

The `update_stats()` procedure has to be cautious when calculating the standard deviation. The first step is to calculate the variance and if there is only one observation then this calculation would divide by zero. Python handles this with a `ZeroDivisionError` exception which in this case would terminate the program! A simple `if` condition avoids this disaster.

```python
if test_num > 1:
    var_s = (sum([(x - stats[test_type]["mean"])**2
                 for x in stats[test_type]["values"]])
             / (test_num - 1))
else:
    var_s = 0.0
```

The reaction time only turns on one NeoPixel using `pixels[0] = red`. This is an attempt to make this operation as fast as possible to make the reaction timing more accurate.

# Circuit Playground Bluefruit Quick Draw Duo

## Reaction Times

![](https://cdn-learn.adafruit.com/assets/assets/000/086/572/medium800/circuitpython_Thorpe-FabreThorpe-Neuroscience-Seeking-categories-in-the-brain-monkey-visual-latency-estimate.jpg?1578059120 Estimated processing flow and minimum-average latencies in a monkey brain from Science Vol. 291 2001: Seeking Categories in the Brain. Simon J. Thorpe, Michele Fabre-Thorpe.)

The time to react can be termed a **response time** composed of:

1. a **reaction** component which will vary depending on many factors including the type of stimulus, the complexity of recognition and the complexity of decision making and
2. a **movement** component.

In this guide, the term **reaction time** is used for the total. The movement time is expected to be low for pressing a touch pad or a button.

The diagram above shows some of the processing in a _monkey_ brain with an estimation of the connectivity and **minimum-average** [latencies](https://en.wikipedia.org/wiki/Latency_(engineering) "Wikipedia: latency (engineering)") in milliseconds (ms). This diagram may be familiar from the [Stadia Streaming Tech: A Deep Dive (Google I/O'19)](https://www.youtube.com/watch?v=9Htdhz6Op1I&t=6m25s "YouTube: Google Developers: Stadia Streaming Tech: A Deep Dive (Google I/O'19)") which takes it and misrepresents it as human and changes the meaning and value of the times.

## Movement Time

A [prototype](https://en.wikipedia.org/wiki/Prototype "Wikipedia: prototype") of the [Reaction Timer](https://learn.adafruit.com/circuit-playground-bluefruit-quick-draw-duo/reaction-timer "Adafruit Learn: Circuit Playground Bluefruit Quick Draw Duo: Reaction Timer") used a touch pad for input. A high-speed video revealed that a typical finger movement took 20-30ms. This may be partly because a cautious user needs to carefully hover about 3-4mm to avoid getting too close and accidentally triggering the capacitive input.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/707/medium800thumb/circuitpython_finger-movement-time-example-1.jpg?1578448661 Frames 3-10 (234fps) showing finger movement time circa 29ms.)

The input was changed to the right button to allow the user to rest their finger on the button and reduce the travel distance.

## Measurement Platform

There are many reaction timing programs including ones that run in the browser. A typical, modern desktop computer is unfortunately not the best platform for measuring reaction times. Dan Luu has studied this and published a list with a great write-up on his [computer latency](https://danluu.com/input-lag/ "Dan Luu's Computer latency: 1977-2017 ") page. His tests measure the time from a keyboard press to the character appearing on screen. The [Apple IIe](https://en.wikipedia.org/wiki/Apple_IIe "Wikipedia: Apple IIe") from 1983 is the current winner! The page explains the elements of this latency from the keyboard to the operating system (o/s) to the screen. There is also another page dedicated to [keyboard latency](https://danluu.com/keyboard-latency/ "Dan Luu: keyboard latency") which discusses travel time and [debouncing](https://learn.adafruit.com/make-it-switch/debouncing "Adafruit Learn: Make It Switch: Debouncing").

For basic reaction timing, this explains why the cheapest microcontroller board with an LED is superior to an expensive computer with a keyboard, general purpose operating system and an LCD screen.

When CRT computer displays were superseded by TFT LCD panels the [refresh rate](https://en.wikipedia.org/wiki/Refresh_rate "Wikipedia: refresh rate") standardised from around 50-90Hz to 60Hz. This means that a modern desktop computer only displays a new image every 16.7ms and many tablets and smartphones have a similar limitation. Television models can vary in their refresh rates but often have added latency from additional image processing. This can sometimes be minimised with a ["game mode"](https://www.cnet.com/news/what-is-game-mode/ "CNET: What is game mode?") setting.

LCD displays also have a significant response time. The small PyGamer's screen can be seen below taking around 6 frames (26ms) to reach full brightness for a red letter **A**.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/682/medium800thumb/circuitpython_screen-latency-only-example1-640x480-dithered.jpg?1578356039 Frames (234fps) showing LCD response time on PyGamer 1.8 inch TFT LCD.)

Most computer displays would be slightly better than the PyGamer's screen but there is no standard way to measure and summarise the response time. Some caution is required when comparing manufacturers' published numbers. Blur Busters have some interesting techniques to [visually compare displays](https://www.blurbusters.com/linustechtips-uses-blur-busters-invention-to-take-photos-of-display-motion-blur/ "Blur Busters: LinusTechTips Uses Blur Busters Invention to Take Photos of Display Motion Blur").

Latency in all its forms is an important factor in games. particularly fast-paced, distributed, multi-player games. Linus Tech Tips conducted a set of [tests on 60, 144 and 240Hz refresh rate displays](https://www.youtube.com/watch?v=OX31kZbAXsA "YouTube: Linus Tech Tips: Does High FPS make you a better gamer? Ft. Shroud - FINAL ANSWER") to see how frame rate affects the gaming experience. This also included some simple reaction time tests using a mouse and reacting to a (visual) red/green banner. The summary of their results is shown below.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/683/medium800/circuitpython_linustechtips-displayfps-test2-reaction-times-dodgystddev-squashed43.png?1578356137 Linus Tech Tips PC-based simple reaction time test results exploring effect of display refresh rate.)

In the video there is mention of "run them until we see statistical convergence" - for a basic reaction time test, this sounds like [cherry picking](https://en.wikipedia.org/wiki/Cherry_picking "Wikipedia: cherry picking") of the test results. This explains the low but plausible mean ( **AVG** ) reaction times. The standard deviation ( **sd** ) numbers look less plausible based on calculating **sd** from the low values actually shown in the video ( **sd** =15.7ms) and from trying to reproduce low **sd** results for a visual stimulus.

On a similar theme, the reaction times for the finalist sprinters from the World Athletics Championships are shown below. These particular results are highly selected in two ways: the elite nature of the athletes; and their success in reaching the _final_. The graph starts at 0.1 seconds (100ms) because IAAF rules regard lower values as impossible, i.e. [false starts](https://en.wikipedia.org/wiki/False_start#Athletics_(track_and_field) "Wikipedia: false start"). These results cannot be directly compared to the previous visual results as athletics uses _sound_ to start the race (from equidistant speakers) and pressure from the starting blocks.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/688/medium800/circuitpython_reaction-times-elite-sprinters-finalists-tonnessen-haugen-shalfawi-fig3-43squashed.png?1578405893 Reaction Time Aspects of Elite Sprinters In Athletics World Championships: mean reaction time and 95% confidence interval of the finalists' reaction time development through competition (2003-2009). Copyright National Strength and Conditioning Association.)

Some results from the Reaction Timer in this guide are shown on the next page.

# Circuit Playground Bluefruit Quick Draw Duo

## Reaction Timer Results

![](https://cdn-learn.adafruit.com/assets/assets/000/086/938/medium800/circuitpython_M75-Rifling-Adafruit-Circuit-Playground-Bluefruit-00CPB.jpg?1579133370 Circuit Playground Bluefruit over M75 canon barrel, photograph by Petar Milosevic.)

## CPX Results

This is a set of graphs showing the results from various trials on a Circuit Playground Express. The graphs only show values between 0ms and 450ms. Any values less than 100ms are not used in the calculations for arithmetic **mean** and [sample standard deviation](https://www.khanacademy.org/math/ap-statistics/summarizing-quantitative-data-ap/more-standard-deviation/v/review-and-intuition-why-we-divide-by-n-1-for-the-unbiased-sample-variance "Khan Academy: Math: More on standard deviation: Review and intuition why we divide by n-1 for the unbiased sample variance") ( **sd** ). The graph on the right shows the same data in the form of a [violin plot](https://en.wikipedia.org/wiki/Violin_plot "Wikipedia: violin plot"). This shows the distribution and provides some indication if there are values above 450ms.

The test conditions _vary wildy -_ these are described in the title on each graph. The degree of practice by the test subject varies too. The later tests were conducted with a button rather than the original use of a touch pad. These three factors make comparisons between the test subjects hard.

![](https://cdn-learn.adafruit.com/assets/assets/000/086/940/medium800thumb/circuitpython_reactiontime-summaryall-20200116.jpg?1579179030 Graphical summary of results from Reaction Timer running on a Circuit Playground Express.)

See [results](https://github.com/kevinjwalters/mini-projects/tree/master/cpx-reaction-timer/results "Github: kevinjwalters/mini-projects master cpx-reaction-timer/results") for the individual graphs.

## Conclusions

- Reaction to an auditory stimulus is faster than a visual one - this is a common and well-known result. The variance may also be less but more data is needed to prove this.
- Minimum reaction times do not vary considerably with age but very young children may struggle with consistency.&nbsp;
- Auditory reaction time decreases with increase in background noise even when there are no sounds which mimic the test sound.
- The auditory reaction time test is much harder if another test is being performed at the same time even if the sound's pitch is different.
- The absence of a penalty for false reactions probably decreases reaction times but this was not studied explicitly.
- Distribution does not follow the [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution "Wikpedia: normal distribution") reducing the significance of the **mean**. It's generally asymmetric unless the subject can maintain a very high level of attention during test.
- The **movement time** appears to be less for a button compared to cautious use of a capacitive touch pad.
- Very tempting to cherry pick results and discard slow times leading to a form of [sampling bias](https://en.wikipedia.org/wiki/Sampling_bias "Wikipedia: sampling bias").

# Circuit Playground Bluefruit Quick Draw Duo

## Going Further

## Ideas for Areas to Explore

### Quick Draw Duo

- Add some winning and losing sounds.
- Use the accelerometer to change the game to one with a physical draw.
- Find some other uses for a pair of synchronised CPB, e.g.&nbsp; light shows, stereo/spatial audio playback.
- Technical challenge 1: increase the [robustness of the communication](https://forums.adafruit.com/viewtopic.php?f=60&t=160711 "Adafruit Forums: Robust Bluetooth LE communication between CPB boards"), e.g. make it recover from transient connectivity issues; match request and response with a suitable identifier.
- Technical challenge 2: understand and set the connection interval for Blutetooth LE GATT transactions and factor this into the design of the board syncronisation process.

### Reaction Timer

- Add a cheat detector to the reaction timer to highlight impossible times and early presses.
- Use the NeoPixels to show the reaction time graphically.
- Increase the complexity of the visual (e.g. different colours, odd vs even) and auditory (e.g. different pitches) stimuli to investigate the additional delays from discrimination.
- Investigate tactile reaction time with some sort of actuator controlled by the CPX/CPB board.
- Examine any effect of using peripheral vision and lower brightness settings on reaction time.

### Both

- Add an announcement of each time or the fastest time using sound samples for each digit.
- Independently verify the reaction timing - many smartphones offer high fps video recording in the form of a slow motion mode.

## Related Projects

- [Circuit Playground Quick Draw](https://learn.adafruit.com/circuit-playground-quick-draw "Adafruit Learn: Circuit Playground Quick Draw") - the original project that this one is based on.
- [Color Remote with Circuit Playground Bluefruit](https://learn.adafruit.com/color-remote-with-circuit-playground-bluefruit "Adafruit Learn: Color Remote with Circuit Playground Bluefruit") and [Circuit Playground Bluefruit NeoPixel Animation and Color Remote Control](https://learn.adafruit.com/circuit-playground-bluefruit-neopixel-animation-and-color-remote-control "Adafruit Learn: Circuit Playground Bluefruit NeoPixel Animation and Color Remote Control")&nbsp;- two other projects showing Bluetooth communication between two CPB boards.
- [De Montfort University Leicester: CTEC1802 Arduino lab work: reaction timers.](http://www.cse.dmu.ac.uk/~sexton/CTEC1802/Arduino%20labs.html "De Montfort University Leicester: CTEC1802 Arduino lab work: reaction timers.")
- [BBC Bitesize: Coordination and control - The nervous system: Investigating human reaction times](https://www.bbc.co.uk/bitesize/guides/zpkhcj6/revision/3 "BBC Bitesize: Coordination and control - The nervous system: Investigating human reaction times") - this is the remarkably simple but effective "ruler drop test".
- [Reaction!](https://makecode.adafruit.com/projects/reaction "MakeCode for Adafruit CPX: Games: Reaction!") game in MakeCode for CPX.
- [Reaction Time](https://makecode.microbit.org/projects/reaction-time "MakeCode for micro:bit: Games: Reaction Time") game in MakeCode for BBC micro:bit.

## Further Reading

- [Introduction to Bluetooth Low Energy](https://learn.adafruit.com/introduction-to-bluetooth-low-energy/introduction "Adafruit Learn: Introduction to Bluetooth Low Energy")
- [MagicLight Bulb Color Mixer with Circuit Playground Bluefruit: Understanding BLE](https://learn.adafruit.com/magiclight-bulb-mixer/understanding-ble-characteristics "Adafruit Learn: MagicLight Bulb Color Mixer with Circuit Playground Bluefruit: Understanding BLE")
- [All the Internet of Things - Epsiode One: Bluetooth & BTLE](https://learn.adafruit.com/alltheiot-transports/bluetooth-btle "Adafruit: All the Internet of Things - Epsiode One: Bluetooth & BTLE")
- [Nordic Semiconductor: Wireless timer synchronization among nRF5 devices](https://devzone.nordicsemi.com/nordic/short-range-guides/b/bluetooth-low-energy/posts/wireless-timer-synchronization-among-nrf5-devices "Nordic Semiconductor: Wireless timer synchronization among nRF5 devices") - an interesting, very low-level approach in C for synchonising devices accurately.
- Timothy Jordan: Characteristics of Visual and Proprioceptive Response Times in the Learning of a Motor Skill. 1972. - discussed on [ResearchGate: Questions: Do you react faster to a haptic stimulus than to a visual one?](https://www.researchgate.net/post/Do_you_react_faster_to_a_haptic_stimulus_than_to_a_visual_one "ResearchGate: Questions: Do you react faster to a haptic stimulus than to a visual one?")
- [Simon Thorpe, Michele Fabre-Thorpe: Seeking Categories in the Brain. 2001.](http://cerco.ups-tlse.fr/pdf0609/thorpe_sj_01_260.pdf "Science Vol 291. Simon Thorpe, Michele Fabre-Thorpe. Seeking Categories in the Brain. 2001.")
- [Espen Tonnessen, Thomas Haugen, Shaher A.I. Shalfawi: Reaction Time Aspects of Elite Sprinters In Athletics World Championships. 2013.](https://www.researchgate.net/publication/228081521_Reaction_Time_Aspects_of_Elite_Sprinters_In_Athletics_World_Championships "Espen Tonnessen, Thomas Haugen, Shaher A.I. Shalfawi. Reaction Time Aspects of Elite Sprinters In Athletics World Championships. 2013. ")

&nbsp;


## Guide Products

### Circuit Playground Bluefruit - Bluetooth® Low Energy

[Circuit Playground Bluefruit - Bluetooth® Low Energy](https://www.adafruit.com/product/4333)
 **Circuit Playground Bluefruit** is our third board in the Circuit Playground series, another step towards a perfect introduction to electronics and programming. We've taken the popular Circuit Playground Express and made it even better! Now the main chip is an nRF52840...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4333)
[Related Guides to the Product](https://learn.adafruit.com/products/4333/guides)
### 3 x AAA Battery Holder with On/Off Switch and 2-Pin JST

[3 x AAA Battery Holder with On/Off Switch and 2-Pin JST](https://www.adafruit.com/product/727)
This battery holder connects 3 AAA batteries together in series for powering all kinds of projects. We spec'd these out because the box is slim, and 3 AAA's add up to about 3.3-4.5V, a very similar range to Lithium Ion/polymer (Li-Ion) batteries and have an on-off switch. That makes...

Out of Stock
[Buy Now](https://www.adafruit.com/product/727)
[Related Guides to the Product](https://learn.adafruit.com/products/727/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)

## Related Guides

- [Adafruit Circuit Playground Bluefruit](https://learn.adafruit.com/adafruit-circuit-playground-bluefruit.md)
- [ABC Soundboards with NeoTrellis](https://learn.adafruit.com/abc-soundboards-with-neotrellis.md)
- [Halloween Countdown Display Matrix](https://learn.adafruit.com/halloween-countdown-display-matrix.md)
- [Make It Pulse](https://learn.adafruit.com/make-it-pulse.md)
- [Chilled Drinkibot](https://learn.adafruit.com/chilled-drinkibot.md)
- [Clue Coffee Scale](https://learn.adafruit.com/clue-coffee-scale.md)
- [Glowing Bottle Castle and Capacitive Touch Piano](https://learn.adafruit.com/glowing-bottle-castle-and-capacitive-touch-piano.md)
- [Makecode para la Circuit Playground Express](https://learn.adafruit.com/makecode-es.md)
- [NeoPixel Fairy Crown](https://learn.adafruit.com/neopixel-fairy-crown.md)
- [Crickit Dancing Marionette Kit](https://learn.adafruit.com/universal-marionette-with-crickit.md)
- [CircuitPython BLE Libraries on Any Computer](https://learn.adafruit.com/circuitpython-ble-libraries-on-any-computer.md)
- [CLUE Sensor Plotter in CircuitPython](https://learn.adafruit.com/clue-sensor-plotter-circuitpython.md)
- [Watchmen's Sister Night NeoPixel Goggles](https://learn.adafruit.com/watchmen-sister-night-circuitpython-neopixel-goggles.md)
- [Custom Scrolling Quote Board Matrix Display](https://learn.adafruit.com/aio-quote-board-matrix-display.md)
- [Unicorn Christmas Stocking with Rainbow Lights & Sound](https://learn.adafruit.com/unicorn-christmas-stocking-with-lights-sound.md)
- [Wirelessly Code your Bluetooth Device with CircuitPython](https://learn.adafruit.com/wirelessly-code-your-bluetooth-device-with-circuitpython.md)
