Go Down

Topic: IMU Data in real-time to PC (Read 311 times) previous topic - next topic

SystemOfADown

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

pylon

Quote
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"!

Quote
With the serial port it is to slow...
Using which baud rate? How fast does it have to be?

Quote
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.

SystemOfADown

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

Code: [Select]
#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);   
}



pylon

Quote
As mentioned bellow, real time should be at least 1Khz
Which should be possible with the serial interface.

Quote
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.

Quote
with a delay of 100 (ms)
That's not a big issue.

Quote
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)

SystemOfADown

#4
Feb 20, 2017, 03:12 pm Last Edit: Feb 20, 2017, 04:32 pm by SystemOfADown Reason: additinal information added
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


Code: [Select]

#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

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.

Code: [Select]
delay(10);

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

SystemOfADown

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.

Code: [Select]
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 :D

pylon

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.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy