IMU Data in real-time to PC

Hello,

i want to know if its possible to send data from the IMU (MPU 92/65) with a sampling rate of 1Khz in real time to a PC. With the serial port it is to slow... Is there a way or do I have to use a SD-Card to save the data in between?

Thanks for your responses

i want to know if its possible to send data from the IMU (MPU 92/65) with a sampling rate of 1Khz in real time to a PC.

Define "real time"!

With the serial port it is to slow...

Using which baud rate? How fast does it have to be?

Is there a way or do I have to use a SD-Card to save the data in between?

That's one of the slowest way I can currently imagine. It's feasible to transfer huge amounts of data but it's very slow.

As mentioned bellow, real time should be at least 1Khz

As Baut-Rate i’m using 115200

with a delay of 100 (ms)

The code, i use is a copy paste of a code i found in the internet

Thank you

#include <Wire.h>
#include <TimerOne.h>

#define    MPU9250_ADDRESS            0x68
#define    MAG_ADDRESS                0x0C

#define    GYRO_FULL_SCALE_250_DPS    0x00  
#define    GYRO_FULL_SCALE_500_DPS    0x08
#define    GYRO_FULL_SCALE_1000_DPS   0x10
#define    GYRO_FULL_SCALE_2000_DPS   0x18

#define    ACC_FULL_SCALE_2_G        0x00  
#define    ACC_FULL_SCALE_4_G        0x08
#define    ACC_FULL_SCALE_8_G        0x10
#define    ACC_FULL_SCALE_16_G       0x18



// This function read Nbytes bytes from I2C device at address Address. 
// Put read bytes starting at register Register in the Data array. 
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.endTransmission();
  
  // Read Nbytes
  Wire.requestFrom(Address, Nbytes); 
  uint8_t index=0;
  while (Wire.available())
    Data[index++]=Wire.read();
}


// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.write(Data);
  Wire.endTransmission();
}



// Initial time
long int ti;
volatile bool intFlag=false;

// Initializations
void setup()
{
  // Arduino initializations
  Wire.begin();
  Serial.begin(115200);
  
  // Set accelerometers low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,29,0x06);
  // Set gyroscope low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,26,0x06);
 
  
  // Configure gyroscope range
  I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_1000_DPS);
  // Configure accelerometers range
  I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_4_G);
  // Set by pass mode for the magnetometers
  I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
  
  // Request continuous magnetometer measurements in 16 bits
  I2CwriteByte(MAG_ADDRESS,0x0A,0x16);
  
   pinMode(13, OUTPUT);
  Timer1.initialize(10000);         // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  
  
  // Store initial time
  ti=millis();
}





// Counter
long int cpt=0;

void callback()
{ 
  intFlag=true;
  digitalWrite(13, digitalRead(13) ^ 1);
}

// Main loop, read and display data
void loop()
{
  while (!intFlag);
  intFlag=false;
  
  // Display time
 // Serial.print (millis()-ti,DEC);
 // Serial.print ("\t");

  // ____________________________________
  // :::  accelerometer and gyroscope ::: 

  // Read accelerometer and gyroscope
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
  
  // Create 16 bits values from 8 bits data
  
  // Accelerometer
  int16_t ax=-(Buf[0]<<8 | Buf[1]);
  int16_t ay=-(Buf[2]<<8 | Buf[3]);
  int16_t az=Buf[4]<<8 | Buf[5];

  // Gyroscope
  int16_t gx=-(Buf[8]<<8 | Buf[9]);
  int16_t gy=-(Buf[10]<<8 | Buf[11]);
  int16_t gz=Buf[12]<<8 | Buf[13];
  
    // Display values
  
  // Accelerometer
  Serial.print (ax); 
  Serial.print ("\t");
  Serial.print (ay);
  Serial.print ("\t");
  Serial.print (az);  
  Serial.print ("\t"); 
  
  // Gyroscope
/*  Serial.print (gx,DEC); 
  Serial.print ("\t");
  Serial.print (gy,DEC);
  Serial.print ("\t");
  Serial.print (gz,DEC);  
  Serial.print ("\t"); */ 

  
  // _____________________
  // :::  Magnetometer ::: 

  
  // Read register Status 1 and wait for the DRDY: Data Ready
  
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS,0x02,1,&ST1);
  }
  while (!(ST1&0x01));

  // Read magnetometer data  
  uint8_t Mag[7];  
  I2Cread(MAG_ADDRESS,0x03,7,Mag);
  

  // Create 16 bits values from 8 bits data
  
  // Magnetometer
  int16_t mx=-(Mag[3]<<8 | Mag[2]);
  int16_t my=-(Mag[1]<<8 | Mag[0]);
  int16_t mz=-(Mag[5]<<8 | Mag[4]);
  
  
  // Magnetometer
 /* Serial.print (mx+200,DEC); 
  Serial.print ("\t");
  Serial.print (my-70,DEC);
  Serial.print ("\t");
  Serial.print (mz-700,DEC);  
  Serial.print ("\t"); */
  
  
  
  // End of line
  Serial.println("");
//  delay(100);    
}

As mentioned bellow, real time should be at least 1Khz

Which should be possible with the serial interface.

As Baut-Rate i'm using 115200

Which means you have about 11 bytes per cycle. Tough but if you make it a bit compressed, it might work.

with a delay of 100 (ms)

That's not a big issue.

The code, i use is a copy paste of a code i found in the internet

If you really need the data that fast (I doubt that there is really a need for that), why the hell do you use the I2C interface? The chip has an SPI interface which is capable of much higher transfer rates.

So my recommendations:

  • Use the SPI interface to query the chip
  • Check if a change to the USB interface is possible to connect to your PC
  • Use a 32bit platform such as the Due
  • Use a binary data transfer and not ASCII as in your code
  • Transfer only the data that you can read (magnetometer has a max. read frequency of 8Hz)

I’m only interested in the accelerometer and the gyro-data
I’ve tried now a baut-rate of 250000 (Arduino 101) but its only possible up to 250 Hz…

I used this code, but somehow it didn’t work

#include <SPI.h>
#include <MPU9250.h>

#define SPI_CLOCK 8000000  // 8MHz clock works.

#define SS_PIN   10 
#define INT_PIN  3
#define LED      13

#define WAITFORINPUT(){            \
	while(!Serial.available()){};  \
	while(Serial.available()){     \
		Serial.read();             \
	};                             \
}                                  \

MPU9250 mpu(SPI_CLOCK, SS_PIN);

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

	pinMode(INT_PIN, INPUT);
	pinMode(LED, OUTPUT);
	digitalWrite(LED, HIGH);

	SPI.begin();

	Serial.println("Press any key to continue");
	WAITFORINPUT();

	mpu.init(true);

	uint8_t wai = mpu.whoami();
	if (wai == 0x71){
		Serial.println("Successful connection");
	}
	else{
		Serial.print("Failed connection: ");
		Serial.println(wai, HEX);
	}

	uint8_t wai_AK8963 = mpu.AK8963_whoami();
	if (wai_AK8963 == 0x48){
		Serial.println("Successful connection to mag");
	}
	else{
		Serial.print("Failed connection to mag: ");
		Serial.println(wai_AK8963, HEX);
	}

	mpu.calib_acc();
	//mpu.calib_mag();

	Serial.println("Send any char to begin main loop.");
	WAITFORINPUT();
}

void loop() {
	// various functions for reading
	// mpu.read_mag();
	// mpu.read_acc();
	// mpu.read_gyro();

	mpu.read_all();

	Serial.print(mpu.gyro_data[0]);   Serial.print('\t');
	Serial.print(mpu.gyro_data[1]);   Serial.print('\t');
	Serial.print(mpu.gyro_data[2]);   Serial.print('\t');
	Serial.print(mpu.accel_data[0]);  Serial.print('\t');
	Serial.print(mpu.accel_data[1]);  Serial.print('\t');
	Serial.println(mpu.accel_data[2]);  Serial.print('\t');
	//Serial.print(mpu.mag_data[0]);    Serial.print('\t');
	//Serial.print(mpu.mag_data[1]);    Serial.print('\t');
	//Serial.print(mpu.mag_data[2]);    Serial.print('\t');
	// Serial.println(mpu.temperature);

	delay(10);
}

The serial monitor shows values but only zeros, even if i shake the sensor…

Has anyone a code to run the sensor with spi? I couldn’t find a code using google. All codes use I2C to run the sensor.
Thank you

Did you change the wiring? The standard setup of most modules (you didn't provide a link to your's) is for I2C. Post a diagram of your wiring!

Why do you still transfer the data in ASCII? You might reach the 1kHz rate with a binary transfer (uncompressed) at 250kbaud.

    delay(10);

That's an absolute no-go if you care for speed!

pylon:
Did you change the wiring? The standard setup of most modules (you didn’t provide a link to your’s) is for I2C. Post a diagram of your wiring!

Why do you still transfer the data in ASCII? You might reach the 1kHz rate with a binary transfer (uncompressed) at 250kbaud.

	delay(10);

That’s an absolute no-go if you care for speed!

Yes, I totaly agree with you. I first wanted to see if the code is runig at all. Later on i will focus on the speed.
Sorry for the picture. I couldn’t find any part in fritzing or in eagle. So i did the paint-circuit :smiley:

There are several errors in the wiring:

  • AD0 is SDO so it must be connected to MISO
  • SDA is SDI so it must be connected to MOSI
  • NCS is not connected at all, should go to D10 (according to your code)

Although the 101 is a 3V device all I/Os have level converter to 5V between the processor and the pin. According to the datasheet the I2C/SPI pins must not have a voltage higher than VDD (which seems to be 3V3 on your board). So you should use a level converter to match that criteria. I hope you didn’t damaged the chip already.