PyBadge Etch-A-Sketch

A fun software project in CircuitPython for the Adafruit PyBadge and compatible boards that uses (almost) all of the builtin board hardware

Public Chat
Similar projects worth following
Digital Etch-A-Sketch in CircuitPython. Includes some useful libraries for real-time button input, buzzer tone playing, and device bitmap drawing

I was looking for a simple project for my Adafruit PyBadge, and pretty quickly realized that a directional pad plus built-in accelerometer would be perfect for a digital Etch-A-Sketch! This could probably be done easily with Microsoft’s MakeCode Arcade but I wanted to try out CircuitPython and honestly it would probably do some good to relearn Python. The idea itself is simple, but I wanted to play around with all of the board’s capabilities including the piezo-electric buzzer speaker, the lis3dh accelerometer, and the front facing neopixel LEDs. The only hardware I couldn’t figure out how to use for this project was the light sensor, but I’m sure something will come to mind for version 2.0 of this project.

If you want to skip this guide and just play with the project, just download all the python files in this repo and copy them (including the lib folder) to the device. Instructions for use are at the start of the next section.

Note: Everything in this project should work out of the box with the PyGamer (and with some small modifications, most CircuitPython microcontrollers) as well, but I don’t have one to test with so please let me know if it doesn’t!

This is a purely Python project, so no additional tools besides a PyBadge or other Adafruit CircuitPython device are required. A battery for the board would be the only thing I recommend, but not required as long as the device is plugged into a usb port.


The project acts like a normal Etch-A-Sketch. The cursor is displayed as a blinking square, which starts off in the middle of the screen. Use the directional pad to control it. The cursor has a few different colors, the last of which is black – this can act as an eraser. The front LEDs will match the current cursor color. The current color can be rotated using the A button, and the size can be rotated through a few options using the B button.

Shaking the device will clear the screen just like the real toy, but to prevent accidental erasing of your masterpiece, there is a countdown. The device must detect shaking for about 2 seconds. To help visualize this, the five LEDs will count down and a tone will play for each detected shake. As a backup, the SELECT button can also be held for 2 seconds to simulate a shake. Currently there is no way to save the images as the flash memory on the PyBadge is not writeable from the device. ☹

  • 1

    A CircuitPython bootloader must be installed on the device. This is very easy to do. This has already been covered by many guides in the past, but I would recommend this one for starters:

    Next, a few libraries need to be copied to the device. These are compiled MicroPython files made by Adafruit/CircuitPython to help with interpreting the signals from the accelerometer. The following items will need to be copied to the device to get the accelerometer to work, which are in this zip folder:

    Download the zip file, extract it, and copy over the lib/adafruit_bus_device/ (the entire folder) and the file lib/adafruit_lis3dh.mpy into the lib folder on the device. To copy any files onto the device with CircuitPython installed, you should be able to simply drag and drop the file or folder onto the drive that shows up when you plug in the device to your computer. Once any file transfer is complete the device will restart automatically.

  • 2

    This is the class that generates tones. Tones can have a frequency in Hertz or can be specified in pitch/octave notation. For example, the call play_note("C4", 0.5) will play middle C for half a second. Alternatively, play_note("R", 1.0) will play nothing (rest) for one second. Tones are generated using a sine wave, and the CircuitPython AudioIO class is used to play the raw wave. Sequencing is done using a queue of notes and their timing, and every time the tick function is called ( calls this in its main loop) the queue is popped. Note timing uses CircuitPython’s built-in time.monotonic() which returns an ever increasing count of seconds. Timing is done using the difference in the current call to that function and a previous check. Due to the nature of the device clock, note timing is not very accurate, but this isn’t much of a problem for a small game. This class is initialized with the audioio.AudioOut object in the constructor, to know where to send the raw signal.

  • 3

    This class handles all CircuitPython DisplayIO related screen drawing using bitmaps. For more information on screen drawing and bitmaps, this is a great resource. In this implementation, there are two bitmaps which are stored a single group, which is sent to the display. The main bitmap, display_bitmap handles the drawn image. Every time the cursor is moved, it draws a square of the current cursor size in the current cursor position, then changes the tuple the current position to reflect the direction moved.

    The second bitmap, cursor_bitmap is more simple. It is the size of the largest possible cursor size, and on display_cursor it draws a square of the current cursor size either in the current color, or the “off” color – this is set to the index of black by This function is called with alternating values for the display parameter in the main program loop to make the blink. The rest of the cursor bitmap is filled with the index for an “invisible” color – this is an index outside of the bitmap palette that looks invisible and allows the display bitmap underneath to be visible even if the cursor bitmap is overlapping.

    There is a custom value for offIdx passed to this constructor which should be the index of black in the rgbColors list. This is used for a special case where if the current cursor color is black, the cursor should flash white (or whatever is the first color in the colors list). This color is also used as the reset color when the bitmap should be cleared, which is triggered by shaking the device. If you would like to use any other color as the background, this would be the parameter to change. The other parameters passed to the class constructor are board_display, the pin to send DisplayIO messages to – this should come from board.DISPLAY, and rgb_colors, a list of RGB colors. This should be a list of lists in the form of [[R0, G0, B0], [R1,G1,B1]… ]. Each of R, G, B represents a value of red, green, and blue between 0-255.

    Some example colors:

    White: [255, 255, 255]
    Red: [255, 0, 0]
    Yellow: [255, 180, 0]
    Black: [0, 0, 0] 

    For more colors, Google has a color picker that can be found by searching for "color picker"

View all 6 instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates