LSM9DS1 9dof Sparkfun sensor help.
Zap-o
Posts: 452
in Propeller 1
I have a propeller boe-bot connected to the LSM9DS1 from spark fun and cant seem to figure out how the start up sequence goes, say just for the accelerator.
I wondered if anyone has a little experience with this fantastic sensor and if so please be a hero and provide a snpit of code for me. Basically I am trying to convert ardino code (clueless to me) to spin and I am having issues. The data sheet is not very clear (imo) as it list many registers but nothing about how they should act or details.
Ill post my code as soon as I can get that new computer on line, windows 10 sucks a little at the moment, for me.
I wondered if anyone has a little experience with this fantastic sensor and if so please be a hero and provide a snpit of code for me. Basically I am trying to convert ardino code (clueless to me) to spin and I am having issues. The data sheet is not very clear (imo) as it list many registers but nothing about how they should act or details.
Ill post my code as soon as I can get that new computer on line, windows 10 sucks a little at the moment, for me.
Comments
It will also likely help if you toss us a link to the arduino code you're using. A quick Google showed this though: https://github.com/sparkfun/SparkFun_LSM9DS1_Arduino_Library
I'm guessing that's it?
For the lookers I am starting to get this sensor to work looks like the boe-bot might balance on two wheels soon.
http://forums.parallax.com/discussion/161040/another-i2c-assembly-driver
Maybe that will work for that chip too?
I am having difficulty putting the two bytes together after polling the registers. Otherwise its fairly straight forward. Something about the 2s complement thats getting me stuck.
I was doing the following after polling a regiater.
X is suppose to be the value of two bytes
XH is high byte and XL is the low byte.
Anyone? Sorry limited code im on a phone.
You need sign bits in upper 16 bits of 32 bit value...
You need to shift 24 bits left and then shift "arithmetic" 16 bits right. Then, you can or in the low byte.
The second line is "sign extend word to long"
Is it true that the gyro data should remain positive say clockwise and negative anti-clockwise?
You need to integrate the acceleration to get velocity.
If your bot starts falling forward, that's positive acceleration.
When it hits the floor there's a large negative acceleration as it stops.
So, that's positive and negative signals even though rotating in same direction all the time....
Was wrong about that... Sensor does measure acceleration, but chip output is velocity in degrees per second...
When the bot is rotating around an axis in one direction, the value for that axis should be positive, and when the bot is rotating in the other direction it should be negative. Bigger absolute values mean you're rotating faster.
If you want to know what your absolute orientation is, that's a harder problem. In one axis it's not too bad though. It involves using the accelerometer readings and atan2() to compute an absolute direction for gravity, using the gyro to compute a rotation rate, and using a complimentary filter to merge them together.
You have two sensors that are useful for this problem in that chip - The accelerometer and the gyro. The gyro gives you your current "instantaneous" rotation speed. The accelerometer gives you your current linear acceleration due to outside forces, which includes the force being applied by the ground that opposes gravity.
To balance the bot, you need to know its angle, and accurately. If you *just* use the accelerometer, it'll be noisy as all get out. If you *just* use the gyro, you can tell how fast you're rotating, but not your absolute angle, because you have no fixed frame of reference. By fusing the two together you can get what you need.
If you take the accelerometer reading for "forward" and the one for "vertical" (probably called Y & Z in your code) you can get your current angle like this:
You can compute a running angle for the gyro like this:
So now you have one value that's "absolute" (the accelerometer angle) but it's *really* noisy. You have another value that's reasonably stable (the gyroAngle) but it's going to be completely wrong before too long, because the math is never going to be perfect. It's like trying to know how far you've driven by reading your speedometer once a second.
The trick is to use one to correct the other, but slowly. Gyros handle noise better than accelerometers, so you can trust them more. Accelerometer, over time, is going to give you a more absolute reading than a gyro will, because it's reading gravity, so you mix a little of the accelerometer angle into the gyro angle to correct it, every update, like this:
...and that's called a complimentary filter, because the two values compliment each other. You can change the 0.98 and 0.02 to different numbers (they have to sum to 1.0). They're chosen based on how much you trust your sensors. Since the gyro is very trustworthy, it gets the higher number.
This is intended as a description, by the way, and the code above is totally un-tested. To actually use this, start by reading the accelerometer and gyro values and make sure that they move in the same way. I might have the signs backwards, or used the wrong axis values, or any of a number of things. You also have to make sure they're working in the same units - that's why I have the GyroUnitsToRadians value there - You'll need to figure out what that number is for your gyro.
As an example, they may tell you that your gyro is 40 LSB's (least significant bits) per degree. In that case, it means a reading of 40 from the gyro is equal to 1 degree per second. To convert that to radians per second, you'd use GyroReading * (PI / (180 * 40)).
From there, you have to convert the "radians per second" value to "radians per update", since you're only interested in how much you rotated since the last time you checked. If your update rate is 100 times per second, you'd divide by 100.
That's a lot to digest - read over it and feel free to harass me with questions.
With that you can fuse (combine) accelerometer, gyroscope, magnetometer inputs into an accurate orientation.
Look for MadgwickAHRS.c or MahonyAHRS.c in there. It's an exercise for the reader to convert that to Spin
Wonder if Spin is fast enough. It might be, but kind of tough with all the floating point operations.
This actually looks like a good use case for PropGCC...
But it is NOT merely about coding in this or that language. The whole concept of tracking rotation and heading involves some fairly exotic maths in order to avoid a problem in calculation called 'gimbal lock'.
You have 9DOH or degrees of heading. 3 by magnetic compass, 3 by accellerometer, and 3 by gyro. Mostly the accellerometer and gyro work well together to correct errors that cause drift. If you use just the accellerometer or just the gyro, you might have less that desired results.
So this is where Madjwick and others - (like Mahoney) have created a way to combine to get the best results. You may not need to bother with Madjwick or Mahoney for a balancing bot that stays upright in one place.
The new Elev8-FC flight controller uses the LSM9DS1 sensor, so I have code that uses it, but it also handles the barometric pressure sensor, drift compensation, and the on-board WS2812 LEDs, so it wouldn't be quite "plug & play" for your needs.
The code is already on GitHub here: https://github.com/parallaxinc/Flight-Controller
There's currently a Spin version and a C/C++ version. It's in-progress, but the sensor reading and IMU code is fully functional. I'm also testing a fusion of the barometer readings with a double-integrated accelerometer height estimate, and it seems to work pretty well. Complimentary filters are useful things. There's a readme file in the "Firmware" folder (the Spin version) that describes all the modules and gives some high-level details on how they work.
How about getting a Bosch 9 degrees sensor which does all that data fusion hard work for you ? https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview
SimpleIDE ships with PropellerGCC, and doesn't require you to set up makefiles to compile a project.