LSM6DSO: Error in Samplingrate and Data lost between the reading

Hello,
I am a Mechanical Engineering Student writing Thesis on Vibration Analysis of a Robot in a company.
I ordered 3 LSM6DSO to measure the vibration of an Cartesian Robot. The sensor is read by the ESP32 and send it on my computer through Wifi. I first tried with I2C communication with the Code below:

#include <Wire.h>
#include <LSM6.h>
#include <WiFi.h>

const char* ssid = " ";
const char* password = "";

WiFiServer server(8686);

IPAddress local_IP(10, 45, 10, 4);
IPAddress gateway(0, 0, 0, 0);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);
IPAddress secondaryDNS(8, 8, 4, 4);

unsigned long PreviousTime_acc = 0;

unsigned long AccDelay = 30;

LSM6 imu;

// Calibration values for the accelerometer
const float x_offset = 0.00;
const float y_offset = 0.00;
const float z_offset = 0.00;

// Conversion factor from raw sensor values to g units
const float conversion_factor = 0.061 / 1000.0;  //For +-2G

//const float conversion_factor = 0.122 / 1000.0;                       //For +- 4G : Roboter_acc = 2 m/s/s i.e großer als 2g so 4G ist besser
// const float conversion_factor = 0.488 / 1000.0;                      // For +-6G

void setup() {
  Serial.begin(9600);

  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("STA Failed to configure");
  }

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();

  Wire.begin();

  if (!imu.init()) {
    Serial.println("Failed to detect and initialize IMU!");
    while (1)
      ;
  }
  imu.enableDefault();
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New client connected!"); 
    while (client.connected()) {
      imu.read();
      if ((millis() - PreviousTime_acc) >= AccDelay) {


        float x = (imu.a.x * conversion_factor) - x_offset;
        float y = (imu.a.y * conversion_factor) - y_offset;
        float z = (imu.a.z * conversion_factor) - z_offset;

        String report = String(millis()) + "," + String(x, 2) + "," + String(y, 2) + "," + String(z, 2) + ";\n";
        PreviousTime_acc = millis();

        Serial.print(report);
        client.print(report);
      }
    }
    Serial.println("Client disconnected!");
    client.stop();
  }
}

The Problem with I2C communication i am facing is that the data i m getting is not in every 30ms rather in 31ms sometimes. The data as Example looks like this: (millis(Timestamp), x,z, y)
8439 -0.00,-2.00,-0.02;
8469 -0.00,-1.98,-0.00; dt: 30 ms
8500 -0.00,-1.99,-0.01; dt: 31 ms
Similarly using SPI, it has better results but when i try to use in 100 hz or to say trigger read data in less than 30 ms, the data is lost in between. (Reading in 10ms)
232851 0.01,0.02,-0.98;
232861 0.01,0.02,-0.98; dt= 10ms
232985 0.03,0.02,-0.98; dt= 125ms
232995 0.03,0.02,-0.98; st = 10 ms
I dont know if the problem is with the type of communication i am using or i should consider other thing. The Datasheet says that it can read upto 6666hz. Thank you.

Hello,

What is your goal in improving the regularity of your readings? Do you need a certain amount of precision for your application or are you mainly just wondering why it isn’t better?

In general, some amount of jitter in the timing should be expected, but there are several things you could do to improve your code. Probably the biggest issue is that you are calling imu.read() in the top level of your while loop; at the default I2C frequency, it takes nearly 2 ms to get a set of readings from the LSM6, so reading it every time through that loop means that you are checking the elapsed time too infrequently. Since you’re not doing anything with most of those readings anyway, a better solution would be to only read the IMU if the time check indicates it’s time to send another report (inside the if block).

Another minor optimization you could make is to call millis() just once every loop, which could help minimize timing drift if your loop takes a significant amount of time to run. So with both of those changes, your while loop could look like this:

    while (client.connected()) {
      unsigned long time = millis();
      if ((time - PreviousTime_acc) >= AccDelay) {
        imu.read();

        float x = (imu.a.x * conversion_factor) - x_offset;
        float y = (imu.a.y * conversion_factor) - y_offset;
        float z = (imu.a.z * conversion_factor) - z_offset;

        String report = String(time) + "," + String(x, 2) + "," + String(y, 2) + "," + String(z, 2) + ";\n";
        PreviousTime_acc = time;

        Serial.print(report);
        client.print(report);
      }
    }

I am not so sure why your SPI code is sometimes giving you a dt of much greater than 10 ms, but part of the reason could be that the ESP32 is handling other tasks in the background that it periodically needs to service (like wireless communication). Your Serial baud rate could also be a bottleneck if you’re trying to output data at 100 Hz; does it get better if you change 9600 to 115200?

Kevin

Hello,
Thank you so much for reaching out my post and helping me. The propose of getting precision in Sampling rate is to do the Vibration Analysis of the cartesian Robot. I am doing my Bachelor Thesis in this. I am from mechanical Background and trying to develop a System to determine the Resonance and Maybe try to develop Feedback system. I am planning to do Fast Fourier Analysis. The Problem i am getting is also the noise. But i am trying to solve it.
The solution you provided helped me like a magic. It worked well now for both I2C and SPI communication. However for SPI communication, i used Adafruit 3rd Party library but it worked well. If you have any post, Blogs, or any things,that would help my Research, i would be really grateful.
Thank you and have a great time.
Best Regards,
Bijay Basnet

Hello,
I am again here for the little help with my LSM6DSO Sensor.
I am experiencing noise in the data so i wanted to use the inbuild Filter function.
i Wanted to do vibration analysis using 104 hz and ± 2g Sensitivity and today i tried to use the inbuild LPF to cutoff frequency above 25 Hz just to test.
I updated the code using writeReg and gave the value :


The problem i got is that the graph looks total different and the values i get doesnot match.
The reason i am using this is to set High pass filter so to remove DC component and noise of the sensor below 1-2 Hz and also maybe cutout the high frequency signal to prevent Anti-aliasing.
i also saw the default ODR/2 value for Lowpass also.
Can u please help me if i am using wrong values or maybe didnot get the right information.
Any information for building a Vibration measuring box would be really helpful.

Can you explain what results you expected from that configuration and what you’re seeing instead? Do you have some example data with and without the LPF enabled? What frequency are the vibrations that you’re trying to measure?

Kevin

Hello Kelvin,
So, here is my intentions to do with the LSM6DSO Sensor.

  1. I want to have ODR = 104 Hz and FS to ± 2g, as I would like to do vibration analysis lower than 50 Hz (Nyquist Theorem).


According to the Datasheet, to activate High Performance, i used 0b01000000 = 0x40 and in CTRL6_C 0x00 to enable High performance mode. i am not sure if i am right that i should also use CTRL6_C because when i checked the LSM6 library, you have enabled the high performance mode without using CTRL6_C.
image

  1. have a Filter to remove antialiasing effect. As I can read from AN5192 - Rev 5 page 17,
    , i want to use ODR/2. for that i need to perform in High Performance mode.
  2. Use Offset Register to deduct the Offset values. Until now i have placed the sensor on the Table and deducted the value that are bigger than the output i wished for i.e 0.00,0.00, 1.00 for each x,y and z.
    Does using the Offset register gives more promising effect?

image.

  1. I want to use HP Filter to cutoff the noise of the filter for ODR/100 i.e. 1.04 Hz.
    The intension is to remove noise and get a clear vibration data.

I tried the following settings.
First i tried only


and got the following result.
image
Secondly activated the high performance mode
image

and got this result
image
the result is same. I am not sure if it uses LPF1.
lastly,i used the hpf filter,
image
the result looks like this
image
there are also certain sudden peaks in the serial plotter.

Where is the Problem. Is that i am not considering or made mistakes with the Bits selection?

The XL_HM_MODE bit defaults to 0 (high performance mode), so our library does not change it (though it is okay to set it to 0 again to make sure it is correct).

As for what you are seeing with the HPF enabled, I think you are probably getting the expected behavior. The high-pass filter should filter out the acceleration due to gravity (since that is basically a constant offset), along with all other low-frequency components, so all the readings should be centered around 0. Beyond that, unless the vibrations you’re measuring are fairly strong, they could be too small (<0.01 g) to see in your output as it is now. If you shake the sensor around, do you see the output change? You can also try printing the readings with more precision, e.g. String(x, 4) or Serial.print(x, 4) to convert or print the float x with 4 decimal places.

Kevin