Is there a faster way to read sensor data?
amalfiCoast
Posts: 132
in Propeller 1
I am reading all three axes of a gyroscope and accelerometer module using my own code below. The update rate using this code is about 70 Hz. However, I tried using my LSM9DS1 IMU module with the supplied library and the update rate is 500 Hz! My question is, what is the Parallax library doing that makes the update rate so fast and what about my code below makes it so slow? Thank you.
// get gyroscope data // x-axis low(CS); //CS low selects chip shift_out(SDA, SCL, MSBFIRST, 8, 0b10101000); //Send read register address (OUT_X_L) xL = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); //De-select chip with CS line high low(CS); shift_out(SDA, SCL, MSBFIRST, 8, 0b10101001); //Send read register address (OUT_X_H) xH = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); gx = (short) (((xH<<8) | xL)-gxAvg)*.0175*PI/180; // y-axis low(CS); //CS low selects chip shift_out(SDA, SCL, MSBFIRST, 8, 0b10101010); //Send read register address (OUT_Y_L) yL = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); //De-select chip with CS line high low(CS); shift_out(SDA, SCL, MSBFIRST, 8, 0b10101011); //Send read register address (OUT_Y_H) yH = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); gy = (short) (((yH<<8) | yL)-gyAvg)*.0175*PI/180; // z-axis low(CS); //CS low selects chip shift_out(SDA, SCL, MSBFIRST, 8, 0b11101100); //Send read register address (OUT_Z_L) zL = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); //De-select chip with CS line high low(CS); shift_out(SDA, SCL, MSBFIRST, 8, 0b10101101); //Send read register address (OUT_Z_H) zH = shift_in(SDA, SCL, MSBPRE, 8); //Get value from register high(CS); gz = (short) (((zH<<8) | zL)-gzAvg)*.0175*PI/180; //2's complement operation, subtract zero rate offset, multiply by //sensitivity value for 500deg/s, "short" needed for 2's complement // get accel data //x-axis low(6); // CS low selects chip shift_out(7, 8, MSBFIRST, 8, 0b00001100); // Send read register address, z-axis x = shift_in(7, 8, MSBPRE, 8); // Get value from register x = x-xOffset; float ax = (float) x; ax = ax/64; high(6); //y-axis low(6); // CS low selects chip shift_out(7, 8, MSBFIRST, 8, 0b00001110); // Send read register address, z-axis y = shift_in(7, 8, MSBPRE, 8); // Get value from register y = y-yOffset; float ay = (float) y; ay = ay/64; high(6); //z-axis low(6); // CS low selects chip shift_out(7, 8, MSBFIRST, 8, 0b00010000); // Send read register address, z-axis z = shift_in(7, 8, MSBPRE, 8); // Get value from register z = z-zOffset; float az = (float) z; az = az/64; high(6); // De-select chip
Comments
The LSM9DS1 is a versatile, motion-sensing system-in-a-chip. It houses a 3-axis accelerometer, 3-axis gyroscope, and 3-axis magnetometer – nine degrees of freedom (9DOF) in a single IC! Each sensor in the LSM9DS1 supports a wide range of…ranges: the accelerometer’s scale can be set to ± 2, 4, 8, or 16 g, the gyroscope supports ± 245, 500, and 2000 °/s, and the magnetometer has full-scale ranges of ± 2, 4, 12, or 16 gauss.
Since the chip has so many axis, and so many scales it can do, is your code is probably using the device at maximum , 16g, 2000 °/s, and 16 gauss?
This creates much more data to transfer and causes the lsm chip to take longer in its response.
After a quick look over the chip .h file --->https://www.parallax.com/sites/default/files/files/prod/docs/l/Learn-Folder-Updated-2018.10.02.zip (its deep in the sensors folder)
It shows that they use a data transmit method that looks like it would be faster than the SHIFT_OUT routine that you use.
Why don't you just include the lsm9ds1.h file and use it?
I didn't look at the parallax code to see what precision they are setting for the lsm9ds1 module in their example. But that is probably where you need to look. And the shift out is probably slow.
Thanks for your response. I'd prefer to stick with C because that's what I'm used to and the rest of my program is also in C but if I can't get anything else to work then I will look further into PASM.
Thanks for your response. I'll need to check to see if my settings are what Parallax is using. Thanks for that suggestion. Also, I thought I saw in the library's imu_read and imu_write functions that they use the shift_in and shift_out commands. I do think these commands are what is slowing down my code but I don't know of another way to do it yet. I feel like there should be something obvious going on here since the Parallax loop is running more than five times as fast as mine.
It takes a long time to write out a serial stream using that method, but that would let you avoid the shift out/in method.
AND as a bonus, if you do it this way, you can EAISLY use PASM. (but one of the prop pasm c gurus here need to convert this c into (c pasm) for us.)
etc... have fun?
Thanks,
David
But even that will take me a long time to show you.
Then you would need input data also.
Which takes even longer, because you need to reconstruct the data into the proper sized variable instead of a bit stream of 1/0 and a variable with just a 1 or a 0.
Currently your method stores 32bits in a variable.
I am talking about storing 1 bit in a variable.
So you can see how LONG that will take to write out and then take all those bits and put them into a single variable.
Those two single lines of code end up being hundreds of lines using bit bashing.
Thats exaclty what i would need to go do because I do not know or remember how that method works exactly.
"SPI / I2C serial interfaces "
Shift out would use the spi interface, i think... but without any bells and whistles...(those might be in the i2c)
Data sheet is teh!
https://www.st.com/resource/en/datasheet/lsm9ds1.pdf
Thanks,
David
I still haven't installed simple ide because I am trying to compile it and haven't gotten it to work yet.. gotta catch up...
You're right I wasn't showing all my code. I was able to get the size down to where it would fit in the LMM memory model by hard coding values, pre-calculating values such as sensor offsets in a separate script, etc. Now the code runs extremely fast. Almost too fast to the point where it messes with the pwm_set() function. I use pwm_set() after a state estimate propagation and then again after a new state estimate from a correction. Those details don't matter but for some reason it only is able to handle one of these pwm_set() functions. I even tried passing the data to a separate function that would handle the pwm_set(), but that didn't work. My code is below, with the separate function I tried commented out. Sorry if this post is confusing.
Cheers,
Jesse
My next question would be, why does the LMM memory model speed up the code so significantly? It's amazing how much faster it runs.
For anyone interested, the code for my working balancing robot running an extended Kalman filter is below. I have pre-computed and fixed the Kalman gain matrix which is not optimal, but it works to speed up the code and ensure the program is able to fit inside the LMM memory model. Any questions, please ask. I'd be happy to help anyone with a similar project if I can.
https://github.com/parallaxinc/propgcc-docs/blob/master/doc/Memory.md
I wrote/stole that library from the Arduino/Sparkfun one for the same chip. I used shift-in and shift-out just like you did, so I don't think the speed difference is there. Just a quick glance at your code in the original post shows a lot of float operations, and a lot of casts from int to float.
Floating point on the Prop, especially in C is time-consuming. I avoid it until the very end, or simply don't use it at all. Try doing all of your math with integers right up to the end - that may help.