Altered accelerometer arduino script seems to get stuck/glitch the COM port

Hi,

I am trying to deploy a model with an arduino Nano 33 BLE Sense, and the example using the build in accelerometer works. Also the binary deployed version for the board works.
But I tried to alter the example script in such a way that all the info of my 3 extra IMUs (acc, gyro and orientation) (using a muliplexer) is also working in the “deployed” script.

I was able to gather all the 33 axis data, but my version of the example script seems to have a bug, it would be greatly appreciated if someone can look into this and give me some pointers! In all honesty: altough the example is well documented, I do not exactly know how the library handles all the data.

//altered from:
/* Edge Impulse Arduino examples
 * Copyright (c) 2020 EdgeImpulse Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// Includes ----------------------------------------------------------------
#include <adice-project-33-axis_v2_inference.h>
#include <Arduino_LSM9DS1.h>

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>

// Constant defines --------------------------------------------------------
#define CONVERT_G_TO_MS2    9.80665f
#define CONVERT_degperS_TO_radperS    0.01745329252f

  
Adafruit_BNO055 bno = Adafruit_BNO055(55);
 
#define TCAADDR 0x70

// Private variables -------------------------------------------------------
static bool debug_nn = true; // Set this to true to see e.g. features generated from the raw signal

const uint8_t TCA_ports[] = {1,2,5};    // define TCA ports that are used
// Ports 4 and 6 seemingly don't work
const uint8_t number_of_IMUs = 3;       // define how many IMU's are used
 
void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}


// Arduino setup function

void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
    Serial.println("Edge Impulse Inferencing Demo");

    if (!IMU.begin()) {
        ei_printf("Failed to initialize IMU on Arduino Nano 33 BLE Sense!\r\n");
    }
    else {
        ei_printf("IMU on Arduino Nano 33 BLE Sense initialized\r\n");
    }

    if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 33) {
        ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 33 (the 33 sensor axes)\n");
        return;
    }
    
    for(uint8_t i=0; i<=number_of_IMUs-1; i++) {
      tcaselect(TCA_ports[i]);
      Serial.begin(9600);
      // Initialise the sensor
      bno.begin();
      /*
      if(!bno.begin())
      {
        // There was a problem detecting the BNO055 ... check your connections
        Serial.print("IMU ");Serial.print(i+1);Serial.print(" not detected... Check wiring or I2C ADDR!");
        while(1);
      }
      */
      
      bno.setExtCrystalUse(true);
    }
}

/**
* @brief      Printf function uses vsnprintf and output using Arduino Serial
*
* @param[in]  format     Variable argument list
*/

// Here, the ei_printf function of edge impulse is defined
void ei_printf(const char *format, ...) {
   static char print_buf[1024] = { 0 };

   va_list args;
   va_start(args, format);
   int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
   va_end(args);

   if (r > 0) {
       Serial.write(print_buf);
   }
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
    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 += 33) {  //unsure about the 33 here
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

        // Reading Nano on-board IMU accelerometer
        IMU.readAcceleration(buffer[ix], buffer[ix + 1], buffer[ix + 2]);

        // Converting to m/s^2
        buffer[ix + 0] *= CONVERT_G_TO_MS2;
        buffer[ix + 1] *= CONVERT_G_TO_MS2;
        buffer[ix + 2] *= CONVERT_G_TO_MS2;
        
        // Reading Nano on-board IMU gyroscope
        IMU.readGyroscope(buffer[ix + 3], buffer[ix + 4], buffer[ix + 5]);

        // Converting to rad/s
        buffer[ix + 3] *= CONVERT_degperS_TO_radperS;
        buffer[ix + 4] *= CONVERT_degperS_TO_radperS;
        buffer[ix + 5] *= CONVERT_degperS_TO_radperS;


        //read other IMUS
        sensors_event_t event;
        for(uint8_t i=0; i<=number_of_IMUs-1; i++) {
          // Switching between TCA ports to read out each sensor
          tcaselect(TCA_ports[i]);
          
          // Reading orientation data from sensor and append in buffer
          bno.getEvent(&event);
          buffer[ix + 9*i + 6] = event.orientation.x;
          buffer[ix + 9*i + 7] = event.orientation.y;
          buffer[ix + 9*i + 8] = event.orientation.z;

          // Reading accelerometer data from sensor and append in buffer
          imu::Vector<3> acceleration = bno.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER);
          buffer[ix + 9*i + 9] = acceleration.x();
          buffer[ix + 9*i + 10] =acceleration.y();
          buffer[ix + 9*i + 11] =acceleration.z();
         

          // Reading accelerometer data from sensor and append in buffer
          imu::Vector<3> ang_velocity = bno.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
          buffer[ix + 9*i + 12] =ang_velocity.x();
          buffer[ix + 9*i + 13] =ang_velocity.y();
          buffer[ix + 9*i + 14] =ang_velocity.z();
        }

        // Wait before taking next sample
        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);
    // Check if buffer has correct dimensions and is classifiable
    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 (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n",
        result.timing.dsp, result.timing.classification, result.timing.anomaly);  // print clasification and anomaly rating
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        ei_printf("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); // print
    }

// Anomaly detection
#if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf("    anomaly score: %.3f\n", result.anomaly);
#endif
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
#error "Invalid model for current sensor"
#endif

When I try to compile the script it takes about 10 min, and it does compile correctly and is able to upload to the board, but from that moment onwards the serial monitor within Arduino cannot be opened. If the serial window is opened whilst resetting the board it only gives:

Greetings,
Rick

Hi Rick,

Could you confirm your project ID is 8430?

I noticed you have a DSP block with only accelerometer data enabled (12 axis).
If you have trained and deployed with this model, you should only fill the buffer with acc values and change your for loop with ix += 12). You can do a quick check in your Arduino library and look for the EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME value in the model_metadata.h file.

Aurelien

1 Like

Hi Aurel,

Indeed that is my project ID, I see you are now also a collaborator.
I was under the impression one should still forward all the data, but it indeed makes more sense to just use the acc values here as that are the only ones I use for the NN indeed.
Indeed EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME = 12.
I changed the script and am uploading it now, will keep you posted!

Rick

1 Like

@Rick1 yeah to get an idea of what the network expects look at Live classification under ‘Raw features’.

This is an array with the exact shape that the run_classifier function expects.