# Adding a Bubble Level to the MEMENTO

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/145/319/medium800thumb/adafruit_products_bubble-level-main.jpg?1785969739)

Have you ever tried taking a top-down photo only to find that you were off by just a little bit and the subject suddenly looks a bit warped? By using the MEMENTO Python-programmable camera with its built-in accelerometer, it's easy to add a bubble level that will help you keep the photos straight and level and get that perfect photo.

The bubble level not only works with horizontal photos so that the camera isn't rotated slightly while taking photos, but also top-down photos so that you can get a perfectly level shot.

This guide uses the [MEMENTO Basic Camera example](https://learn.adafruit.com/adafruit-memento-camera-board/basic-camera) as a base and builds on top of that. It makes use of a little bit of space on the bottom bar between the mode and image type.

## Parts
Featured
### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
![Video of a DIY camera on a lazy susan.](https://cdn-shop.adafruit.com/product-videos/640x480/5420-05.jpg)

Featured
### Adafruit MEMENTO Camera Enclosure & Hardware Kit

[Adafruit MEMENTO Camera Enclosure & Hardware Kit](https://www.adafruit.com/product/5843)
Once you've picked up your **MEMENTO Camera** and you're ready to take it out into the world, here is a chic and minimalist enclosure that will look great on the runways of Paris or the street photography of New York City! These front and back plates have been...

In Stock
[Buy Now](https://www.adafruit.com/product/5843)
[Related Guides to the Product](https://learn.adafruit.com/products/5843/guides)
![Overhead shot of two square-shaped PCB boards for a DIY camera above eight black plastic screws and four black plastic hex nuts with 3pin to 3pin JST PH cable and adhesive sticker.](https://cdn-shop.adafruit.com/640x480/5843-05.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

# Adding a Bubble Level to the MEMENTO

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Warning: Make sure you use CircuitPython 9.0.0 final or later. CircuitPython 9.0.0-beta.1 and earlier have a bug that can corrupt the fileystem.

```auto
import storage
storage.erase_filesystem()
```

Your board will reboot after running this.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_esp32s3_camera/)
Warning: As of CircuitPython 9, you'll need to create a folder called "sd" on your CIRCUITPY drive to mount the microSD card, if it's not already there.

[Follow these steps to create the /sd directory](https://learn.adafruit.com/adafruit-memento-camera-board/circuitpython-memento-starter-projects)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/126/734/medium800/adafruit_products_resetNeo.jpg?1702908010)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Double-click the **reset** button (highlighted in red above), and you will see the **RGB status LED(s)** turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

If you do not see the LED turning purple, you will need to reinstall the UF2 bootloader. See the **Factory Reset** page in this guide for details.

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

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

You will see a new disk drive appear called **CAMERABOOT**. Drag the **adafruit-circuitpython-adafruit\_esp32s3\_camera-etc.uf2** file to **CAMERABOOT**.

![adafruit_products_cameraboot.png](https://cdn-learn.adafruit.com/assets/assets/000/126/740/medium640/adafruit_products_cameraboot.png?1702932896)

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# Adding a Bubble Level to the MEMENTO

## Code the Bubble Level

The project uses a specific set of CircuitPython libraries, and the main&nbsp; **code.py** &nbsp;file. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

We can do this in one go. In the example code block below, click the&nbsp; **Download Project Bundle** &nbsp;button to download the necessary libraries and the&nbsp; **code.py** &nbsp;file as a zip file. Extract the contents of the zip file, open the directory **MEMENTO/**** Memento\_Bubble\_Level/ **&nbsp;and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your&nbsp;** CIRCUITPY**&nbsp;drive.

Your&nbsp; **CIRCUITPY** &nbsp;drive should now look similar to the following image:

![Screenshot of required project files and libraries](https://adafruit.github.io/Adafruit_Learning_System_Guides/MEMENTO_Memento_Bubble_Level.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/MEMENTO/Memento_Bubble_Level/code.py

## How the Code Works

The code starts off with a few imports and a number of settings. We'll start by going over the settings. The first couple of settings are from the basic camera code and set the Resolution and LED modes:

```auto
# Settings
PHOTO_RESOLUTION = 8  # 0-12 preset resolutions:
#                      0: 240x240, 1: 320x240, 2: 640x480, 3: 800x600, 4: 1024x768,
#                      5: 1280x720, 6: 1280x1024, 7: 1600x1200, 8: 1920x1080, 9: 2048x1536,
#                      10: 2560x1440, 11: 2560x1600, 12: 2560x1920

LED_LEVEL = 0 # 0-4 preset brightness levels
```

The next series of settings are for the bubble level itself:

```auto
FULL_SCALE_DEGREES = 8.0  # Bubble reaches the end at this much error
GREEN_DEGREES = 1.5
AMBER_DEGREES = 4.0
SMOOTHING = 0.18  # 0.0 = frozen, 1.0 = no filtering

# The gap between these angles prevents AUTO mode from flickering.
DOWN_ENTER_DEGREES = 35
DOWN_EXIT_DEGREES = 45

# Level geometry within the 240 x 32 band below the live preview.
BAR_WIDTH = 64
BAR_HEIGHT = 25
BAR_BOTTOM_MARGIN = 2
BUBBLE_RADIUS = 6

```

Here are the settings specific to the bubble level:

- **FULL\_SCALE\_DEGREES:** The amount of tilt between one end of the level and the and the other on each axis
- **GREEN\_DEGREES:** The tolerance in degrees for the bubble to show green
- **AMBER\_DEGREES:** The tolerance in degrees for the bubble to show amber. This should always be larger than GREEN\_DEGREES.
- **SMOOTHING:** This value is between 0.0 and 1.0 and controls how fast the bubble moves side to side. If it's too low, it will move very slowly and too fast will make it appear jittery. This is similar to controlling the viscosity of the liquid that the bubble moves through with low numbers being more viscous.
- **DOWN\_ENTER\_DEGREES:** This is the point in degrees that the bubble level changes modes and enters into a downward type level.
- **DOWN\_EXIT\_DEGREES:** This is the point in degrees that the bubble level changes modes and enters into a horizontal type level.
- **BAR\_WIDTH:** The width of the bubble level bar
- **BAR\_HEIGHT:** The height of the bubble level bar
- **BAR\_BOTTOM\_MARGIN:** The amount of gap from the bottom of the display
- **BUBBLE\_RADIUS:** The size of the bubble itself

### Helper Functions

There are a few functions that help with either simplifying the code by grouping sections that need to run multiple times or by just making the code easier to read:

`clamp()`: This function will keep a given value within a certain range. Any number outside this range will be set to the end of the range that it exceeds.

`level_color()`: This will return the color based on how close to the amount of levelness the camera is off by.

`update_level()`: This function will take the accelerometer values along with the current mode and update the UI elements to reflect the current level.

`take_photo()`: This function is the photo capture section from the basic camera example.

`white_rectangle():` This function just creates and returns a white vectorio rectangle.

### UI Elements

The UI elements are made from vectorio shapes. Since there are no line elements, they are mostly created using white rectangles. First the bar is added and then the downward facing and horizontal facing level elements are added, which display depending on the angle of the level.

The bubble itself is drawn next with an outline of white and a fill of the color determined by the amount of error. Afterwards, the rest of the UI is drawn as normal.

### Main Loop

The main loop involves reading the accelerometer, applying a smoothing factor so that the bubble doesn't move too fast, and monitoring which mode the bubble level is in. After that, the `update_level()` function is called to update the UI elements.

The rest of the main loop involves checking for the SD card and updating the pycam library by calling its refresh method.

# Adding a Bubble Level to the MEMENTO

## Use the Bubble Level

The bubble level is pretty simple to use. You would use the camera like normal, except you would use the bubble level on the bottom of the camera to adjust the angle of your camera in order to keep it straight. The level has 2 modes that can be switched between just by tilting the camera down or forward.

### Horizontal Mode

For horizontal mode, the bubble shows the amount of tilt to either side. The level is drawn in a more traditional level style with lines and the bubble changes color with the amount of tilt.

In **horizontal mode** , if your camera is off by a larger degree, then the bubble will show up as red. This would mean a tilt angle of **more than 4 degrees** if using the default values.

![Horizontal bubble Level red due to being offset by large degree.](https://cdn-learn.adafruit.com/assets/assets/000/145/270/medium640/adafruit_products_IMG_7977.jpeg?1785966706)

In **horizontal mode** , if your camera is off by a smaller degree, then the bubble will show up as yellow. This would mean a tilt angle **between 1.5 and 4 degrees** if using the default values.

![Horizontal bubble Level red due to being offset by small degree.](https://cdn-learn.adafruit.com/assets/assets/000/145/273/medium640/adafruit_products_IMG_7979.jpeg?1785966870)

In **horizontal mode** , if your camera is relatively level, then the bubble will show up as green. This would mean a tilt angle of **1.5 degrees or less** if using the default values.

![Horizontal bubble Level green due to being straight and centered.](https://cdn-learn.adafruit.com/assets/assets/000/145/272/medium640/adafruit_products_IMG_7978.jpeg?1785966812)

### Vertical Mode

For vertical mode, the bubble shows the amount of tilt in 2 different axes. The level is drawn with a plus to indicate the optimal center and the bubble changes color with the amount of tilt.

In **vertical mode** , if your camera is off by a larger degree in either axis, then the bubble will show up as red. This would mean a tilt angle of **more than 4 degrees** if using the default values.

![Vertical bubble Level red due to being offset by large degree.](https://cdn-learn.adafruit.com/assets/assets/000/145/279/medium640/adafruit_products_IMG_7983.jpeg?1785966925)

In **vertical mode** , if your camera is off by a smaller degree in either axis, then the bubble will show up as yellow. This would mean a tilt angle **between 1.5 and 4 degrees** if using the default values.

![Vertical bubble Level yellow due to being offset by small degree.](https://cdn-learn.adafruit.com/assets/assets/000/145/271/medium640/adafruit_products_IMG_7982.jpeg?1785966831)

In **vertical mode** , if your camera is relatively level in both axes, then the bubble will show up as green. This would mean a tilt angle of&nbsp; **1.5 degrees or less** if using the default values.

![Vertical bubble Level green due to being straight and centered.](https://cdn-learn.adafruit.com/assets/assets/000/145/280/medium640/adafruit_products_IMG_7980.jpeg?1785966984)

This bubble level could probably be pretty easily adapted to work with other cameras besides the basic camera. Feel free to play with the values in the script and see how it affects the bubble level to get it to your liking and most of all, have fun!


## Guide Products

### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
### Adafruit MEMENTO Camera Enclosure & Hardware Kit

[Adafruit MEMENTO Camera Enclosure & Hardware Kit](https://www.adafruit.com/product/5843)
Once you've picked up your **MEMENTO Camera** and you're ready to take it out into the world, here is a chic and minimalist enclosure that will look great on the runways of Paris or the street photography of New York City! These front and back plates have been...

In Stock
[Buy Now](https://www.adafruit.com/product/5843)
[Related Guides to the Product](https://learn.adafruit.com/products/5843/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

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

## Related Guides

- [Adafruit MEMENTO Camera Board](https://learn.adafruit.com/adafruit-memento-camera-board.md)
- [NeoTrellis MIDI Feedback Controller](https://learn.adafruit.com/neotrellis-midi-feedback-controller.md)
- [NextBus Transit Predictions for Adafruit MagTag](https://learn.adafruit.com/nextbus-transit-predictions-for-adafruit-magtag.md)
- [Tile-Matching Game on the Fruit Jam and Metro RP2350](https://learn.adafruit.com/tile-matching-game-on-the-adafruit-metro-rp2350.md)
- [Apple //e Emulator on Fruit Jam](https://learn.adafruit.com/apple-e-emulator-on-fruit-jam.md)
- [NeoPixel Remote: IR Control with WLED](https://learn.adafruit.com/neopixel-remote-ir-control-with-wled.md)
- [Matrix Portal New Guide Scroller](https://learn.adafruit.com/matrix-portal-new-guide-scroller.md)
- [May Pad Macropad with the KB2040, KMK, and CircuitPython](https://learn.adafruit.com/maypad-macropad-with-the-kb2040-kmk-and-circuitpython.md)
- [xLights for Sparkle Motion Board](https://learn.adafruit.com/xlights-for-sparkle-motion-board.md)
- [ESPHole Ad Blocker](https://learn.adafruit.com/esphole-ad-blocker.md)
- [LED Masquerade Masks with n00ds](https://learn.adafruit.com/led-masquerade-masks-with-n00ds.md)
- [Funhouse Door Alert with Email Notification](https://learn.adafruit.com/funhouse-door-alert-email-notification.md)
- [Digital Inputs with Adafruit IO WipperSnapper](https://learn.adafruit.com/digital-inputs-with-adafruit-io-wippersnapper.md)
- [RPi Stock Alert Alarm](https://learn.adafruit.com/rpi-stock-alert-alarm.md)
- [LOVE Light](https://learn.adafruit.com/love-light.md)
- [No-Code DS18B20 Temperature Sensor with WipperSnapper](https://learn.adafruit.com/using-ds18b20-temperature-sensor-with-wippersnapper.md)
