Skip to content

Commit 5931c19

Browse files
committed
Update README example
1 parent 9491c29 commit 5931c19

File tree

1 file changed

+111
-104
lines changed

1 file changed

+111
-104
lines changed
Lines changed: 111 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
# LED Matrix Painter
22

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.
3+
The **LED Matrix Painter** example transforms your Arduino UNO Q into a design tool for the built-in LED Matrix. It features a web-based pixel editor that allows you to draw frames, create animations, and export the results as ready-to-use C++ code.
44

5-
![LED Matrix Painter](assets/docs_assets/led-matrix-painter.png)
5+
![LED Matrix Painter Example](assets/docs_assets/thumbnail.png)
66

77
## Description
88

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:
9+
This App provides a complete workflow for designing LED matrix visuals. It uses the `web_ui` Brick to host a graphical editor where you can draw pixels with 8 levels of brightness. Changes are reflected instantly on the UNO Q's physical matrix.
1010

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
11+
The application uses the `dbstorage_sqlstore` Brick to persist your designs in a database, allowing you to save multiple frames, reorder them via drag-and-drop, and organize them into animations. Finally, the "Export .h" feature generates the exact C++ code needed to use your designs in standalone Arduino sketches.
1712

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.
13+
Key features include:
14+
- **Real-time Preview:** Drawing on the web interface updates the UNO Q matrix instantly.
15+
- **8-bit Grayscale:** Support for 8 brightness levels per pixel (0-7 in the editor, mapped to 0-255).
16+
- **Frame Management:** Create, delete, and reorder frames using a persistent database.
17+
- **Transform Tools:** Quickly invert, rotate, or flip your designs.
18+
- **Animation Mode:** Sequence frames to create and preview animations on the board.
19+
- **Code Generation:** Export frames or animations as `uint32_t` arrays compatible with the `Arduino_LED_Matrix` library.
1920

2021
## Bricks Used
2122

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.
23+
The LED Matrix Painter example uses the following Bricks:
24+
25+
- `web_ui`: Brick to create the interactive grid editor and manage API endpoints.
26+
- `dbstorage_sqlstore`: Brick to persist frames and animation sequences using a SQLite database.
2427

2528
## Hardware and Software Requirements
2629

@@ -35,127 +38,131 @@ The application uses the Router Bridge to communicate between the web interface
3538

3639
## How to Use the Example
3740

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.
41+
1. **Run the App**
42+
Launch the App from Arduino App Lab.
8643

87-
- **`designer = FrameDesigner()`**: Initializes the frame designer utility from `arduino.app_utils`, which provides transformation operations (invert, rotate, flip).
44+
2. **Access the Editor**
45+
Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000`.
8846

89-
- **`store.init_db()`**: Creates the SQLite database and tables for storing frames if they don't exist.
47+
3. **Draw Frames**
48+
- **Click** a cell in the grid to toggle it on.
49+
- **Click again** (or hover and wait) to open the brightness slider and adjust the intensity (0-7).
50+
- The design appears immediately on the UNO Q LED Matrix.
9051

91-
- **`ui.expose_api('POST', '/persist_frame', persist_frame)`**: Exposes an HTTP endpoint that saves or updates frames in the database.
52+
4. **Manage Your Session**
53+
- **Auto-save:** Changes are automatically saved to the database as you draw.
54+
- **Create:** Use the **+** button in the sidebar to create new empty frames.
55+
- **Reorder:** Drag and drop frames in the list to change their sequence.
56+
- **Transform:** Use the toolbar buttons to **Invert**, **Rotate 180°**, or **Flip** the current frame.
9257

93-
- **`ui.expose_api('POST', '/load_frame', load_frame)`**: Loads a frame from the database by ID or retrieves the last edited frame.
58+
5. **Create Animations**
59+
- Switch the radio button in the sidebar to **Animations**.
60+
- Select multiple frames by clicking on them in the sidebar.
61+
- Click **Play Animation** to see the sequence run on the UNO Q.
9462

95-
- **`ui.expose_api('GET', '/list_frames', list_frames)`**: Returns all saved frames for display in the sidebar.
63+
6. **Export Code**
64+
- Click **Export .h** to download a C++ header file containing your designs.
65+
- Copy the generated code (displayed in the right column) directly into your Arduino sketch.
9666

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.
67+
## How it Works
10068

101-
- **`Bridge.call("draw", frame_bytes)`**: Sends frame data to the Arduino sketch to update the LED matrix display.
69+
The LED Matrix Painter consists of three main components working together:
10270

103-
- **`AppFrame` class**: Custom extension of `arduino.app_utils.Frame` that adds metadata like frame name, position, duration, and database persistence methods.
71+
1. **Web Interface**: An interactive grid editor that captures user input and sends pixel data to the backend.
72+
2. **Python Backend**: Manages the database, handles frame transformations, and communicates with the hardware.
73+
3. **Arduino Sketch**: Receives raw data and renders it on the physical matrix.
10474

105-
### 💻 Frontend (`app.js` + `index.html`)
75+
**High-level data flow:**
10676

107-
The web interface provides an interactive pixel grid editor and frame management tools.
77+
```
78+
Web Browser ──► HTTP API ──► Python Backend ──► Router Bridge ──► Arduino Sketch
79+
│ │
80+
▼ ▼
81+
SQLite Database LED Matrix Display
82+
```
10883

109-
- **Pixel Grid**: An 8×13 canvas that responds to mouse clicks and drag operations for painting pixels.
84+
## Understanding the Code
11085

111-
- **Brightness Control**: A slider (0-7) that controls the current brush brightness level.
86+
### 🔧 Backend (`main.py` & `store.py`)
11287

113-
- **Frame List**: Displays all saved frames in a sidebar with options to load, delete, or reorder them.
88+
The Python backend acts as the controller, managing the API and database interactions.
11489

115-
- **Animations Mode**: Allows creating and managing animation sequences by dragging frames into animation containers.
90+
- **Persistence**: The application uses `SQLStore` to manage a `frames` table. This allows frames to be loaded, reordered, and updated efficiently.
11691

117-
- **Transform Tools**: Buttons for applying transformations (invert, rotate 180°, flip horizontal/vertical).
92+
```python
93+
# store.py
94+
db = SQLStore(database_name="led_matrix_frames")
11895

119-
- **Export Modal**: Generates and displays C++ code for selected frames or animations.
96+
def save_frame(frame: AppFrame) -> int:
97+
# Logic to calculate position and insert record
98+
record = frame.to_record()
99+
db.store("frames", record, create_table=False)
100+
# ...
101+
```
120102

121-
- **HTTP API calls**: Uses `fetch()` to communicate with the Python backend for all frame operations (save, load, delete, transform, export, play).
103+
- **Bridge Communication**: When a frame is loaded or edited, it is sent to the board. The `AppFrame` class handles the conversion of pixel data into the specific byte format required by the sketch.
122104

123-
### 🔧 Hardware (`sketch.ino`)
105+
```python
106+
# main.py
107+
def apply_frame_to_board(frame: AppFrame):
108+
"""Send frame bytes to the Arduino board."""
109+
frame_bytes = frame.to_board_bytes()
110+
Bridge.call("draw", frame_bytes)
111+
```
124112

125-
The Arduino code handles LED matrix control and Router Bridge communication.
113+
- **Code Export**: The `AppFrame` class includes logic to generate C++ source code strings (`uint32_t` arrays), which are returned to the frontend for display.
126114

127-
- **`matrix.begin()`**: Initializes the Arduino_LED_Matrix library for controlling the UNO Q LED matrix.
115+
```python
116+
# app_frame.py
117+
def to_c_string(self) -> str:
118+
c_type = "uint32_t"
119+
parts = [f"const {c_type} {self.name}[] = {{"]
120+
# ... formats array data as hex/int ...
121+
parts.append("};")
122+
return "\n".join(parts)
123+
```
128124

129-
- **`matrix.setGrayscaleBits(8)`**: Configures the matrix to accept 8-bit brightness values (0-255) for each pixel.
125+
### 🔧 Arduino Component (`sketch.ino`)
130126

131-
- **`Bridge.begin()`**: Initializes Router Bridge for receiving commands from the Python application.
127+
The sketch initializes the matrix and registers Bridge functions to receive data from Python.
132128

133-
- **`Bridge.provide("draw", draw)`**: Registers the `draw` function to be callable from Python, which accepts frame data and renders it on the matrix.
129+
- **Matrix Configuration**: The matrix is configured to accept 8-bit values, allowing for smooth gradients (0-255) rather than just on/off.
134130

135-
- **`Bridge.provide("play_animation", play_animation)`**: Registers the animation playback function that accepts multiple frames and plays them sequentially.
131+
```cpp
132+
void setup() {
133+
matrix.begin();
134+
// configure grayscale bits to 8 so the display can accept 0..255 brightness
135+
matrix.setGrayscaleBits(8);
136+
Bridge.begin();
137+
// ...
138+
}
139+
```
136140

137-
- **`matrix.draw(frame.data())`**: Renders a single frame on the LED matrix using raw byte data.
141+
- **Drawing Frames**: The `draw` function receives a vector of bytes, which represents the frame data, and passes it to the matrix driver.
138142

139-
- **`matrix.loadWrapper()` + `matrix.playSequence()`**: Loads an animation sequence and plays it on the LED matrix.
143+
```cpp
144+
void draw(std::vector<uint8_t> frame) {
145+
// Direct draw of received bytes
146+
matrix.draw(frame.data());
147+
}
148+
```
140149
141-
## Frame Data Format
150+
- **Playing Animations**: The `play_animation` function receives a stream of bytes representing multiple frames and durations. It reconstructs them into `uint32_t` arrays (the native format for the matrix library) and plays the sequence.
142151
143-
Frames are stored as 8×13 arrays where each value represents LED brightness (0-255):
152+
### 🔧 Frontend (`app.js`)
144153
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-
```
154+
The JavaScript frontend handles the interactive grid logic.
153155
154-
For animations, frames are stored as `uint32_t` arrays compatible with the Arduino_LED_Matrix library:
156+
- **Brightness Control**: It supports multi-level brightness by managing a dataset attribute `data-b` on each cell.
157+
- **Auto-Persist**: To ensure a smooth user experience, changes are debounced and automatically sent to the backend via `schedulePersist()`, which updates both the database and the physical board simultaneously.
155158
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-
};
159+
```javascript
160+
// Unified persist: save to DB and update board together
161+
function schedulePersist(){
162+
if (persistTimeout) clearTimeout(persistTimeout);
163+
persistTimeout = setTimeout(()=> {
164+
persistFrame();
165+
persistTimeout = null;
166+
}, AUTO_PERSIST_DELAY_MS);
167+
}
161168
```

0 commit comments

Comments
 (0)