Jump to content
I2Cdevlib Forums

Jeff Rowberg

Administrators
  • Posts

    62
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by Jeff Rowberg

  1. Unfortunately, the only people who can give you a good idea of how the DMP works work at InvenSense, and they are extremely hesitant to explain it (understandable from a business perspective, but annoying for us). The most complete set of "setup" steps that I have found are the ones in the DMP6 example sketch, which are implemented in the MPU6050_DMP6_MotionApps20.h file that is part of the device code library. This alternative library from GitHub user "Pansenti" is another good reference, specifically for the 9150: https://github.com/Pansenti/MPU9150Lib/blob/master/libraries/MPU9150Lib/MPU9150Lib.h The DMP is a very tightly closed "black box" component for most us; my code in the I2Cdevlib only works by imitating when the eval board does over the I2C bus. Some registers are documented in the datasheet, but the actual DMP binary code block and subsequent configuration commands are not explained there.
  2. Is this running on a standard Arduino Uno platform, and do you know if any other output formats work correctly? This looks like the FIFO data is misaligned, so that e.g. the quaternion data is off by one or more bytes. Try dumping the FIFO count out the serial port as well and make sure that it is in fact growing in 42-byte chunks. If it is some other increment, then the data is not being generated and/or read properly.
  3. Using an accelerometer by itself to determine incline works perfectly and is very accurate, but only as long as the sensor is not moving linearly. If it is only rotating, then the only acceleration will be due to gravity, and you can determine the orientation based on gravity. But if it starts moving, then there will be more than just gravity involved, and it is impossible to tell which acceleration is because of gravity and which is not. That's why you need another sensor; one of them estimates the orientation over time, and the other one is used to provide a gravity reference to compensate for gyro drift and errors in the rotational velocity estimations. Of course, the math that actually does this is beyond my level of understanding... :-)
  4. I haven't done much with the AK8975 operating inside the MPU-9150, but there is this sketch meant to use the AK8975 through the MPU-6010: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/AK8975/Examples/AK8975_MPUEVB_heading The register map for the device is here: http://www.i2cdevlib.com/devices/ak8975#registers The same code applies to the 9150, but I think it needs to be modified for the different slave address.
  5. I've never tried to run two at the same time, but one thing that comes to mind (since the wiring seems correct to me) is that perhaps the power requirements for both are higher than the source can provide. They don't take much power and this isn't likely to be an issue unless you're actually providing power from a GPIO instead of a supply pin. A logic analyzer on the SDA/SCL lines would definitely be helpful.
  6. How fast are you running each DMP, and can you tell whether the FIFO is overflowing due to trying to do too much at once? Can you try cutting down the DMP output rate? See line 261 on the MotionApps21 include file: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/MPU6050_6Axis_MotionApps20.h#L261 0x02, 0x16, 0x02, 0x00, 0x01 // D_0_22 inv_set_fifo_rate // This very last 0x01 WAS a 0x09, which drops the FIFO rate down to 20 Hz. 0x07 is 25 Hz, // 0x01 is 100Hz. Going faster than 100Hz (0x00=200Hz) tends to result in very noisy data. // DMP output frequency is calculated easily using this equation: (200Hz / (1 + value)) // It is important to make sure the host processor can keep up with reading and processing // the FIFO output at the desired rate. Handling FIFO overflow cleanly is also a good idea.
  7. Hi Ben, The numbers you are seeing appear to be all multiples of 4. This is extremely unlikely in a real-world situation, and makes me think that the way you are reading registers and/or converting data for storage in your variables has a problem with (1) register read orders, (2) byte orders, or (3) bit orders. Or, possibly, you are shifting values somehow after reading them. The various ACCEL_*OUT_H/L registers each contain 8 bits of the 16-bit raw sensor value. The _H register is the high byte (MSB), and the _L register is the low byte (LSB). If you read them independently and combine them, then you should store them into a signed 16-bit integer container something like this: int16_t accel_x = (ACCEL_XOUT_H << 8) + ACCEL_XOUT_L; Is this what you are doing, or something very close anyway?
  8. Hi Vigil, Other than overclocking (not typically a good idea) or switching to a faster CPU (e.g. Arduino Due), one thing you can do to help with I2C transactions is to change the I2C clock rate from 100kHz (default) to 400kHz (assuming you are running at 16MHz, otherwise it will be 200kHz). This is done with the following direct register write after you call "Wire.begin()": TWBR = 12; // set 400kHz mode @ 16MHz CPU or 200kHz mode @ 8MHz CPU Alternatively, you can change the DMP output rate by modifying the last bye of the last DMP configuration command on line 261 of the MPU6050_6Axis_MotionApps_20.h file: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/MPU6050_6Axis_MotionApps20.h#L261 0x02, 0x16, 0x02, 0x00, 0x01 // D_0_22 inv_set_fifo_rate // This very last 0x01 WAS a 0x09, which drops the FIFO rate down to 20 Hz. 0x07 is 25 Hz, // 0x01 is 100Hz. Going faster than 100Hz (0x00=200Hz) tends to result in very noisy data. // DMP output frequency is calculated easily using this equation: (200Hz / (1 + value)) // It is important to make sure the host processor can keep up with reading and processing // the FIFO output at the desired rate. Handling FIFO overflow cleanly is also a good idea. You do have to read all of the data that goes into the FIFO in order to prevent an overflow, but you can slow down the data that goes into the FIFO easily enough.
  9. Hi Winnie, If you are using the MPU6050_raw.ino example, then the INT pin is not necessary, since the measurements are polled from the accel/gyro registers without doing any interrupt detection. Are you sure that you have a solid 3.3v supply on VCC, the AD0 pin is connected to GND, and all connections are securely soldered?
  10. The main problem is (fortunately) not inside the DMP binary block, since its only job is to generate quaternions, which behave perfectly. The problem is in the math in the two conversion functions in MPU6050_6Axis_MotionApps20.h starting on line 639: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/MPU6050_6Axis_MotionApps20.h#L639 uint8_t MPU6050::dmpGetEuler(float *data, Quaternion *q) { data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1); // psi data[1] = -asin(2*q -> x*q -> z + 2*q -> w*q -> y); // theta data[2] = atan2(2*q -> y*q -> z - 2*q -> w*q -> x, 2*q -> w*q -> w + 2*q -> z*q -> z - 1); // phi return 0; } uint8_t MPU6050::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) { // yaw: (about Z axis) data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1); // pitch: (nose up/down, about Y axis) data[1] = atan(gravity -> x / sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z)); // roll: (tilt left/right, about X axis) data[2] = atan(gravity -> y / sqrt(gravity -> x*gravity -> x + gravity -> z*gravity -> z)); return 0; } I got those calculations from somewhere else, but quaternions have always been a bit of a struggle for me and the conversion to Euler or YPR angles is definitely more of a magic black box to me than anything else. If someone more familiar with the required math can improve these, or find other sources which do the conversion properly, this is where the fix would need to go.
  11. The MPU6050.* files (the actual device libraries) don't have any of the actual interrupt detection or pin assignment code in them; this is found in the MPU6050_DMP6.ino example sketch, specifically (at the moment) on line 196: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/Examples/MPU6050_DMP6/MPU6050_DMP6.ino#L196 // enable Arduino interrupt detection Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)...")); attachInterrupt(0, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); This uses interrupt 0, which on the Arduino Uno is digital pin 2. You would need to assign an additional interrupt with a different pin connection, and duplicate the "dmpDataReady" function (perhaps into "dmpDataReady2") and set a new "mpuIntStatus2" variable which can be tested in the main loop.
  12. The code you link to in the Keyglove repository works tolerably well, but since it relies entirely on the accelerometer readings (e.g. tilt with respect to gravity), it only works if the accelerometer is holding still. If there is any linear motion, then the calculations are messed up because non-gravitational acceleration is introduced. This is why the DMP is so valuable; it fuses the data from both the gyroscope and accelerometer to produce accurate results regardless of whether the sensor is moving or not.
  13. Is there a particular reason you are writing to every register as part of the initialization? After a reset, they should all be in the 0x00 state automatically with the exception of PWR_MGMT_1, which defaults to sleep mode. For a simple test, can you power it on and write 0x00 to register 0x6B, and then read ACCEL_XOUT_H/L (sequentially) repeatedly to see what comes out? You do have the AD0 pin tied to either GND or VDD, and (if applicable) the VIO pin also tied to VDD?
  14. Hi @rreay, Sorry for the long delay; I've been swamped with work and traveling a lot. In your tests, can you verify that whatever is causing the problem, the issue has to do with the FIFO overflowing? So as long as the FIFO is fine, then it continues, but when it overflows, that's what breaks the loop? I recall from earlier tests that the FIFO check loop as written wasn't bullet-proof.
  15. Hi George, Given that these values are relatively close to 0 on the scale of 1g (~5% of 8192), this is most likely due to calibration offsets in that specific sensor. You can overcome these with manual offsets in your own code, or with the various OFFSET registers in the MPU.
  16. Hi George, You probably aren't doing anything wrong, actually. The raw accel data comes in a 16-bit container with data stored in 2's complement form. This means that the variable range is [-32768, +32767]. Negative numbers are represented by anything >= 32768. Compilers and often map this 2-byte memory spaces right onto another 16-bit signed variable container and work with negative numbers automatically, but if you want to compute it by hand, you would do the following after the Processing code you listed: if (accel[0] > 32767) accel[0] -= 65536; if (accel[1] > 32767) accel[1] -= 65536; if (accel[2] > 32767) accel[2] -= 65536; This will offset all of the values to the correct range. The MPU actually only uses [-16384, +16383] for its raw data (not sure why), which means you should never see any unshifted numbers between 16384 and 49151.
  17. I'd be happy to answer any questions I am capable of answering, but I'm afraid that would be a pretty short list. We've only been able to get the DMP to work as well as it is by sniffing and then replicating the I2C traffic that shows up on the official InvenSense evaluation board for the 6050/9150, and the memory dumps are a "black box" for me. I can occasionally guess at what they might be doing, but I'm ever totally sure. Sorry for the lengthy silence by the way; I've been pretty occupied with work and other projects lately.
  18. You can gather data at 100Hz on an 8MHz Arduino, but you have very little time left for processing it, especially if your I2C bus is running at 100KHz instead of 400KHz. Many people have run into a problem where they use Serial.println() a lot to output data, and that takes a whole lot of time; generally, you have to make sure you have very tight code if you want 100Hz motion processing on an 8MHz host.
  19. Hi LagaV, I have tested the code with a 9150, and it does work (though you may have to modify the AK8975's slave address to be something else--0x0C or 0x0E or something like that--depending on your specific 9150. Some people have had it work as written, and some people have needed to change the slave address of the mag. I'm not sure what the pattern is, or if it relates to engineering samples or what, but in short, the answer is that you should be able to use it. The MotionApps v4.1 code is required, of course, since the v2.0 stuff doesn't have any mag support.
  20. Hello, I know that the quaternion orientation is correct, since the ToxicLibs-supported Processing sketch is able to represent the orientation accurately using the quaternion output. However, there is a flaw somewhere in the math that converts quaternions to yaw/pitch/roll values such that it never registers as being upside-down, even when it actually is upside-down. This is one known bug which I have yet to troubleshoot and fix. The axis orientation issue you are seeing may be related to this, since there is definitely something wrong with the math already. I (or someone) have to look into it further.
  21. It does, yes. That's the only device that the existing DMP binary I have supports, I think.
  22. I'm glad to hear that! I haven't actually worked with freefall detection at all, so I wouldn't be able to provide much help myself. I hope you are able to find some help in the older datasheets.
  23. I haven't added support for anything besides the AK8975, which is what was built into the MotionApps code. However, Github user @muzhig has made it work with the HMC5883L: https://github.com/jrowberg/i2cdevlib/issues/18#issuecomment-18402160 Note that this doesn't work with the DMP, but does provide raw magnetometer readings in the external sensor data registers as described in his comment.
  24. Hi guys, The setRate() method only applies to raw measurements, but not to the DMP which has its own rate. This is defined on line 261 (currently) of MPU6050_6Axis_MotionApps_20.h. The default rate is 100Hz (the last byte is 0x01), but you can increase it to 50Hz by changing that byte to 0x03 instead. To the best of my knowledge, the internal sensors are still read at a very fast rate, but the DMP algorithms compensate such that the output data is appropriate for 50Hz intervals. If you don't want to use the interrupt pin (which is a shame since it's much more efficient), you can simply poll regularly for a FIFO count that is >= 42 (which is the size of a typical MotionApps 2.0 DMP packet), and read those 42 bytes anytime they are available until there are less than 42 bytes available. It's kind of an ugly way to do it, but it does work as long as you read fast enough that the FIFO doesn't overflow (>= 1024 bytes).
  25. Hi pfalcon, I ended up with the XML format I have as a logical representation of the MySQL db backend I built specifically for the register maps. I built it to fit what I needed which is basically a device which has some properties an a list of registers, and each register has bitfields, and each bitfield has some options (some of them do anyway). The XML compliance changes (CDATA etc.) were recommended by the guy who originally asked for XML output. He created his own XSLT file to go along with it, and needed something that was 100% XML compliant. I'm open to YAML or other formats, or other data structures which make sense; I only built this to fit with what I needed at the time. Any potentially major changes would be better made earlier than later, before lots of people start using it.
×
×
  • Create New...