PersonalSoundtrack: Development Blog

The open-source music player that detects your walking or running speed and plays songs from your music library that match your pace. Song speed is adjusted in real-time to match subtle variations in your gait, while larger, deliberate pace changes cause the device to change songs. You simply put it on and begin moving; that's it.

Monday, December 04, 2006

Version 3.0 Complete.

So, in almost exactly 30 days, I've accomplished my goals. I have the finished product in my hand (though I still need to figure out how to custom design a case for it).

First, here are some fuzzy (sorry, it's late!) pics of the device without its jacket:





Time to go over the meta-list of what I've accomplished thus far:


  • Develop power solution that requires only one single-cell Li-Ion battery

  • Develop a pocket-sized, light version

  • Develop a deployable method for recreating the OS easily should the image become corrupt

  • Decrease power consumption by 75%

  • Reduce computational load by %50

  • Develop a custom circuit for measuring steps

  • Custom circuit must be cheap, light, require little power, and be robust

  • Custom circuit must fit into 1"x1" space, and be only .15" thick.

  • Custom circuit must accurately detect steps in less rigid and stable environments (pockets instead of belt)

  • Cost of ALL parts must be below $250 including battery, case, memory cards, etc.



Many of these require elaboration.

To reduce power usage to allow for a single-cell li-ion battery, I had to build my own accelerometer circuit. This was odd because li-ion's tend to run from 3.7 down to 3.0/2.8, and the gumstix has a minimum voltage of 3.3. Thus, my custom circuit needed to function well in the 3.3 to 3.7 range. This affected the capicitors and oscillator i used in the custom circuit.

To develop the pocket-sized version, i had to essentially cut the previous thickness down to 1/4 the size of version2, and reduce its height and weidth down to the size of the audiostix board. I did this by dropping the compact flash board and using MMC storage instead, using li-ion batteries, creating the custom step-detection circuit that is the size and thickness of a silver dollar, and rewriting logic to compensate for the bizarre vibrations that as a result of the device beingi placed in the pocket. Versoin 2.0 was securely fastened to the waist with a large belt, which helped minimize noise on the accelerometer. While this works, and other developers rely on armbands and such for accurate accelerometer data, I wasn't satisfied with being forced to wear a belt or armband. The pocket version only requires vertical orientatoin at this time, but works fine while being bounced off the leg during walking. Orientation will be compensated for in subsequent versions. Unfortunately, the largest part of the device is the antenna used for bluetooth communication. I'm looking into smaller, chip-based antennaes as an alternative.

Typically, the gumstix has 16MB of flash memory onto which the OS is flashed. This is a slow process requiring access via serial to the gumstix console. The problem is that the jffs2 based images can become corrupt if power is unexpectedly lost, or for a host of other reasons. In the past, this happened to me and I had to disasseble the entire device, reattach the serial board (none of my previous purchased boards had breakouts for ttyS0), and reprogram it. Furthermore, the process would have to be duplicated for additional devices. Instead, an involuntary requirement forced me into a better solution. There was a shortage of bluetooth motherboards from gumstix during the time I needed to purchase another (I was still demoing version 2.0). I ended up tracking down an old gumstix bluetooth motherboard that someone was selling. Unfortunately, it only had 4MB of flash memory (python alone takes up 7MB). Thus, I wouldn't be able to flash the entire OS onto the gumstix motherboard. After some communication with a gumstix developer, he told me there was a method of placing the filesystem on the mmc card and pivot-root'ing that after boot. After several exchanges, he provided me with many commands to achieve this. After some testing and modification to his commands, I was able to create the filesystem and pivot-root from a small OS stored on the 4MB flash to the full-sized filesystem stored on the MMC card. The benefits of this are obvious: if the filesystem on the MMC becomes corrupt for whatever reason, it can simply be removed, plugged into my laptop, where i keep a backup copy of the mmc card files, and i just copy the filesystem back over. plug the mmc card back in, and i'm back up and running in less than 5 minutes. of course, its always a possibility that the filesystem stored in the 4MB flash could become corrupt, but since its very unlikely that the system will be powered on and powered off right at the time when the default OS has booted, but before the new root has been pivot-root'd (which gracefully unmounts the filesystem stored in the on-board flash), this is much less likely.

To decrease power consumption by 75% and reduce computational load by 50%, i simply had to create the custom circuit and reduce computational load. By offloading processing on the pic (which is better suited to high-speed analog reading than the linux motherboard), the gumstix boards do VERY little, and use less power. Furthermore, the pic can be run at lower voltages, which allows for smaller/different battery types. Previously, the gumstix board was forced to read from the accelerometer over serial at 30hz, which tied up quite a bit of IO and computational power.

The development of the custom circuit was the main push of my time. I ended up using a pic chip that reads a PWM accelerometer, determines if a step has occurred, computes steps per minute, and sends that value over the serial line to the gumstix. The code was written in assembly, and timed at the microsecond level. An LED is lit up whenver a step is detected for feedback. The trials and tirbulations of developing this circuit is spelled out in length in this blog and in my reports.

In order to fit the circuit into the size requirements, i ended up cutting off the pins of the pic chip, and soldering the parts directly to the chip. no circuit board was used as it added too much thickness. the entire circuit could be no thicker than the height of the pic chip if it was to fit nearly flush with the li-ion battery. This was difficult and required several prototypes including a breadboard version, and debug version, a final version 1, and a resoldered version to that moved the custom circuit to a different spot on the gumstix board and incoporated an on/off switch and led for step detection feedback.

Cost of parts was limited to the best value parts available where substitable (that is, anythign other than the gumstix):
Gumstix Motherboard w/ Bluetooth: $179
Gumstix Audiostix: $40
MMC card 1gig: $35
Pic Chip: $0.75
Li-Ion 860mAh battery: $7
Caps, oscillators, resistors, LED: $1
Total: $262

So my goal was $250 and it costs $262. pretty close. I haven't added the cost of a case as it hasn't been designed, but it should be worth noting my original estimate didn't include the MMC card, which would have made my goal $285.
In fact, the current device sitting next to me is an older gumstix board.

The final things to implement are creature comforts: volume control via GPIO interrupts (easy) and case design.

I'll be building the second device next week as I've already received the parts, so I expect to just solder together the step detection circuit and copy over the mmc card files to the new mmc, and that should be it! Very easy to assemble, actually.

Lastly, I'll include a final abstract diagram of the hardware components involved, which I may use someday to develop a completely custom device.

Sunday, December 03, 2006

Pictures of Nano-sized PersonalSoundtrack

so i was wandering around fry's yesterday, with personalsoundtrack jammed into a small clear plastic box, looking for a suitable case. i couldn't find anything small enough. i kept thinking to myself, i need some container the size of an ipod... hmmm... then it hit me: for a temporary solution, why not just buy an ipod nano case? brilliant.

went to the apple store and found a nice stretchy neoprene case by incase, that fits personalsoundtrack almost perfectly.
THIS IS NOT THE FINAL CASE! i have a demo on monday and for testing, it will be very easy to carry around like this. i'll be designing a custom case soon.

i'll also post pictures of personalsoundtrack without its jacket on later today/tomorrow.



Friday, December 01, 2006

SUCCESS!!!!!!!!!!!!!!!!!!!

victory dance time. the pocket-sized version is essentially ready for a case. right now i've got it crammed into the gumstix plastic casing that one of the boards came in. this thing is TINY. with battery its the size of my ipod nano.

pictures, diagrams and videos to come. now i'm off to relaaaaaaax before finals week begins.

Monday, November 27, 2006

Version 3.0 Ready for FINAL test build

Well, it's been a semi-long road, but i'm finally ready to build the complete unit. i'll recap what i've done since my last post.

i solved the accelerometer non-linear output issue. my delay loop was the culprit. before explaining the solution, it's important to understand the problem.

how am i determining steps per minute? one method is to keep a counter that allows me to track how much time has passed directly. that is, every 10 microseconds i increment a counter, and simply count how much time has passed and deduce steps per minute. for example, if 1 second passes between each step, that means the user is taking a step 60 times per minute, or 60 steps per minute. likewise, if 0.5 seconds passes between each step, the user is taking 2 steps every second, or 120 steps per minute. easy right?

i'm not so crazy about using time dependency like that because it relies too heavily on the accuracy of my timer. this is bad because time is highly dependent on the speed of the processor.

an alternative method to using time directly, is to measure time indirectly. we can do this by looking at how many samples the accelerometer has output. why? well, what is a sample rate? it is the number of samples that occur PER SECOND. that means the sample rate is a time-based measurement, but doesn't depend on the pic's clock speed. so how can we use the sample rate? well, first we need to know the sample rate of the accelerometer. for example's sake, let's say the accelerometer outputs 100 samples per second, a sample rate of 100hz. we can count how many samples are output by the accelerometer, by simply reading one complete pulse from the pulse wave. since we can do that, we can count how many samples are output between each step that is detected. continuing with our example, if the sample rate is 100 hz, and lets say we are busy reading samples, incrementing our counter every time one sample is read. if we read 100 samples, then detect a step, then read another 100 samples, then a step, how fast is the user walking? well, the user is taking 1 step every 100 samples, and we know that 100 samples are output every 1 second, thus the user is taking 1 step every second. likewise, if we read 50 samples then detect a step, then read another 50 samples, and detect another step, how fast is the user walking? the user is taking 1 step in every 50 samples, and we know that 50 samples is half 100, so half a second. thus, the user is walking 120 steps per minute.

now, the samples quite short. in fact, the accelerometer i have has a sample rate of 138hz; that's a full sample every 7 milliseconds. needless to say, when we are detecting how many samples go by, miniscule errors in the human step pattern result in large variations. no one can step to a beat with an accuracy of 7ms. so, if the system is off by the tiniest bit, the number of samples that we see occurring between each step detected will be greatly affected. while we might expect stepping at 60 steps per minute would be 138 samples, and 120 steps per minute would be half that (~70 samples), my incorrect code was only reading 40 samples at 120 steps per minute. that's less than half the number of samples that occur at 60 steps per minute, which doesn't make sense. it should be roughly half.

fine. so that was the issue. here's how i fixed it:

because the accelerometer is quite sensitive, and measuring vibration leads to an incredibly rough signal (the accelerometer's output looks like the output from a seismograph), we need to do some filtering so that we only count real steps. one step could be seen as 5-6 depending on how closely we look at the accelerometer's output. while i have tried several algorithms to filter the output, the most trivial method worked the best: if the accelerometer's output is large enough, we detect it as a step. this simple one beat out peak and valley measuring, dynamic max/min comparisons, windowed filtering, etc. while i'd like to say i created some nice algorithm to filter it, i can't; the stupid algorithm was the best.

so, the moment i detect a step, i punt out of reading the accelerometer, compute the steps per minute, AND (here's where the error occurred) i then did nothing for 250 milliseconds.

but why?

well, my reasoning was, the moment we see a step, we can simply ignore the next 250 milliseconds because a step every 250 milliseconds is approximately 300 steps per minute. that's very fast. i don't know many people that run that fast in normal situations. so, i figured hey just wait 250 ms then start reading again. that way, i don't count all the garbage vibrations that occur with every step. this was the error in my code.

first, the accelerometer does not output at a constant sample rate. instead, the sample rate is allowed to fluctuate, but the ratio between the on time of the pulse and the off time is always consistent. that means, the sample rate could drop to 80, but the pulses would be sized accordingly. armed with this new information, i set out to make my delay smarter. instead of just waiting a blind 250 ms, i decided to count a certain number of samples, in order to compensate for the changing sample rate. that way, i'd know that after each step, i ignored exactly 30 samples before resuming the program.

this also failed. why?

i wrote some code to output the length of each pulse as it was read. then i tested it. sure enough, the sample rate wasn't varying that much, and only varied when i took a step. we're talking 5-7 samples more or less when a step was taken. was it really THAT big a deal?

then i remembered the time scale i was measuring: one sample was only 7 ms. the slight variation in sample rate could throw the samples off by 5-7, and since that error was created each time i took a step, then the more steps i took per second, the more error accrued. ERRORS ARE CUMULATIVE! so, stepping at 60 steps per minute, i'm only incurring an error once per second, so the overall steps per minute calculation would be off by around 5 samples. not a big deal, but at 180 steps per minute, i was incurring somewhere around 15-21 sample errors. this was further exacerbated by the fact that higher steps per minute usually meant more vigorous vibrations which lead to larger sample rate variations.

so what i was assuming is that ignoring 30 samples would be the same amount of time delayed for each steps per minute. what's in fact happening is the length of time 30 samples takes is different for each steps per minute interaction. at 180 steps per minute, 30 samples a different amount of time than at 60 steps per minute.

my solution was to change the filtering from time-based to sample-based (in a different way). first, i removed the delay, tried it out, and saw that overall the samples were coming out correctly (138 for 60 steps per minute and 69 for 120 steps per minute). however, now i was detecting 2-3 steps for each real step that occurred. my new solution was this:


step detected?
if yes:
     was the step humanly possible?
     if yes:
         blink led
         calculate steps per minute
         send steps per minute out serial line
     if no:
         ignore


so what does humanly possible mean? well, i sat down and tapped this circuit at 300 beats per minute and how it tell me how many samples it was reading between each tap at that pace. it was able to read 30 samples between each step at 300 beats per minute. so humanly possible means, did you read at least 30 samples? now, the device will say "hey i saw a step" multiple times for a single step that actually occurrs, but it won't DO anything about it unless enough samples have been read since the last step. simple solution, perfect results.

now everything is working. next step is to build the prototype board (no breadboard) in a very small size using a pic socket ( so i can reprogram it as needed after real-world testing), and solder everything up to the gumstix board. simon penny has given me a bunch of non-rechargeable li-ion batteries that i can use for testing. i'll be ordering some 1000mhA li-ion batteries from sparkfun that are rechargeable.

tom has ordered some pic sockets, and hopefully they'll be here soon.

so in the end, it seems i've been able to take a large, belt-mounted power hungry device and shrink it down into a device that's the same size as my ipod nano, uses less power, and is SIGNIFICANTLY less computationally expensive.

:)

Tuesday, November 21, 2006

non-linear output of accelerometer solved... sort of

spoke with tom a bit today about the issue of non-linear output from the step detector.

he mentioned two problematic areas: the delay that i take after a step is detected, and the fact that i'm not taking the entire length of the pulse into account.

basically, i'm only looking at the t1 part of the pulse, the part where it's high. as soon as i've read all of the high part of the pulse, i punt, determine if the pulse was wide enough to count as a step, then dump the number of samples i'd read since the last step i detected.

so, t2 (the length of each pulse in total) isn't static. it's period changes based on how much acceleration is being applied, which in turn means the sample rate isn't constant. i went home and made some code changes to have it output t2 constnatly and started playing moving the accelerometer wildly. turns out t2 varies only a small amount, and not in a way that would create the non-linearity of the output. basically, the variation of t2 isn't really a big deal, and 99% of the time t2 is constant.

i wrote some code to have the step detector do nothing but loop as fast as possible reading the pulses, and blink the led after it had read X number of pulses. i then started trying to find how many samples were actually being read in 1 second. i put on a metronome, and found that about 138 samples between blinks = 1 second between blinks, more or less. it was close enough that the desynchornization period between the led and metronome took about 1 min. close enough for me.

SO. that means that, theoretically, if the accelerometer IS putting out a linear change in pulse width, i should be able to set the pic to blink an led every 69 samples and it will blink the led twice as fast, in fact, exactly 120 bpm. so i had it do that, set the metronome to 120, and guess what? almost perfect. 68 samples is close to 120 bpm, but hey, an error on that level is probably my eyes and is completely acceptable.

so the acceleromete IS outputting a linear curve. 138 samples = 60 bpm, and 68 samples = 120 bpm. yay.

i then tried to find the section of my code that would break this linearity. once i got to the delay between steps (after a step is detected, do nothing for about 30 samples so that we don't get double step detection for a single step). i could tap with 60bpm and get about 137 samples on average, and at 120 bpm i could tap the step detector and get about 70 samples between steps.

now i have to figure out why delaying for 30 samples after a step is detected screws things up. my guess is, as soon as a step is taken, t2 is changing the most. 30 samples at 120bpm may not be as long as 30 sample at 60bpm because t2 is sort of bouncing around while the signal settles down from the step.

perhaps filtering somewhere else less time-critical is a solution. i could simply have my python program on the gumstix ignore steps where only a few samples have passed. after all, it seems that 300 bpm is allows 30 samples to be read between steps. not many people can run 300 steps per minute (thats five steps every second) unless you're really sprinting. i could just make an upper bound on things, so that any step that has less than 30 samples between steps is just ignored.

Monday, November 20, 2006

Step detection circuit and the non-linearity of accelerometer output

so here's a more standard circuit diagram for the step detection circuit. of course it won't work without some code for the pic chip..



i'm still stuck on the weird output from the accelerometer. to calculate steps per minute, i'm looking at the number of samples that are read between each step that is detected. the idea is that at 60 steps per minute, the pic chip would read a number of samples from the accelerometer at the sample rate (say, 100hz). then, at 120 steps per minute, the pic chip would be reading about half as many samples between each step (if the sample rate is 100hz, for 120 steps per minute we'd be seeing 50 samples between each step). problem is, i mapped out BPM versus the number of samples that were read from the accelerometer, and it's not a linear curve. that is, at 60 BPM i get a consistent 110 samples read, but at 120 BPM i get around 45. huh?! it's also surprisingly a consistent curve.

need to talk to tom on this one..

Sunday, November 12, 2006

step detector!

so it's done. i have a full-fledged step detector.

final components:

3 capicators
1 resistor
1 led
1 accelerometer
1 pic chip
1 xtal (external oscillator)

it sends an alert out over serial when it detects a step, so that my gumstix board can interface with it.
code will be online soon.


here's a short video of the bread-board version in action (the LED lights up when a step is detected):