Getting Started
Adafruit Playground is a wonderful and safe place to share your interests with Adafruit's vibrant community of makers and doers. Have a cool project you are working on? Have a bit of code that you think others will find useful? Want to show off your electronics workbench? You have come to the right place.
The goal of Adafruit Playground is to make it as simple as possible to share your work. On the Adafruit Playground users can create Notes. A note is a single-page space where you can document your topic using Adafruit's easy-to-use editor. Notes are like Guides on the Adafruit Learning System but guides are high-fidelity content curated and maintained by Adafuit. Notes are whatever you want them to be. Have fun and be kind.
Click here to learn more about Adafruit Playground and how to get started.
-
Building a Sci-Fi Movie Prop Overview
A local production company is working on filming the first of a three-part sci-fi movie and needed a piece of scientific equipment for a laboratory scene. The executive producer/director found an obsolete flow cytometer analyzer in a government surplus sale, winning the bid for US$12. The device had the potential to look like a working DNA synthesizer with the addition of lighting and a bit of animation.
In its day, the analyzer was a high-quality device that was robustly built to provide exceptional mechanical stability for its sensitive optical components. It was therefore quite heavy in spite of its size, requiring at least two persons to lift and position, which would increase the challenge to modify for use in the film. It was not a typical theatrical prop made from foam and balsa wood, for certain.
I was tasked with installing color lighting to enhance the device’s operational appearance for its brief appearance on-screen. To achieve this, I devised a plan to incorporate several NeoPixel LED strips, which would be controlled by a CircuitPython-based microcontroller, such as the Adafruit M4 Express Feather. The multi-colored NeoPixel LEDs could be strategically positioned both within and outside the device, thereby providing ambient illumination and symbolizing various functions, including sample loading and the incubation process.
Given that the initial device employed industrial-grade servos (specifically, three IMS MDI-17 Drive Plus Motion Control motors) for sample positioning and operating the sample fluid “sipper” needle, there was a preliminary aspiration to incorporate robotic physical movements beyond the lighting sequence. However, this objective was deferred due to the imminent project deadline, so a short puppetry cable would likely be attached to the sample positioning cam to animate movement of the test tube rack.
-
The Doctor will see you know - a chatbot nobody needs I remember being impressed when I first saw ELIZA decades ago, but also thought ... I knew people who "conversed" with less attention to what you were saying and that would be easier to program. So I did a few BASIC programs with a large set of things to say that it would put out without reference to what was typed in.
So, of course, I had to do it in CircuitPython eventually....
This is a VERY simple chatbot - originally for the neotrinkey and now in the FruitJam
Minimal "chat" with NO parsing. The doctor chooses between Nulls, Questions, Affirmations, Comments, and "Wisdom" (Asimov and Tolkien quotes) to converse with the subject. Silly, but shows how little it takes to create the illusion of sentience. You can edit the pools to your own liking.
Note: DrDroid.py will work on the neotrinkey as well, though you'll need an IDE like Mu or Thonny to run it. And delete the last line "reload()"
Create a directory in your Fruit Jam called apps/DrDroid and copy these files into it.
_ _ __| | ___ ___| |_ ___ _ __ / _` |/ _ \ / __| __/ _ \| '__| | (_| | (_) | (__| || (_) | | \__,_|\___/ \___|\__\___/|_| _ _ _ __| |_ __ ___ (_) __| | / _` | '__/ _ \| |/ _` | | (_| | | | (_) | | (_| | \__,_|_| \___/|_|\__,_| Hello, what is your name? >> mrklingon Thanks for coming by, mrklingon! This is a nice computer - I like it here. >> good to hear Have you heard not all those who wander are lost. >> Indeed What will tomorrow bring? >> I wish I knew You are good at typing! >> Thanks! Have you heard short cuts make long delays.. >> sounds familiar.... I'm getting a little tired. >> okay I'm happy you came by today. >> quit _ _ __| | ___ ___| |_ ___ _ __ / _` |/ _ \ / __| __/ _ \| '__| | (_| | (_) | (__| || (_) | | \__,_|\___/ \___|\__\___/|_| _ _ _ __| |_ __ ___ (_) __| | / _` | '__/ _ \| |/ _` | | (_| | | | (_) | | (_| | \__,_|_| \___/|_|\__,_| -
Pyboom - A game for the Fruit Jam Py-Boom
Py-Boom is a fast-paced, 8-bit-style arcade game written in CircuitPython for the Adafruit Fruit Jam and other compatible display boards.
This game is a modern take on a classic "catcher" formula, featuring both a single-player mode against an AI and a competitive two-player versus mode.
Game Modes
At the title screen, you can select your game mode:
-
1-Player Mode: You control the Bucket (P1) at the bottom of the screen. An AI-controlled Bomber moves at the top, dropping bombs at an increasing rate. Your goal is to catch as many bombs as possible to survive the level.
-
2-Player Mode: Player 1 controls the Bucket, and Player 2 controls the Bomber. P1's goal is to survive, while P2's goal is to drop bombs strategically to make P1 miss.
How to Play
P1 (Bucket) - The Catcher
-
Goal: Catch every bomb that is dropped. If you miss a bomb, you lose one of your buckets (lives). If you lose all three, the game is over.
-
Winning: If you (P1) successfully catch all bombs in a level (e.g., 10 bombs in Level 1), you win the round and advance to the next, more difficult level.
P2 (Bomber) - The Attacker
-
Goal: Make P1 miss! You have a limited number of bombs per level. Use your movement and timing to drop bombs where P1 isn't.
-
Winning: If you (P2) successfully make P1 lose all three of their buckets, you win the game!
Controls
Action
Player 1 (Bucket)
Player 2 (Bomber)
Move Left
AkeyLeft ArrowkeyMove Right
DkeyRight ArrowkeyDrop Bomb
N/A
Down ArrowkeyStart / Ready
SpacebarEnterkeyOther Controls
-
Select Mode: On the title screen, press the
1or2key. -
Restart Game: On the "Game Over" screen, press the
Rkey to return to the title screen.
Required Files
To run this game, you will need the following files on your CircuitPython device:
-
code.py: The main game code. -
The Fruit Jam OS library package.
-
pyboom.bmp: The title screen logo. -
bomb_icon.bmp: The bomb sprite icon (used in development).
Download at: Pyboom Git Hub
Background
This project was started on Microsoft Make Code for my Pygamer and was called Prison Break. With the introduction of the Fruit Jam I wanted to port this over to Circuit Python. The graphics in Make Code (MC) are saved in a TypeScript file so I had to copy the codes for the sprites over to my Circuit Python. I used the AI tools that are part of Visual Studio Code (VS) the develop functions to map the sprites maps into bitmaps and tile grids. I continued to use the AI tools to help convert the Python code from MC. I mostly used Gemini as I have 3 months of premium from purchasing my phone. Though there were times where Gemini would get stuck on fixing issues it was making so I would switch to the free tokens in VS and use Claude or Chat-GPT. I ran out of free tokens in VS and moved on to Gemini for versions 2 and 3 of the game. I am in the process of uploading my prompts that I still have access to (I lost my VS conversations :( ) and hope to have them done in the next week. I also hope to get controllers setup and maybe make paddle controllers in the future.
I found this a fun project to learn Circuit Python and coding with AI. I'm still learning the concepts of using classes and learned a lot while looking at the errors the AI was coming up with.
-
-
ASTRO - SF Starmaps for the Neotrinkey simple SF starmap creator - github repository here
I wrote this program for the neotrinkey - but will be merging it into "Traveler" a simple SF game for the Fruit Jam based on my earlier neotrinkey progam "Adventure-Engine".
Files:
- astro.py (copy to code.py}
- wise.py
- prt.py (set REPL=True for printing in REPL, False to print via HID)
- ncount.py
When you touch pad #1, produces output like:
Ahghie:3, 1 Mieas:7, 1 Syaei:1, 7 Syuuas:1, 4 Giafnk:5, 4 Zoid:7, 6 .......... ...*...*.. .......... .......... .*...*.... .......... .......*.. .*........ .......... ..........A list of stars and their x,y coordinates in a 10x10 grid, then a map of the stars.
When you touch pad #2, A random star will be picked as your "location" and the list of stars will be displayed AND the distance to each one from your current location:
location = Syuuas Ahghie:3, 1: 3.60555 Mieas:7, 1: 6.7082 Syaei:1, 7: 3.0 Syuuas:1, 4: 0.0 Giafnk:5, 4: 4.0 Zoid:7, 6: 6.32455 location = Zoid Ahghie:3, 1: 6.40312 Mieas:7, 1: 5.0 Syaei:1, 7: 6.08276 Syuuas:1, 4: 6.32455 Giafnk:5, 4: 2.82843 Zoid:7, 6: 0.0 -
Teensy 4.1 Spacemouse to Midi Bridge Here's some Arduino code for the Teensy 4.1 (Adafruit Product ID: 4622) that lets my Spacemouse Wireless from 3Dconnexion appear as a standard USB midi controller to my computer, and presumably any other USB midi hosting device. It provides six high-resolution CC pairs from the knob motion, and two on/off CC's for the two buttons.
The Teensy needs a jumper between the board Vin and the USB Host 5v pins to power the Spacemouse Dongle (unless a powered USB hub is inserted between them).
The teensy, of course, also needs to be fitted with a USB Host socket connected to the USB host pins on the board to to recieve the 3DConnexion dongle or USB wire.
The code was provided by ChatGPT after some relentless back and forth. I'm pretty clueless myself about it. But for a souless device planning to take over the world and annihilate us all, The Chatster has so far proved to be very patient and accomodating. Beyond the obviously tunable lines, the LLM should be able to adapt it more to your liking, even if your skills are as meager as my own.
-
Talking to Aliens with my Fruit Jam I have been writing, and rewriting a very simple "translator" for around 30 years. It started many years ago after getting my first copy of the Klingon Dictionary and I started experimenting with very simple programs. Not true machine translation, I just made what I called a "Universal Translator Assistant" that relexifies a language (like English) into the alien words it has matched to them. Since starting, It has kind of become my personal "hello world" program and I've written versions of this program in C, Perl, Python, BASIC, VisualBasic, CBMBasic, Javascript, Java and Scratch. And now CircuitPython
As noted, it's linguistically more than a little suspect - but it's been a fun project all the same. The languages here are Klingon, Vulcan, Mando'a and Romulan.
The github repository is here
Language sources:
- Mando'a vocab originated in Karen Traviss's Star Wars novels. For more info, see https://mandoa.org/
- tlhIingan (Klingon) vocab is a custom one I created - more official Klingon from: https://kli.org and https://hol.kag.org
- Vulcan vocab from: https://tinyurl.com/VulcanArchive - archive.org of Marketa Zvelbil's original Vulcan work.
- Romulan is from Diane Duane's Rihannsu novels, but I generated more words for use here. See also http://www.rihannsu.org/arch/www.rihan.org/drupal/lessons/introduction.html
The files should be put in apps/UTA, with the .lng files all put in a subdirectory langs.
Enter text and UTA will match English words with the Alien languages. This is not true translation, but provides vocabulary you can use to translate into the target language. It will also match Alien words back to English. Because more than one English word may map to an Alien word, the back translation may look odd.
_ _ _____ _ | | | |_ _|/ \ | | | | | | / _ \ | |_| | | |/ ___ \ \___/ |_/_/ \_\ Universal _... Translator ,' `. Assistant / \ | -._ | \ \ `._ \ \ `... `-..-`. `-._ `. _,-- `. -' '. | '.| ' loading tlhingan text: hello what is your name nuqneH nuq ghaH lIj pong text: *lang vulcan loading vulcan text: live long and prosper tich tor ang tesmur text: *help _ _ _____ _ | | | |_ _|/ \ | | | | | | / _ \ | |_| | | |/ ___ \ \___/ |_/_/ \_\ Universal Translator Assistant Help commands: *help - this file *pItlh - quit program *lang [filename] - loads langs/filename.lng Languages: vulcan, tlhingan, mandoa, romulan text: tich tor ang tesmur live long and prosper text: *lang mandoa loading mandoa text: I love you ni riduurok gar text: ni riduurok gar me love your text:You can create your own language files as NAME.lng in the langs/ directory. The format should be:
"English word", "Alien word" "English word", "Alien word" "English word", "Alien word" "English word", "Alien word" ...You would load that language with the command "*lang NAME"
-
Troubleshooting CircuitPython Programs - Beyond the Print Statement The print() function is your first debugging tool
When creating a CircuitPython program a great way to follow program flow and to examine parameters and values is to use a print() statement sending the information to the REPL. This is simple, tried and true, and you can comment them out when no longer needed to turn them off. Many times this is the way to go.
Sometimes, however, you might have a lot of print statements and multiple function calls and all of the information flowing into the REPL becomes a bit hard to follow.
Making print() output easier to read
At this point one strategy to make the print outputs easier to follow is to add divider lines, line feeds, special characters, etc. For example:
Get creative and use different characters for divider lines (i.e. =, +, *). You can also combine characters such as:
-
Displaying Images on Pico Mac Emulator for Fruit Jam With my recent retro mac classic inspired enclosure project for the Fruit Jam, I got the crazy idea to display my own images on the mac emulator. Sure, you can run MacPaint, but wouldn't it be cool to display custom graphics like the Fruit Jam logo? Well, it turns out there's a bit of a process to get images to display on System 7.5, specifically on 68K architecture (which is what the pico-mac emulator is based on).
Image File Formats
JPEG, PNG and GIF images are the norm with modem day computers. But, in 1984, these image formats were not yet a thing. I thought, surely displaying a bitmap image on Mac OS System 7 shouldn't be too hard, right?
After searching google, easiest approach seemed to be: Use the Graphic Converter mac app to convert a JPEG into a MacPaint document. This however, didn't quite seem to work. When I import the converted macpaint image file into Mini vMac, it wouldn't open in MacPaint. Weird, Ok, lets try a native image file format. Again, that's not really a thing. Enter the world of the .PICT (QuickDraw picture).
-
Using the Fruit Jam Intel 286 Emulator The new 286 PC Emulator for Fruit Jam provides many interesting possibilities and a lot of fun.
This Playground Note will provide information that may not be evident or may otherwise help others.
Initial Impressions
Having wide emulation through the 80286 is helpful, through it wasn't until the '386 that memory handling got better.
I was really excited about all the display modes. But trying to get to them in DOS or QBASIC was impossible. Maybe they'll work in games but I'd like a high resolution DOS screen too.
-
Fun with Fruit Jam Neopixels The adafruit_fruitjam library makes controlling the five neopixels on the board pretty easy...
Start with the basics
We begin by initializing the library and setting things up:
[note these are code snippets only - not a complete project]
From here you can use the standard neopixel "fill" and "show" to control the neopixels altogether. To refer to the neopixel object you reference them by 'jam.neopixels' (note the s on the end) followed by the command. For example, a classic red blink would simply be:
-
TPL5111 - Low Power projects (WipperSnapper, Arduino, CircuitPython, etc) Overview
The TPL5110 (with driven output line) or the TPL5111 (with toggling enable line) allow some really simple low-power projects. Use the zero to sever and supply power, or the one to control enable pins (for LDO/MCU).
Just adjust the potentiometer to tweak the turn-on time, and then with the TPL5111 you send a low high transition to the Done pin to go to sleep. The Enable pin goes low and MCU sleeps until the next cycle.
All of that means you can easily create a no-code low-power project, just by hooking up the TPL5111 to a WipperSnapper compatible board, and combine that with an E-ink display for the ultimate low power setup.
The board wakes up, connects to WiFi and Adafruit IO, get's the latest messages (E-Ink Display) and sends some sensor data. Two small Actions on Adafruit IO switch the Done pin to a high level, and then ten seconds later back to low. A third action updates the screen message with time + weather every 10mins.
Add a third action to update the display or whatever is appropriate (like acting on some sensor data).
Use
\nto force a line break when working with Displays on WipperSnapper
-
Fizzgig I built Fizzgig and would like to share a few notes on my build (made in October 2025). I hope that this is helpful to anyone attempting to build it as well. I had a lot of fun building it!
Speaker
I tried using an external speaker connected with the headphone jack cable. It turned out that this speaker is not deactivated when no sound is played, and it produces very loud white noise (this happens with any speaker connected via this connection). Thankfully, the Adafruit support team reproduced this, and it seems that this behaviour cannot be resolved. So I went along with the oval mini speaker that is connected to the board via PicoBlade. To improve its sound a little, I attached the speaker to a Tic Tac box as a resonator, which worked quite well.
Servo / Jaw
I used lots of hot glue to attach all the hair, so the jaw became rather heavy. I attached some cardboard to the jaw to stabilise it, but this was not enough to support the weight. As a result, the jaw would not close properly. To resolve this, I stabilised the jaw with ice cream sticks. I also extended the servo horn with a piece of carbon tube. I could securely fix this to the servo horn using heat shrink tube with hot glue. My extended servo horn ends in a grommet made out of another piece of carbon tube with a larger diameter that I glued to the jaw. This makes the placement of the servo a lot easier and the connection more stable.
I thought about also adding a spring taken out of a retractable pen to the servo horn extension to help the servo along. In my build, this was not possible to integrate, but there may be setups where adding a spring is possible and makes sense.
Since I could not use a spring, I added a counterweight in the part where the servo horn ends. I glued in a screw and added two nuts for added weight. This helps the servo along.
Code
I used the UF2 file provided in the instruction. I would have liked to change the code to reduce the jaw opening angle (this would have enabled me to use a spring). Adafruit support pointed me to the code, and I was able to identify the place where the servo angles are defined. In my current Arduino IDE, the code would compile successfully, and the IDE even told me that the code had been successfully transferred to the board. However, CIRCUITPY was still visible as a drive after this supposedly successful transfer, and I had to re-upload the original UF2 file to go back to that version. I re-tried with several different methods, but I was not able to make the compiled code transfer to the board successfully. This may be due to my inability, since I am not very experienced using microcontrollers at all. If you are planning to alter the code, do check if it works for you before making your build.
Wig
It makes a lot of sense to buy a wig with really long hair. The instructions advise to cut off the hair along the longest section. I did this, but it would have made more sense to plan ahead to first check where the nose will go. Most hair under the nose will not be needed, as that's where the mouth goes. Depending what your particular wig looks like, it may be better to keep the long hair in the back and trim under the nose.
Also, the hair will be all over the place when you're done.
I styled my Fizzgig's hair with transparent lacquer from a spray can. This was necessary especially around the eyes and the nose.
Frame
I built a wooden frame for my Fizzgig. I had originally used a cardboard box, but for more stability I replaced it with a wooden frame that basically had the same dimensions. My frame is about 31 x 18 x 10 cm. The required dimensions very much depend on the size of the wig and the length of the hair.
-
USB, XT, PS2 keycode cross reference in CSV Recently for the Fruitjam-286 emulator, I needed to create a good mapping from USB HID codes to XT codes.
There are many resources online including Keyboard Scancodes (Andries Brouwer) which is a nice HTML table.
I converted the table into a csv file, and then used a bespoke Python program to convert it to a format for the emulator.
First, my program opens the csv file and checks its structure
-
2025-1017 Speedy-Vi Note I created this Note so I can link a section of CircuitPython Essentials to it. Unfortunately, when I click "Link Note" it still says "You do not have any notes available to link to this guide. To create a new note please visit the Adafruit Playground and create a note." I just created this note so I could link the section of CircuitPython Essentials to it. I must be doing something wrong...
-
CircuitPython Functions to Pretty Up Strings Here's a short one...
Sometimes I find myself wanting to pretty up a string. For example, a value might come in all in lower case letters and I want to capitalize the first letter or maybe go for capitalizing all first letters. Another use case is using variable names (conventionally all lower case) for captions.
- 'this is my string' ===> 'This is my string'
- 'top values' ===> 'Top Values'
Python has title() and capitalize() functions but these are not implemented in CircuitPython.
Also, strings may be in camel case that I want to fix - the Weather Powerup on AdafruitIO sends text data back this way:
- 'mostlyClear' ===> 'Mostly Clear'
When there is a limited set of data I've used if/elif/else statements or used look-up dictionaries, but in some cases the inputs may not be known. Also, who wants to write all of the repetitive code!
Since CircuitPython does include upper() and lower() functions we can build functions to do this. So with the help of CoPilot I drafted and now include these three functions in my code when I am doing anything with strings:
In these sample functions I only apply to strings that are greater than three characters long as generally when I have short strings, I want them to keep the case (such as 'MPH'). But you can change this if you want it to make the change to all input strings. In the camel_to_title() function I also replace underscores with spaces, primarily for when I use variable names as captions.
Hope you find this useful - and be sure to share any custom functions you can't live without.