Components and supplies
Nicla Sense ME
Apps and platforms
Edge Impulse Studio
Project description
Code
Smelly Coat
cpp
Signals a Red light or Green light if you smell
1/* Edge Impulse ingestion SDK 2 * Copyright (c) 2022 EdgeImpulse Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 * 15 */ 16 17/* Includes ---------------------------------------------------------------- */ 18#include <smelly-coat_inferencing.h> 19 #include "Nicla_System.h" 20#include "Arduino_BHY2.h" //Click here to get the library: http://librarymanager/All#Arduino_BHY2 21 22/** Struct to link sensor axis name to sensor value function */ 23typedef struct{ 24 const char *name; 25 float (*get_value)(void); 26 27}eiSensors; 28 29 30/** Number sensor axes used */ 31#define NICLA_N_SENSORS 1 32 33 34/* Private variables ------------------------------------------------------- */ 35static const bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 36 37 38Sensor gas(SENSOR_ID_GAS); 39 40static bool ei_connect_fusion_list(const char *input_list); 41static float get_gas(void){return gas.value();} 42 43static int8_t fusion_sensors[NICLA_N_SENSORS]; 44static int fusion_ix = 0; 45 46/** Used sensors value function connected to label name */ 47eiSensors nicla_sensors[] = 48{ 49 "gas", &get_gas, 50}; 51 52/** 53* @brief Arduino setup function 54*/ 55void setup() 56{ 57 /* Init serial */ 58 Serial.begin(115200); 59 // comment out the below line to cancel the wait for USB connection (needed for native USB) 60 //while (!Serial); 61 Serial.println("Edge Impulse Sensor Fusion Inference\r\n"); 62 63 /* Connect used sensors */ 64 if(ei_connect_fusion_list(EI_CLASSIFIER_FUSION_AXES_STRING) == false) { 65 ei_printf("ERR: Errors in sensor list detected\r\n"); 66 return; 67 } 68 69 /* Init & start sensors */ 70 BHY2.begin(NICLA_I2C); 71 gas.begin(); 72 73 nicla::begin(); 74 nicla::enableCharge(100); 75 nicla::leds.begin(); 76 nicla::leds.setColor(yellow); 77} 78 79/** 80* @brief Get data and run inferencing 81*/ 82void loop() 83{ 84 ei_printf("\nStarting inferencing in 2 seconds...\r\n"); 85 86 delay(2000); 87 88 if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != fusion_ix) { 89 ei_printf("ERR: Nicla sensors don't match the sensors required in the model\r\n" 90 "Following sensors are required: %s\r\n", EI_CLASSIFIER_FUSION_AXES_STRING); 91 return; 92 } 93 94 ei_printf("Sampling...\r\n"); 95 96 // Allocate a buffer here for the values we'll read from the IMU 97 float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 }; 98 99 for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME) { 100 // Determine the next tick (and then sleep later) 101 int64_t next_tick = (int64_t)micros() + ((int64_t)EI_CLASSIFIER_INTERVAL_MS * 1000); 102 103 // Update function should be continuously polled 104 BHY2.update(); 105 106 for(int i = 0; i < fusion_ix; i++) { 107 buffer[ix + i] = nicla_sensors[fusion_sensors[i]].get_value(); 108 ei_printf("Gas Sensor: %.2f\n",buffer[ix + i]); 109 } 110 111 int64_t wait_time = next_tick - (int64_t)micros(); 112 113 if(wait_time > 0) { 114 delayMicroseconds(wait_time); 115 } 116 } 117 118 // Turn the raw buffer in a signal which we can the classify 119 signal_t signal; 120 int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); 121 if (err != 0) { 122 ei_printf("ERR:(%d)\r\n", err); 123 return; 124 } 125 126 // Run the classifier 127 ei_impulse_result_t result = { 0 }; 128 129 err = run_classifier(&signal, &result, debug_nn); 130 if (err != EI_IMPULSE_OK) { 131 ei_printf("ERR:(%d)\r\n", err); 132 return; 133 } 134 135 // print the predictions 136 BHY2.update(); 137 float current = gas.value(); 138 ei_printf("Gas Sensor: %.2f\n",current); 139 ei_printf("Predictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.):\r\n", 140 result.timing.dsp, result.timing.classification, result.timing.anomaly); 141 for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 142 ei_printf("%s: %.5f\r\n", result.classification[ix].label, result.classification[ix].value); 143 } 144 if (result.classification[0].value > 0.80) { 145 nicla::leds.setColor(green); 146 } else if (result.classification[1].value > 0.80) { 147 nicla::leds.setColor(red); 148 } else { 149 nicla::leds.setColor(yellow); 150 } 151#if EI_CLASSIFIER_HAS_ANOMALY == 1 152 ei_printf(" anomaly score: %.3f\r\n", result.anomaly); 153#endif 154} 155 156#if !defined(EI_CLASSIFIER_SENSOR) || (EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_FUSION && EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER) 157#error "Invalid model for current sensor" 158#endif 159 160 161/** 162 * @brief Go through nicla sensor list to find matching axis name 163 * 164 * @param axis_name 165 * @return int8_t index in nicla sensor list, -1 if axis name is not found 166 */ 167static int8_t ei_find_axis(char *axis_name) 168{ 169 int ix; 170 for(ix = 0; ix < NICLA_N_SENSORS; ix++) { 171 if(strstr(axis_name, nicla_sensors[ix].name)) { 172 return ix; 173 } 174 } 175 return -1; 176} 177 178/** 179 * @brief Check if requested input list is valid sensor fusion, create sensor buffer 180 * 181 * @param[in] input_list Axes list to sample (ie. "accX + gyrY + magZ") 182 * @retval false if invalid sensor_list 183 */ 184static bool ei_connect_fusion_list(const char *input_list) 185{ 186 char *buff; 187 bool is_fusion = false; 188 189 /* Copy const string in heap mem */ 190 char *input_string = (char *)ei_malloc(strlen(input_list) + 1); 191 if (input_string == NULL) { 192 return false; 193 } 194 memset(input_string, 0, strlen(input_list) + 1); 195 strncpy(input_string, input_list, strlen(input_list)); 196 197 /* Clear fusion sensor list */ 198 memset(fusion_sensors, 0, NICLA_N_SENSORS); 199 fusion_ix = 0; 200 201 buff = strtok(input_string, "+"); 202 203 while (buff != NULL) { /* Run through buffer */ 204 int8_t found_axis = 0; 205 206 is_fusion = false; 207 found_axis = ei_find_axis(buff); 208 209 if(found_axis >= 0) { 210 if(fusion_ix < NICLA_N_SENSORS) { 211 fusion_sensors[fusion_ix++] = found_axis; 212 } 213 is_fusion = true; 214 } 215 216 buff = strtok(NULL, "+ "); 217 } 218 219 ei_free(input_string); 220 221 return is_fusion; 222}
Comments
Only logged in users can leave comments
robotasticdc
0 Followers
•0 Projects
+1
Work attribution
1
0
Smelling Fresh, Feeling Fresh! | Arduino Project Hub