Skip to content

Commit fd59b91

Browse files
committed
Content update (example code)
1 parent 67de5e6 commit fd59b91

File tree

4 files changed

+107
-75
lines changed

4 files changed

+107
-75
lines changed

content/hardware/03.nano/boards/nano-r4/tutorials/02.anomaly-detection-application-note/content.md

Lines changed: 107 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: 'Motor Anomaly Detection with the Arduino® Nano R4'
2+
title: 'Motor Anomaly Detection with the Nano R4'
33
description: "This application note describes how to implement a motor anomaly detection system using the Nano R4 board, an accelerometer and Edge Impulse."
44
difficulty: intermediate
55
compatible-products: [nano-r4]
@@ -214,7 +214,7 @@ The complete example sketch is shown below.
214214
accelerometer or Modulino Movement connected to an Arduino Nano R4.
215215
The data is formatted for Edge Impulse data collection and training.
216216
217-
@version 2.0 01/06/25
217+
@version 2.5 01/06/25
218218
@author Arduino Product Experience Team
219219
*/
220220
@@ -223,7 +223,7 @@ The complete example sketch is shown below.
223223
// #define USE_MODULINO // For Modulino Movement (LSM6DSOXTR)
224224
225225
#ifdef USE_MODULINO
226-
#include <Arduino_Modulino.h>
226+
#include <Modulino.h>
227227
ModulinoMovement movement;
228228
#endif
229229
@@ -254,14 +254,38 @@ unsigned long lastSample = 0;
254254
255255
void setup() {
256256
Serial.begin(115200);
257+
while (!Serial);
257258
258259
#ifdef USE_MODULINO
259-
// Initialize Modulino Movement
260+
// Initialize Modulino I2C communication
260261
Modulino.begin();
261-
movement.begin();
262+
263+
// Detect and connect to movement sensor module
264+
if (!movement.begin()) {
265+
Serial.println("Failed to initialize Modulino Movement!");
266+
while (1);
267+
}
262268
263269
Serial.println("- Motor Vibration Data Collector (Modulino Movement)");
264270
Serial.println("- LSM6DSOXTR 6-axis sensor initialized");
271+
272+
// Wait for sensor stabilization
273+
delay(500);
274+
275+
// Test initial reading
276+
movement.update();
277+
float testX = movement.getX();
278+
float testY = movement.getY();
279+
float testZ = movement.getZ();
280+
281+
Serial.print("- Initial readings (g): X=");
282+
Serial.print(testX, 3);
283+
Serial.print(", Y=");
284+
Serial.print(testY, 3);
285+
Serial.print(", Z=");
286+
Serial.println(testZ, 3);
287+
288+
Serial.println("- Sensor ready - values already in g units");
265289
#endif
266290
267291
#ifdef USE_ADXL335
@@ -283,17 +307,18 @@ void loop() {
283307
284308
if (currentTime - lastSample >= sampleTime) {
285309
float xAccel, yAccel, zAccel;
310+
bool dataValid = false;
286311
287312
#ifdef USE_MODULINO
288-
// Read acceleration data from Modulino Movement
289-
if (movement.isDataReady()) {
290-
xAccel = movement.getAccelerationX();
291-
yAccel = movement.getAccelerationY();
292-
zAccel = movement.getAccelerationZ();
293-
} else {
294-
// Skip this sample if data not ready
295-
return;
296-
}
313+
// Read new movement data from the sensor
314+
movement.update();
315+
316+
// Get acceleration values (already in g units)
317+
xAccel = movement.getX();
318+
yAccel = movement.getY();
319+
zAccel = movement.getZ();
320+
321+
dataValid = true;
297322
#endif
298323
299324
#ifdef USE_ADXL335
@@ -311,14 +336,18 @@ void loop() {
311336
xAccel = (xVoltmV - supplyMidPointmV) / mVperg;
312337
yAccel = (yVoltmV - supplyMidPointmV) / mVperg;
313338
zAccel = (zVoltmV - supplyMidPointmV) / mVperg;
339+
340+
dataValid = true;
314341
#endif
315342
316343
// Output CSV format for Edge Impulse
317-
Serial.print(xAccel, 4);
318-
Serial.print(",");
319-
Serial.print(yAccel, 4);
320-
Serial.print(",");
321-
Serial.println(zAccel, 4);
344+
if (dataValid) {
345+
Serial.print(xAccel, 4);
346+
Serial.print(",");
347+
Serial.print(yAccel, 4);
348+
Serial.print(",");
349+
Serial.println(zAccel, 4);
350+
}
322351
323352
lastSample = currentTime;
324353
}
@@ -343,7 +372,7 @@ The sketch begins by allowing you to choose which sensor you're using through pr
343372
// #define USE_MODULINO // For Modulino Movement (LSM6DSOXTR)
344373
345374
#ifdef USE_MODULINO
346-
#include <Arduino_Modulino.h>
375+
#include <Modulino.h>
347376
ModulinoMovement movement;
348377
#endif
349378
```
@@ -394,14 +423,17 @@ For the Modulino Movement option, the configuration uses digital I²C communicat
394423

395424
```arduino
396425
#ifdef USE_MODULINO
397-
void setup() {
398-
// Initialize Modulino Movement
399-
Modulino.begin();
400-
movement.begin();
401-
402-
Serial.println("- Motor Vibration Data Collector (Modulino Movement)");
403-
Serial.println("- LSM6DSOXTR 6-axis sensor initialized");
426+
// Initialize Modulino I2C communication
427+
Modulino.begin();
428+
429+
// Detect and connect to movement sensor module
430+
if (!movement.begin()) {
431+
Serial.println("Failed to initialize Modulino Movement!");
432+
while (1);
404433
}
434+
435+
Serial.println("- Motor Vibration Data Collector (Modulino Movement)");
436+
Serial.println("- LSM6DSOXTR 6-axis sensor initialized");
405437
#endif
406438
```
407439

@@ -411,7 +443,7 @@ In this code:
411443
- `movement.begin()` specifically initializes the Movement sensor with default settings
412444
- No pin assignments are needed as the sensor communicates via I²C through the Qwiic connector
413445
- The sensor automatically configures itself with optimal settings for vibration monitoring
414-
446+
- Values are returned directly in g units without requiring additional conversion
415447

416448
### Data Collection Timing and Control
417449

@@ -470,45 +502,46 @@ For the digital Modulino Movement, the conversion is handled internally by the s
470502

471503
```arduino
472504
#ifdef USE_MODULINO
473-
// Read acceleration data from Modulino Movement
474-
if (movement.isDataReady()) {
475-
xAccel = movement.getAccelerationX();
476-
yAccel = movement.getAccelerationY();
477-
zAccel = movement.getAccelerationZ();
478-
} else {
479-
// Skip this sample if data not ready
480-
return;
481-
}
505+
// Read new movement data from the sensor
506+
movement.update();
507+
508+
// Get acceleration values (already in g units)
509+
xAccel = movement.getX();
510+
yAccel = movement.getY();
511+
zAccel = movement.getZ();
482512
#endif
483513
```
484514

485515
In this code:
486516

487-
- `isDataReady()` checks if new data is available from the sensor
517+
- `movement.update()` refreshes the sensor data
488518
- The acceleration values are returned directly in g units, eliminating manual calibration
489519
- Built-in digital filtering provides clean, noise-free measurements
490-
- Data skipping prevents invalid readings when sensor data isn't ready
520+
- No conversion calculations are needed as the sensor handles all processing internally
491521

492522
### Edge Impulse Data Formatting
493523

494524
The final step formats our acceleration data so it can be used with Edge Impulse data collection tools:
495525

496526
```arduino
497-
// Output CSV format
498-
Serial.print(xAccel, 4);
499-
Serial.print(",");
500-
Serial.print(yAccel, 4);
501-
Serial.print(",");
502-
Serial.println(zAccel, 4);
527+
// Output CSV format for Edge Impulse
528+
if (dataValid) {
529+
Serial.print(xAccel, 4);
530+
Serial.print(",");
531+
Serial.print(yAccel, 4);
532+
Serial.print(",");
533+
Serial.println(zAccel, 4);
534+
}
503535
```
504536

505537
In this code:
506538

507539
- CSV format with four decimal places gives us the precision needed for machine learning training
508540
- Single-line output per sample makes it easy to integrate with the Edge Impulse data forwarder
509541
- Comma separation follows standard CSV format that most data processing tools expect
542+
- The output format is identical regardless of which sensor is used, ensuring compatibility with Edge Impulse
510543

511-
After uploading the example sketch to the Nano R4 board, you should see this output in the Arduino IDE's Serial Monitor when data collection is active:
544+
After uploading the example sketch to the Nano R4 board, you should see output in the Arduino IDE's Serial Monitor similar to this:
512545

513546
![Example sketch output showing vibration data collection](assets/example-sketch-1.png)
514547

@@ -724,7 +757,7 @@ The complete enhanced example sketch is shown below:
724757
either an ADXL335 accelerometer or Modulino Movement and Edge Impulse
725758
machine learning model deployed on Arduino Nano R4 for predictive maintenance.
726759
727-
@version 2.0 01/06/25
760+
@version 2.1 01/06/25
728761
@author Arduino Product Experience Team
729762
*/
730763
@@ -736,7 +769,7 @@ The complete enhanced example sketch is shown below:
736769
// #define USE_MODULINO // For Modulino Movement (LSM6DSOXTR)
737770
738771
#ifdef USE_MODULINO
739-
#include <Arduino_Modulino.h>
772+
#include <Modulino.h>
740773
ModulinoMovement movement;
741774
#endif
742775
@@ -792,9 +825,14 @@ void setup() {
792825
while (!Serial);
793826
794827
#ifdef USE_MODULINO
795-
// Initialize Modulino Movement
828+
// Initialize Modulino I2C communication
796829
Modulino.begin();
797-
movement.begin();
830+
831+
// Detect and connect to movement sensor module
832+
if (!movement.begin()) {
833+
Serial.println("Failed to initialize Modulino Movement!");
834+
while (1);
835+
}
798836
799837
ei_printf("Motor Anomaly Detection System (Modulino Movement)\n");
800838
ei_printf("LSM6DSOXTR 6-axis sensor initialized\n");
@@ -860,16 +898,13 @@ void collectVibrationWindow() {
860898
float xAccel, yAccel, zAccel;
861899
862900
#ifdef USE_MODULINO
863-
// Read acceleration data from Modulino Movement
864-
if (movement.isDataReady()) {
865-
xAccel = movement.getAccelerationX();
866-
yAccel = movement.getAccelerationY();
867-
zAccel = movement.getAccelerationZ();
868-
} else {
869-
// Use last known values if data not ready
870-
sample--; // Retry this sample
871-
continue;
872-
}
901+
// Read new movement data from the sensor
902+
movement.update();
903+
904+
// Get acceleration values (already in g units)
905+
xAccel = movement.getX();
906+
yAccel = movement.getY();
907+
zAccel = movement.getZ();
873908
#endif
874909
875910
#ifdef USE_ADXL335
@@ -1034,7 +1069,7 @@ The enhanced sketch starts by selecting the appropriate sensor and including the
10341069
// #define USE_MODULINO // For Modulino Movement (LSM6DSOXTR)
10351070
10361071
#ifdef USE_MODULINO
1037-
#include <Arduino_Modulino.h>
1072+
#include <Modulino.h>
10381073
ModulinoMovement movement;
10391074
#endif
10401075
@@ -1093,16 +1128,13 @@ For the digital Modulino Movement, the system reads calibrated acceleration valu
10931128

10941129
```arduino
10951130
#ifdef USE_MODULINO
1096-
// Read acceleration data from Modulino Movement
1097-
if (movement.isDataReady()) {
1098-
xAccel = movement.getAccelerationX();
1099-
yAccel = movement.getAccelerationY();
1100-
zAccel = movement.getAccelerationZ();
1101-
} else {
1102-
// Use last known values if data not ready
1103-
sample--; // Retry this sample
1104-
continue;
1105-
}
1131+
// Read new movement data from the sensor
1132+
movement.update();
1133+
1134+
// Get acceleration values (already in g units)
1135+
xAccel = movement.getX();
1136+
yAccel = movement.getY();
1137+
zAccel = movement.getZ();
11061138
#endif
11071139
```
11081140

@@ -1140,7 +1172,7 @@ This function reads vibration data from the selected accelerometer and converts
11401172

11411173
### Machine Learning Inference Execution
11421174

1143-
The system analyzes the collected vibration data using both machine learning models to determine motor state and detect anomalies.
1175+
The system analyzes the collected vibration data using both machine learning models to determine motor state and detect anomalies. The inference process is identical regardless of which sensor you're using, as both provide the same data format to the models.
11441176

11451177
```arduino
11461178
void performInference() {
@@ -1182,7 +1214,7 @@ This function runs both models on the collected data. The classification model d
11821214

11831215
### Anomaly Detection and Alert System
11841216

1185-
The system provides feedback when it detects problems with the motor.
1217+
The system provides feedback when it detects problems with the motor, using the same alert mechanism regardless of which sensor is providing the data.
11861218

11871219
```arduino
11881220
void triggerAnomalyAlert() {
@@ -1211,7 +1243,7 @@ After uploading the enhanced sketch to the Nano R4 board, you should see the fol
12111243

12121244
![Enhanced example sketch output showing real-time anomaly detection](assets/ml-monitor-output.png)
12131245

1214-
When an anomaly is detected, the built-in LED will flash twice and the serial output will display the anomaly score above the configured threshold along with a warning message.
1246+
When an anomaly is detected, the built-in LED will flash three times and the serial output will display the anomaly score above the configured threshold along with a warning message.
12151247

12161248
### Complete Enhanced Example Sketch
12171249

@@ -1222,7 +1254,7 @@ The complete intelligent motor anomaly detection sketch can be downloaded [here]
12221254

12231255
### System Integration Considerations
12241256

1225-
When deploying the intelligent anomaly detection system in industrial environments, consider the following factors:
1257+
When deploying the intelligent anomaly detection system in industrial environments, consider the following factors based on your sensor choice:
12261258

12271259
- **Environmental Protection**: Protect the Nano R4 board and accelerometer from dust, moisture and temperature extremes using appropriate enclosures rated for the operating environment.
12281260
- **Mounting Stability**: Ensure secure mechanical mounting of both the accelerometer sensor and the Nano R4 enclosure to prevent sensor movement that could affect measurement accuracy.

0 commit comments

Comments
 (0)