Cave exploration support using Nicla Sense ME: Arduino x Kway project
Log ambient levels and use machine learning to assist spelunkers map a cave
Components and supplies
1
Nicla Sense ME
Tools and machines
1
Android Smartphone
1
Computer
Apps and platforms
1
PlatformIO
1
Edge Impulse Studio
1
Arduino IDE 2.0 (beta)
Project description
Code
Main
cpp
Initial version has Model and BLE in the same file
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 <Arduino.h> // include if any arduino specific functions are needed 19#include <Nicla_Sense_ME_K-Way__cave_exploration_support__accelerometer__inferencing.h> 20#include "Arduino_BHY2.h" 21#include "Nicla_System.h" 22#include <ArduinoBLE.h> 23 24#define DEBUG 25 26#ifdef DEBUG 27#define log(x) Serial.print(x); 28#define logln(x) Serial.println(x); 29#else 30#define log(x) x; 31#define logln(x) x; 32#endif 33 34/* pause between cycles */ 35int const SLEEP_BETWEEN_CYCLES = 5000; 36 37/* BLE definitions */ 38#define BLE_SENSE_UUID(val) ("19b10000-" val "-537e-4f6c-d104768a1214") 39const int VERSION = 0x00000000; 40String name; // String to calculate the local and device name 41bool connected = false; 42 43 44/* Battery related definitions */ 45unsigned const BATT_CHECK_PERIOD = 30000; 46unsigned long batteryLastCheckTime; 47unsigned long co2BlinkLastCheckTime; 48uint8_t batteryValue; 49uint8_t batteryLevelRead(); 50 51 52/* Serial communication definitions */ 53const byte numChars = 32; 54char receivedChars[numChars]; 55bool newData = false; 56void checkSerialInput(); 57void processCommand(); 58 59void co2LedBlink(int co2Level); 60 61/* BLE services and characteristics */ 62BLEService service(BLE_SENSE_UUID("0000")); 63BLEUnsignedIntCharacteristic versionCharacteristic(BLE_SENSE_UUID("1001"), BLERead); 64BLEFloatCharacteristic temperatureCharacteristic(BLE_SENSE_UUID("2001"), BLERead); 65BLEUnsignedIntCharacteristic humidityCharacteristic(BLE_SENSE_UUID("3001"), BLERead); 66BLEFloatCharacteristic pressureCharacteristic(BLE_SENSE_UUID("4001"), BLERead); 67BLECharacteristic accelerometerCharacteristic(BLE_SENSE_UUID("5001"), BLERead | BLENotify, 3 * sizeof(float)); // Array of 3x 2 Bytes, XY 68BLECharacteristic gyroscopeCharacteristic(BLE_SENSE_UUID("6001"), BLERead | BLENotify, 3 * sizeof(float)); // Array of 3x 2 Bytes, XYZ 69BLECharacteristic quaternionCharacteristic(BLE_SENSE_UUID("7001"), BLERead | BLENotify, 4 * sizeof(float)); // Array of 4x 2 Bytes, XYZW 70BLEFloatCharacteristic bsecCharacteristic(BLE_SENSE_UUID("9001"), BLERead); 71BLEIntCharacteristic co2Characteristic(BLE_SENSE_UUID("9002"), BLERead); 72BLEUnsignedIntCharacteristic gasCharacteristic(BLE_SENSE_UUID("9003"), BLERead); 73BLECharacteristic rgbLedCharacteristic(BLE_SENSE_UUID("8001"), BLERead | BLEWrite, 3 * sizeof(byte)); // Array of 3 bytes, RGB 74BLEUnsignedIntCharacteristic batteryLevelCharacteristic(BLE_SENSE_UUID("1002"), BLERead | BLENotify); 75 76void blePeripheralDisconnectHandler(BLEDevice central); 77void onTemperatureCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 78void onHumidityCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 79void onPressureCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 80void onBsecCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 81void onCo2CharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 82void onGasCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 83void onRgbLedCharacteristicWrite(BLEDevice central, BLECharacteristic characteristic); 84void onBatteryLevelCharacteristicRead(BLEDevice central, BLECharacteristic characteristic); 85 86Sensor temperature(SENSOR_ID_TEMP); 87Sensor humidity(SENSOR_ID_HUM); 88Sensor pressure(SENSOR_ID_BARO); 89SensorBSEC bsec(SENSOR_ID_BSEC); 90 91 92/** ==== Trained model and inference processing ==== **/ 93 94/** Struct to link sensor axis name to sensor value function */ 95typedef struct{ 96 const char *name; 97 float (*get_value)(void); 98 99}eiSensors; 100 101/* Constant defines -------------------------------------------------------- */ 102#define CONVERT_G_TO_MS2 9.80665f 103 104/** Number sensor axes used */ 105#define NICLA_N_SENSORS 17 106 107 108/* Private variables ------------------------------------------------------- */ 109static const bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 110 111SensorXYZ accel(SENSOR_ID_ACC); 112SensorXYZ gyro(SENSOR_ID_GYRO); 113SensorOrientation ori(SENSOR_ID_ORI); 114SensorQuaternion rotation(SENSOR_ID_RV); 115Sensor temp(SENSOR_ID_TEMP); 116Sensor baro(SENSOR_ID_BARO); 117Sensor hum(SENSOR_ID_HUM); 118Sensor gas(SENSOR_ID_GAS); 119 120static bool ei_connect_fusion_list(const char *input_list); 121static float get_accX(void){return (accel.x() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 122static float get_accY(void){return (accel.y() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 123static float get_accZ(void){return (accel.z() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 124static float get_gyrX(void){return (gyro.x() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 125static float get_gyrY(void){return (gyro.y() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 126static float get_gyrZ(void){return (gyro.z() * 8.0 / 32768.0) * CONVERT_G_TO_MS2;} 127static float get_oriHeading(void){return ori.heading();} 128static float get_oriPitch(void){return ori.pitch();} 129static float get_oriRoll(void){return ori.roll();} 130static float get_rotX(void){return rotation.x();} 131static float get_rotY(void){return rotation.y();} 132static float get_rotZ(void){return rotation.z();} 133static float get_rotW(void){return rotation.w();} 134static float get_temperature(void){return temp.value();} 135static float get_barrometric_pressure(void){return baro.value();} 136static float get_humidity(void){return hum.value();} 137static float get_gas(void){return gas.value();} 138 139static int8_t fusion_sensors[NICLA_N_SENSORS]; 140static int fusion_ix = 0; 141 142/** Used sensors value function connected to label name */ 143eiSensors nicla_sensors[] = 144{ 145 "accX", &get_accX, 146 "accY", &get_accY, 147 "accZ", &get_accZ, 148 "gyrX", &get_gyrX, 149 "gyrY", &get_gyrY, 150 "gyrZ", &get_gyrZ, 151 "heading", &get_oriHeading, 152 "pitch", &get_oriPitch, 153 "roll", &get_oriRoll, 154 "rotX", &get_rotX, 155 "rotY", &get_rotY, 156 "rotZ", &get_rotZ, 157 "rotW", &get_rotW, 158 "temperature", &get_temperature, 159 "barometer", &get_barrometric_pressure, 160 "humidity", &get_humidity, 161 "gas", &get_gas, 162}; 163 164/** 165* @brief Arduino setup function 166*/ 167void setup() 168{ 169 nicla::begin(); 170 nicla::leds.begin(); 171 nicla::leds.setColor(green); 172 nicla::enableCharge(50); 173 batteryLastCheckTime = millis(); 174 co2BlinkLastCheckTime = millis(); 175 176 /* Init serial */ 177 Serial.begin(115200); 178 Serial.println("Start"); 179 180 if (!BLE.begin()){ 181 Serial.println("Failed to initialized BLE!"); 182 while (1); 183 } 184 185 String address = BLE.address(); 186 187 Serial.print("address = "); 188 Serial.println(address); 189 190 address.toUpperCase(); 191 192 name = "NiclaSenseME-"; 193 name += address[address.length() - 5]; 194 name += address[address.length() - 4]; 195 name += address[address.length() - 2]; 196 name += address[address.length() - 1]; 197 198 Serial.print("name = "); 199 Serial.println(name); 200 201 int BatteryStatusValue = BQ25120A().getStatus(); 202 Serial.print("Battery status (1-5): "); 203 Serial.println(BatteryStatusValue); 204 205 BLE.setLocalName(name.c_str()); 206 BLE.setDeviceName(name.c_str()); 207 BLE.setAdvertisedService(service); 208 209 // Add all the previously defined Characteristics 210 service.addCharacteristic(temperatureCharacteristic); 211 service.addCharacteristic(humidityCharacteristic); 212 service.addCharacteristic(pressureCharacteristic); 213 service.addCharacteristic(versionCharacteristic); 214 service.addCharacteristic(accelerometerCharacteristic); 215 service.addCharacteristic(gyroscopeCharacteristic); 216 service.addCharacteristic(quaternionCharacteristic); 217 service.addCharacteristic(bsecCharacteristic); 218 service.addCharacteristic(co2Characteristic); 219 service.addCharacteristic(gasCharacteristic); 220 service.addCharacteristic(rgbLedCharacteristic); 221 service.addCharacteristic(batteryLevelCharacteristic); 222 223 // Disconnect event handler 224 BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); 225 226 // Sensors event handlers 227 temperatureCharacteristic.setEventHandler(BLERead, onTemperatureCharacteristicRead); 228 humidityCharacteristic.setEventHandler(BLERead, onHumidityCharacteristicRead); 229 pressureCharacteristic.setEventHandler(BLERead, onPressureCharacteristicRead); 230 bsecCharacteristic.setEventHandler(BLERead, onBsecCharacteristicRead); 231 co2Characteristic.setEventHandler(BLERead, onCo2CharacteristicRead); 232 gasCharacteristic.setEventHandler(BLERead, onGasCharacteristicRead); 233 rgbLedCharacteristic.setEventHandler(BLEWritten, onRgbLedCharacteristicWrite); 234 versionCharacteristic.setValue(VERSION); 235 batteryLevelCharacteristic.setEventHandler(BLERead, onBatteryLevelCharacteristicRead); 236 237 BLE.addService(service); 238 BLE.advertise(); 239 240 // comment out the below line to cancel the wait for USB connection (needed for native USB) 241 while (!Serial); 242 Serial.println("Edge Impulse Sensor Fusion Inference\r\n"); 243 244 /* Connect used sensors */ 245 if(ei_connect_fusion_list(EI_CLASSIFIER_FUSION_AXES_STRING) == false) { 246 ei_printf("ERR: Errors in sensor list detected\r\n"); 247 return; 248 } 249 250 /* Init & start sensors */ 251 BHY2.begin(NICLA_STANDALONE); 252 accel.begin(); 253 gyro.begin(); 254 ori.begin(); 255 rotation.begin(); 256 temp.begin(); 257 baro.begin(); 258 hum.begin(); 259 gas.begin(); 260 bsec.begin(); 261} 262 263/** 264* @brief Get data and run inferencing 265*/ 266void loop() 267{ 268 BHY2.update(); 269 connected = BLE.connected(); 270 271 if (connected){ 272 BHY2.update(); 273 274 275 if (accelerometerCharacteristic.subscribed()){ 276 float x, y, z; 277 x = accel.x(); 278 y = accel.y(); 279 z = accel.z(); 280 float accelerometerValues[] = {x, y, z}; 281 accelerometerCharacteristic.writeValue(accelerometerValues, sizeof(accelerometerValues)); 282 } 283 284 285 if (gyroscopeCharacteristic.subscribed()){ 286 float x, y, z; 287 288 x = gyro.x(); 289 y = gyro.y(); 290 z = gyro.z(); 291 float gyroscopeValues[3] = {x, y, z}; 292 gyroscopeCharacteristic.writeValue(gyroscopeValues, sizeof(gyroscopeValues)); 293 } 294 295 296 if (quaternionCharacteristic.subscribed()){ 297 float x, y, z, w; 298 x = rotation.x(); 299 y = rotation.y(); 300 z = rotation.z(); 301 w = rotation.w(); 302 float quaternionValues[] = {x,y,z,w}; 303 quaternionCharacteristic.writeValue(quaternionValues, sizeof(quaternionValues)); 304 } 305 306 307 ei_printf("\nStarting inferencing in %d seconds...\r\n", int(SLEEP_BETWEEN_CYCLES/1000)); 308 309 delay(SLEEP_BETWEEN_CYCLES); 310 311 if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != fusion_ix) { 312 ei_printf("ERR: Nicla sensors don't match the sensors required in the model\r\n" 313 "Following sensors are required: %s\r\n", EI_CLASSIFIER_FUSION_AXES_STRING); 314 return; 315 } 316 317 ei_printf("Sampling...\r\n"); 318 319 // Allocate a buffer here for the values we'll read from the IMU 320 float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 }; 321 322 for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME) { 323 // Determine the next tick (and then sleep later) 324 int64_t next_tick = (int64_t)micros() + ((int64_t)EI_CLASSIFIER_INTERVAL_MS * 1000); 325 326 // Update function should be continuously polled 327 BHY2.update(); 328 329 for(int i = 0; i < fusion_ix; i++) { 330 buffer[ix + i] = nicla_sensors[fusion_sensors[i]].get_value(); 331 } 332 333 int64_t wait_time = next_tick - (int64_t)micros(); 334 335 if(wait_time > 0) { 336 delayMicroseconds(wait_time); 337 } 338 } 339 340 // Turn the raw buffer in a signal which we can the classify 341 signal_t signal; 342 int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); 343 if (err != 0) { 344 ei_printf("ERR:(%d)\r\n", err); 345 return; 346 } 347 348 // Run the classifier 349 ei_impulse_result_t result = { 0 }; 350 351 err = run_classifier(&signal, &result, debug_nn); 352 if (err != EI_IMPULSE_OK) { 353 ei_printf("ERR:(%d)\r\n", err); 354 return; 355 } 356 357 // print the predictions 358 ei_printf("Predictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.):\r\n", 359 result.timing.dsp, result.timing.classification, result.timing.anomaly); 360 for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 361 ei_printf("%s: %.5f\r\n", result.classification[ix].label, result.classification[ix].value); 362 } // TODO: create and treat the classification as a characteristic, for BLE 363 364 #if EI_CLASSIFIER_HAS_ANOMALY == 1 365 ei_printf(" anomaly score: %.3f\r\n", result.anomaly); 366 #endif 367 368 369 } // end of BLE connected block 370 371 if (millis() - co2BlinkLastCheckTime >= 5000){ 372 co2LedBlink(bsec.co2_eq()); 373 co2BlinkLastCheckTime = millis(); 374 } 375 // Check and send to serial battery level (not directly %) 376 if (millis()-batteryLastCheckTime >= BATT_CHECK_PERIOD){ 377 batteryLevelRead(); 378 batteryLastCheckTime = millis(); 379 } 380 381 checkSerialInput(); 382 if (newData){ 383 processCommand(); 384 } 385 386} // end loop 387 388#if !defined(EI_CLASSIFIER_SENSOR) || (EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_FUSION && EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER) 389#error "Invalid model for current sensor" 390#endif 391 392 393/** 394 * @brief Go through nicla sensor list to find matching axis name 395 * 396 * @param axis_name 397 * @return int8_t index in nicla sensor list, -1 if axis name is not found 398 */ 399static int8_t ei_find_axis(char *axis_name) 400{ 401 int ix; 402 for(ix = 0; ix < NICLA_N_SENSORS; ix++) { 403 if(strstr(axis_name, nicla_sensors[ix].name)) { 404 return ix; 405 } 406 } 407 return -1; 408} 409 410/** 411 * @brief Check if requested input list is valid sensor fusion, create sensor buffer 412 * 413 * @param[in] input_list Axes list to sample (ie. "accX + gyrY + magZ") 414 * @retval false if invalid sensor_list 415 */ 416static bool ei_connect_fusion_list(const char *input_list) 417{ 418 char *buff; 419 bool is_fusion = false; 420 421 /* Copy const string in heap mem */ 422 char *input_string = (char *)ei_malloc(strlen(input_list) + 1); 423 if (input_string == NULL) { 424 return false; 425 } 426 memset(input_string, 0, strlen(input_list) + 1); 427 strncpy(input_string, input_list, strlen(input_list)); 428 429 /* Clear fusion sensor list */ 430 memset(fusion_sensors, 0, NICLA_N_SENSORS); 431 fusion_ix = 0; 432 433 buff = strtok(input_string, "+"); 434 435 while (buff != NULL) { /* Run through buffer */ 436 int8_t found_axis = 0; 437 438 is_fusion = false; 439 found_axis = ei_find_axis(buff); 440 441 if(found_axis >= 0) { 442 if(fusion_ix < NICLA_N_SENSORS) { 443 fusion_sensors[fusion_ix++] = found_axis; 444 } 445 is_fusion = true; 446 } 447 448 buff = strtok(NULL, "+ "); 449 } 450 451 ei_free(input_string); 452 453 return is_fusion; 454} 455/* end inference/fusion process */ 456 457 458void onTemperatureCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 459 float temperatureValue = temp.value(); 460 temperatureCharacteristic.writeValue(temperatureValue); 461} 462 463void onHumidityCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 464 uint8_t humidityValue = hum.value() + 0.5f; //since we are truncating the float type to a uint8_t, we want to round it 465 humidityCharacteristic.writeValue(humidityValue); 466} 467 468void onPressureCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 469 float pressureValue = baro.value(); 470 pressureCharacteristic.writeValue(pressureValue); 471} 472 473void onBsecCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 474 float airQuality = float(bsec.iaq()); 475 bsecCharacteristic.writeValue(airQuality); 476} 477 478void onCo2CharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 479 uint32_t co2 = bsec.co2_eq(); 480 co2Characteristic.writeValue(co2); 481} 482 483void onGasCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 484 unsigned int g = gas.value(); 485 gasCharacteristic.writeValue(g); 486} 487 488void onRgbLedCharacteristicWrite(BLEDevice central, BLECharacteristic characteristic){ 489 byte r = rgbLedCharacteristic[0]; 490 byte g = rgbLedCharacteristic[1]; 491 byte b = rgbLedCharacteristic[2]; 492 nicla::leds.setColor(r, g, b); 493} 494 495void blePeripheralDisconnectHandler(BLEDevice central){ 496 nicla::leds.setColor(red); 497} 498 499// FIXME: Recheck why the client reads "notification and indications disabled", instead of value 500void onBatteryLevelCharacteristicRead(BLEDevice central, BLECharacteristic characteristic){ 501 uint8_t BattLevel = batteryLevelRead(); 502 batteryLevelCharacteristic.writeValue(BattLevel); 503} 504 505 506uint8_t batteryLevelRead(){ 507 batteryValue = BQ25120A().readByte(BQ25120A_ADDRESS, BQ25120A_BATT_MON); 508 log("Battery value: "); 509 logln(batteryValue); 510 uint8_t batteryStatus = nicla::getBatteryStatus(); 511 Serial.print("nicla::getBatteryStatus: "); 512 Serial.println(batteryStatus); 513 return batteryStatus; 514} 515 516void co2LedBlink(int co2Level){ 517 int pauseON = 400; 518 int pauseOFF = 250; 519 RGBColors color; 520 Serial.print("CO2 value: "); 521 Serial.println(co2Level); 522 523 if (co2Level >= 25000) 524 { 525 // nicla::leds.setColor(red); // No blink ! or maybe as fast blinking and staying on 526 color = red; 527 pauseON = 600; 528 pauseOFF = 150; 529 } 530 else if (co2Level >= 15000) 531 { 532 color = blue; 533 } 534 else if (co2Level >= 10000) 535 { 536 color = cyan; 537 } 538 else if (co2Level >= 5000) 539 { 540 color = yellow; 541 } 542 else 543 { 544 color = green; 545 } 546 547 nicla::leds.setColor(color); 548 delay(pauseON); 549 nicla::leds.setColor(off); 550 delay(pauseOFF); 551 nicla::leds.setColor(color); 552 delay(pauseON); 553 nicla::leds.setColor(off); 554} 555 556void checkSerialInput() { 557 static byte ndx = 0; 558 char endMarker = '\n'; 559 char rc; 560 561 while (Serial.available() > 0 && newData == false) { 562 rc = Serial.read(); 563 564 if (rc != endMarker) { 565 receivedChars[ndx] = rc; 566 ndx++; 567 if (ndx >= numChars) { 568 ndx = numChars - 1; 569 } 570 } 571 else { 572 receivedChars[ndx] = '\0'; // terminate the string 573 ndx = 0; 574 newData = true; 575 } 576 } 577} 578 579void processCommand(){ 580 int time_before_shutdown = 30; // in seconds 581 Serial.print("Command: "); 582 Serial.println(receivedChars); 583 //if ("shutdown" == receivedChars){ 584 if (strcmp("shutdown", receivedChars) == 0){ 585 Serial.print("Entering low power mode in "); 586 Serial.print(time_before_shutdown); 587 Serial.println(" seconds."); 588 Serial.println("please disconnect cable."); 589 delay(time_before_shutdown * 1000); 590 nicla::enterShipMode(); 591 } 592 else { 593 Serial.println("Unkown command."); 594 } 595 newData = false; 596} 597/* EOF */
model header
cpp
From Edge Impulse model
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#ifndef _INFERENCE_H 18#define _INFERENCE_H 19 20// Undefine min/max macros as these conflict with C++ std min/max functions 21// these are often included by Arduino cores 22#include <Arduino.h> 23#include <stdarg.h> 24#ifdef min 25#undef min 26#endif // min 27#ifdef max 28#undef max 29#endif // max 30#ifdef round 31#undef round 32#endif // round 33// Similar the ESP32 seems to define this, which is also used as an enum value in TFLite 34#ifdef DEFAULT 35#undef DEFAULT 36#endif // DEFAULT 37// Infineon core defines this, conflicts with CMSIS/DSP/Include/dsp/controller_functions.h 38#ifdef A0 39#undef A0 40#endif // A0 41#ifdef A1 42#undef A1 43#endif // A1 44#ifdef A2 45#undef A2 46#endif // A2 47 48/* Includes ---------------------------------------------------------------- */ 49#include "edge-impulse-sdk/classifier/ei_run_classifier.h" 50#include "edge-impulse-sdk/dsp/numpy.hpp" 51#include "model-parameters/model_metadata.h" 52#include "edge-impulse-sdk/classifier/ei_classifier_smooth.h" 53 54extern void ei_printf(const char *format, ...); 55 56#endif // _INFERENCE_H
Documentation
Nicla Sense ME cheat sheet
For more details on the board and functions
https://docs.arduino.cc/tutorials/nicla-sense-me/cheat-sheet
Nicla Sense ME datasheet
Technical specs
https://docs.arduino.cc/static/1039aadab8f0d31540011aa2b0a9bbdc/ABX00050-datasheet.pdf
Comments
Only logged in users can leave comments