Josh Leverette's blog

Josh Leverette's picture

Applying Mathematica to Quaternions

This evening, I spent several hours writing out the Mathematica needed to load the thousands of data points coming out of my microcontroller into lists of 3-element tuples, one for each sensor, in preparation for being manipulated. I began experimenting with the data using the Quaternion information on Keith Packard's website as well, but I didn't finish with that.

Also: ever since this Drupal website was re-themed, which is pleasant, the form submission has stopped working on my Raspberry Pi under normal circumstances. In both the built-in browser and IceWeasel, the form submission (clicking "Preview") appears to do nothing but reload the page to a blank slate. Incidentally, Chromium actually works for this website, but I find it interesting that nothing else does on my Pi. I haven't tried to replicate the issues on my Mac mini, so I can't be sure there isn't something strange going on with just Raspberry Pis trying to interact with or if it is all non-Chromium-based browsers. Something to think about.

Josh Leverette's picture

Data Analysis

Since I'm on my Raspberry Pi 2, I have free access to Mathematica 10, so right now I am working with the built in quaternion library to try to process the data that I collected yesterday. For practical purposes, I'm not convinced that it matters when the data is processed. Both the software I'm writing to run on the microcontroller and Mathematica will have to assume that the n-th data point is being generated consistently at t = n*(1/ODR), where ODR is the Output Data Rate of each particular 3-axis sensor. I mentioned a few posts ago that I would like to actually process some data with Quaternions involved before getting too deep into the code on the microcontroller. Understanding the algorithms should be easier when the data is manipulated in a responsive, real-time fashion, rather than on the remote, resource-constrained microcontroller target. Certainly, once a technique is clearly in mind, this microcontroller should not have any trouble crunching these numbers.

Josh Leverette's picture

Tangible progress

This evening, I fixed the magnetometer so it actually works for more than one sample. I found that I had done the math wrong when I calculated the ODR constant and I was thus writing an invalid data rate to the magnetometer.

I also re-organized demo code so it collects all of the data before printing, which should help keep data samples as time-aligned as possible, something that had previously concerned me, though I may not have noted it here. I also separated a few useful functions from the demo into a helper file, removed some commented out code that had been forgotten in the demo, and collected some new data.

In lifereckoner, I re-organized the code so that dead reckoning is now a task, in some form or another. I'm not using a proper RTOS, though I would like to be using FreeRTOS, but I've never used it so I haven't tried integrating that yet. Just having the code broken out into a task means that it is possible I could implement a rudimentary RTOS now, which might be helpful at some point. I also created some global state that will be shared in the RTOS, namely the LSM9DS0 driver and the Serial port connection. None of that is really thread safe at this point, but as I don't have threading, that isn't much of a concern. I also added a quaternion to keep track of current orientation, and I plan to begin implementing the code to calculate initial orientation as Keith Packard discussed in his blog post.

In short, I felt like I actually made some useful progress today.

Josh Leverette's picture


I spent time this evening discussing quaternions with a friend who has a masters in mathematics, and I believe we narrowed down what needs to be done, but his area of expertise is not quaternions, so we did not get the problem solved. I'm still awaiting a reply from my mentor to the email I sent last night. At this point, I intend to begin pursuing a solution through converting quaternions back into Euler angles and using those angles to rotate the accelerometer data back into the inertial reference frame, which will allow me to make progress. I am uncertain if that tactic will suffer from gimbal lock, since the device's orientation is being maintained in a quaternion and I will be using the gyro data to directly update the quaternion, rather than dealing with euler angles there. I expect to make significantly more progress starting next week.

Josh Leverette's picture

Continued quaternion stuff

Today, I've continued looking at and thinking about how to utilize quaternions effectively. I believe I've made some progress on that front, all I seem to be missing at this point is how to use a given quaternion to rotate the axially-locked data from the LSM9DS0 into the inertial reference frame so it can be used to update the current position.

I've reached out to my mentor in hopes of getting a little more insight on this topic. I'm still very new to quaternions, but I think I can make more forward progress once I have this figured out.

Josh Leverette's picture

Lifereckoner Progress

This evening, I added the excellent quaternion implementation from Keith Packard's AltOS to my lifereckoner project. Doing this required that my code be GPLv2 licensed as well, so the license for both the LSM9DS0 driver and the lifereckoner code has been changed to GPLv2. I also spent time adding main.cpp, a modified Makefile, and importing a variety of mbed support files to make lifereckoner now a buildable project.

In my main.cpp file, I verified that importing the quaternion header did not generate any errors, and although I have not tested the actual functions themselves, I don't expect them to generate any errors.

The code is now ready to start working with quaternions, so we'll see how that goes.

Josh Leverette's picture

More Quaternions

At this point, I feel like I understand what quaternions are and how they work. I'm still not entirely comfortable with them, but I'm currently planning to re-license my code to GPLv2 tomorrow and integrate Keith Packard's quaternion code. I think that by starting to use them, it might fill in the gaps. At this point, I'm just not certain exactly how the quaternions are used to get compute the devices location, even after spending some time on Saturday looking into quaternions.

Quaternions represent orientation, of course, but using them as part of the calculations involving the accelerometer to get current location isn't intuitive for me. I've worked it all out on paper using traditional euclidean methods and have a pretty good understanding, but I think I'm still missing one critical connection with quaternions. I'm definitely glad to be learning about quaternions, since they seem applicable to many fields that interest me, including aerospace.

Josh Leverette's picture

Research and Evaluations

Today I continued learning about quaternions, but not in as much detail as I had hoped to. Right now I'm planning to spend some hours tomorrow learning more about them and hopefully doing research on quaternion libraries. I also worked my way through the GSoC midterm evaluation and submitted that. I like to be done with important paperwork such as that as soon as possible, lest I forget to do it at all, which would be very unfortunate. I am definitely appreciative of the opportunity to be working on this project under the auspices of Google Summer of Code. I had worked with microcontrollers before this summer on a number of occasions, but I've definitely learned a lot. Theory that I had known before has become more practical know-how on several topics.

Josh Leverette's picture


I've been studying on the subject, and Keith Packard's blog post on it has been a pretty good resource so far. I could implement my own quaternion library, but I'm not certain it would be the best use of my time. I'm considering relicensing my code under GPLv2 to be compliant with Keith Packard's code and use his, but I honestly prefer the MIT license and similar ones, since they're more permissive. I'm looking around to see what options exist, but I'm not completely opposed to using the GPLv2, so I may end up going that route.

I also spent some time refreshing my memory on trigonometry, some calc-based physics concepts like the relationship between position, velocity, and acceleration, and how all of that could be applied to take data in from the 9-axis sensor and compute positional updates. Unfortunately, that intuitive system suffers from Gimbal Lock, so I'll be using Quaternions, I believe, but it was still good to refresh my memory on the more traditional trigonometric relationships.

Josh Leverette's picture

Data collection

Today, I finished setting up my Raspberry Pi 2 to be able to serve as my development station and it works. I collected some 9 axis data and stored it in a file for later analysis. For some reason, my magnetometer is only generating one triple of data. After that, it never generates another until reset or re-initialized. I need to read more documentation on that, I probably forgot to set a bit somewhere. My internet at my apartment has been effectively non-existant today, and the same is true of at least one other friend's apartment in town, so I'm hoping Charter figures it out soon. Going from 60 megabits/s to about 100 kilobits per second is rather limiting.

What I would like to do at this point is just work on algorithms. I have some data, and I'd like to figure out how to process it and get something useful out. Quaternions seem useful, but I need to get a working knowledge of them if I'm going to do anything involving them. But, algorithmically I'm attempting to calculate X, Y, and Z positional offset from when the device was turned on using data gathered from the 9 axes.

Once I have an algorithm, implementing it on the Nucleo shouldn't be much of a challenge; the math seems like it will be much more challenging.

Syndicate content