I want to track my bike rides and get some experience with CoreFlight
Blue is the GPS track, red is the filter output
Portable Network Graphics (PNG) - 49.07 kB - 07/03/2019 at 22:19
Blue is the GPS track, red is the filter output
Portable Network Graphics (PNG) - 55.90 kB - 07/03/2019 at 22:19
I'm nowhere close to having all the electronics integrated, but I took my laptop on a quick drive the other day and recorded this from the kalman filter.
Red line is the filter track. Looks great, right? Well, here's the raw GPS data (in blue):
Yep, same basically the same track. What does this mean? Well, I had a really good GPS signal on this drive, I think I just had great resolution. No major tracking errors. The accuracy meets everything I think I'd need for an actual bike trip, but I'd like to do better and add more bells and whistles, re-enable speed based prediction and include an accelerometer.
In addition, the data ends early for some reason. I was recording this with a CoreFlight app, and whatever I wrote had some error, although it didn't crash anything. I've included more error checking in case this happens again, though an app crash/restart could overwrite the log files, which would be a problem.
I'm seriously getting stuck on how to safely integrate an unprotected 18650 battery into this project though. It looks like I'll have to include separate charging, protection, and 5V regulation ICs to get the Raspberry Pi powered. I'll then send the data lines from the Raspberry Pi straight through to the charging port so that a computer can talk to the Pi while charging the battery.
Next problem: I think I need a high-side battery protection IC now. Most of them are low-side, but the battery will still be grounded through the charging IC.
I'm only parsing the most generic message from the gps_reader application, which greatly simplifies the source code. In addition, I noticed that when the GPS loses a lock, the filter lat/lon quickly goes back to 0/0, so for now the filter isn't run unless the GPS indicates that PDOP isn't maxed out.
Next up is going to be figuring out the power systems to make this portable. I have a bunch of unprotected 18650 batteries, but my cheap ebay electronics don't get all the power out of the batteries that they could. I need to research higher performance boost controllers and battery protection ICs. In addition, I don't want to overcharge these batteries by plugging a USB cable into the Pi and pushing current backwards though a boost controller and battery protector.
I finally got all the steps for a matrix inversion working in C. It hasn't been verified yet and I don't have any new data to work with, but so far things seem promising. In regards to inverting a matrix, which had me stuck for some time, the solution is apparently an LU decomposition and then an inversion:
int signum; gsl_permutation *permut = gsl_permutation_calloc(DIMS); gsl_matrix *Scratch = gsl_matrix_calloc(DIMS, DIMS); gsl_matrix *Scratch2 = gsl_matrix_calloc(DIMS, DIMS); gsl_linalg_LU_decomp(Scratch, permut, &signum); gsl_linalg_LU_invert(Scratch, permut, Scratch2);
Currently, `Scratch` and `Scratch2` are actually statically allocated in order to reduce dynamic memory. Requires a little bit of indirection between `gsl_matrix_view` and `gsl_matrix`, but I prefer it overall.
The new filter output is in green here, overlaid on the sensor data (blue) and the octave version of the filter (red).
Velocity data is still not being used here, which is a big TODO. Without it, the filter is basically just a running average. I still need to collect more data to evaluate, and also integrate this filter into a CoreFlight app.
I've starting writing the kalman algorithm in a CoreFlight app. It receives GPS data messages from another application that handles the serial parsing, and this one is supposed to run the kalman filter.
I've got most of it working right now, but I stuck on how to calculate the inverse of a matrix in C. I've been using the GSL library for the matrix math, since it supports BLAS functions and it makes it easy to write the code for an arbitrary matrix size, but I just can't figure out the inverse thing.
I decided to start on testing the sensor algorithms. I chose a kalman filter to experiment with first, mostly because it can handle a wide variety of input, and there's lots of resources online. My state vector is currently just the measurements from the GPS.
I'm not including my actual filter computations because the current LaTeX embedding on this site is pretty janky and it was just too painful to try and write out the matrices and put them in the correct places. There's tons of resources online for kalman filters if people are curious. If they really want to look at what I'm doing, I'll try and post it.
I took my laptop for a walk around the block, with the GPS module attached to a CP2102 USB-Serial converter, recorded the data, and put my filter over it in Octave.
Oof. The blue line is the GPS track, and the red is the kalman filter. The filtered data is even worse than the raw data, but neither is great. That blue thing is supposed to be a diagonal rectangle in the shape of my block. I've got no idea what's going on with that big loop in the bottom. In real life, that's gotta be at least a hundred meters in the wrong direction.
I decided to take velocity information out of the filter:
I spent a few minutes today writing down my requirements for this device, as the end customer. Hopefully this will give people a better idea of what I'm thinking of, though it's still pretty generic.