A four-shade greyscale dither camera.
Built with the Pimoroni Badger 2350 and a PTC06 TTL serial JPEG camera connected to the Qw/ST port, powered by Pimoroni's Badgeware API.
📖 Read the story behind the build on my blog
- Photos: Camera module captures at 320x240, downsampled into the panel's 234x176 view (and saves byte-for-byte exactly what is on the screen).
- Tone modes: The camera handles exposure automatically, so these four modes act as a post-processing style. They let you select which slice of the incoming range gets stretched across the display's four shades:
- A (All): Maps the full input range (0–255).
- H (High): Stretches the darkest 50% (0–128), resulting in a brighter image.
- M (Mid): Stretches the middle 50% (64–192), boosting overall contrast.
- L (Low): Stretches the brightest 50% (128–255), resulting in a darker image.
- Dither modes: Bayer 4x4 ordered, Floyd-Steinberg, Atkinson, and flat posterise (the selected mode is shown as a cute mini swatch on the screen next to C).
- Gallery storage: Safely stores up to 60 photos (fits in 1MB LittleFS storage available to apps).
- Indexed PNG exports: Files are saved as uncompressed 2-bit indexed PNGs matching the hardware palette (
[0, 85, 170, 255]).
- Pimoroni Badger 2350 (running Badgeware v3.0.2 or later).
- PTC06 TTL serial JPEG camera.
- Qw/ST (JST-SH) to bare wire cable.
- Tiny M1 screws.
Solder the Qw/ST cable to the camera's power and serial pads, then connect it to the Badger 2350's Qw/ST port.
Install alongside existing Badger apps, or replace the main launcher to boot directly into the camera.
- Put the badge into disk mode (press RESET twice).
- Wait for it to mount as
BADGER. - Copy the application files:
# Copy the camera app directory cp app/dithcam/*.py app/dithcam/icon.png /path/to/BADGER/apps/dithcam/ # Optional: Replace the default launcher to boot directly to the camera cp boot/main.py /path/to/BADGER/main.py
- Sync and unmount the drive before resetting:
sync udisksctl unmount -b /dev/sda
- Press RESET on the badge to test the software.
Once you have tested the camera, print the back case which replaces the factory one. I used GratKit clear PETG for the print.
The .stl for printing is here: hardware/DITHRPIX_BACK_CASE.stl
I recommend printing the case upside down for a balance between supports and strength.
Note: The case mounts the camera upside-down for clearance, so the app applies a 180-degree rotation by default to compensate.
First, connect the badge to your computer via USB. Ensure it is powered on and in its normal running state (not disk mode) so that mpremote can communicate with it over serial.
To pull your photos off the badge, you can use mpremote:
mpremote cp -r :photos/ ./my-photos/To wipe the gallery and reclaim space on the 1MB partition, run:
mpremote exec "import os; [os.remove('photos/' + f) for f in os.listdir('photos')]"| Button | Camera Mode | Gallery Mode |
|---|---|---|
| A | Cycle tone mode | — |
| B | Take a photo | Back to camera |
| C | Cycle dither mode | Delete photo (asks first) |
| UP | Open gallery | View older photo |
| DOWN | Refresh the preview | View newer photo (or back to camera) |
dithrpix/
├── app/dithcam/ # The application (installed to /system/apps/dithcam)
├── boot/main.py # Boot script (installed to /system/main.py)
├── hardware/ # 3D models and physical design files
└── tools/ # Probe scripts used for testing hardware behaviors
Feedback, ideas, and PRs are super welcome! Whether you want to add a new dither mode, tweak the UI, or just fix a typo, feel free to jump in and open an issue or pull request.
MIT © 2026 Jonothan Hunt — see LICENSE for the full text.


















