Skip to content

Commit 12567bb

Browse files
authored
Ernesto Structure and Review (#27)
1 parent 44d3800 commit 12567bb

File tree

1 file changed

+106
-84
lines changed
  • examples/vibration-anomaly-detection

1 file changed

+106
-84
lines changed
Lines changed: 106 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# Fan Vibration Monitoring
1+
# Vibration Anomaly Detection
22

3-
The **Fan Vibration Monitoring** example creates a smart vibration detector that monitors a fan (or any vibrating machinery) for anomalies. It visualizes raw accelerometer data in real-time and allows users to dynamically adjust the anomaly detection sensitivity through a web dashboard.
3+
The **Vibration Anomaly Detection** example creates a smart vibration detector that monitors a fan (or any vibrating machinery) for anomalies. It visualizes raw accelerometer data in real-time and allows users to dynamically adjust the anomaly detection sensitivity through a web dashboard.
44

5-
![Fan Vibration Monitoring](assets/docs_assets/vibration-anomaly.png)
5+
![Vibration Monitoring](assets/docs_assets/vibration-anomaly.png)
66

77
## Description
88

99
Monitor the physical status of a fan in real-time. This example uses a Modulino Movement to capture acceleration data and a dedicated Brick to detect vibration anomalies.
1010

11-
Unlike simple threshold detectors, this app provides:
11+
Unlike simple threshold detectors, this App provides:
1212
* **Live Data Visualization:** A real-time scrolling plot of X, Y, and Z acceleration.
1313
* **Dynamic Sensitivity:** A slider to adjust the anomaly scoring threshold on the fly.
1414
* **History:** A log of the most recent detected anomalies with timestamps.
@@ -33,106 +33,128 @@ The example uses the following Bricks:
3333

3434
- Arduino App Lab
3535

36-
**Note:** You can run this example using your Arduino UNO Q as a Single Board Computer (SBC) using a [USB-C hub](https://store.arduino.cc/products/usb-c-to-hdmi-multiport-adapter-with-ethernet-and-usb-hub) with a mouse, keyboard, and monitor attached.
36+
**Note:** You can also run this example using your Arduino UNO Q as a Single Board Computer (SBC) using a [USB-C hub](https://store.arduino.cc/products/usb-c-to-hdmi-multiport-adapter-with-ethernet-and-usb-hub) with a mouse, keyboard, and monitor attached.
3737

3838
## How to Use the Example
3939

40-
1. Connect the Modulino Movement sensor to the Arduino UNO Q via the Qwiic connector.
41-
2. Run the App.
42-
3. Open the App on your browser.
43-
4. Observe the **Accelerometer Data** chart to see the live vibration waveforms.
44-
5. Use the **Set anomaly score** slider to adjust how sensitive the detector is. Lower values make it more sensitive; higher values require stronger vibrations to trigger an alert.
45-
6. Shake the sensor or attach it to a fan to simulate an anomaly. The "Feedback" section will show a warning, and the event will be logged in "Recent Anomalies".
40+
1. **Hardware Setup**
41+
Connect the Modulino Movement sensor to the Arduino UNO Q via the Qwiic connector.
42+
43+
2. **Run the App**
44+
Launch the App from Arduino App Lab.
45+
46+
3. **Access the Web Interface**
47+
Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000`.
48+
49+
4. **Monitor Vibrations**
50+
Observe the **Accelerometer Data** chart to see the live vibration waveforms.
51+
52+
5. **Adjust Sensitivity**
53+
Use the **Set anomaly score** slider to adjust how sensitive the detector is.
54+
- **Lower values (1):** High sensitivity (small vibrations trigger alerts).
55+
- **Higher values (10):** Low sensitivity (requires strong, irregular vibrations to trigger).
56+
57+
6. **Trigger an Anomaly**
58+
Shake the sensor or attach it to a fan to simulate an anomaly. The "Feedback" section will show a warning, and the event will be logged in "Recent Anomalies".
4659

4760
## How it Works
4861

49-
Here is a brief explanation of the full-stack application:
62+
Once the App is running, it performs the following operations:
63+
64+
- **Acquisition**: The sketch reads the sensor every 16ms and sends data to Python via Bridge.
65+
- **Processing**: The backend converts units, feeds the detection Brick, and streams data to the UI.
66+
- **Detection**: The Brick analyzes vibration patterns and triggers an event if the threshold is exceeded.
67+
- **Tuning**: Slider adjustments in the web interface instantly update the detection sensitivity.
5068

51-
### 🔧 Backend (main.py)
69+
## Understanding the Code
70+
71+
Here is a brief explanation of the App components:
72+
73+
### 🔧 Backend (`main.py`)
74+
75+
The Python backend serves as the central hub. It performs the following tasks:
5276

5377
- Initializes the `vibration_anomaly_detection` Brick.
5478
- Receives raw sensor data via `Bridge`, converts it from gravity units ($g$) to acceleration ($m/s^2$), and forwards it to the UI for plotting.
5579
- Accumulates samples in the detection Brick.
5680
- Listens for threshold overrides from the UI to update the detection sensitivity in real-time.
5781
- Broadcasts anomaly alerts containing the anomaly score and timestamp.
5882

59-
### 💻 Frontend (index.html + app.js)
83+
**Data Processing Logic:**
84+
85+
The `record_sensor_movement` function receives the raw data, converts the units, feeds the detector, and simultaneously pushes the data to the frontend for the live plot.
86+
87+
```python
88+
def record_sensor_movement(x: float, y: float, z: float):
89+
# Convert g -> m/s^2 for the detector
90+
x_ms2 = x * 9.81
91+
y_ms2 = y * 9.81
92+
z_ms2 = z * 9.81
93+
94+
# Forward raw data to UI for plotting
95+
ui.send_message('sample', {'x': x_ms2, 'y': y_ms2, 'z': z_ms2})
96+
97+
# Forward samples to the vibration_detection brick
98+
vibration_detection.accumulate_samples((x_ms2, y_ms2, z_ms2))
99+
```
100+
101+
**Dynamic Thresholds:**
102+
103+
When you move the slider in the browser, the frontend emits an event. The backend updates the detection brick's sensitivity immediately.
104+
105+
```python
106+
def on_override_th(value: float):
107+
logger.info(f"Setting new anomaly threshold: {value}")
108+
vibration_detection.anomaly_detection_threshold = value
109+
```
110+
111+
### 💻 Frontend (`index.html` + `app.js`)
112+
113+
The web interface handles visualization and user input:
60114

61115
- **Real-time Plotting:** Uses an HTML5 Canvas to draw the live X, Y, Z acceleration waveforms.
62116
- **Interactive Controls:** Sends slider values to the backend to tune the algorithm parameters.
63-
- **Alert System:** visualizes anomalies with status icons and maintains a chronological list of recent detections.
117+
- **Alert System:** Visualizes anomalies with status icons and maintains a chronological list of recent detections.
64118

65-
## Understanding the Code
119+
**Visualizing the Data:**
120+
121+
The frontend receives the `sample` event and pushes it into an array. The `drawPlot` function clears the canvas and redraws the lines for X, Y, and Z to create the scrolling chart effect.
122+
123+
```javascript
124+
function drawPlot() {
125+
if (!hasDataFromBackend) return;
126+
127+
// Clear the canvas before drawing the new frame
128+
ctx.clearRect(0, 0, currentWidth, currentHeight);
129+
130+
// ... grid drawing code ...
131+
132+
// Draw series (X, Y, Z)
133+
drawSeries('x','#0068C9');
134+
drawSeries('y','#FF9900');
135+
drawSeries('z','#FF2B2B');
136+
}
137+
```
66138

67-
Once the application is running, you can access it from your web browser. At that point, the device begins performing the following:
139+
### 🔧 Arduino Component (`sketch.ino`)
68140

69-
- **Reading sensor data on the MCU (Arduino sketch).**
141+
The firmware reads the Modulino Movement sensor every 16ms. It sends the X, Y, and Z values to the Python backend using `Bridge.notify`.
70142

71-
The firmware reads the Modulino Movement sensor every 16ms. It sends the X, Y, and Z values to the Python backend using `Bridge.notify`.
143+
```cpp
144+
void loop() {
145+
// ... timing logic (16ms interval) ...
146+
147+
// Read new movement data from the sensor
148+
has_movement = movement.update();
72149

73-
```cpp
74-
void loop() {
75-
// ... timing logic (16ms interval) ...
76-
77-
// Read new movement data from the sensor
78-
has_movement = movement.update();
150+
if(has_movement == 1) {
151+
// Get acceleration values
152+
x_accel = movement.getX();
153+
y_accel = movement.getY();
154+
z_accel = movement.getZ();
79155

80-
if(has_movement == 1) {
81-
// Get acceleration values
82-
x_accel = movement.getX();
83-
y_accel = movement.getY();
84-
z_accel = movement.getZ();
85-
86-
// Send data to Python
87-
Bridge.notify("record_sensor_movement", x_accel, y_accel, z_accel);
88-
}
89-
}
90-
```
91-
92-
- **Processing data and updating the UI (Python).**
93-
94-
The backend serves as the central hub. It receives the raw data, converts the units for the algorithm, feeds the detector, and simultaneously pushes the data to the frontend for the live plot.
95-
96-
```python
97-
def record_sensor_movement(x: float, y: float, z: float):
98-
# Convert g -> m/s^2 for the detector
99-
x_ms2 = x * 9.81
100-
y_ms2 = y * 9.81
101-
z_ms2 = z * 9.81
102-
103-
# Forward raw data to UI for plotting
104-
ui.send_message('sample', {'x': x_ms2, 'y': y_ms2, 'z': z_ms2})
105-
106-
# Forward samples to the vibration_detection brick
107-
vibration_detection.accumulate_samples((x_ms2, y_ms2, z_ms2))
108-
```
109-
110-
- **Handling Dynamic Thresholds.**
111-
112-
When you move the slider in the browser, the frontend emits an event. The backend updates the detection brick's sensitivity immediately.
113-
114-
```python
115-
def on_override_th(value: float):
116-
logger.info(f"Setting new anomaly threshold: {value}")
117-
vibration_detection.anomaly_detection_threshold = value
118-
```
119-
120-
- **Visualizing the Data (JavaScript).**
121-
122-
The frontend receives the `sample` event and pushes it into an array. The `drawPlot` function clears the canvas and redraws the lines for X, Y, and Z to create the scrolling chart effect.
123-
124-
```javascript
125-
function drawPlot() {
126-
if (!hasDataFromBackend) return;
127-
128-
// Clear the canvas before drawing the new frame
129-
ctx.clearRect(0, 0, currentWidth, currentHeight);
130-
131-
// ... grid drawing code ...
132-
133-
// Draw series (X, Y, Z)
134-
drawSeries('x','#0068C9');
135-
drawSeries('y','#FF9900');
136-
drawSeries('z','#FF2B2B');
137-
}
138-
```
156+
// Send data to Python
157+
Bridge.notify("record_sensor_movement", x_accel, y_accel, z_accel);
158+
}
159+
}
160+
```

0 commit comments

Comments
 (0)