Speed I2C transfer rate

Hi,

I'm working with Arduino M0 and three 9-axis IMUs by Adafruit (FXOS8700+FXAS21002). My goal is to get relative motion between the first one with the second one and the third one with the second one.
Currently my idea is to extract quarterion/euler angles and afterthat to convert it in relative motion.
Does someone know how to do it?
And second question, using the attached code:

i need to speed the communication because i saw (using millis()) that the time between two reading from the same IMU is roughly 30ms.
More, do you have some ideas about why the measurements from IMUs is quiet accetable, but from Madwick output the angles is not sensible at the movement.. seems that filters does not work.

Thank you for your help ahead in time.

3IMU_cal_angles.ino (18.2 KB)

My goal is to get relative motion between the first one with the second one and the third one with the second one.

What exactly is the "first one", "second one" and "third one" in this context?

Currently my idea is to extract quarterion/euler angles and afterthat to convert it in relative motion.

Forget that, the relative error sums up to complete uselessness within no time. You might get a rough direction but forget a useful distance value.

i need to speed the communication because i saw (using millis()) that the time between two reading from the same IMU is roughly 30ms.

The time needed to transfer the values from one IMU is below 4ms. How did you measure the 30ms? There is no measuring code in the posted sketch.

You can increase the I2C speed to 400kHz but your circuit design might not allow that (overall capacitance of the bus).

pylon:
What exactly is the "first one", "second one" and "third one" in this context?

One IMU to another one. So having 3 IMUs i'll get 2 Relative motion.

pylon:
Forget that, the relative error sums up to complete uselessness within no time. You might get a rough direction but forget a useful distance value.

Using something like Magdwick filter? (or similar)

pylon:
The time needed to transfer the values from one IMU is below 4ms. How did you measure the 30ms? There is no measuring code in the posted sketch. You can increase the I2C speed to 400kHz but your circuit design might not allow that (overall capacitance of the bus).

This is the code i'm using. I'm getting 9-axis measaurements from these 3 IMUs connected through multiplex I2C.
I fixed the ODR (output data rate) for the IMUs at 400Hz, but i see (with millis() function) the temporal distance from one reading and the next one is roughly 20ms, so 55Hz. I've already setted up setClock to 400KHz.

// Including Libraries
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_FXOS8700.h>
#include <Adafruit_FXAS21002C.h>

// Definition Multiplex's address
#define TCAADDR 0x70
// Assignation Sensors' ID
Adafruit_FXOS8700 accelmag = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag1 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro1 = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag2 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro2 = Adafruit_FXAS21002C(0x0021002C);

// definition of the variables
float accx, accy, accz;
float gyrox, gyroy, gyroz;
float magx, magy, magz;
float accx1, accy1, accz1;
float gyrox1, gyroy1, gyroz1;
float magx1, magy1, magz1;
float accx2, accy2, accz2;
float gyrox2, gyroy2, gyroz2;
float magx2, magy2, magz2;


// tcaselect to choose which channel has to work
void tcaselect (uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}


void setup() {
  delay(5000);
  //SerialUSB.println("TEST With Matlab!");
  Wire.begin();
  Wire.setClock(400000);
  SerialUSB.begin(115200);
  tcaselect(7);
  if(!gyro.begin())
  {
    /* There was a problem detecting the FXAS21002C ... check your connections */
    SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring!");
    while(1);
  }
  /* Initialise Accelerometer and Magnetometer */
  if(!accelmag.begin())
  {
    /* There was a problem detecting the FXOS8700 ... check your connections */
    SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring!");
    while(1);
  }
  /* SECOND IMU */
  tcaselect(2);
  if(!gyro1.begin())
  {
    /* There was a problem detecting the FXAS21002C ... check your connections */
    SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring!");
    while(1);
  }
  /* Initialise Accelerometer and Magnetometer */
  if(!accelmag1.begin())
  {
    /* There was a problem detecting the FXOS8700 ... check your connections */
    SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring!");
    while(1);
  }
  /* THIRD IMU */
  tcaselect(4);
  if(!gyro2.begin())
  {
    /* There was a problem detecting the FXAS21002C ... check your connections */
    SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring!");
    while(1);
  }
  /* Initialise Accelerometer and Magnetometer */
  if(!accelmag2.begin())
  {
    /* There was a problem detecting the FXOS8700 ... check your connections */
    SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring!");
    while(1);
  }
}

void loop() {
 if(SerialUSB.available()>0) {
 if(SerialUSB.read() == 'a') {
  //SerialUSB.println("1000");

  /* READING FROM 1° IMU */
  sensors_event_t aevent, mevent;  
  /* Get first sensor event */
  tcaselect(7);
  accelmag.getEvent(&aevent, &mevent);
  sensors_event_t event;
  // tcaselect(7);
  gyro.getEvent(&event);
  // FIRST IMU
  /* Display the accel results (acceleration is measured in m/s^2) */
  SerialUSB.print(aevent.acceleration.x, 3); SerialUSB.print(",");
  SerialUSB.print(aevent.acceleration.y, 3); SerialUSB.print(",");
  SerialUSB.print(aevent.acceleration.z, 3); SerialUSB.print(",");
  /* Display the mag results (mag data is in uTesla) */
  SerialUSB.print(mevent.magnetic.x, 3); SerialUSB.print(","); 
  SerialUSB.print(mevent.magnetic.y, 3); SerialUSB.print(",");
  SerialUSB.print(mevent.magnetic.z, 3); SerialUSB.print(",");
  /* Display the gyro results (speed is measured in rad/s) */
  SerialUSB.print(event.gyro.x, 3); SerialUSB.print(",");
  SerialUSB.print(event.gyro.y, 3); SerialUSB.print(",");
  SerialUSB.print(event.gyro.z, 3); SerialUSB.print(",");
  
  /* READING FROM 2° IMU */
  sensors_event_t aevent1, mevent1;
  tcaselect(2);
  accelmag.getEvent(&aevent1, &mevent1);
  /* Get second sensor event */
  sensors_event_t event1;
  // tcaselect(2);
  gyro.getEvent(&event1); 
  // SECOND IMU
  /* Display the accel results (acceleration is measured in m/s^2) */
  SerialUSB.print(aevent1.acceleration.x, 3); SerialUSB.print(",");
  SerialUSB.print(aevent1.acceleration.y, 3); SerialUSB.print(",");
  SerialUSB.print(aevent1.acceleration.z, 3); SerialUSB.print(",");
  /* Display the mag results (mag data is in uTesla) */
  SerialUSB.print(mevent1.magnetic.x, 3); SerialUSB.print(","); 
  SerialUSB.print(mevent1.magnetic.y, 3); SerialUSB.print(",");
  SerialUSB.print(mevent1.magnetic.z, 3); SerialUSB.print(",");
  /* Display the gyro results (speed is measured in rad/s) */
  SerialUSB.print(event1.gyro.x, 3); SerialUSB.print(",");
  SerialUSB.print(event1.gyro.y, 3); SerialUSB.print(",");
  SerialUSB.print(event1.gyro.z, 3); SerialUSB.print(",");
  //SerialUSB.println("Time");SerialUSB.println(millis());

  /* READING FROM 3° IMU */
  sensors_event_t aevent2, mevent2;  
  /* Get first sensor event */
  tcaselect(4);
  accelmag.getEvent(&aevent2, &mevent2);
  sensors_event_t event2;
  // tcaselect(4);
  gyro.getEvent(&event2);
  // THIRD IMU
  SerialUSB.print(aevent2.acceleration.x, 3); SerialUSB.print(",");
  SerialUSB.print(aevent2.acceleration.y, 3); SerialUSB.print(",");
  SerialUSB.print(aevent2.acceleration.z, 3); SerialUSB.print(",");
  /* Display the mag results (mag data is in uTesla) */
  SerialUSB.print(mevent2.magnetic.x, 3); SerialUSB.print(","); 
  SerialUSB.print(mevent2.magnetic.y, 3); SerialUSB.print(",");
  SerialUSB.print(mevent2.magnetic.z, 3); SerialUSB.print(",");
  /* Display the gyro results (speed is measured in rad/s) */
  SerialUSB.print(event2.gyro.x, 3); SerialUSB.print(",");
  SerialUSB.print(event2.gyro.y, 3); SerialUSB.print(",");
  SerialUSB.print(event2.gyro.z, 3); SerialUSB.print(",");
  SerialUSB.println(millis());
 }
}
}
[code]

How could I speed up the communication?

[/code]

One IMU to another one. So having 3 IMUs i'll get 2 Relative motion.

No, you have 3 relative motions (1 -> 2, 2 -> 3 and 3 -> 1).

This is the code i'm using. I'm getting 9-axis measaurements from these 3 IMUs connected through multiplex I2C.

That code does not measure the time to read all 3 IMUs but the measured time includes the output to the USBSerial and the I2C multiplexer switching. By increasing the I2C speed you might get that faster but as you're trying to calculate relative motion I guess you bus is already at the limit for the 100kHz so and increase to 400kHz would collapse the bus. But you didn't provide detail information about the circuit so there a lot of speculation on my side.

pylon:
No, you have 3 relative motions (1 -> 2, 2 -> 3 and 3 -> 1).

Yes, definitely. But this issue will occur later than I speed up the communication.

pylon:
But you didn't provide detail information about the circuit so there a lot of speculation on my side.

I'm sorry, so sorry. Now i'm going to explain the circuit.
So, basically, i'm using Arduino M0 Native port (that required the SerialUSB and not the Serial to print over the monitor) with 3 IMUs (Adafruit Precision NXP 9-DOF Breakout Board [FXOS8700 + FXAS21002] : ID 3463 : $14.95 : Adafruit Industries, Unique & fun DIY electronics and kits) 6 axis (acc+mag) and 3 axis(gyro). These support I2C communication and to interface the sensors to Arduino i'm using the multiplexer,o better called I2C expander (Overview | Adafruit TCA9548A 1-to-8 I2C Multiplexer Breakout | Adafruit Learning System).
The idea is to interface this IMUs to Arduino and try to speed up the communication to get just raw data (without any more operations in Arduino IDE) and moving this data (maybe real time) to MATLAB to do the calibration phase, and after that the processing up to the relative motion (but these problems will be dealt with after I speed up communication).
To interface MATLAB to arduino i'm using this code:

%% PORT INITIALIZATION
close all
clear all
clc
% reset all communications
instrreset;
% set port and its features
SerialPort = serial('COM6','BaudRate',115200);
fopen(SerialPort);
uiwait(msgbox('ARDUINO IS READY','Success','modal'));
%% INITIALIZATION
samples = 0.2*10^3;
data_stored = zeros(samples,28); % Big matrix where to allocate raw data.
count = 1; % Counter
action = 'a';
%% SAVING RAW DATA

while(count<=size(data_stored,1))
    fprintf(SerialPort, '%c', action); % send the command to read data    
    %PROVA = str2num(fgets(SerialPort)); %
    data_stored(count,:) = str2num(fgets(SerialPort)); % read,convert and save the value from the Serial Port
    count = count + 1; % refresh the counter for the next iteration
end

But i understood, through millis() function that the problems (about speeding) are in Arduino IDE. I'm gonna attach the arduino code that I currently use and i realized that the event's generation

  sensors_event_t aevent, mevent;
  sensors_event_t event;
  sensors_event_t aevent1, mevent1;
  sensors_event_t event1;
  sensors_event_t aevent2, mevent2;
  sensors_event_t event2;

spent 8-9 ms every cycle, and the reading itself from Acc+Mag and Gyro

aevent2.acceleration.x,aevent2.acceleration.y; aevent2.acceleration.z
mevent2.magnetic.x;mevent2.magnetic.y;mevent2.magnetic.z
event2.gyro.x;event2.gyro.y;event2.gyro.z

spents roughly 4ms for each device (acc+mag and gyro so 8ms)

So this is the general scenario, if you need more details just let me know.
Thank you so much.

3IMU_cal_matlab_2201.ino (5.55 KB)

(but these problems will be dealt with after I speed up communication)

You should think about that now because even if you can speed up the communication you won't be able to get the relative motion from acceleration values. The chips have a too high noise value and a much too low read out speed to even get a chance to get the integral value of it without having more error in the result than the actual value contains.

spents roughly 4ms for each device (acc+mag and gyro so 8ms)

That's about what I expected from the transferred amount of data.

So, basically, i'm using Arduino M0 Native port (that required the SerialUSB and not the Serial to print over the monitor) with 3 IMUs (Adafruit Precision NXP 9-DOF Breakout Board [FXOS8700 + FXAS21002] : ID 3463 : $14.95 : Adafruit Industries, Unique & fun DIY electronics and kits) 6 axis (acc+mag) and 3 axis(gyro). These support I2C communication and to interface the sensors to Arduino i'm using the multiplexer,o better called I2C expander (Overview | Adafruit TCA9548A 1-to-8 I2C Multiplexer Breakout | Adafruit Learning System).

What do you use them for? How long are the individual I2C buses?

Have you tried to increase the I2C clock speed to 400kHz?

pylon:
You should think about that now because even if you can speed up the communication you won't be able to get the relative motion from acceleration values.

Yeah, of course. I'd like to use a filter like Magdwick (or similar) to get roll, pitch and yaw using 9 axis measurements (acc+gyro+mag).

pylon:
Have you tried to increase the I2C clock speed to 400kHz?

Yes I tried in tha past but nothing was changing because I was doing a mistake overwritting the SetClock() function in the libraries.
Now, I have fixed it and i get a cycle every 5 ms (that could be fine) but for the future i'll have to speed up the process (maybe using another library? i'm using those one provided by Adafruit).
Anyway now, i have 2 main problems:

  1. How to communicate with MATLAB? (since Serial.print() is very low and downgrade the communication rate too much). Using Serial.write? How do i do to reiceve date in MATLAB corretly?
  2. How to synchronize the readings in Arduino?
  1. How to communicate with MATLAB? (since Serial.print() is very low and downgrade the communication rate too much). Using Serial.write? How do i do to reiceve date in MATLAB corretly?

Using the write method won't speed that up and you'd have to do the low level stuff.
You can try to increase the USBSerial baudrate but many implementations simply ignore this value anyway.

If you really must do those calculations in Matlab you probably have to make a special CDC implementation that puts as much data as possible into one USB message. Using the write(byte *, length) method might increase the speed as it does the same probably (I haven't checked the latest library version).

  1. How to synchronize the readings in Arduino?

Synchronize to what?

pylon:
Using the write(byte *, length) method might increase the speed as it does the same probably

It's what i want to reach. In the libraries are available the raw data (in uint_16 format). So How could i do to send this format through Serial.Write and to read properly it in MATLAB?

So How could i do to send this format through Serial.Write and to read properly it in MATLAB?

I have no clue about MATLAB.

Actually looks that i was able to realize a preliminary connection. Now the problem is that Arduino does not provide a precise sampling frequency.
Has someone suggestions?

This is the code:

// Including Libraries
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_FXOS8700.h>
#include <Adafruit_FXAS21002C.h>

// Definition Multiplex's address
#define TCAADDR 0x70
// Assignation Sensors' ID
Adafruit_FXOS8700 accelmag = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag1 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro1 = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag2 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro2 = Adafruit_FXAS21002C(0x0021002C);

// definition of the variables
// in micros
long interval = 10000;
long PreviousMicros = 0;
// tcaselect to choose which channel has to work
void tcaselect (uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}


void setup() {
delay(4000);
      Wire.begin();
      Wire.setClock(100000);
      SerialUSB.begin(115200);
      tcaselect(7);
      if (!gyro.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring 1!");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring! 1");
        while (1);
      }
      /* SECOND IMU */
      tcaselect(0);
      if (!gyro1.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring! 2");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag1.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring! 2 ");
        while (1);
      }
      /* THIRD IMU */
      tcaselect(4);
      if (!gyro2.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring!3");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag2.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring!3");
        while (1);
      }
    }


void loop() {
  unsigned long CurrentMicros = micros();
  if ((CurrentMicros - PreviousMicros) > interval)
  {
    PreviousMicros = CurrentMicros;

    /*----------------------------------------------------------------------------------*/
    // Generation Event
    /*----------------------------------------------------------------------------------*/
    //SerialUSB.println("start");SerialUSB.println(micros());
    sensors_event_t aevent, mevent;
    sensors_event_t event;
    sensors_event_t aevent1, mevent1;
    sensors_event_t event1;
    sensors_event_t aevent2, mevent2;
    sensors_event_t event2;

    /* READING FROM 1° IMU */
    tcaselect(7);
    accelmag.getEvent(&aevent, &mevent);
    gyro.getEvent(&event);
    /* READING FROM 2° IMU */
    tcaselect(0);
    accelmag1.getEvent(&aevent1, &mevent1);
    gyro1.getEvent(&event1);
    /* READING FROM 3° IMU */
    tcaselect(4);
    accelmag2.getEvent(&aevent2, &mevent2);
    gyro2.getEvent(&event2);
    unsigned long t = event2.timestamp;
    
    int16_t gyro_x = gyro.raw.x;
    int16_t gyro_y = gyro.raw.y;
    int16_t gyro_z = gyro.raw.z;
    int16_t mag_x = accelmag.mag_raw.x;
    int16_t mag_y = accelmag.mag_raw.y;
    int16_t mag_z = accelmag.mag_raw.z;
    int16_t acc_x = accelmag.accel_raw.x;
    int16_t acc_y = accelmag.accel_raw.y;
    int16_t acc_z = accelmag.accel_raw.z;
    
    int16_t gyro_1_x = gyro1.raw.x;
    int16_t gyro_1_y = gyro1.raw.y;
    int16_t gyro_1_z = gyro1.raw.z;
    int16_t mag_1_x = accelmag1.mag_raw.x;
    int16_t mag_1_y = accelmag1.mag_raw.y;
    int16_t mag_1_z = accelmag1.mag_raw.z;
    int16_t acc_1_x = accelmag1.accel_raw.x;
    int16_t acc_1_y = accelmag1.accel_raw.y;
    int16_t acc_1_z = accelmag1.accel_raw.z;
    
    int16_t gyro_2_x = gyro2.raw.x;
    int16_t gyro_2_y = gyro2.raw.y;
    int16_t gyro_2_z = gyro2.raw.z;
    int16_t mag_2_x = accelmag2.mag_raw.x;
    int16_t mag_2_y = accelmag2.mag_raw.y;
    int16_t mag_2_z = accelmag2.mag_raw.z;
    int16_t acc_2_x = accelmag2.accel_raw.x;
    int16_t acc_2_y = accelmag2.accel_raw.y;
    int16_t acc_2_z = accelmag2.accel_raw.z;

    // Split Register in 2 bytes to allow sending through Serial.Write - Gyro:
    byte gyro_x_H = highByte(gyro_x);
    byte gyro_x_L = lowByte(gyro_x);
    byte gyro_y_H = highByte(gyro_y);
    byte gyro_y_L = lowByte(gyro_y);
    byte gyro_z_H = highByte(gyro_z);
    byte gyro_z_L = lowByte(gyro_z);
    byte gyro_1_x_H = highByte(gyro_1_x);
    byte gyro_1_x_L = lowByte(gyro_1_x);
    byte gyro_1_y_H = highByte(gyro_1_y);
    byte gyro_1_y_L = lowByte(gyro_1_y);
    byte gyro_1_z_H = highByte(gyro_1_z);
    byte gyro_1_z_L = lowByte(gyro_1_z);
    byte gyro_2_x_H = highByte(gyro_2_x);
    byte gyro_2_x_L = lowByte(gyro_2_x);
    byte gyro_2_y_H = highByte(gyro_2_y);
    byte gyro_2_y_L = lowByte(gyro_2_y);
    byte gyro_2_z_H = highByte(gyro_2_z);
    byte gyro_2_z_L = lowByte(gyro_2_z);

    // Split Register in 2 bytes to allow sending through Serial.Write - Mag:
    byte mag_x_H = highByte(mag_x);
    byte mag_x_L = lowByte(mag_x);
    byte mag_y_H = highByte(mag_y);
    byte mag_y_L = lowByte(mag_y);
    byte mag_z_H = highByte(mag_z);
    byte mag_z_L = lowByte(mag_z);
    byte mag_1_x_H = highByte(mag_1_x);
    byte mag_1_x_L = lowByte(mag_1_x);
    byte mag_1_y_H = highByte(mag_1_y);
    byte mag_1_y_L = lowByte(mag_1_y);
    byte mag_1_z_H = highByte(mag_1_z);
    byte mag_1_z_L = lowByte(mag_1_z);
    byte mag_2_x_H = highByte(mag_2_x);
    byte mag_2_x_L = lowByte(mag_2_x);
    byte mag_2_y_H = highByte(mag_2_y);
    byte mag_2_y_L = lowByte(mag_2_y);
    byte mag_2_z_H = highByte(mag_2_z);
    byte mag_2_z_L = lowByte(mag_2_z);

    // Split Register in 2 bytes to allow sending through Serial.Write - Acc:
    byte acc_x_H = highByte(acc_x);
    byte acc_x_L = lowByte(acc_x);
    byte acc_y_H = highByte(acc_y);
    byte acc_y_L = lowByte(acc_y);
    byte acc_z_H = highByte(acc_z);
    byte acc_z_L = lowByte(acc_z);
    byte acc_1_x_H = highByte(acc_1_x);
    byte acc_1_x_L = lowByte(acc_1_x);
    byte acc_1_y_H = highByte(acc_1_y);
    byte acc_1_y_L = lowByte(acc_1_y);
    byte acc_1_z_H = highByte(acc_1_z);
    byte acc_1_z_L = lowByte(acc_1_z);
    byte acc_2_x_H = highByte(acc_2_x);
    byte acc_2_x_L = lowByte(acc_2_x);
    byte acc_2_y_H = highByte(acc_2_y);
    byte acc_2_y_L = lowByte(acc_2_y);
    byte acc_2_z_H = highByte(acc_2_z);
    byte acc_2_z_L = lowByte(acc_2_z);
    /*----------------------------------------------------------------------------------*/
    // Communication DATA
    /*----------------------------------------------------------------------------------*/
    byte reading[] = {gyro_x_H, gyro_x_L, gyro_y_H, gyro_y_L, gyro_z_H, gyro_z_L, gyro_1_x_H, gyro_1_x_L, gyro_1_y_H, gyro_1_y_L, gyro_1_z_H, gyro_1_z_L,
                      gyro_2_x_H, gyro_2_x_L, gyro_2_y_H, gyro_2_y_L, gyro_2_z_H, gyro_2_z_L, mag_x_H, mag_x_L, mag_y_H, mag_y_L, mag_z_H, mag_z_L,
                      mag_1_x_H, mag_1_x_L, mag_1_y_H, mag_1_y_L, mag_1_z_H, mag_1_z_L, mag_2_x_H, mag_2_x_L, mag_2_y_H, mag_2_y_L, mag_2_z_H, mag_2_z_L,
                      acc_x_H, acc_x_L, acc_y_H, acc_y_L, acc_z_H, acc_z_L, acc_1_x_H, acc_1_x_L, acc_1_y_H, acc_1_y_L, acc_1_z_H, acc_1_z_L,
                      acc_2_x_H, acc_2_x_L, acc_2_y_H, acc_2_y_L, acc_2_z_H, acc_2_z_L
                     };
    SerialUSB.write(reading, 54);
    SerialUSB.println(t);
  }
}

Define what "precise sampling frequency" means in this context. You asked for a read as fast as possible, a constant sampling frequency wasn't specified yet. And you cannot have both. Decide what's more important for you.

What are you trying to achieve? What setup are we talking about? Provide more information about where those sensors are used and what for.

I need to collect data to do analysis and processing to extract relative motion for kinematics investigation. Basically this is the aim. I need, firstly, to have a consistent sampling frequency.
It looks that i've arrived there.

I'm using this code in Arduino:

// Including Libraries
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_FXOS8700.h>
#include <Adafruit_FXAS21002C.h>

// Definition Multiplex's address
#define TCAADDR 0x70
// Assignation Sensors' ID
Adafruit_FXOS8700 accelmag = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag1 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro1 = Adafruit_FXAS21002C(0x0021002C);
Adafruit_FXOS8700 accelmag2 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro2 = Adafruit_FXAS21002C(0x0021002C);

// definition of the variables
// in millis
double interval = 10;
long PreviousMicros = 0;
// tcaselect to choose which channel has to work
void tcaselect (uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}


void setup() {
      delay(4000);
      Wire.begin();
      Wire.setClock(100000);
      SerialUSB.begin(115200);
      tcaselect(7);
      if (!gyro.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring 1!");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring! 1");
        while (1);
      }
      /* SECOND IMU */
      tcaselect(0);
      if (!gyro1.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring! 2");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag1.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring! 2 ");
        while (1);
      }
      /* THIRD IMU */
      tcaselect(4);
      if (!gyro2.begin(GYRO_RANGE_250DPS))
      {
        /* There was a problem detecting the FXAS21002C ... check your connections */
        SerialUSB.println("Ooops, no FXAS21002C detected ... Check your wiring!3");
        while (1);
      }
      /* Initialise Accelerometer and Magnetometer */
      if (!accelmag2.begin(ACCEL_RANGE_2G))
      {
        /* There was a problem detecting the FXOS8700 ... check your connections */
        SerialUSB.println("Ooops, no FXOS8700 detected ... Check your wiring!3");
        while (1);
      }
    }


void loop() {
  unsigned long CurrentMicros = millis();
  if ((CurrentMicros - PreviousMicros) >= interval)
  {
    PreviousMicros = CurrentMicros;
    /*----------------------------------------------------------------------------------*/
    // Generation Event
    /*----------------------------------------------------------------------------------*/
    //SerialUSB.println("start");SerialUSB.println(micros());
    sensors_event_t aevent, mevent;
    sensors_event_t event;
    sensors_event_t aevent1, mevent1;
    sensors_event_t event1;
    sensors_event_t aevent2, mevent2;
    sensors_event_t event2;
    /* READING FROM 1° IMU */
    tcaselect(7);
    accelmag.getEvent(&aevent, &mevent);
    gyro.getEvent(&event);
    /* READING FROM 2° IMU */
    tcaselect(0);
    accelmag1.getEvent(&aevent1, &mevent1);
    gyro1.getEvent(&event1);
    /* READING FROM 3° IMU */
    tcaselect(4);
    accelmag2.getEvent(&aevent2, &mevent2);
    gyro2.getEvent(&event2);
    unsigned long t = millis();
    int16_t gyro_x = gyro.raw.x;
    int16_t gyro_y = gyro.raw.y;
    int16_t gyro_z = gyro.raw.z;
    int16_t mag_x = accelmag.mag_raw.x;
    int16_t mag_y = accelmag.mag_raw.y;
    int16_t mag_z = accelmag.mag_raw.z;
    int16_t acc_x = accelmag.accel_raw.x;
    int16_t acc_y = accelmag.accel_raw.y;
    int16_t acc_z = accelmag.accel_raw.z;
    
    int16_t gyro_1_x = gyro1.raw.x;
    int16_t gyro_1_y = gyro1.raw.y;
    int16_t gyro_1_z = gyro1.raw.z;
    int16_t mag_1_x = accelmag1.mag_raw.x;
    int16_t mag_1_y = accelmag1.mag_raw.y;
    int16_t mag_1_z = accelmag1.mag_raw.z;
    int16_t acc_1_x = accelmag1.accel_raw.x;
    int16_t acc_1_y = accelmag1.accel_raw.y;
    int16_t acc_1_z = accelmag1.accel_raw.z;
    
    int16_t gyro_2_x = gyro2.raw.x;
    int16_t gyro_2_y = gyro2.raw.y;
    int16_t gyro_2_z = gyro2.raw.z;
    int16_t mag_2_x = accelmag2.mag_raw.x;
    int16_t mag_2_y = accelmag2.mag_raw.y;
    int16_t mag_2_z = accelmag2.mag_raw.z;
    int16_t acc_2_x = accelmag2.accel_raw.x;
    int16_t acc_2_y = accelmag2.accel_raw.y;
    int16_t acc_2_z = accelmag2.accel_raw.z;

    // Split Register in 2 bytes to allow sending through Serial.Write - Gyro:
    byte gyro_x_H = highByte(gyro_x);
    byte gyro_x_L = lowByte(gyro_x);
    byte gyro_y_H = highByte(gyro_y);
    byte gyro_y_L = lowByte(gyro_y);
    byte gyro_z_H = highByte(gyro_z);
    byte gyro_z_L = lowByte(gyro_z);
    byte gyro_1_x_H = highByte(gyro_1_x);
    byte gyro_1_x_L = lowByte(gyro_1_x);
    byte gyro_1_y_H = highByte(gyro_1_y);
    byte gyro_1_y_L = lowByte(gyro_1_y);
    byte gyro_1_z_H = highByte(gyro_1_z);
    byte gyro_1_z_L = lowByte(gyro_1_z);
    byte gyro_2_x_H = highByte(gyro_2_x);
    byte gyro_2_x_L = lowByte(gyro_2_x);
    byte gyro_2_y_H = highByte(gyro_2_y);
    byte gyro_2_y_L = lowByte(gyro_2_y);
    byte gyro_2_z_H = highByte(gyro_2_z);
    byte gyro_2_z_L = lowByte(gyro_2_z);

    // Split Register in 2 bytes to allow sending through Serial.Write - Mag:
    byte mag_x_H = highByte(mag_x);
    byte mag_x_L = lowByte(mag_x);
    byte mag_y_H = highByte(mag_y);
    byte mag_y_L = lowByte(mag_y);
    byte mag_z_H = highByte(mag_z);
    byte mag_z_L = lowByte(mag_z);
    byte mag_1_x_H = highByte(mag_1_x);
    byte mag_1_x_L = lowByte(mag_1_x);
    byte mag_1_y_H = highByte(mag_1_y);
    byte mag_1_y_L = lowByte(mag_1_y);
    byte mag_1_z_H = highByte(mag_1_z);
    byte mag_1_z_L = lowByte(mag_1_z);
    byte mag_2_x_H = highByte(mag_2_x);
    byte mag_2_x_L = lowByte(mag_2_x);
    byte mag_2_y_H = highByte(mag_2_y);
    byte mag_2_y_L = lowByte(mag_2_y);
    byte mag_2_z_H = highByte(mag_2_z);
    byte mag_2_z_L = lowByte(mag_2_z);

    // Split Register in 2 bytes to allow sending through Serial.Write - Acc:
    byte acc_x_H = highByte(acc_x);
    byte acc_x_L = lowByte(acc_x);
    byte acc_y_H = highByte(acc_y);
    byte acc_y_L = lowByte(acc_y);
    byte acc_z_H = highByte(acc_z);
    byte acc_z_L = lowByte(acc_z);
    byte acc_1_x_H = highByte(acc_1_x);
    byte acc_1_x_L = lowByte(acc_1_x);
    byte acc_1_y_H = highByte(acc_1_y);
    byte acc_1_y_L = lowByte(acc_1_y);
    byte acc_1_z_H = highByte(acc_1_z);
    byte acc_1_z_L = lowByte(acc_1_z);
    byte acc_2_x_H = highByte(acc_2_x);
    byte acc_2_x_L = lowByte(acc_2_x);
    byte acc_2_y_H = highByte(acc_2_y);
    byte acc_2_y_L = lowByte(acc_2_y);
    byte acc_2_z_H = highByte(acc_2_z);
    byte acc_2_z_L = lowByte(acc_2_z);
    /*----------------------------------------------------------------------------------*/
    // Communication DATA
    /*----------------------------------------------------------------------------------*/
    byte reading[] = {gyro_x_H, gyro_x_L, gyro_y_H, gyro_y_L, gyro_z_H, gyro_z_L, gyro_1_x_H, gyro_1_x_L, gyro_1_y_H, gyro_1_y_L, gyro_1_z_H, gyro_1_z_L,
                      gyro_2_x_H, gyro_2_x_L, gyro_2_y_H, gyro_2_y_L, gyro_2_z_H, gyro_2_z_L, mag_x_H, mag_x_L, mag_y_H, mag_y_L, mag_z_H, mag_z_L,
                      mag_1_x_H, mag_1_x_L, mag_1_y_H, mag_1_y_L, mag_1_z_H, mag_1_z_L, mag_2_x_H, mag_2_x_L, mag_2_y_H, mag_2_y_L, mag_2_z_H, mag_2_z_L,
                      acc_x_H, acc_x_L, acc_y_H, acc_y_L, acc_z_H, acc_z_L, acc_1_x_H, acc_1_x_L, acc_1_y_H, acc_1_y_L, acc_1_z_H, acc_1_z_L,
                      acc_2_x_H, acc_2_x_L, acc_2_y_H, acc_2_y_L, acc_2_z_H, acc_2_z_L
                     };
    SerialUSB.write(reading, 54);
    SerialUSB.println(t);
    
  }
}

What do you think?

What do you think?

That code probably gets you a more or less constant sample rate.

I need to collect data to do analysis and processing to extract relative motion for kinematics investigation.

I already told you that you will fail with that one. Acceleration sensors (consumer parts) are not suitable to get a velocity.