|
| 1 | +# LED Matrix Painter |
| 2 | + |
| 3 | +The **LED Matrix Painter** example provides a web-based tool for designing frames and animations for the Arduino UNO Q 8×13 LED matrix. You can create individual frames, organize them into animations, preview them in real-time on the board, and export them as C++ code. |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +## Description |
| 8 | + |
| 9 | +This example allows you to design LED matrix frames using an interactive web interface. Each frame can have custom brightness levels (0-7) for each LED pixel. You can: |
| 10 | + |
| 11 | +- **Design frames** with pixel-by-pixel control using an interactive grid |
| 12 | +- **Preview in real-time** on the Arduino UNO Q LED matrix |
| 13 | +- **Save and organize** multiple frames with a persistent database |
| 14 | +- **Create animations** by sequencing multiple frames together |
| 15 | +- **Export code** as C++ arrays ready to use in your Arduino sketches |
| 16 | +- **Transform frames** with operations like invert, rotate, and flip |
| 17 | + |
| 18 | +The application uses the Router Bridge to communicate between the web interface (running on Linux) and the Arduino sketch (running on the microcontroller), enabling real-time updates to the physical LED matrix. |
| 19 | + |
| 20 | +## Bricks Used |
| 21 | + |
| 22 | +- `web_ui`: Provides the web server and HTTP API endpoints for the interactive frame designer interface. |
| 23 | +- `dbstorage_sqlstore` (implicit): Stores frame data persistently in a SQLite database. |
| 24 | + |
| 25 | +## Hardware and Software Requirements |
| 26 | + |
| 27 | +### Hardware |
| 28 | + |
| 29 | +- Arduino UNO Q (x1) |
| 30 | +- USB-C® cable (for power and programming) (x1) |
| 31 | + |
| 32 | +### Software |
| 33 | + |
| 34 | +- Arduino App Lab |
| 35 | + |
| 36 | +## How to Use the Example |
| 37 | + |
| 38 | +1. Launch the App by clicking the **Play** button in the top-right corner. Wait until the App has launched. |
| 39 | +2. **Design a frame:** |
| 40 | + - Click on individual pixels in the 8×13 grid to toggle them on/off |
| 41 | + - Use the brightness slider to adjust LED intensity (0-7) |
| 42 | + - Click on pixels with different brightness values to paint with varying intensities |
| 43 | +3. **Save your frame:** |
| 44 | + - Click the **Save Frame** button to persist the current design |
| 45 | + - Frames are automatically saved to a database and appear in the sidebar |
| 46 | +4. **Create animations:** |
| 47 | + - Save multiple frames |
| 48 | + - Switch to **Animations** mode in the sidebar |
| 49 | + - Create a new animation and add frames to it |
| 50 | + - Use **Play** to preview the animation on the board |
| 51 | +5. **Export code:** |
| 52 | + - Select the frames or animations you want to export |
| 53 | + - Click **Export** to generate C++ code |
| 54 | + - Copy the generated arrays into your Arduino sketch |
| 55 | + |
| 56 | +## How it Works |
| 57 | + |
| 58 | +The LED Matrix Painter consists of three main components working together: |
| 59 | + |
| 60 | +- **Web Interface (Frontend)**: An interactive grid editor built with HTML/CSS/JavaScript that sends pixel data to the backend via HTTP API calls. |
| 61 | + |
| 62 | +- **Python Backend**: Handles frame storage in a SQLite database, manages frame transformations, and communicates with the Arduino via Router Bridge. |
| 63 | + |
| 64 | +- **Arduino Sketch**: Receives frame data over Router Bridge and displays it on the physical LED matrix using the `Arduino_LED_Matrix` library. |
| 65 | + |
| 66 | +High-level data flow: |
| 67 | + |
| 68 | +``` |
| 69 | +Web Browser → HTTP API → Python Backend → Router Bridge → Arduino LED Matrix |
| 70 | + ↓ |
| 71 | + SQLite Database |
| 72 | +``` |
| 73 | + |
| 74 | +The workflow: |
| 75 | +1. User edits a frame in the web interface |
| 76 | +2. Changes are sent to Python backend via HTTP POST |
| 77 | +3. Backend validates and stores the frame in SQLite |
| 78 | +4. Backend sends frame data to Arduino via Bridge |
| 79 | +5. Arduino sketch renders the frame on the LED matrix |
| 80 | + |
| 81 | +## Understanding the Code |
| 82 | + |
| 83 | +### 🔧 Backend (`main.py`) |
| 84 | + |
| 85 | +The Python application manages the HTTP API, database operations, and communication with the Arduino. |
| 86 | + |
| 87 | +- **`designer = FrameDesigner()`**: Initializes the frame designer utility from `arduino.app_utils`, which provides transformation operations (invert, rotate, flip). |
| 88 | + |
| 89 | +- **`store.init_db()`**: Creates the SQLite database and tables for storing frames if they don't exist. |
| 90 | + |
| 91 | +- **`ui.expose_api('POST', '/persist_frame', persist_frame)`**: Exposes an HTTP endpoint that saves or updates frames in the database. |
| 92 | + |
| 93 | +- **`ui.expose_api('POST', '/load_frame', load_frame)`**: Loads a frame from the database by ID or retrieves the last edited frame. |
| 94 | + |
| 95 | +- **`ui.expose_api('GET', '/list_frames', list_frames)`**: Returns all saved frames for display in the sidebar. |
| 96 | + |
| 97 | +- **`ui.expose_api('POST', '/play_animation', play_animation)`**: Sends a sequence of frames to the Arduino to play as an animation. |
| 98 | + |
| 99 | +- **`ui.expose_api('POST', '/export_frames', export_frames)`**: Generates C++ code arrays from selected frames for use in Arduino sketches. |
| 100 | + |
| 101 | +- **`Bridge.call("draw", frame_bytes)`**: Sends frame data to the Arduino sketch to update the LED matrix display. |
| 102 | + |
| 103 | +- **`AppFrame` class**: Custom extension of `arduino.app_utils.Frame` that adds metadata like frame name, position, duration, and database persistence methods. |
| 104 | + |
| 105 | +### 💻 Frontend (`app.js` + `index.html`) |
| 106 | + |
| 107 | +The web interface provides an interactive pixel grid editor and frame management tools. |
| 108 | + |
| 109 | +- **Pixel Grid**: An 8×13 canvas that responds to mouse clicks and drag operations for painting pixels. |
| 110 | + |
| 111 | +- **Brightness Control**: A slider (0-7) that controls the current brush brightness level. |
| 112 | + |
| 113 | +- **Frame List**: Displays all saved frames in a sidebar with options to load, delete, or reorder them. |
| 114 | + |
| 115 | +- **Animations Mode**: Allows creating and managing animation sequences by dragging frames into animation containers. |
| 116 | + |
| 117 | +- **Transform Tools**: Buttons for applying transformations (invert, rotate 180°, flip horizontal/vertical). |
| 118 | + |
| 119 | +- **Export Modal**: Generates and displays C++ code for selected frames or animations. |
| 120 | + |
| 121 | +- **HTTP API calls**: Uses `fetch()` to communicate with the Python backend for all frame operations (save, load, delete, transform, export, play). |
| 122 | + |
| 123 | +### 🔧 Hardware (`sketch.ino`) |
| 124 | + |
| 125 | +The Arduino code handles LED matrix control and Router Bridge communication. |
| 126 | + |
| 127 | +- **`matrix.begin()`**: Initializes the Arduino_LED_Matrix library for controlling the UNO Q LED matrix. |
| 128 | + |
| 129 | +- **`matrix.setGrayscaleBits(8)`**: Configures the matrix to accept 8-bit brightness values (0-255) for each pixel. |
| 130 | + |
| 131 | +- **`Bridge.begin()`**: Initializes Router Bridge for receiving commands from the Python application. |
| 132 | + |
| 133 | +- **`Bridge.provide("draw", draw)`**: Registers the `draw` function to be callable from Python, which accepts frame data and renders it on the matrix. |
| 134 | + |
| 135 | +- **`Bridge.provide("play_animation", play_animation)`**: Registers the animation playback function that accepts multiple frames and plays them sequentially. |
| 136 | + |
| 137 | +- **`matrix.draw(frame.data())`**: Renders a single frame on the LED matrix using raw byte data. |
| 138 | + |
| 139 | +- **`matrix.loadWrapper()` + `matrix.playSequence()`**: Loads an animation sequence and plays it on the LED matrix. |
| 140 | + |
| 141 | +## Frame Data Format |
| 142 | + |
| 143 | +Frames are stored as 8×13 arrays where each value represents LED brightness (0-255): |
| 144 | + |
| 145 | +```cpp |
| 146 | +// Example frame in C++ format |
| 147 | +const uint8_t frame[][12] = { |
| 148 | + {255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255}, |
| 149 | + {0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0}, |
| 150 | + // ... 6 more rows |
| 151 | +}; |
| 152 | +``` |
| 153 | + |
| 154 | +For animations, frames are stored as `uint32_t` arrays compatible with the Arduino_LED_Matrix library: |
| 155 | + |
| 156 | +```cpp |
| 157 | +const uint32_t animation[][5] = { |
| 158 | + {0x12345678, 0x9abcdef0, 0x12345678, 0x9abcdef0, 1000}, // Frame 1, 1000ms duration |
| 159 | + {0xfedcba98, 0x76543210, 0xfedcba98, 0x76543210, 1000}, // Frame 2, 1000ms duration |
| 160 | +}; |
| 161 | +``` |
0 commit comments