On this Wildcard Week we need to make something new, that the plan doesn't cover in the other assignement. Definitions generated by ChatGPT.
Machine Learning (ML) is a part of AI that focus on machines learning patterns and make their own decisions without a lot of programming.
The difference with TinyML and ML is the deployment of the model on devices with limited computational resources (microcontrollers). Having limits in power, memory, processing capabilities, etc.
It is a platform to develop machine learningn models.
All the information is on the MOtion Recognition SEEED STUDIO webpage (Click Here).
Before we start with everything it is important to create an Account
on Edge Impulse (Click Here).
After having a profile we can start with training a model.
Installing Libraries
First we need the Seeed Arduino LSMDS3 Library.
After, for set the XIAO on edge impulse we need:
Edge Impulse
Create a new project on Edge Impulse and connect the XIAO into the computer.
Click on Collect New Data.
Get Data
When clicking on collect new data there are 3 available options: Scan Qr, from your computer or device/developement board.
Click on the third option.
Accelerometer data
Here we have to upload the first XIAO Code (Above) for sending the parameters we want, in this case: Acceleration (x,y,z).
The library link is on the first step (LSM6DS3).
#include "LSM6DS3.h"
#include "Wire.h"
//Create a instance of class LSM6DS3
LSM6DS3 myIMU(I2C_MODE, 0x6A); //I2C device address 0x6A
#define CONVERT_G_TO_MS2 9.80665f
#define FREQUENCY_HZ 50
#define INTERVAL_MS (1000 / (FREQUENCY_HZ + 1))
static unsigned long last_interval_ms = 0;
void setup() {
Serial.begin(115200);
while (!Serial)
;
if (myIMU.begin() != 0) {
Serial.println("Device error");
} else {
Serial.println("Device OK!");
}
}
void loop() {
if (millis() > last_interval_ms + INTERVAL_MS) {
last_interval_ms = millis();
Serial.print(myIMU.readFloatAccelX() * CONVERT_G_TO_MS2, 4);
Serial.print('\t');
Serial.print(myIMU.readFloatAccelY() * CONVERT_G_TO_MS2, 4);
Serial.print('\t');
Serial.println(myIMU.readFloatAccelZ() * CONVERT_G_TO_MS2, 4);
}
}
Send data
For sending the data to Edge impulse we need to open the terminal CLI or cmd and run:
edge-impulse-data-forwarder
Connect with Impulse
On data acquisition you can select the device (Previously named) on the right of the page.
Start Sampling
On the Record new data window we can select the device, label (name of the data), wich parameters, sample lenght (ms) and frequency.
First we will start with an Up-down motion for 20000 ms of sampling.
It will start a countdown wherw you have to make a repeatly movement (Up-down).
Split Data
After the 20 seconds a graph will be shown below, with the movement of the 3 axis.
Repeat
We will repeat the previous step for another movement (Left-right).
Perform Train
Click on Dashboard > Drop down the page click on Perform train.
Save Impulse
Navigate to Impulse Design > Add a processing block > Add Learning Block > Add Classification > Save Impulse.
Save Parameters
Click on Flatten > Scroll Down > Click on Save Parameters
Freatures
On Spectral featyres > Down on the page > Generate features
Train for Output
Click on the Classifier > Start training (Unoptimized[float32])
Model Testing
Scroll down the left bar and Click on Model training and Classify All
Arduino Library
Now we have to create and add an Arduino Library with the model.
Click Deployment > Select Arduino Library > Build
/* Includes */
#include gg_inferencing.h
#include LSM6DS3.h
#include Wire.h
/* Constant defines */
#define CONVERT_G_TO_MS2 9.80665f
#define MAX_ACCEPTED_RANGE 2.0f
/* Private variables */
static bool debug_nn = false;
LSM6DS3 myIMU(I2C_MODE, 0x6A);
const int RED_ledPin = 11;
const int BLUE_ledPin = 12;
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Edge Impulse Inferencing Demo");
//if (!IMU.begin()) {
if (!myIMU.begin()) {
ei_printf("Failed to initialize IMU!\r\n");
}
else {
ei_printf("IMU initialized\r\n");
}
if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME
should be equal to 3 (the 3 sensor axes)\n");
return;
}
}
float ei_get_sign(float number) {
return (number >= 0.0) ? 1.0 : -1.0;
}
void loop()
{
uint8_t buf2[64]="left&right";
uint8_t buf3[64]="up&down";
ei_printf("\nStarting inferencing in 2 seconds...\n");
delay(2000);
ei_printf("Sampling...\n");
// Allocate a buffer here for the values we'll read from the IMU
float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) {
// Determine the next tick (and then sleep later)
uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);
buffer[ix] = myIMU.readFloatAccelX();
buffer[ix+1] = myIMU.readFloatAccelY();
buffer[ix+2] = myIMU.readFloatAccelZ();
//buffer[ix] = myIMU.readFloatGyroX();
//buffer[ix+1] = myIMU.readFloatGyroY();
//buffer[ix+2] = myIMU.readFloatGyroZ();
for (int i = 0; i < 3; i++) {
if (fabs(buffer[ix + i]) > MAX_ACCEPTED_RANGE) {
buffer[ix + i] = ei_get_sign(buffer[ix + i])
* MAX_ACCEPTED_RANGE;
}
}
buffer[ix + 0] *= CONVERT_G_TO_MS2;
buffer[ix + 1] *= CONVERT_G_TO_MS2;
buffer[ix + 2] *= CONVERT_G_TO_MS2;
delayMicroseconds(next_tick - micros());
}
// Turn the raw buffer in a signal which we can the classify
signal_t signal;
int err = numpy::signal_from_buffer(buffer,
EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
if (err != 0) {
ei_printf("Failed to create signal from buffer (%d)\n", err);
return;
}
// Run the classifier
ei_impulse_result_t result = { 0 };
err = run_classifier(&signal, &result, debug_nn);
if (err != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", err);
return;
}
// print the predictions
ei_printf("Predictions ");
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
result.timing.dsp, result.timing.classification, result.timing.anomaly);
ei_printf(": \n");
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf("%s: %.5f\n", result.classification[ix].label,
result.classification[ix].value);
}
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf(" anomaly score: %.3f\n", result.anomaly);
#endif
if (result.classification[1].value > 0.5) {
digitalWrite(RED_ledPin, LOW);
digitalWrite(BLUE_ledPin, HIGH); // updown red
delay(2000);
}
if (result.classification[0].value > 0.5) {
digitalWrite(RED_ledPin, HIGH); //left&right blue
digitalWrite(BLUE_ledPin, LOW);
delay(2000);
}
}
After adding the code and oppening the serial monitor we got this output.