Not able to deploy model to Raspberry Pi Pico

Question/Issue: Not able to deploy model to Raspberry Pi Pico

Project ID: 135755

Context/Use case: I have built a model using custom DSP block and I tried to deploy it to Raspberry Pi pico using the C++ library. After following all the steps mentioned in the documentation, that is dragging and dropping the pico_standalone.uf2 file created in the build folder to the USB mass storage, when I run the command edge-impulse-run-impulse --raw, I get the following error:

I have tried a lot of things and seen that other code like printing “Hello World” works, which means that the Raspberry Pi pico is working. Please help me understand where I am going wrong.

Hi @sayani,

Is it possible to share your custom DSP block C++ implementation or even better your full firmware including the custom DSP block? If not it would be great to see how you’re calling your custom block in the firmware.

Aurelien

Yes sure. This is the main.cpp file. The same code is running fine on ESP32 which I have built using the instructions for the same.

int extract_ecg_analysis_features(signal_t *signal, matrix_t *output_matrix, void *config_ptr, const float frequency){
    // Implement the DSP block
    ei_dsp_config_ecg_analysis_t config = *((ei_dsp_config_ecg_analysis_t*)config_ptr);
    int ret;


    const float sampling_freq = frequency;
    matrix_t input_matrix(signal->total_length/config.axes, config.axes);

    if(!input_matrix.buffer){
        EIDSP_ERR(EIDSP_OUT_OF_MEM);
    }

    signal->get_data(0, signal->total_length, input_matrix.buffer);

    // transpose the matrix so we have one row per axis (nifty!)
    ret = numpy::transpose(&input_matrix);
    if (ret != EIDSP_OK) {
        ei_printf("ERR: Failed to transpose matrix (%d)\n", ret);
        EIDSP_ERR(ret);
    }
    // Applying the butterworth high pass filter to the signal
    ret = spectral::processing::butterworth_highpass_filter(&input_matrix, sampling_freq, 20, 1);
    if(ret != EIDSP_OK){
        ei_printf("ERR: Failed to filter the frequency (%d)\n", ret);
        EIDSP_ERR(ret);
    }
    //ei_printf("\nAfter filtering:(%f)", input_matrix.buffer[10]);
    

    // Printing the size of the input_matrix
    //ei_printf("\nThe size of the signal matrix is (%zu),",signal->total_length);
    //ei_printf("\nThe size of the input_matrix is ((%zu), (%zu))", input_matrix.rows, input_matrix.cols);


    // Calculate the RR intervals and the heart rates
    matrix_t mean_matrix(1,1);
    matrix_t std_matrix(1,1);

    numpy::mean(&input_matrix, &mean_matrix);
    numpy::stdev(&input_matrix, &std_matrix);


    //ei_printf("\nThe mean is (%f)", mean_matrix.buffer[0]);
    //ei_printf("\nThe std deviation is (%f)", std_matrix.buffer[0]);
    //ei_printf("\nThe first element is (%f)", input_matrix.buffer[0]);

    float thres = mean_matrix.buffer[0]+ 2*(std_matrix.buffer[0]);
    //ei_printf("Threshold :(%f)", thres);
    matrix_t overThres(input_matrix.rows, input_matrix.cols);
    for(size_t row = 0; row < input_matrix.rows; row++){
        for(size_t col = 0; col < input_matrix.cols; col++){
            overThres.buffer[(row*input_matrix.cols)+col]=(1*(input_matrix.buffer[(row*input_matrix.cols)+col]>thres));
        }
    }

    //ei_printf("\nThe size of the overThres:(%zu)", overThres.cols);

    matrix_t changes(1,input_matrix.cols-2);
    for(size_t col = 0; col < changes.cols; col++){
            changes.buffer[col]=overThres.buffer[col+2]-overThres.buffer[col+1];
    }

    
    matrix_t ndx(1, changes.cols/2);
    int count = 0;
    for(size_t col = 0; col < changes.cols; col++){
        if(changes.buffer[col]>0){
            ndx.buffer[count] = col+2;
            count++; 
        }
        if(count>changes.cols/2)
        break;
    }

    size_t ndxlen = count;

    matrix_t RRIntervals(1, (ndxlen)/2);
    RRIntervals.buffer[0] = 0.0f;
    for(size_t col = 0; col < RRIntervals.cols; col++){
        RRIntervals.buffer[col] = ndx.buffer[col+2]-ndx.buffer[col+1];
    }

    
    float sum1 = 0.0f;
    for(size_t col = 0; col < RRIntervals.cols; col++){
        sum1+=RRIntervals.buffer[col];
    }
    float AmeanRR = sum1/RRIntervals.cols;
    for(size_t col=0; col < RRIntervals.cols; col++){
        if(RRIntervals.buffer[col]>(AmeanRR+(AmeanRR/3)))
        RRIntervals.buffer[col]=AmeanRR;
        if(RRIntervals.buffer[col]<(AmeanRR-(AmeanRR/3)))
        RRIntervals.buffer[col]=AmeanRR;
    }
    output_matrix->cols = 150;
    output_matrix->rows = 1;

    for(size_t col = 0; col < 150; col++){
        output_matrix->buffer[col] = RRIntervals.buffer[col];
    }
    
   
    return EIDSP_OK;

}

int raw_feature_get_data(size_t offset, size_t length, float *out_ptr)
{
  memcpy(out_ptr, features + offset, length * sizeof(float));
  return 0;
}

int main()
{
  stdio_usb_init();

  gpio_init(LED_PIN);
  gpio_set_dir(LED_PIN, GPIO_OUT);

  ei_impulse_result_t result = {nullptr};

  while (true)
  {
    ei_printf("Edge Impulse standalone inferencing (Raspberry Pi Pico)\n");

    if (sizeof(features) / sizeof(float) != EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE)
    {
      ei_printf("The size of your 'features' array is not correct. Expected %d items, but had %u\n",
                EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, sizeof(features) / sizeof(float));
      return 1;
    }

    while (1)
    {
      // blink LED
      gpio_put(LED_PIN, !gpio_get(LED_PIN));

      // the features are stored into flash, and we don't want to load everything into RAM
      signal_t features_signal;
      features_signal.total_length = sizeof(features) / sizeof(features[0]);
      features_signal.get_data = &raw_feature_get_data;

      // invoke the impulse
      EI_IMPULSE_ERROR res = run_classifier(&features_signal, &result, false);

      ei_printf("run_classifier returned: %d\n", res);

      if (res != 0)
        return 1;

      ei_printf("Predictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n",
                result.timing.dsp, result.timing.classification, result.timing.anomaly);

      // print the predictions
      ei_printf("[");
      for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++)
      {
        ei_printf("%.5f", result.classification[ix].value);
#if EI_CLASSIFIER_HAS_ANOMALY == 1
        ei_printf(", ");
#else
        if (ix != EI_CLASSIFIER_LABEL_COUNT - 1)
        {
          ei_printf(", ");
        }
#endif
      }
#if EI_CLASSIFIER_HAS_ANOMALY == 1
      printf("%.3f", result.anomaly);
#endif
      printf("]\n");

      ei_sleep(2000);
    }
  }
}

Also as to the steps I have followed:

  1. Created the C++ library
  2. Cloned the standalone-inferencing-pico from Edge Impulse Github
  3. Copied the directories from the C++ library to the above standalone-inferencing-pico
  4. set pico-SDK path
  5. Created the build directory and ran the commands cmake … and make -j4
  6. Mounted the Raspberry pi pico in mass storage
  7. Copied the pico-standalone.uf2 file to the RP1 RP2
    But then Pico boots and when I run edge-impulse-run-impulse --raw, I get the output as shown above.
    i have no idea why this happens. Could you please help me with the correct steps if these are wrong?

Hi Sayani

Try to connect to the device over the serial port using screen if you are on Linux and run AT+HELP to see if this runs.
If you can run any AT command there, you have flashed your device correctly.
Here is a list of AT commands

I reduced the complexity of my model by decreasing some of the steps and it worked. Why is that so?

Just my guess, but if reducing the complexity of the model helps, then I guess probably the old model was using up too much RAM on the Pico, which stalls the program execution and makes the Pico not answering anymore via serial.