Arduino nano 33 BLE gyro data acquisition

So I’m attempting to include gyro data from the IMU in the 33 BLE firmware(https://github.com/edgeimpulse/firmware-arduino-nano-33-ble-sense), most current master(e380fbfd20e560cf9bac721b4008d062fdff05a8). After data acquisition is started, it never completes and I think it is due to the firmware hanging. Below are my changes to increase the axis count to 6, and it looks like there was some preliminary effort to make this functionality available already. I converted the units to rad and not rad per sec, because rad is a valid SenML identifier, where the previous “dps” isn’t according to the validator in the firmware. Did I miss something? I’m assuming I must have.

diff --git a/src/sensors/ei_inertialsensor.cpp b/src/sensors/ei_inertialsensor.cpp
index 3695097..dc0ed50 100644
--- a/src/sensors/ei_inertialsensor.cpp
+++ b/src/sensors/ei_inertialsensor.cpp
@@ -20,6 +20,7 @@ using namespace events;
 
 /* Constant defines -------------------------------------------------------- */
 #define CONVERT_G_TO_MS2    9.80665f
+#define CONVERT_degperS_TO_radperS    0.01745329252f
 
 
 extern void ei_printf(const char *format, ...);
@@ -56,6 +57,10 @@ void ei_inertial_read_data(void)
     #if(N_AXIS_SAMPLED == 6)
     if (IMU.gyroscopeAvailable()) {
         IMU.readGyroscope(imu_data[3], imu_data[4], imu_data[5]);
+
+        imu_data[3] *= CONVERT_degperS_TO_radperS;
+        imu_data[4] *= CONVERT_degperS_TO_radperS;
+        imu_data[5] *= CONVERT_degperS_TO_radperS;
     }
     #endif
 
@@ -85,7 +90,7 @@ bool ei_inertial_setup_data_sampling(void)
     // Check available sample size before sampling for the selected frequency
     uint32_t requested_bytes = ceil((ei_config_get_config()->sample_length_ms / ei_config_get_config()->sample_interval_ms) * SIZEOF_N_AXIS_SAMPLED * 2);
     if(requested_bytes > available_bytes) {
-        ei_printf("ERR: Sample length is too long. Maximum allowed is %ims at %.1fHz.\r\n", 
+        ei_printf("ERR: Sample length is too long. Maximum allowed is %ims at %.1fHz.\r\n",
             (int)floor(available_bytes / ((SIZEOF_N_AXIS_SAMPLED * 2) / ei_config_get_config()->sample_interval_ms)),
             (1000 / ei_config_get_config()->sample_interval_ms));
         return false;
@@ -100,8 +105,8 @@ bool ei_inertial_setup_data_sampling(void)
         ei_config_get_config()->sample_interval_ms,
         // The axes which you'll use. The units field needs to comply to SenML units (see https://www.iana.org/assignments/senml/senml.xhtml)
         { { "accX", "m/s2" }, { "accY", "m/s2" }, { "accZ", "m/s2" },
-        /*{ "gyrX", "dps" }, { "gyrY", "dps" }, { "gyrZ", "dps" } */},
+          { "gyrX", "rad" }, { "gyrY", "rad" }, { "gyrZ", "rad" } },
     };
 
     return ei_sampler_start_sampling(&payload, SIZEOF_N_AXIS_SAMPLED);
-}
\ No newline at end of file
+}
diff --git a/src/sensors/ei_inertialsensor.h b/src/sensors/ei_inertialsensor.h
index db19e18..2f77b71 100644
--- a/src/sensors/ei_inertialsensor.h
+++ b/src/sensors/ei_inertialsensor.h
@@ -7,7 +7,7 @@
 
 /** Number of axis used and sample data format */
 typedef float sample_format_t;
-#define N_AXIS_SAMPLED			3
+#define N_AXIS_SAMPLED			6
 #define SIZEOF_N_AXIS_SAMPLED	(sizeof(sample_format_t) * N_AXIS_SAMPLED)
 
 
@@ -16,4 +16,4 @@ bool ei_inertial_init(void);
 bool ei_inertial_sample_start(sampler_callback callback, float sample_interval_ms);
 bool ei_inertial_setup_data_sampling(void);
 
-#endif
\ No newline at end of file
+#endif

I am aware of the data forwarder and I suppose I could write a set of scripts to use that but I would prefer to stick with the autostart and other functionality available with the standard firmware, as the task I’m trying to classify requires a bit of concentration to carry out and I’m already under a sampling time-crunch.

Hi @mabarnett0, from what I understand, in ei_inertial_sensor.cpp we have:

void ei_inertial_read_data(void)
{
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(imu_data[0], imu_data[1], imu_data[2]);

    imu_data[0] *= CONVERT_G_TO_MS2;
    imu_data[1] *= CONVERT_G_TO_MS2;
    imu_data[2] *= CONVERT_G_TO_MS2;
}

#if(N_AXIS_SAMPLED == 6)
if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(imu_data[3], imu_data[4], imu_data[5]);
}
#endif

I think the gyroscope data is supposed to be by default in degrees per sec.

I’m wondering if you try increasing #define EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME 3
to 6 in model_metadata.h to see if this would solve the problem.

Hope this helps.

Hi @mabarnett0 so I tried to make this run, and I can confirm that this is currently not supported, but our dev team confirms that this will be fixed when we release support for sensor fusion, which should be relatively soon-ish. Until then, your best bet maybe to use the data forwarder. Apologize for any inconvenience caused in the meantime. :frowning:

Hi!
As @yodaimpulse mentioned, sensor fusion will be released soon. Then you will be able to combine the sensors easily. For now, setting N_AXIS_SAMPLED to 6 and using this sensor list works (mind the extra space character after the first rad, this is needed to align the message).

        { { "accX", "m/s2" }, { "accY", "m/s2" }, { "accZ", "m/s2" },
        { "gyrX", "rad " }, { "gyrY", "rad" }, { "gyrZ", "rad" }, },
1 Like

Hello everyone, I have a question. Regarding the raw data collected on Edge Impulse, should we consider “imu_data[0]” as is, or “imu_data[0] *= CONVERT_G_TO_MS2”? Thank you very much.

Hi,
We convert accelerometer data to m/s^2 to be able to use the same accelerometers based models on all of the supported boards. In case you want to do the same, you should make sure the data in the correct format (m/s^2). This can be either done with the conversion algorithm you copied in your message (assuming the data from the sensor is represented in G. Or the IMU is able to output data in m/s^2 directly. For machine learning models in general is doesn’t matter which unit you choose, as long you use the same for collecting data and running inference.