tag:blogger.com,1999:blog-68971301258647721512024-03-13T21:40:52.893-05:00Steely Eyed Codeslingersudo apt-get install happinessDennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.comBlogger63125tag:blogger.com,1999:blog-6897130125864772151.post-16606634850896249512013-05-15T21:20:00.002-05:002013-05-15T21:23:48.987-05:00Propeller VGA-lyzer Part 2The circuit for this is pretty simple - QX-10 video in one end of a Propeller protoboard, VGA out the other. There's some resistors to protect the Propeller inputs. Since the QX-10 sends 12V power down the video cable, I can power the Propeller board on the QX-10 video cable alone (the white connector on the right).<br />
<div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-dH2ibg3GV9E/UZRBppNhNQI/AAAAAAAAAyk/RkpuNv_XUbY/s1600/board.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="174" src="http://3.bp.blogspot.com/-dH2ibg3GV9E/UZRBppNhNQI/AAAAAAAAAyk/RkpuNv_XUbY/s320/board.jpg" width="320" /></a></div>
<div>
As it turns out this circuit is too simple, because I have the pixel input going straight into the Propeller with no preprocessing. I accidentally dropped a zero in my back of the envelope calculations about the input data rate. I estimated the pixel clock to be about 1.44 MHz, which can easily be sampled by a 20 MIPS Propeller core. In fact the pixel clock is going to be in the 14.4 MHz range, and you need more than 20 million instructions per second to read and store that many pixels per second (you have to burn some of your instructions budget to shift, store, and loop).</div>
<div>
<br /></div>
<div>
There's various tricks I could do with the Propeller to get around this. Some existing Propeller video drivers use as many as four cores working together to achieve higher video output resolutions than normally would be possible. I could use a similar technique here to share the sampling load among multiple cores. However going to such software gymnastics to save on hardware seems like it would make it harder to debug than is worthwhile. Since there's no penalty for reading in data 8 bits at a time rather than 1 bit at a time, I can get a free performance improvement simply by sampling the pixel data into a 74HC595 8 bit shift register on the front end before consuming it in 8 bit chunks. This will provide a second tangible advantage over the multiple-cores method: with a shift register on the front end I can skew the phase of the pixel clock independently of, and more finely than, the microcontroller software instruction rate. That's important because if you sample pixels at the right rate but the wrong time you'll get shimmering. Optimizing the phase of the pixel sampling clock with respect to the video signal will get the best picture.</div>
<div>
<br /></div>
<div>
However that will be a future revision of the circuit; rather than make that hardware change immediately, I decided to see what I could accomplish with the hardware I have built. (Who knows maybe I'll discover an additional tweak or feature I need to make to the hardware, so I might as well find out what I can.)</div>
<div>
<br /></div>
<div>
Although I will certainly need to use assembly language for the final product, I chose to use the interpreted language Spin for preliminary exploration, because it will be easier to debug. Even though Spin is woefully slow compared to the video data rate, it does still allow accurate and precise wait timing, and there is a trick you can do with precision timing to capture a video frame slowly over time. The idea is rather than try to capture the entire frame at once, you wait a precise amount of time after the sync signal to capture a certain single pixel from a line, then you have to wait an entire frame to capture the next and so on. It is slow but it will work for static images.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-d2pQupk3Swk/UZRBrqhFsEI/AAAAAAAAAys/46f7BpT2wgo/s1600/scope.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="146" src="http://1.bp.blogspot.com/-d2pQupk3Swk/UZRBrqhFsEI/AAAAAAAAAys/46f7BpT2wgo/s320/scope.jpg" width="320" /></a></div>
<div>
Speaking of debugging, I also found that an important debugging technique is to have the software toggle one or more pins at certain times in the loops. For instance originally I tried the slow-capture trick based off the horizontal sync signal, but when that didn't work I suspected my Spin code might be too slow for the 19kHz signal and may be dropping syncs. By having the code toggle a pin every time it captured an hsync I was able to see with the scope (actually with its frequency counter feature) that indeed the code was indicating fewer hsyncs captured than expected, and it was unstable.</div>
<div>
<br /></div>
<div>
After discovering my Spin code could not keep up with the horizontal sync, I swapped the nesting of my "x" and "y" loops and switched to basing all of my video capture timing off the much slower vertical syncs. Doing this with only vertical sync is 400 times slower than even the slow horizontal sync way. I am able to read just one pixel per frame.</div>
<div>
<br /></div>
<div>
I was at last able to capture something from the QX-10 video signal! Since it takes so long to capture a frame, I tweaked the code to concentrate on just the section of the frame where something interesting is onscreen, oversampled it and blew it up. The image below is 2x super-sampled and 2x to 3x magnified. I can't quite be sure, but I believe through the terrible mess of jitter and noise in that frame capture I can make out the message "INSERT DISKETTE". (The E's are suggestive.)</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-0rNz1zsJg_w/UZQtuKDqSyI/AAAAAAAAAyE/_ZqL09wh7WQ/s1600/20130515_193731.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="http://4.bp.blogspot.com/-0rNz1zsJg_w/UZQtuKDqSyI/AAAAAAAAAyE/_ZqL09wh7WQ/s400/20130515_193731.jpg" width="400" /></a></div>
<div>
<br /></div>
<div>
I'm a little disappointed that the image isn't clearer, but I guess I should be amazed that it even works. Because what is happening in this picture is that it is taking a single sync signal for the whole frame, waiting a calculated period of time that has to be accurate to an average of 1 part in 160,000, and capturing a single pixel out of hundreds of thousands.</div>
</div>
Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-11813655355562333512013-05-14T19:09:00.000-05:002013-05-14T19:09:13.433-05:00Propeller VGA-lyzer Part 1<br />
My first computer was an Epson QX-10, which is an old monochrome green screen 8-bit machine. The unit I had is long gone, but I picked up a replacement on E-bay some years ago. I got a good deal partly because it lacked a monitor. (The QX-10 monitor used a proprietary connector and proprietary signaling scheme, so you can't simply plug in a modern - or even an old - PC monitor.) I was not too concerned about this, since I had tinkered before with video signals in Earl Martin's Industrial Electronics class at Vo-Tech, including a similar proprietary-video-to-PC-monitor adapter project that was successful, albeit with a different video signal and analog CRTs (now I would use an LCD monitor).<br />
<br />
Having occasion to reorganize my home office / lab and to pull this among sundry other computing curios from storage, now is opportune to tackle this video conversion challenge. Like most of my projects I started off assuming it would be easy and it has turned out not to be so, but I am also learning more than I expected to.<br />
<br />
An obvious first step is to make a simple circuit that reconciles the merely electrical differences between the mystery signal and VGA spec, to say nothing of timing, and just hook up a VGA multisync monitor to see if it can lock onto the oddball timing. In fact this was the approach that worked for the Vo-Tech project many years ago, so that I never had to go on to the next step of dealing with sync timings. (I think I just had to make a passive R2R D/A circuit to integrate the colors or something, and I passed the sync signals straight through.) Well I say "worked," actually the first CRT monitor I plugged that Vo-Tech project into self-destructed with the bang and acrid smoke of blown capacitors. A lesser engineer might have doubted his circuit prototype, but I theorized the problem must be that the cheap, used monitor I'd tried it on couldn't handle the high resolution input and had burned itself up trying. If I just connected my circuit to one of these brand new, large, expensive monitors that belonged to the school, surely it would work there. Fortunately for my instructor's classroom budget, I was proven right and it did work then.<br />
<br />
For the current project I looked at the sync signals in the scope to figure out what I'd need to do them electrically. VGA is a positive-sync video standard and I could see in the scope that waveform pattern inverted in the QX-10 syncs, so I ran the sync signals through a TTL inverter chip before connecting them to the monitor. (For the record you can also easily tell which sync signal is which by looking at the frequencies, but I had a wiring diagram to tell me that too.) I don't think I'd connected the color signal(s) yet, but if I had I could have used a voltage divider between a resistor and a forward biased diode, since the QX-10 monochrome signal is 0-5V and the VGA colors are 0-0.7V, and I don't care about intermediate intensities just on and off. However, after I hooked up the sync signals I could see it wasn't going to work; the LCD monitor I used was already displaying the message "Cannot sync to this video mode." Perhaps LCD monitors have lost the multisync capability good CRTs had, or perhaps it's because I'd connected my prototype up to an old, second hand LCD monitor. I decided not to bother to try connecting it to my own brand new, large, expensive LCD monitor.<br />
<br />
Right, so, onto sync timings, frame buffering, and phase locking! I will be designing "real" video converter hardware for this after all. Here's the situation. Completely opposite to that Vo-Tech project, the big problem with the resolution / sync frequencies from the QX-10 is that they are <i>too slow</i>. Well actually the QX-10's screen resolution in pixels - 640x400 - is coincidentally the same as a VGA standard resolution, but it does its vertical refresh at the leisurely pace of 45 Hz. (Normal would be about 60 Hz.) This in turn makes the horizontal sync frequency lower, and the pixels clock out slower. Thus even though the number of horizontal syncs per vertical sync is "right", the frequency at which they happen is too slow.<br />
<br />
This difference in vertical sync refresh rates makes buffering the entire frame the obvious and really the only option. See, if it were merely a problem of not enough lines (not enough HSyncs/second), I could buffer one line at a time, and sometimes play back the same line twice in a row to spoof a higher number of horizontal lines than the input really has. But there's no way to fake it with a vsync mismatch; one can easily see mathematically (45-60=-15 and 45/|15|=3) that every three seconds you'll build up such a deficit of lines that your output will demand a line an entire frame away (and the new one hasn't been transmitted yet). I am not really an expert on video conversion, but I think I can say if you have a v sync mismatch you must to buffer a whole frame.<br />
<br />
That's ok. This is what I wanted to do anyway. I need 32K to buffer a whole QX-10 video frame, and my favorite microcontroller, the Propeller, has exactly 32K RAM. I wanted to be sure I wasn't missing an obvious way to do it with less RAM, so that the premise of the project isn't invalid. Once I have this working for the QX-10, the Propeller object I write for this might be useful for connecting all manner of vintage computer and video game systems to more modern monitors or televisions. That's why I'm calling this project the VGA-lyzer.<br />
Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-47725072596448134542009-12-25T14:23:00.027-06:002009-12-26T01:07:35.207-06:00Freerunner Battery Mod, Case Mod, Runs Android<p>Oklahoma was hit by the biggest snow storm in state history this Christmas. Since we were snowed in and couldn't visit relatives, I found myself with some unexpected time on my hands. So I built my own Android phone.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SzU9zmgDBGI/AAAAAAAAAXY/dvC-ed0gHZQ/s1600-h/snowed+in.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 237px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SzU9zmgDBGI/AAAAAAAAAXY/dvC-ed0gHZQ/s400/snowed+in.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5419305683327845474" /></a></p><br /><p>I bought a Neo Freerunner last year, but some design flaws kept it from being usable to me as an everyday phone: pitiful battery life, audio problems, and no single Linux distribution stood out as the one best choice to use. But the battery was the worst problem.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SzVDTEBsPPI/AAAAAAAAAXg/GZz3Ca8qGHE/s1600-h/P3100056.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SzVDTEBsPPI/AAAAAAAAAXg/GZz3Ca8qGHE/s320/P3100056.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419311721387670770" /></a></p><br /><p>My previous experiments had shown that if you remove the battery monitor circuit board from the original battery:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SzVDxkovnoI/AAAAAAAAAXo/O_ivNEZ00rg/s1600-h/P3100065.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SzVDxkovnoI/AAAAAAAAAXo/O_ivNEZ00rg/s400/P3100065.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419312245537480322" /></a></p><br /><p>...you can transfer it to a larger Li-Ion battery, like this one from a portable DVD player, and it will work. Surprisingly the BQ27000 chip on the smart battery board is able to learn the larger battery capacity.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzVHnzuP-oI/AAAAAAAAAXw/zFOQGlplbDc/s1600-h/P3100080.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzVHnzuP-oI/AAAAAAAAAXw/zFOQGlplbDc/s400/P3100080.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419316475834923650" /></a></p><br /><p>Of course, I didn't let the old battery go to waste either...<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzW04zPb5zI/AAAAAAAAAZY/zAXAKuG6wTw/s1600-h/P3120094.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzW04zPb5zI/AAAAAAAAAZY/zAXAKuG6wTw/s400/P3120094.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419436614530885426" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SzW0VqJhtMI/AAAAAAAAAZQ/6XII6WKxkUQ/s1600-h/P3120119.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SzW0VqJhtMI/AAAAAAAAAZQ/6XII6WKxkUQ/s400/P3120119.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419436010794759362" /></a><br /></p><br /><p>The prototype battery mod worked but I needed to give the phone a bigger enclosure so the battery wouldn't have to be on the outside where it might be damaged.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SzWyTFNUX2I/AAAAAAAAAZA/1zTw4_Sawuw/s1600-h/P3100085.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SzWyTFNUX2I/AAAAAAAAAZA/1zTw4_Sawuw/s400/P3100085.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419433767495556962" /></a></p><br /><p>Having proved the concept, I exchanged the junk DVD player battery for a brand new 6 AH Li-Ion battery from Sparkfun, and put it all into the case from a 2.5 inch portable hard drive. (To put that in perspective, the original battery was only 1100 mAH.)<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWVUb-1_eI/AAAAAAAAAYI/eq3Z6_8-Y1Y/s1600-h/PC250619.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWVUb-1_eI/AAAAAAAAAYI/eq3Z6_8-Y1Y/s400/PC250619.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419401904951524834" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SzWR-r95sCI/AAAAAAAAAX4/PFnAWzPnnrw/s1600-h/PC250618.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SzWR-r95sCI/AAAAAAAAAX4/PFnAWzPnnrw/s400/PC250618.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419398232750534690" /></a></p><br /><p>Rather than try to cut the hard drive case to perfectly match the Freerunner circuit board, I simply reused the original phone faceplate since it already had the proper board mounting locations. I cut an oval hole in the hard drive case (free hand with a dremel), and then used JB Weld to join the two pieces and to even out the gaps between them. I put the JB Weld on sloppy but used a wet paper towel to wash away the excess, leaving a nice even seam all the way around. (Turns out JB Weld is water soluble - who knew!)<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWUdy_TQOI/AAAAAAAAAYA/gNUB6QqdGs0/s1600-h/PC250612.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWUdy_TQOI/AAAAAAAAAYA/gNUB6QqdGs0/s400/PC250612.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419400966234652898" /></a></p><br /><p>By the way that silver squiggle shape on the front is the cellular antenna. I ran out of room on the inside, so I put the antenna on the outside! And putting the antenna next to my cheek is a good way to extend a sarcastic "bite me" to all those idiots who argue from a position of ignorance that cell phone signals cause cancer without knowing the first thing about the physics of radio signals.</p><br /><p>Although from the faceplate it may appear as though an entire Freerunner has been simply embedded into the new case, behind the faceplate there is nothing left of the original Freerunner case, and some components have been moved and some improvements made as I tried to rectify my main complaints about the original phone.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWcmb5JRUI/AAAAAAAAAYQ/Y-D8gD6-4QU/s1600-h/fast+charge.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 360px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWcmb5JRUI/AAAAAAAAAYQ/Y-D8gD6-4QU/s400/fast+charge.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5419409910746662210" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SzWcmnqfxrI/AAAAAAAAAYY/w8pIu9MHr5g/s1600-h/other+annotations.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SzWcmnqfxrI/AAAAAAAAAYY/w8pIu9MHr5g/s400/other+annotations.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5419409913906448050" /></a></p><br /><p><br />Here it is charging at a total rate of nearly 2 amps using both the fast charge board and the Freerunner's internal charging circuitry. No apparent harm comes of running them both at once, and the extra charger doesn't confuse the battery gas gauge chip either.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SzWsXx7yf5I/AAAAAAAAAYo/_vgUPFsTyXs/s1600-h/PC240584.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SzWsXx7yf5I/AAAAAAAAAYo/_vgUPFsTyXs/s400/PC240584.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419427251151339410" /></a></p><br /><p>The BQ27000 learns the battery capacity by observing a complete battery discharge cycle. Unfortunately software will shut down the phone when it thinks the battery is empty, so we'll never actually reach a full discharge of the new battery to recalibrate the gas gauge! Luckily I built a battery discharge device a while back, which is really just a mess of enormous low-ohm power resistors strapped to a massive heatsink with a fan on top. And a fancy digital temperature readout so I know whether I'm actually frying my power resistors. This discharges this battery at a rate of 1 amp, which is a bit too fast, but with a 6 AH battery I could be waiting all weekend for it to discharge at "normal" current draws.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWsXRr1JlI/AAAAAAAAAYg/cijBuaslZpY/s1600-h/PC240587.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWsXRr1JlI/AAAAAAAAAYg/cijBuaslZpY/s400/PC240587.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419427242494469714" /></a><br /></p><br /><p>The documentation for the BQ27000 gas gauge chip mentions that it doesn't revise its capacity estimate downward more than 1/8th of the total at a time. It doesn't say anything about how the estimate gets revised upward, but experimentation with the test battery from the DVD player indicates that it caps the upward change at 1/4th of the previous estimate each time. The test battery reached 2.2 AH, so I can only expect the BQ27000 to revise the estimate up by about 0.55 AH on this cycle. It's probably not worth the trouble to work it up to the full 6 AH reading, since the process takes 12 hours and I'll be slightly damaging the battery every time I completely discharge it! Maybe when the battery is deteriorated in a few years, I'll calibrate it to whatever reduced capacity is still in it.</p><br /><p>Not really visible in the pictures, but I removed the speakerphone (which was useless in its old location because its proximity to the microphone made it impossible to actually use speakerphone without getting a loud feedback squeal) and connected it in place of the earpiece. I thought that, because it was bigger, it would be louder than the earpiece, but instead it is much softer, nearly inaudible. I think that's because the earpiece measures as high impedance while the speakerphone speaker is low impedance, so there isn't an efficient transfer of power. Tomorrow I'll cannibalize the audio amplifier IC from that same portable DVD player I got the test battery from, and use it to fabricate a tiny audio amplifier board to drive the earpiece & match the impedances. (I can design a circuit in my head and build it on a new board as fast as I can take the components off the board I'm cannibalizing.)</p><br /><p>That will also provide me a physical volume control so I won't have to rely on the goofy software volume settings that never seem to work right on the Freerunner. Hmmm... Maybe I'll make it stereo while I'm at it. The Neo 1971 (prototype to the Freerunner) had stereo speakers in it, but not the Freerunner. The audio amplifier chip in the DVD player is stereo, and I can pull a stereo signal from the headphone jack. Interesting...<br /></p><br /><p>So... Android right? Remember at the top I said that my original goal was to address some specific flaws with the Freerunner, one of which being lack of a definite distribution to stick with. I didn't actually like Android when I first tried it (still not sure about it) but it seems to be where the ball is rolling. When I began to think I wanted a Motorola Droid, and when blogs and podcasts started going crazy over the (latest) rumored Google phone, I had to stop and remember, wait a minute, I already HAVE hardware capable of running Android. It's just been sitting on my desk in pieces waiting for me to put it together.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SzWsYIV_-7I/AAAAAAAAAYw/4FhdChbbK10/s1600-h/PC250611.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SzWsYIV_-7I/AAAAAAAAAYw/4FhdChbbK10/s400/PC250611.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419427257166855090" /></a></p><br /><p>Installing Android was a breeze; easier than any other install I've done on the Freerunner. You just untar a file onto an SD card, and then booting off the SD card prepares Android on the Freerunner. No messing around with the flashing the phone over USB, and no messing around with bootstrapping the system on the phone itself like Debian does. Just pop in the SD card and it just works. Not much else to it - except wifi doesn't work. Why does wifi never work for me on Linux? Oh well...<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWsYtGgFgI/AAAAAAAAAY4/3zShSWvWABI/s1600-h/PC250617.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SzWsYtGgFgI/AAAAAAAAAY4/3zShSWvWABI/s400/PC250617.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5419427267033961986" /></a></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com15tag:blogger.com,1999:blog-6897130125864772151.post-31575695941595936192009-10-09T18:30:00.003-05:002009-10-09T18:38:42.771-05:00Anything That's Not Tied DownThis morning when I got out of class I found someone had undone several of the velcro straps that hold my electric bicycle's battery on. Fortunately the battery (and the bicycle!) were still ok.<br /><br />My guess is someone just saw a bulky black bag and decided to steal it without knowing what was inside. Walk-by snatch and grab. I like to think the sheer weight of 30 lbs of lead acid batteries scared them into letting go of it. And anyway there's more straps holding that thing down on the front side.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-48038793567307001292009-10-03T19:49:00.007-05:002009-10-03T22:09:03.080-05:00Everything Takes Longer In C++So I had tonsil surgery last Monday. Even though I didn't feel up to programming for my day job, I couldn't stay away from trying to work on the MMO game project called Emergence that Ben and I are creating. When it seems like progress is going glacially slow on our game Ben and I always say "if only we had more free time to work on this..." Well I've had time this week - and I still made only baby steps in progress on it. Granted I was resting from surgery and on pain medicine, but still... I'm beginning to think it's not (just) that we have no free time. It's that with programming you put in enormous effort yet make only incremental progress.<br /><br />If it takes a certain amount of effort to write software of a given complexity, writing software that's twice as complex doesn't take twice as long, it takes, I don't know, ten times as long, twenty times as long. The effort increases exponentially. Invert that and you get an equation that says that you only get logarithmic increases in output for every increase in effort. If you don't know what a logarithmic curve looks like, it has a knee bend. If you stay to the left side of the curve you get pretty good output for input, but as you move right it levels off quickly. To the right side of the curve, increasingly large increases in input result in increasingly small changes in output.<br /><br />So I think I've been working dangerously close to right side of the curve lately, where what you can accomplish tapers off faster than the increase in effort. I've been getting better with some of the new programming techniques I'm using, and I've streamlined my build process and improved my debugging techniques. But here's the funny thing - all those improvements really just help me increase my work input. They don't directly increase the output. You see if I streamline my build process and my debugging techniques so that I can make a change and test it in half the time, that just means I can test twice as many code updates in the same amount of time. But if I'm on the inefficient side of a logarithmic curve, I may actually need to make four, or ten, or twenty times as many code changes at a time to actually double my output.<br /><br />So that's what's so frustrating about this work. You run faster and faster but never seem to get anywhere. It's not hopeless though. I think the fact that the ratio of accomplishments from effort is logarithmic is some kind of fundamental law of software, but it is possible to tweak the shape of the curve. Although it will always eventually taper off, it doesn't need to taper so as quickly. I think changing the programming language you program in does the most to change this curve. C++ is very powerful and generates efficient programs, but it has a very sharp bend in its complexity curve. This is because doing anything substantial in C++ just involves so many fiddly little details, and the language does so little for you automatically. I'm not saying you can't build large systems in C++, but I am saying it probably took exponentially more work to do it than it would have to do it in a scripting language. And I'm not saying you shouldn't use C++; in order to get good performance in our game, we need to. But we're going to use both C++ and script language in our game, and I need to get out of the C++ part and into the scripting as soon as possible.<br /><br />The ironic thing is that the component which is giving me all this trouble, where I'm working too far on the right side of the complexity curve, is the C++ component that will bind our C++ side of our game to our scripting side. In order to leave C++ behind I need to first overcome a trial by fire of the toughest C++ I've ever worked on.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-46189673008628269052009-09-04T20:34:00.015-05:002009-09-05T00:50:06.795-05:00Electric Bicycle Conversion<p><br />A student parking pass at the University of Oklahoma costs ~$200 a semester. As if that weren't bad enough, they first try to trick you into buying the <span style="font-style:italic;">nine hundred dollar</span> reserved pass. Instead of paying "the man" $200 just so I can park in overcrowded, confusingly marked lots, I decided my money would be better spent upgrading my bicycle so I can park a few miles away and bike to class.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqH6QpJ0MtI/AAAAAAAAAWg/EBLSuhwArQ0/s1600-h/ou+parking.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 200px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqH6QpJ0MtI/AAAAAAAAAWg/EBLSuhwArQ0/s400/ou+parking.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5377854593888957138" /></a><br /></p><br /><br /><p><br />I knew about these electric bicycle conversion kits because a couple of CS Ph.D. students I'm friends with, Lawrence Kinchloe and Mark Woehrer, put electric conversion kits on their bicycles a couple years ago. (Hey guys! We should start a club!)<br /><br />It turns out WeRelectrified.com sells a <a href="http://www.werelectrified.com/ProductDetails.asp?ProductCode=BD24+Kit">low-end, but complete bicycle conversion kit</a> for $200. (Ha! Exactly the same as I would have spent on a parking pass!) While I could have fabricated my own motor controller, and scrounged my own batteries, the complete kit is such a good deal that it didn't make sense not to just use it as-is. There's even more than what's in the picture - it also comes with a metal rack to go on the back of the bike for the batteries.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHz6OTR6JI/AAAAAAAAAWY/woa4Fhfa_7k/s1600-h/BD24+Kit-2.gif"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 306px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHz6OTR6JI/AAAAAAAAAWY/woa4Fhfa_7k/s400/BD24+Kit-2.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5377847611654006930" /></a><br /></p><br /><br /><p><br />The way this thing works is there's actually a motor inside the front wheel, a big fat metal hub that makes the front wheel turn by itself. (Nothing gets changed on the back wheel - so you can still pedal it too, like a normal bike.) In theory, you can just replace the front wheel of your bicycle, put the batteries on the back and the throttle on your handlebars, and you're ready to go!<br /></p><br /><br /><p><br />That's the idea, anyway. Of course, this is a Project, and as we all know Projects rarely go according to plan. The first problem I had was that the hub is too wide to fit between my front forks. Earl Martin would probably just have grabbed the front forks and pulled them out, but I'm not that strong. Instead, I took the scissor jack that came with my car, slipped it over the front forks, and just <span style="font-style:italic;">cranked it on out there.</span> (Nick Johnson asks "Is that SAFE?" Come on, Nick, it's a steel frame! You could probably safely bend it into a pretzel if you wanted to.)<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHqtAfM3yI/AAAAAAAAAUo/okKT5Cu0X-M/s1600-h/P8280556.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHqtAfM3yI/AAAAAAAAAUo/okKT5Cu0X-M/s400/P8280556.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377837489002962722" /></a><br /></p><br /><br /><p><br />OK, now the hub fits - but the axle is too big to go in the notches on the end of the forks.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHqtn14zmI/AAAAAAAAAUw/MuYQRPgyt88/s1600-h/P8280558.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHqtn14zmI/AAAAAAAAAUw/MuYQRPgyt88/s400/P8280558.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377837499567099490" /></a><br /></p><br /><br /><p><br />Not a problem for a man who owns more kinds of steel files than socks! This is a delicate operation - the axle has flat sides on it, and I want the notch just wide enough for the flat sides to fit, but not wide enough for the axle to rotate in place. When the hub motor turns the wheel, it's pushing against the axle to do so, and you don't want the axle to be able to start spinning within the forks.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHquD3CXpI/AAAAAAAAAU4/qiAl2D76has/s1600-h/P8280560.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHquD3CXpI/AAAAAAAAAU4/qiAl2D76has/s400/P8280560.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377837507088113298" /></a><br /></p><br /><br /><p><br />Great! Front wheel fits now!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHrZem9tOI/AAAAAAAAAVA/m2BFSb0dpg0/s1600-h/P8280561.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHrZem9tOI/AAAAAAAAAVA/m2BFSb0dpg0/s400/P8280561.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377838253002831074" /></a><br /></p><br /><br /><p><br />OK, now to transfer the tire from the old wheel to the new wheel. Except the tire doesn't fit. In fact, these aren't the same size at all! Did I buy the wrong size wheel? Oh, never mind. This is the same thing I went through last time I worked on this bicycle! The wheels I put on it then were narrow 26 inch, which means they have less tire material and more rim circumference than the moutain bike wheels it came with; the new wheel brings us back full circle, with smaller diameter rims under thicker tires. Means I need to buy a tire.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHrZ734weI/AAAAAAAAAVI/CpjFqrAcZAQ/s1600-h/P8280563.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHrZ734weI/AAAAAAAAAVI/CpjFqrAcZAQ/s400/P8280563.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377838260858438114" /></a><br /></p><br /><br /><p><br />Off to the bicycle store!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHvYvzt8tI/AAAAAAAAAVg/mS9kOhoXry4/s1600-h/bicycle+store.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHvYvzt8tI/AAAAAAAAAVg/mS9kOhoXry4/s400/bicycle+store.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5377842638486368978" /></a><br /></p><br /><br /><p>Since the front wheel is now a different size, I decided to change the back wheel to that size too, and buy new tires for front and back. I've been meaning to replace the back wheel anyhow (between either the wheel starting out warped or my asymmetric weaving pattern, the wheel was getting ever so slightly out of round). I didn't think I needed to buy new gears though because I could just take the gears from the old wheel, right?<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHtXRSzeYI/AAAAAAAAAVQ/mnMxmyUvHD0/s1600-h/P8290564.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHtXRSzeYI/AAAAAAAAAVQ/mnMxmyUvHD0/s400/P8290564.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377840414092130690" /></a><br /></p><br /><br /><p><br />Oops... that's not how you remove the gear pack. (If ball bearings fall out all over the place, you're doin' it wrong.) If I read my own damn blog from last year I MIGHT have remembered that. I never was actually able to get the center portion of the hub off.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHtX1aljoI/AAAAAAAAAVY/uMvTwYsEK9g/s1600-h/P8290565.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHtX1aljoI/AAAAAAAAAVY/uMvTwYsEK9g/s400/P8290565.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377840423788449410" /></a><br /></p><br /><br /><p><br />BACK to the bicycle store!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHvYvzt8tI/AAAAAAAAAVg/mS9kOhoXry4/s1600-h/bicycle+store.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHvYvzt8tI/AAAAAAAAAVg/mS9kOhoXry4/s400/bicycle+store.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5377842638486368978" /></a><br /></p><br /><br /><p><br />Another one hour drive. This time I came back with a gear pack. I put yellow teflon tape on the threads of the new back wheel - hopefully if I ever need to remove the new gear pack, this will keep the gear hub from getting stuck as badly as the old one did.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHw1GeoyaI/AAAAAAAAAVo/cvVzAxd6xKU/s1600-h/P8290569.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHw1GeoyaI/AAAAAAAAAVo/cvVzAxd6xKU/s400/P8290569.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377844225119930786" /></a><br /></p><br /><br /><p><br />Then I remembered that on the second trip to the bicycle store, I forgot to return the inner tubes I bought on the first trip. The guy at the store mixed up the two sizes of 26 inch just like I did with the wheels, and sold me the skinnier, larger circumference narrow tubes when I needed the wide 26 inch tubes. These tubes don't fit in the tires I bought (there's excess tube), but by this point I'm beyond caring so I just jammed them in there anyway, kinks and all. I haven't gotten a flat yet so I guess it's OK.<br /></p><br /><br /><p><br />I'm kind of proud of the way the throttle mount turned out. I didn't want to unwrap all my handlebar tape to slide the throttle assembly on, so I wasn't sure how I was going to mount it. Eventually I realized it would just as easily fit on a piece of 3/4 inch PVC pipe, so I mounted the throttle vertically on a piece of pipe. I knew if a convex pipe edge butted against a convex handlebar edge it would never stay in place, so I cut a half-circle indention in the side of the PVC pipe where it mates to the handlebar. The mounting feels solid and the throttle is not any harder to use in this position.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHzIDkZskI/AAAAAAAAAWI/TyQB9RoHDUA/s1600-h/P9040574.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHzIDkZskI/AAAAAAAAAWI/TyQB9RoHDUA/s400/P9040574.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377846749779571266" /></a><br /></p><br /><br /><p><br />It has a key for an on/off switch. It happened to be a perfect fit for this space under the bicycle seat. While it might look a little rude if I reach between my legs to turn the key, I figure this will keep the rain off it.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHzIkZXiDI/AAAAAAAAAWQ/FKPjx_ac9ac/s1600-h/P9040578.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHzIkZXiDI/AAAAAAAAAWQ/FKPjx_ac9ac/s400/P9040578.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377846758591662130" /></a><br /></p><br /><br /><p><br />I mounted the motor controller box upside down under the battery, and I made all the wire connectors come out in the space hidden between seat and the battery bag. Hopefully that will make the wiring less obvious from above. Although I'm not doing anything wrong, I don't exactly want to advertise that something strange is going on. My experience with authority has been that even harmless things will be treated with suspicion if they out of the ordinary. Besides, I don't want to give potential bicycle thieves any reason to think my bicycle is special.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHpNDx6cOI/AAAAAAAAAUg/HBB_Lm6_8MQ/s1600-h/P9040580.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHpNDx6cOI/AAAAAAAAAUg/HBB_Lm6_8MQ/s400/P9040580.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377835840619311330" /></a><br /></p><br /><br /><p><br />Here's the completed bicycle. As long as I had to buy new tires, I thought I'd have a little fun and get ones with a red stripe. I think it's a nice effect. You can see the batteries here in the unzipped bag; it came with a block of styrofoam in the back where I assume the 3rd battery would go if this were a 36 volt kit instead of 24 volts.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHyH93V6_I/AAAAAAAAAWA/vvc3t5fEVZQ/s1600-h/P9040573.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHyH93V6_I/AAAAAAAAAWA/vvc3t5fEVZQ/s400/P9040573.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377845648736775154" /></a><br /></p><br /><p><br />On my first day riding it to class, the zipper failed on the bag where the corner of the battery meets it. The batteries, which are sealed lead acid (heavy as hell but cheaper than lithium ion), rest directly on the metal frame of the rack. There's no padding in the bag, so with every bump the batteries slam down against the rack and then up against the zipper. <br /><br />Catastrophic zipper failure!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHw1nDhhuI/AAAAAAAAAVw/Rxm9hW2ThpA/s1600-h/P9040570.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHw1nDhhuI/AAAAAAAAAVw/Rxm9hW2ThpA/s400/P9040570.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377844233864578786" /></a><br /></p><br /><br /><p><br />When this happened, I wasn't even sure how I would secure the batteries for the ride home. I actually have a pair of shoes that I've threaded two sets of laces into for MacGuyver emergencies. I could have taken out one set of laces to tie down the batteries and still have had the other set of laces to keep my shoes on. Wouldn't you know it but this would be the day I wore a different pair of shoes though? Darn the luck. Fortunately I had previously fixed the water bottle holder with baling wire, and there turned out to be enough when I unwrapped that to hold the batteries down.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHyHHBI6NI/AAAAAAAAAV4/BnPtj-ZNtsE/s1600-h/P9040571.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHyHHBI6NI/AAAAAAAAAV4/BnPtj-ZNtsE/s400/P9040571.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377845634013915346" /></a><br /></p><br /><br /><p><br />The foam from this padded laptop bag will be just what I need to cushion the batteries. After I cut out the foam, I'll fold it in half and put it under the battery bag.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHpMhOKEMI/AAAAAAAAAUY/HeITVLQr7ro/s1600-h/P9040582.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHpMhOKEMI/AAAAAAAAAUY/HeITVLQr7ro/s400/P9040582.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377835831342534850" /></a><br /></p><br /><br /><p><br />A zipper is completely off one side. How will I get back it on track? By cutting deeper into the throat of the zipper, I was able to give myself enough slack to re-thread it from the end.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHpLkHQ5BI/AAAAAAAAAUI/3-7lOMnyraE/s1600-h/P9040588.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SqHpLkHQ5BI/AAAAAAAAAUI/3-7lOMnyraE/s400/P9040588.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377835814939059218" /></a><br /></p><br /><br /><p><br />Then I made the two zippers meet at the corner where the original tear happened, so I don't ever have to cross the damaged section! The amount of offset I created from rethreading the zipper on the left side happens to the same length as the stretched portion here, so everything matches up properly.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHpMFaNJ7I/AAAAAAAAAUQ/48oSp-vKdd8/s1600-h/P9040590.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHpMFaNJ7I/AAAAAAAAAUQ/48oSp-vKdd8/s400/P9040590.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377835823876876210" /></a><br /></p><br /><br /><p><br />The next time I have something go wrong with the bicycle, I'll have some duct tape stowed onboard. I removed the hard cardboard center from a roll of duct tape so I could fold it up. I think I saw that trick on Instructables.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHpLDh1xII/AAAAAAAAAUA/9twXW_Z_NcY/s1600-h/P9040594.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SqHpLDh1xII/AAAAAAAAAUA/9twXW_Z_NcY/s400/P9040594.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377835806192157826" /></a><br /></p><br /><br /><p><br />And there it is, back together and nicely padded.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHntXbXp3I/AAAAAAAAAT4/MiQV1_r5eGs/s1600-h/P9040595.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHntXbXp3I/AAAAAAAAAT4/MiQV1_r5eGs/s400/P9040595.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377834196626024306" /></a><br /></p><br /><br /><p><br />Unfortunately the cheap made-in-china 24V battery charger that came with the kit died after just one use! I can use my car battery charger to recharge the batteries, but to do so I have to change the wiring on the battery pack from a 24V serial configuration to a 12V parallel configurations every time I hook up the 12V charger.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHnItPCVgI/AAAAAAAAATw/LdcImZ1Rxvg/s1600-h/P9040597.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SqHnItPCVgI/AAAAAAAAATw/LdcImZ1Rxvg/s400/P9040597.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377833566824715778" /></a><br /></p><br /><br /><p><br />Finally done, fully charged and put back together. Despite the problems, I would say the project has gone better than I anticipated. It's lots of fun to ride and completely practical. I think if more people understood that we'd see as many electric bicycles in stores and on the road as regular ones. It still works as a bicycle, so you can rely on electrical power as much or as little as you want. For a casual rider like me, this makes me more confident about taking the bicycle out for rides because I know if I'm too out of shape to pedal any further I can still get home on battery power.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHmp578G5I/AAAAAAAAATo/IBlGCAhm3oM/s1600-h/P9040596.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SqHmp578G5I/AAAAAAAAATo/IBlGCAhm3oM/s400/P9040596.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5377833037658332050" /></a><br /></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com1tag:blogger.com,1999:blog-6897130125864772151.post-26932307480645680882009-06-06T16:45:00.004-05:002009-06-06T16:53:02.513-05:00Public Key Authentication - UpdateTurns out it's not easy to uninstall Ubuntu's encrypted home directory feature either, at least not while logged in over an ssh session. All I succeeded in doing when attempting to uninstall was screwing up both computers so bad I can't log in to them any more, and losing all my files. (Luckily there wasn't much on there yet to lose.)<br /><br />As long as I have to go to trouble of digging these computers out and hooking up a keyboard and monitor so I can reinstall everything, I'm going to put Debian on them instead.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-1820176734674504172009-05-30T18:07:00.003-05:002009-06-06T15:30:04.466-05:00Public Key AuthenticationI haven't been updating this blog lately because I've been trying to get my webserver set up first, so that I could put the pictures there and just link to them from the blog posts. (Uploading pictures to this blog is a tedious process, so I'm planning to create a website that I can just drop a folder full of pictures onto and have them all display nicely. I suppose I could just get a Flicker account instead, but I like doing things the hard way.)<br /><br />So that I won't have to type my password over and over again to manage my webserver, I took an evening to set up public/private key authentication so I can just use that to prove to my webserver who I am when I log in, and then I don't need a password. Well that was the plan. It ended up taking an evening, then a weekend, then another few evenings, then a week... Every time I thought I had everything set up properly, the next time I came back and tried to log in, the key didn't work. Eventually it got to the point where I'd make a key, it would work exactly one time, and then never work again until I made a new key. (If you know how public/private keys work, this makes NO SENSE. But there it was.)<br /><br />I spent more time troubleshooting this problem than all the cumulative time I will save from not having to type a password in the future. Nothing wastes your time like a technology designed to save you time, right? But I'm stubborn and the longer this went on the more determined I got to figure it out. See, I have a theory about life: success or failure is self-reinforcing between your beliefs and your actions. If you believe you can't make technology work for you, then when faced with a problem you'll give up too soon. By failing you proved right your own conviction that you would fail. Because you'll never know if the right solution was miles away from what you attempted, or whether it would have been just around the corner. On the other hand if you maintain an unshakeable belief that eventually, <span style="font-style:italic;">something</span> you try will work, eventually it does, and you <span style="font-style:italic;">vindicate</span> the confidence you had in the first place.<br /><br />Turned out the problem in this case stemmed from an innocent decision I made when installing Ubuntu Linux on the server. In this new version of Ubuntu, they added a feature for encrypting your home directory. The install program asked me if I want to do this, and explained that it would be perfectly transparent to me; the operating system would magically decrypt and mount the home directory for me when I log in, and safely unmount it when I log off. Totally convenient - I'd never notice anything different. "Why not?" I thought. It didn't sound like much trouble and who wouldn't want more security on their webserver? So I left it enabled. BIG MISTAKE.<br /><br />I would never have guessed there would be an interaction between this feature and using public/private key logins until I was looking at the ssh logs to try to figure out why I couldn't log in with my key. At first I thought I had the wrong log - why were there messages from the home directory encryption service mixed in with my ssh logs? And why was it not finding the key sometimes? Wait wait the order of those operations doesn't look right - shouldn't it be decrypting the home directory <span style="font-style:italic;">before</span> looking in it for the key? Ahhhhh... Dammit. Now I get it.<br /><br />Here's what was going on: the way public/private key ssh logins work is the server looks in your home directory for your public key to use to recognize you. But your home directory is encrypted. It gets decrypted for you <span style="font-style:italic;">when you log in</span>. But you can't log in until it uses the public key to authenticate you, which it can't pull out of the home directory because it's still encrypted. "There's a hole in my bucket, dear Liza, dear Liza..."<br /><br />You can verify if you've got the same problem as I did: as long as you're logged into the server in one terminal window, public/private key authentication will work in a 2nd terminal window. Log out of all the sessions, and now you can't authenticate anymore with your key. Log back in, and now your key works again in other terminals too. If this works, send an angry email to Canonical. Tell them I sent you.<br /><br />The moral of the story is don't use the encrypted home directory feature, it was released half-baked. Have you heard the expression "Beware Greeks bearing gifts?" The meta-moral here is beware operating systems bearing gifts of "features" you didn't need!Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-31649196346684339732009-04-10T11:41:00.005-05:002009-04-10T12:34:46.799-05:00Final Days Before Robot CompetitionThe Hardware is (mostly) done but as usual Software is holding up the show. Lateness is the nature of software; it's worse with robots because given the choice between finishing the hardware and finishing the software, you work on the hardware first: the software can't get around without a body. Then you try to get all the software done in the final 10% of the schedule. I told my team (only half joking) that the first time it runs the whole course, if it runs it, will be at the starting line at the competition!<br /><br />Testing the GPS is particularly challenging because you have to be outside in a big area to test it well. It's been unseasonably (brutally) cold here some days, mixed with many other forms of inclement weather, so I haven't wanted to walk around outside with a circuit board and laptop, especially at night which is the only time I have to really work on things. Luckily I'm off work today on a three day weekend; I'm going to need every minute of it.<br /><br />When I did a cursory test of the GPS in a park several weeks ago, I tried to test the minimum resolution of the GPS by standing in a location, and walking a few meters to see how much it changed per every meter. That proved to be futile, so I tried standing in one place, walking several meters away, and then returning to where the GPS coordinates said I should be in the same starting location. Inevitably, I ended up nowhere near where I started, even though the coordinates were the same.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/Sd99Gr1G3_I/AAAAAAAAASo/DUQ7dGpvmDE/s1600-h/gps+points+2.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 328px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/Sd99Gr1G3_I/AAAAAAAAASo/DUQ7dGpvmDE/s400/gps+points+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323110838373375986" /></a><br /><br />Today I realized that if you leave the GPS unit facing a window long enough, it will eventually get a fix, even though you may be indoors. The picture above plots all the results returned by the GPS over a 20 minute period. (Use the cars in the picture to judge scale.) My incorrect assumption had been that the GPS might be off by several meters, but that you could compensate for that and get a stead progression of readings. The problem is that the amount it is off varies from one reading to the next, even if you are standing still. What you really get is a cluster of points near your real location. Now, the center of that cluster as a whole might be off a fixed amount, and you can compensate for that a bit, but you can't take any individual reading and apply a fixed offset and say "ah, this is where I am". It's more like darts shot at a dart board. Also, the cluster as a whole eventually shifts over time - twenty minutes after this screenshot was taken, the GPS began giving readings further down and to the right.<br /><br />So, where does this leave our navigation algorithm? Since the data is statistical, maybe our control routine should be as well. Instead of doing 90 degree turns and full stops every time a new reading puts us 10 meters left or right of where we thought we were, maybe lots of readings should have an aggregate effect on the direction of travel. For instance, if we're heading N, the first time we get a reading indicating we should really got E, we won't head directly east but instead shift our heading slightly NE. Maybe the next reading comes in affirming a northerly course, at which point we head N again; it would not be until several readings confirm "go east" that we completely turn N -> NNE -> NE -> E.<br /><br />Oh and did I mention the compass sensor that tells us whether we actually are going north or east is also not 100% accurate? Guesses stacked on top of guesses...Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-41546589448320540282009-02-03T22:49:00.005-06:002009-02-04T22:19:46.554-06:00Giant Robot Headed for Colorado<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SYkiPGuH2sI/AAAAAAAAASI/SZgC4TFZi2M/s1600-h/hagrid.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SYkiPGuH2sI/AAAAAAAAASI/SZgC4TFZi2M/s400/hagrid.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5298804079475546818" /></a><br /><br />Woot! We're going to Colorado! <a href="http://www.sparkfun.com">Sparkfun.com</a> is hosting an <a href="http://www.sparkfun.com/commerce/product_info.php?products_id=9016">Unmanned Autonomous Vehicle contest</a> in their parking lot in April. This is exactly the kind of contest my powerwheels robot is designed for!<br /><br />When I first read about the competition, my first reaction was "of course we never have anything like this in Oklahoma." Then I thought, damn it, after all the cool robot events I miss out on because they're in <a href="http://www.seattlerobotics.org/">Seattle</a>, or <a href="http://www.parallax.com/TopLevelMenu/Company/2008EmbeddedSystemsConference/tabid/640/Default.aspx">California</a>, I'm sick and tired of getting left out just because I live in the sticks. I'm going to this one. Colorado isn't <span style="font-style:italic;">that</span> far.<br /><br />It's funny because you could see the same thought process go on when I asked my friend Earl Martin to come with me. "Oh I'd love to go, but really I can't..." It was his wife who convinced him, "Go! Go have fun!" (Wives of geeks, take note: you may not be able to break us of the habit of taking over the kitchen table with an occaisional soldering project, or the habit of accumulating mountains of computer electronics junk, no matter how often you roll your eyes at it, but a just little bit of encouragement from you goes a long way to making us feel enthusiastic again when we need that approval. I'm indebted to my own wife for selflessly sacrificing our living room so I can have a place to work on the robot to get it ready for the contest.)<br /><br />I also asked my friend Ben to come along. He's a great guy to have around, but he's hard to pin down. When I wanted him to be one of my groomsman in my wedding, he was off in England! So I don't know if he'll be available for the trip but I hope so. He said he might be able to fix me up with a mini-ITX board running Intel's open source machine vision library - very cool!<br /><br />My sister Ginny also asked to come along. I had automatically assumed it wouldn't be something she would be interested in, but when I mentioned it, she asked to come along. I don't know how the transportation situation will play out because my car doesn't have a lot of room, and most of it will be taken up by the robot, but I'm sure things will work out. If she wants to go I certainly don't object and who knows? We might turn her into an engineer, by osmosis.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com2tag:blogger.com,1999:blog-6897130125864772151.post-60053543031638814022009-01-22T23:04:00.005-06:002009-01-22T23:52:16.524-06:00Meatloaf RecipeThis is a meatloaf recipe that sort of just evolved out of cooking experiments done by my mother and myself with the help of my brothers and sisters when I was a teenager. We (especially my mother and I) are not big on measuring, so everything is approximate, guessed on what looks good, and seasoned to taste. Sometimes it comes out really good and sometimes really awful, but either way, we never make a bland meatloaf!<br /><br />In a large pyrex bowl, crush 3 large handfuls of Kellogg's Cornflakes to powder using your hands.<br />Add:<br />1/4 teaspoon black pepper<br />1/4 teaspoon salt<br />a dash of parsley<br />a dash of sage<br />1/2 teaspoon fresh thyme<br />1/2 teaspoon fresh rosemary<br /><br />Mix these dry ingredients together.<br /><br />Then add:<br />2 cloves minced garlic<br />1/3 of a whole onion, chopped<br />1/3 of a whole green pepper, chopped<br /><br />In a separate bowl, beat 2 whole eggs<br />Add the eggs and vegetables to the dry ingredients in the pyrex bowl, and mix<br /><br />After mixing the other ingredients, only then add the hamburger. How much hamburger? I dunno - enough to fill the bowl! The key to making good meatloaf is to handle the ground beef as little as possible. It's already been ground up, and if you mush it around too much mixing it, you'll end up with a meatloaf the consistency of canned cat food. A good meatloaf has the same texture as a grilled hamburger patty.<br /><br />To mix the meatloaf right, first pull the hamburger apart while breaking as few "strands" as possible. Then fluff the mixture almost as you would if you were mixing butter into popcorn. The goal is distribute the seasonings and vegetables throughout the meat, not to homogenize it. Don't push the meat back together as you mix it; we'll take care of the density by packing it down when we actually put it in the pan.<br /><br />Place the mixed meatloaf in the pan, and pack it down as solidly but don't smush it. Set aside.<br /><br />In another bowl, mix the SECRET sauce:<br />1/2 cup ketchup<br />1 heaping teaspoon brown sugar<br />two dashes of chili powder<br />a hint of nutmeg<br />a heavy dash of black pepper<br />1 clove of garlic, ground to a paste<br />a sprinkle of fresh rosemary, crushed and torn<br />one drop of yellow mustard<br /><br />The sauce - I just made that up. Tastes great. Tangy, like teryaki sauce. Melissa's grandmother had suggested the brown sugar and mustard.<br /><br />Pour the sauce over the top of the meatloaf and spread evenly.<br /><br />Preheat oven to 350 degrees and bake 1 hour or until firm. If it isn't delicious, don't blame me - you must be doing it wrong. :DDennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com1tag:blogger.com,1999:blog-6897130125864772151.post-82595971841333160202008-12-01T09:28:00.015-06:002008-12-17T21:01:11.696-06:00PROP6502 Laptop Project<p><br />I made a laptop. It won <a href="http://www.parallax.com/tabid/708/Default.aspx">honorable mention</a> in the <a href="http://www.parallax.com/tabid/720/Default.aspx">Parallax 2008 Propeller Design Contest</a>. The point of the contest was to do something that shows off the unique capabilities of the <a href="http://www.parallax.com/tabid/407/Default.aspx">Propeller microcontroller</a>. I made a 6502-based laptop that uses the Propeller as its "chipset". I started with a toy laptop, and replaced all of the electronics with my own design to make it into a real working computer.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_s7k3i46yEG0/SS93jLt9A1I/AAAAAAAAAQo/uvV2gQCKm0g/s1600-h/laptop-closed2.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_s7k3i46yEG0/SS93jLt9A1I/AAAAAAAAAQo/uvV2gQCKm0g/s400/laptop-closed2.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273565134998799186" /></a><br /></p><br /><p><br />The screen is a 5.5 inch LCD TV for the laptop screen. The video decoder board, which was piggybacked on the LCD, made too tall a stack to fit inside the screen. After watching this <a href="http://benheckpodcast.com/blog/?p=61">presentation about modding</a> by <a href="http://benheck.com/">Benjamin Heckendorn</a>, I decided not to try to make the laptop thicker. He gives the advice that you have to pick a height constraint and stick to it or else your project will grow to be "the Marvel Mystery House." Instead I figured out a way to unfolded the TV circuit board flat and place it below (not behind) the screen. Unfortunately that makes the LCD sit very high up the lid, so I made a nice decorative faceplate to distract the eye from how high and small the screen is.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SUBbTzg3rtI/AAAAAAAAARY/sX7KuzhYWm0/s1600-h/laptop-open.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SUBbTzg3rtI/AAAAAAAAARY/sX7KuzhYWm0/s400/laptop-open.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5278319159081938642" /></a><br />The battery holder is embedded face up in the bottom so I wouldn't have to fashion a battery cover; the lid keeps the batteries in place when the laptop is closed.<br /></p><br /><p><br />Inside the laptop: at the top of the picture you see the back of the keyboard. In the second row, components from left to right: the keyboard decoder, back of the battery holder, and the CPU board. (More on the CPU board in a minute.) This toy laptop had a QWERTY keyboard, but it was not PS/2. Decoding this key matrix with the Propeller would be a waste of I/O pins. I realized that all keyboards are key matrices, including standard computer keyboards. So I simply cut the circuit board out of a real PS/2 keyboard from a Dell PC, and soldered the toy keyboard to the PS/2 board! The fact that that actually works (it does work!) is hilarious. Of course the key codes generated will be different; for instance pressing "A" might make the PS/2 board think you are pressing "X", but I simply translate the keycodes in software.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SUm1UJFwWgI/AAAAAAAAARg/eGOJUMbTMcQ/s1600-h/inside-laptop.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SUm1UJFwWgI/AAAAAAAAARg/eGOJUMbTMcQ/s400/inside-laptop.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5280951395710687746" /></a><br /></p><br /><p><br />The laptop is based on a 6502 processor. I used the Propeller microcontroller as the "chipset" for the computer. The Propeller provides video, I/O, and memory control. The 6502 addresses a 64K static RAM chip, and the Propeller manipulates the control signals in order to load the initial program and monitor the address and data buses. Reducing chip count was key to making this board fit inside the laptop shell.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SS9xPWL3ehI/AAAAAAAAAQg/CSRtpnxmKjM/s1600-h/board-component-side.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SS9xPWL3ehI/AAAAAAAAAQg/CSRtpnxmKjM/s400/board-component-side.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273558197141469714" /></a><br /></p><br /><p><br />The reason I was able to do it with so few chips is a combination of the Propeller microcontroller's versatility, and a neat timing trick that allowed me to multiplex the data bus. After reading how old 6502 computers interleaved video access with processor accesses on the same bus, I realized I could use the same technique to allow the Propeller to access the bus in the interim period between each 6502 bus cycle. Since the 6502 puts the address out before the data is read or written, the Propeller can quickly transfer the 16 bit address onto the 8 bit data bus in two transfers, and still finish in time to return the data bus to a "normal" state so that the 6502 never knows anything happened.<br /><br />What I learned from this project is that pins and signals are ways of dividing up the physical dimensions, but you can also think of time as a dimension that can be sliced up and parceled out. Making use of this extra dimension in a design can allow you to fold a complex system into a smaller physical space than it would seem to fit.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SS997Ibba4I/AAAAAAAAARA/HUZJDBzI67M/s1600-h/Prop6502.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SS997Ibba4I/AAAAAAAAARA/HUZJDBzI67M/s400/Prop6502.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273572143502420866" /></a><br /></p><br /><p><br />Once you've pared down your design, you've still got to wire it, and even a simple computer involves a nightmare of wiring. This part is harder than choosing the right chips to wire in the first place!<br /><br />In a closely packed board, you can have a problem wiring it just from the sheer mass of copper packed into each square inch. I used strips cut from 80 conductor IDE ribbon cables to wire up the board. (Credit to Benjamin Heckendorn for giving this advice as well, in the same <a href="http://benheckpodcast.com/blog/?p=61">presentation</a> I mentioned above.) These extremely thin IDE cable wires allowed me to pack more wiring into a smaller space, and it makes the wiring neater when you can group 4 or 8 together into ribbon cables.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SS9-J-egJKI/AAAAAAAAARI/HNIY26Z89OM/s1600-h/board-wire-side.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SS9-J-egJKI/AAAAAAAAARI/HNIY26Z89OM/s400/board-wire-side.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273572398528996514" /></a><br /></p><br /><p><br />This project gave me an excuse to finally use my Fluke 9010A Microcomputer Troubleshooter (pictured, front and center). My friend and former teacher, Earl Martin, once told me there were only ever two pieces of electronics equipment he wanted his whole life. One is a multichannel logic analyzer; the other is this Fluke 9010A, which he gave to me.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SS98uYTTHAI/AAAAAAAAAQ4/YBP73ss5SEs/s1600-h/PA040001.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SS98uYTTHAI/AAAAAAAAAQ4/YBP73ss5SEs/s400/PA040001.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273570824913361922" /></a><br /><br />What this unit allows you to do is plug in to the CPU socket of a computer and exercise control of any aspect of the computer. You can test bus signals, read/write memory, even run programs and break on conditions. Technically it's an in-circuit emulator, but that term doesn't begin to cover the depth of what this tool can do. I would not have even attempted this project without it.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SS97a5VMEBI/AAAAAAAAAQw/6JkWV_aSaAc/s1600-h/during-testing.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SS97a5VMEBI/AAAAAAAAAQw/6JkWV_aSaAc/s400/during-testing.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273569390670647314" /></a><br /></p><br /><p><br />I had hoped to get better than honorable mention, but at least I'm on the same web page with the other winners, and received a $100 prize. I took the prize payment in the form of $100 of Parallax electronics components. I used the prize from this contest to buy parts for my project for next year's Propeller design contest: Norbert 2.0, a Propeller-controlled mobile Lego robot with a 5-degree of freedom manipulator arm. See you next time!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_s7k3i46yEG0/SS9vTpJgM9I/AAAAAAAAAQY/xinVgoMk02M/s1600-h/holding-laptop.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_s7k3i46yEG0/SS9vTpJgM9I/AAAAAAAAAQY/xinVgoMk02M/s400/holding-laptop.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273556071928050642" /></a><br /></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com3tag:blogger.com,1999:blog-6897130125864772151.post-78577127924068704852008-09-01T10:25:00.004-05:002008-09-01T11:42:52.271-05:00Success at Last: Wireless on the Freerunner with Om2008Since I lose the USB network device when the Freerunner powers down, it would be helpful if I <a href="http://wiki.openmoko.org/wiki/USB_Networking">set up Ubuntu</a> to automatically reconfigure the device when it does come back online. I haven't tested if that would unstick a frozen SSH session, but it might. Unfortunately I read Ubuntu has a <a href="https://bugs.launchpad.net/ubuntu/+source/ifupdown/+bug/130437">bug</a> that <a href="http://wiki.openmoko.org/wiki/USB_Networking#Ubuntu_Issues">makes the reconnect not work</a>.<br /><br />The fix isn't exactly hard but before I did that, I decided to give my Freerunner's wifi configuration another try. It turns out the reason I couldn't get wifi to work before was due to a really silly thing. In the new keyboard app in Om2008, it shows what word it thinks you're typing, but it doesn't actually enter it unless you tap on the word. Whenever I tried to enter my WPA password, I would see the word suggestion from the keyboard app right below the blank password textbox, and I thought I was typing in the password box. Actually I hadn't entered anything yet because I didn't click on the word. Once I figured that out, I was able to connect to my wifi network.<br /><br />But how to be sure that I was connected? I hit upon the idea of going into my router configuration to see if it had assigned a DHCP address to my Freerunner. Sure enough, there it was, and now I knew what IP to type in to ssh to it. Having wifi working solves some of my problems I had with USB networking. Even though my ssh session still freezes when the Freerunner goes into standby, the ssh session also unfreezes when I wake the phone back up, so I can continue where I left off while working. Still trying to figure out how to fix the shutdown problem.<br /><br />Once you have wifi connected, you should be able to ping internet IP addresses, but DNS doesn't work yet because the Freerunner doesn't know your DNS server. I followed the instructions from <a href="http://wiki.openmoko.org/wiki/USB_Networking#Configure_Default_Neo_DNS">the USB networking page</a> to set up DNS, using the address of my router, as that part of the instructions works equally well for wifi networking as it does for USB networking.<br /><br />Once DNS works, then the package manager works. <del>I still haven't figured out the suspend problem.</del><br /><br />Update: I must have missed that in the <a href="http://wiki.openmoko.org/wiki/Om_2008.8">known issues</a> for Om2008, they said that the builds from the last days of August (which I'm using) have to have the X screensaver disabled. The fix is to run the command "xset s off". What they didn't mention (and since it's a wiki, I was able to fix it for them :) ) is that you can't run xset from the ssh session, you have to install the terminal app (after getting DNS working) and run the command on the phone itself.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-1725389115709685132008-08-31T21:46:00.002-05:002008-08-31T22:09:55.979-05:00USB Networking on the Neo FreerunnerWell the new version of the open moko software isn't much better; they changed a lot in the interface but it still has some serious bugs.<br /><br />This version of the software has a bug that causes my phone to suspend every 30 seconds when the USB cable is connected, even if you have suspend set to "disabled". Guys you have GOT to fix these bugs! Seriously. I was honestly better off <i>before</i> I upgraded, in terms of reliability.<br /><br />In order to do much with the Neo Freerunner, you really have to have USB networking set up. I found some <a href="http://sebastian-bergmann.de/archives/801-OpenMoko-Freerunner-and-Ubuntu.html">instructions</a> that work nicely on Ubuntu. However, if the phone suspends at any time during the process (as mine does constantly due to the bug I was talking about), then -poof- your USB device magically goes away and you lose your ifconfig settings or crash your ssh session!<br /><br />Unfortunately you have to have USB networking set up in order to run the install scripts to put Debian onto the SD card. Maybe I can type in a command that will force it not to suspend, but I have to do it faster than thirty seconds over SSH because it looks like they took the terminal app out of the newer release. (The one thing that was actually any good in the old release, and they take it <b>out</b>? WTF?)<br /><br />I'm almost ready to flash Qtopia over the open moko software and forget about it, but I did really want to see what apps the open moko distribution would have available if I could get networking so the package manager will work.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-29019451209844426542008-08-31T10:17:00.009-05:002008-08-31T11:06:16.608-05:00My Neo Freerunner Arrives<p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq2-jQ_fcI/AAAAAAAAAPo/z-Fm5NJULn8/s1600-h/P8290001.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq2-jQ_fcI/AAAAAAAAAPo/z-Fm5NJULn8/s400/P8290001.JPG" alt="" id="BLOGGER_PHOTO_ID_5240702302133648834" border="0" /></a><br /><div style="text-align: center">It's here! It's finally here! My <a href="http://en.wikipedia.org/wiki/A_Christmas_Story"><del>Secret Decoder Ring</del></a> Neo Freerunner!</div><br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq3lqUirSI/AAAAAAAAAPw/SmhvNsiRyBA/s1600-h/P8290003.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq3lqUirSI/AAAAAAAAAPw/SmhvNsiRyBA/s400/P8290003.JPG" alt="" id="BLOGGER_PHOTO_ID_5240702974042484002" border="0" /></a><br />When you open the box, you're greeted by a quote from the Tao De Ching. I keep that same book on my desk. How cool is that?<br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq4AlhGucI/AAAAAAAAAP4/ziMIGxKE4Rs/s1600-h/p8290002-1.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq4AlhGucI/AAAAAAAAAP4/ziMIGxKE4Rs/s400/p8290002-1.jpg" alt="" id="BLOGGER_PHOTO_ID_5240703436609468866" border="0" /></a><br />The quote seems to be about the empty hole in the bottom of the phone. Funny, I figured that was where the <a href="http://www.soaponarope.com/Merchant2/merchant.mvc?Screen=PROD&Store_Code=soap&Product_Code=7033&Category_Code=A">rope</a> goes.<br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq4Tcb0ZXI/AAAAAAAAAQA/4R2HOuKm9K8/s1600-h/p8290005.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq4Tcb0ZXI/AAAAAAAAAQA/4R2HOuKm9K8/s400/p8290005.jpg" alt="" id="BLOGGER_PHOTO_ID_5240703760588891506" border="0" /></a><br />Here's what you get in the box: a stylus, USB cable, a charger with plugs for various countries, and a 512MB SD card. The back side of the green card says "Thank you for your efforts to Free The Phone."<br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq4lhMeITI/AAAAAAAAAQI/8xr5AmhR71I/s1600-h/p8290004-1.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_s7k3i46yEG0/SLq4lhMeITI/AAAAAAAAAQI/8xr5AmhR71I/s400/p8290004-1.jpg" alt="" id="BLOGGER_PHOTO_ID_5240704071104340274" border="0" /></a><br />The Neo Freerunner comes with the coolest stylus I've ever seen. On the top side of the device is a laser pointer and a bright LED flashlight. The bottom of the device has a clever mechanism which when twisted one way extends a plastic stylus tip, but when twisted the other way reveals a ballpoint pen tip. Not quite a <a href="http://tardis.wikia.com/wiki/Sonic_screwdriver">Sonic Screwdriver but close!</a> I ended up using the flashlight on this thing just a few hours later when a thunderstorm knocked our light out.<br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq48pIDX2I/AAAAAAAAAQQ/v9RdpQBcAPo/s1600-h/p8290009.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_s7k3i46yEG0/SLq48pIDX2I/AAAAAAAAAQQ/v9RdpQBcAPo/s400/p8290009.jpg" alt="" id="BLOGGER_PHOTO_ID_5240704468370284386" border="0" /></a><br />The display on the phone is really quite beautiful.<br /></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com4tag:blogger.com,1999:blog-6897130125864772151.post-42136908722621841732008-08-31T09:25:00.002-05:002008-08-31T10:17:41.567-05:00Getting the OpenMokoAs our cell phone contracts expire soon, I wanted to take the opportunity to get a phone that I can hack the software on (I've been quite frustrated by the horrible software on my Sprint phone). I've wanted an OpenMoko Freerunner phone because it runs Linux and you have true freedom to change the software on the phone as you like, but I wasn't sure if I could convince my wife we should spend money on it. She surprised me, however, by promising me one for my birthday!<br /><br />Actually buying an OpenMoko Freerunner turns out to be a bit difficult. The "Store" section of the openmoko site simply showed "Sold Out" with a claim that more phones would be coming in July, but it was already August and they hadn't updated that message. You have to go through one of their 3rd-party distributors. There's a catch: the only US 3rd-party distributor (GP2X) doesn't actually sell the latest version of the phone!! They are selling the Neo 1973, which is a prototype to the Neo Freerunner. Due to the similar sounding names, it would be easy to accidently buy the older hardware, which lacks some features and already isn't always supported in newer software releases. Read carefully before you buy!<br /><br />As of today when I look on the site, it seems you can now buy the new phones directly from OpenMoko, but when we ordered mine earlier this month, the only place that had it was the Canadian distributor, Koolu. Having never bought anything from another country before, my wife and I were unsure how to pay for something in Canadian dollars with a US checking account, but it turns out the exchange rate is all handled automatically. We didn't have any problems with the Canadian company, Koolu, but we had a string of problems trying to go through the US company PayPal to get the phone paid for. First PayPal froze my wife's PayPal account because they flagged it as suspicious activity (because it was my wife's name on the account but the ship to was my name). After jumping through a bunch of arbitrary hoops to get my wife's PayPal account unlocked, PayPal dropped the transaction <i>anyway</i> because too much time had passed. So I ended up buying the phone on my account and PayPal ran it as an echeck instead of a credit card, which is not what I wanted. It turns out if you are PayPal customer, there is no way to tell PayPal to run it as credit, even though if you are <b>not</b> a PayPal customer, PayPal <i>will</i> run it as credit! What kind of crap company denies a service to their members that they will give to nonmembers? So I canceled the original transaction and re-ran it as credit and not as a PayPal member, and finally got the phone. However, instead of refunding my first transaction, PayPal double charged me, wiping out my bank account. The funds PayPal sucked from my bank account were there in my PayPal account, true, but I had only intended to pass money through PayPal, not deposit it there. PayPal wasn't going to return my money from the canceled transaction unless I specifically asked for it back. As long as I don't notice what they did, PayPal effectively had an interest-free loan from me. Bastards.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-18195260951027539212008-08-25T23:58:00.002-05:002008-08-26T00:13:29.985-05:00I Feel Stupid And TriumphantFor years I haven't been able to run Linux on my laptop because my wireless card is not supported on Ubuntu. Dell used several different Broadcom chipsets in different runs of the laptop I got, and I had the bad luck to get the ONE chipset that is completely unsupported on Linux. The model stepping BEFORE this wireless card works, and the one after, but this one just proved to be too tough a nut to crack for the Linux driver people. By a ridiculous stroke of bad luck it ALSO has a Windows driver which can't be used with the NDIS wrapper. Trust me I've tried everything; many sleepless nights to no avail.<br /><br />But in an unrelated project, I've been playing with these WRAP PC Engines router boards that I got for free because they were lightning damaged. A couple of them had mini-PCI wireless cards attached to them. These cards use Atheros chipsets, which are the most well-supported wireless chips under Linux. They would fit in my laptop, but I didn't think they worked because I could never get them to work in any of the WRAP boards. Plus I imagined tearing down the laptop to find the wireless card inside it would be a pain in the butt, so I put off actually swapping in a card to check if it worked.<br /><br />When I upgraded the RAM in my laptop today I found out that the wireless card is not hidden in the bowels of the machine; it's just located under the same access panel with the RAM! I also had had the WRAP boards out and I noticed that the Atheros wireless cards I had weren't just crappy wireless "B" cards, they were really wireless "G". So I finally swapped one in and it worked! I'm writing this post from Ubuntu Linux now on my laptop, wirelessly! Yipee!<br /><br />Then I realized that I could have done this six months ago. Now I feel stupid.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-21230323944697211862008-08-24T05:35:00.006-05:002008-08-25T21:51:40.862-05:00C++ IteratorsA friend of mine and I are collaborating on a game in the C++ programming language. The part I'm writing is a general purpose engine that will be used on both the game server and the game client, so I decided to use templates to allow basic game objects to be replaced with entirely different classes in the client and server, yet still use all the same code on top of them.<br /><br />In the process of moving my code from regular classes to template classes, I uncovered a fundamental language wart or compiler flaw. It has to do with a problem I ran into using STL iterators. Before I go into what the problem is, let me explain iterators a bit.<br /><br />The people who wrote C++'s standard template library want to break you of the habit of writing things like:<br /><br />for (int i=0; i < vec.size(); i++)<br /><br />Instead you should write this:<br /><br />for (vector< int >::iterator i=vec.begin(); i != vec.end(); i++)<br /><br />Do you see the improvement? No? It's supposed to simplify code for traversing containers--except that it's twice as much typing! OK, well it also gives your code portability to use different containers besides vector ...theoretically... except that we have to specify "vector" directly in the for loop to say what kind of iterator it is! Oops.<br /><br />The real motivation behind iterators is that it unifies the concepts for the people who <span style="font-style:italic;">write the container classes</span>. I won't say the users of the container classes can't use iterators in ways that also provide benefit, but the users also bear a burden of extra boilerplate that adds as much work as it saves. This is the sort of thing Bjarne Stroustroup means when he talks about the compiler vendors and library/tools group being overrepresented on the C++ standards committee compared to actual users of C++. At least we users are finally going to get the auto keyword in C++0x, which will allow us to just write the word "auto" in place of the vector<int>::iterator gobbledygook.<br /><br />But being the good little C++ citizen that I am, I've taken the trouble to use iterators in all my code, even if it is a lot more typing. That's how when I moved my engine definition into templates, I got burned badly.<br /><br />Where before I had this:<br /><br />for (vector< GameObj >::iterator i=vec.begin(); i != vec.end(); i++)<br /><br />I now have:<br /><br />template < typename T ><br /> ... ...<br />for (vector< T >::iterator i=vec.begin(); i != vec.end(); i++)<br /><br />What is <span style="font-weight:bold;">supposed</span> to happen is that when I instantiate the code with T=GameObj or T=OtherGameObj, the code will get built at the point I instantiated it and the result of the latter will look like the former except with either GameObj or OtherGameObj substituted for T.<br /><br />Instead, it turns out that you can't (at least on my compiler) use a template argument like T to specify the type argument to a container iterator. You can <span style="font-style:italic;">declare the container</span> using that T, but you cannot access the iterator of the container you just created! On some containers like vector you can just go back to the old notation, but for containers like map<>, iterators are the only way to loop over the container. This is a Really F*ing Big Problem. This is like laying the foundation for a building and realizing you didn't leave room in the floor plan for any doors. The irony is that iterators from the standard <span style="font-weight:bold;">template</span> library don't work with <span style="font-weight:bold;">template</span> arguments! This is like forgetting to leave room for doors in the plans for a f*ing door factory!Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com6tag:blogger.com,1999:blog-6897130125864772151.post-28794916485551862582008-07-31T21:03:00.003-05:002008-07-31T21:58:05.328-05:00Host OfflineI was trying to think of a catchy title for my first post after being away so long. Due some ironic glitch in my blogging software, "Host Offline" appeared as the default text in the title box. Why, yes, I have been!<br /><br />I've had so much going on that I haven't had any time to blog about it! In the last two months I graduated college, moved, got married, and started a new job. My routine changed a lot and I haven't figured out where blogging fits in to it. Two a.m. used to be my prime writing time, but these days I'm in bed by ten so I can get up early for work. I almost decided to give up this blog, but I found out my father reads it (hi dad!), so I think I'll give it another go. <br /><br />Life's been great. Melissa and I had a beautiful wedding, no family members disowned each other over the wedding planning stress, and then we had a wonderful week in Jamaica to unwind. (I'll put some wedding pictures up... eventually...) When I got back I started my new job as a programmer for an insurance company and it's turned out to be a good gig, they run a clean shop and treat people right. The only unfortunate thing is that I work during the day and Melissa works at night (she's a nurse). Our hours mean I leave for work before she gets home, and she leaves just as I get home.<br /><br />Melissa found us a nice apartment in Norman, which IMO is the best city in Oklahoma. I got all my stuff moved up here and - this is really shocking: I'm actually organized! Kinda. I'm still a big pack rat and leave a lot of clutter around, but all my junk box goodies are in individual draws, bins, or containers. If you name something, I can lay my hands on it in 2 minutes without rummaging. I had had a week off by myself before the wedding, and I busted ass to get my organization project finished then because it could be years before I get another opportunity like that. While sorting my 100's of TTL chips into individual bins by part number, I suddenly remembered that I had actually started sorting them 10 years ago, and hadn't finished. So this is a once-in-a-decade event.<br /><br />These days I'm working on a MMO game engine, and hand-wiring an 8-bit computer, among other things, on evenings when my wife is at work. I used to think it was not possible to get anything constructive done in short shifts, but I've actually gotten pretty good at working on my projects now for just 30 minutes or an hour at a time. Having my junk box organized helps.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-20835380712639459802008-05-20T22:12:00.007-05:002008-05-22T13:25:33.121-05:00My New Old 64-bit AMD<span style="font-style:italic;">It might be a sign it's time to upgrade when you find a better computer in the dumpster!</span><br /><br />Melissa (my future wife) and I just moved to a nice little apartment in Norman. One of the perks of living in "the city" is people throw out way better stuff here. Just our first day in the apartment I spotted a computer tower sitting next to the dumpster. I was surprised Melissa didn't say anything when I came back from taking out the trash, carrying something larger back into the house than what was in the bag when I went out. She rolled her eyes but let me keep my new little "toy". Maybe she's used to it by now, or just tired of trying to talk me out of it! Because I'm a bit of a junk collector - it runs in the family. But I just get such a charge out of taking things that were broken/worthless and turning them into something that can be used.<br /><br />This one was a real find - a 64 bit AMD Athlon 3200+; only a few years old. I was hoping it was a dual-core; it wasn't, but the board supports one, and as it is this processor is still slightly faster than my current best computer (a 2.6 GHz Pentium 4). Even though the clock speed of my Pentium is greater, AMD chips get more work done in each clock cycle, and this AMD one is 64 bit vs. my old one which is only 32 bit.<br /><br />I can only imagine what kind of hot rig the previous owner must have if he throws away a good 64 bit machine! Perhaps he thought it was broken? Dead computers are almost always salvageable; usually a dying hard drive or finicky power supply is the only ailment, but I guess owners get so frustrated with such problems that they get pissed and throw out the whole thing. Or they don't understand that the CPU tower has interchangeable components inside it, many of which contain no moving parts and theoretically never wear out. This guy obviously knew at least a little about computers, because he removed the RAM, which I was sad to see missing because I'm always short of DDR sticks.<br /><br />I cannibalized some RAM from one of my other computers, and I'm super excited now because the junk-computer seems to work fine!<br /><br />In order to furnish this new computer, I'm going to basically split my best computer in half and make two: my best computer had 2 GB of RAM and matched hard drives in a mirror RAID; so I'm just going to put 1 GB of RAM in each and break the mirror. Sure it was fun setting up the mirror RAID a few months ago... (What am I saying? It was a pain in the ass setting up a software RAID to work with both Windows and Linux! Way more trouble than it's worth!) Anyhow as I was saying it's been fun playing with a RAID, but I can get more use out of the drives separately at the moment.<br /><br />(Gosh, how <b>do</b> you break a mirror RAID? Do you just yank out one drive and just make the system deal with it?)<br /><br />Unfortunately there'll be no pictures of this project. My beat up old camera finally died its last death. Cracked LCD, confused CPU, and it won't stay on anymore no matter how high I boost the voltage (it previously had an undervolt problem that I fixed by adding a 3rd battery). Even I can't fix it.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-71039620585087775332008-04-27T23:18:00.020-05:002008-04-28T04:24:28.634-05:00Mountain Bike to Road Bike Conversion<p>Since my '63 Huffy was stolen, I've been saving parts for a new bicycle. I wanted another road bike, but all I found was a used mountain bike. I hate mountain bikes! Still, it was in good shape, so I bought it. When a derelict road bike showed up at the dump, I combined them to make the bike I really wanted. The Frankenbike! Skinny wheels, drop handlebars, and a big ironic sticker on it that says "Mountain Bike".<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBVQZ8oyueI/AAAAAAAAAH8/RUhXWmK3K7M/s1600-h/Bicycle+outside.jpg"><img style="margin: 10px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBVQZ8oyueI/AAAAAAAAAH8/RUhXWmK3K7M/s320/Bicycle+outside.jpg" alt="" id="BLOGGER_PHOTO_ID_5194146151945910754" border="0" /></a></p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBWSzMoyuuI/AAAAAAAAAJ8/I75koAedEpM/s1600-h/IM000865.JPG"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBWSzMoyuuI/AAAAAAAAAJ8/I75koAedEpM/s200/IM000865.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194219153505041122" /></a>It has a thick steel frame and extra low gears from the mountain bike. The cargo rack came from the junk bike; I need to paint it. Did I say I was making a road bike? Maybe I mean <span style="font-weight:bold;">touring bike.</span> This thing's a tank! But I like to ride slow and steady anyway.</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBWTRMoyuvI/AAAAAAAAAKE/N4sPBLgYtGk/s1600-h/blue+bike.jpg"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBWTRMoyuvI/AAAAAAAAAKE/N4sPBLgYtGk/s200/blue+bike.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5194219668901116658" /></a>My original intent was to just swap wheels, but the donor road bike was a real wreck - rusty frame, taco-ed wheels, and seized bearings had eaten the hubs. With the rims I wanted to use attached to bad hubs, and rims I didn't want attached to my good hubs, I hatched a plan I figured was either mad or brilliant. Knowing nothing about wheel lacing or truing, I decided I'd take all the spokes out of the wheels, and transplant the good mountain bike hubs into the road bike rims.</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBWSOcoyutI/AAAAAAAAAJ0/2gs37-vLvvk/s1600-h/sorting+spokes.JPG"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBWSOcoyutI/AAAAAAAAAJ0/2gs37-vLvvk/s200/sorting+spokes.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194218522144848594" /></a>When I tried to lace the new hubs into the road rims, I found the road bike rims have a larger inside diameter. It wasn't much, but it was enough that the mountain bike spokes wouldn't reach. I needed to use at least some mountain bike spokes, because a few of the road bike spokes were broken. Usually when you lace wheels, you pick a lacing pattern and buy spokes the right length. I needed to find lacing patterns that used the random combination of lengths I already had!</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBVW1coyuhI/AAAAAAAAAIU/CUcWYbhXXTU/s1600-h/crows+foot+and+bearings+closeup.jpg"><img style="display:block; margin:0px auto 10px; float:right; cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBVW1coyuhI/AAAAAAAAAIU/CUcWYbhXXTU/s320/crows+foot+and+bearings+closeup.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5194153221462080018" /></a>I found a site which described the Crow's Foot pattern. This was perfect for what I needed, as I could use the shorter mountain bike spoke for the radial spokes, and the longer road bike spokes for the two crossing "toes". The pattern looks nice and it's very stiff. In this picture, you can see the distinctive 3-spoke crossings of the crow's foot.</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBWTxMoyuwI/AAAAAAAAAKM/oWO6rlvd1_w/s1600-h/you+can+see+the+bearings.JPG"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBWTxMoyuwI/AAAAAAAAAKM/oWO6rlvd1_w/s200/you+can+see+the+bearings.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194220218656930562" /></a>That's a front fork but it's got a rear wheel hub stuck in it, sans gears. The mountain bike spokes were just too short, even for Crow's Foot. But a rear wheel hub has a larger diameter than a front wheel hub; it gets these shorter spokes closer to rim, just enough to make it work. Of course that caused problems all its own. A rear hub is wider than a front hub, which means the front fork isn't wide enough to go around the cone nuts. I didn't want to bend the forks out, so I had to bring the cone nuts in. Using the angle grinder and nerves of steel, I cut the cone nuts down to mere slivers, leaving only the sloped bearing race. I cut them so thin I could fit both them and the nuts that lock them within the forks. I also had to notch the axle bolt so it would slip into the smaller fork holes.</p><br /><br /><p>Despite the difficulties, using a rear hub for the front wheel is a great mod. Front wheel hubs are narrow and use smaller bearings on a smaller axle. Why? You'd think the front wheel is the one you'd least want to wobble, and it will take the brunt of any crash. Rear hubs, being wider, place the bearings further apart, so play in the bearings has less effect at the rim than with narrow hubs. It gives a steeper dish to the spokes, which also resists side to side forces better. And this hub has uncaged bearings, more of them, in a larger race. The difference is noticeable. There is zero wobble. None. It rides like it's on rails.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_s7k3i46yEG0/SBWIUsoyupI/AAAAAAAAAJU/RaiHbzmf7uI/s1600-h/IM000858.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_s7k3i46yEG0/SBWIUsoyupI/AAAAAAAAAJU/RaiHbzmf7uI/s320/IM000858.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194207634402753170" /></a></p><br /><br /><p>Funny story about the bearings. I tried the smaller axle from the old front hub to see if it would hold the large bearings in. It didn't, and the bearings went bouncing all over my shop. I recovered all but one of the bearings.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBWU0coyuyI/AAAAAAAAAKc/DXfFLPOTkAk/s1600-h/crows+foot+pattern.JPG"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBWU0coyuyI/AAAAAAAAAKc/DXfFLPOTkAk/s200/crows+foot+pattern.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194221374003133218" /></a> When I finally found that last bearing, I noticed it had hole drilled through it. I'd never seen that before, and I couldn't figure out why someone would make a bearing with a hole in it! But it was clearly one of the right bearings - it was the same size as all the others, and the same shiny silver color. Maybe the hole was so it would retain grease? I shrugged and put it into the race with the others. Well the next day I found the missing bearing. I thought, if I'm holding the missing bearing in my hand, what the crap did I put into the bearing race yesterday? I removed the bearing with the hole in it and scratched it. Silver paint flaked off. What I had was one of those metalized plastic beads they use for craft necklaces! By chance it happened to be on the floor in the same place I dropped my bearings! I don't know what would have happened if I'd left it in, but the wheel turned fine with a plastic bearing.</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBV9_MoyumI/AAAAAAAAAI8/jO2D9bkQ9iw/s1600-h/IM000875.JPG"><img style="display:block; margin:0px auto 10px; float:right;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBV9_MoyumI/AAAAAAAAAI8/jO2D9bkQ9iw/s320/IM000875.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194196269919287906" /></a>For the rear wheel, I used Crow's Foot on one side, and made up my own pattern for the other. I came up with a daring plan to use an <span style="font-weight:bold;">unbalanced lacing pattern</span>. There are two forward-pulling spokes for every one backward-pulling spoke. The idea is that when you're pedalling, there are two spokes transmitting your torque to the ground for every one that's not. Does it lead to the wheel twisting under load? It's hard to be sure because the rim was already bent when I got it. But I've been riding it like this and haven't had a problem. I call it the "Dreamcatcher" lacing pattern; the spokes weave many times.</p><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBVQ6MoyugI/AAAAAAAAAIM/3gFkI58Fe9w/s1600-h/handlebars+with+shifters+on+the+outside.jpg"><img style="display:block; margin:0px 20px 10px; text-align:center; cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBVQ6MoyugI/AAAAAAAAAIM/3gFkI58Fe9w/s320/handlebars+with+shifters+on+the+outside.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5194146705996691970" /></a>I didn't want to restring the shifter cables, so I kept the original shifters. Unfortunately they were designed for a straight bar. On the drop bars always the shift lever was blocked, or the cable interfered with the brakes or my hands. Putting them on the outside was the least bothersome place. I'm saving the two levers on the stem for clutch levers to engage the motors if I make the bike electric.</p><br /><br /><p>The handlebars had awful rubber grips that kept slipping off. I got rid of them and wrapped the handlebars with some good Cinelli cork tape. Not bad for my first try.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBWBr8oyunI/AAAAAAAAAJE/4HILmKRa-yA/s1600-h/IM000856.JPG"><img style="display:block; margin:10px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBWBr8oyunI/AAAAAAAAAJE/4HILmKRa-yA/s320/IM000856.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5194200337253317234" /></a></p><br /><br /><p>Well, that's my bicycle. There's nothing like riding a bike knowing every piece that makes up the whole is there because you chose it, not the factory.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBWJXMoyurI/AAAAAAAAAJk/vQd_HtcnrIE/s1600-h/me+with+bicycle+in+front+of+construction.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBWJXMoyurI/AAAAAAAAAJk/vQd_HtcnrIE/s400/me+with+bicycle+in+front+of+construction.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5194208776864053938" /></a></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com4tag:blogger.com,1999:blog-6897130125864772151.post-45813521943650848032008-04-24T19:58:00.018-05:002008-04-24T23:20:12.462-05:00Ferron's Guaranteed No Mess No Mixups Method for Swapping Rims without Relacing<p>I'm restoring my fiancée's bicycle. The hub and spokes are ok, but the bottom of the rims once sat in a puddle until they rusted out. Luckily I had a spare pair of rims left over from my last bicycle project.</p><br /><p><br />It's fairly easy to de-lace a wheel. But getting the lacing right when you put the new rims on looks really hard! All those criss-crossings and spokes going alternating ways... Who can keep track of it? And if you miss a spoke, you'll throw off the whole process. I found websites which provide wheel lacing patterns, but I've got a much easier way than lacing from scratch.<br /></p><br /><p><br />The basic idea is that you only transfer one lace at a time. You copy the pattern from the old wheel step by step, and you'll never miss a spoke.<br /></p><br /><p>Start by holding the two wheels side-by-side between your knees. Make sure the right side spoke holes in one wheel are next to the right side holes in the other, and the left are by the left. As seen in this picture, the valve holes might not line up although the left-right spoke holes do.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBExUcoyuVI/AAAAAAAAAGs/gKKcNsNxaQY/s1600-h/IM000815.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBExUcoyuVI/AAAAAAAAAGs/gKKcNsNxaQY/s320/IM000815.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5192986072689326418" /></a></p><br /><br /><p>With a flat head bit, completely unscrew a <span style="font-weight:bold;">left side</span> nipple.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBE5v8oyuWI/AAAAAAAAAG0/IxQXHyNJir4/s1600-h/IM000818.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBE5v8oyuWI/AAAAAAAAAG0/IxQXHyNJir4/s320/IM000818.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5192995341228751202" /></a></p><br /><br /><p>Move the spoke over to the other rim and screw it in loosely.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBE71MoyuYI/AAAAAAAAAHE/v4GbILrbqYs/s1600-h/IM000820.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBE71MoyuYI/AAAAAAAAAHE/v4GbILrbqYs/s320/IM000820.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5192997630446320002" /></a></p><br /><br /><p>Spokes which cross underneath are blocked by the ones on top. Always transfer the spoke that crosses on top first, then transfer the one that crossed under it.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBE6ocoyuXI/AAAAAAAAAG8/RCn7BLlXQIU/s1600-h/IM000823.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBE6ocoyuXI/AAAAAAAAAG8/RCn7BLlXQIU/s320/IM000823.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5192996311891360114" /></a></p><br /><br /><p>As you go around transfering each left side spoke, <span style="font-weight:bold;">loosen</span> but do not remove each <span style="font-weight:bold;">right side</span> nipple.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_s7k3i46yEG0/SBE9KsoyuZI/AAAAAAAAAHM/fTy8JzeuKc8/s1600-h/IM000819.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_s7k3i46yEG0/SBE9KsoyuZI/AAAAAAAAAHM/fTy8JzeuKc8/s320/IM000819.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5192999099325135250" /></a></p><br /><br /><p>Save any extra nipples you can get off other wheels, because you will most likely round off a few nipples during the transfer, and you'll need to replace them.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBE-QMoyuaI/AAAAAAAAAHU/oi9-Q8RgHT8/s1600-h/IM000821.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBE-QMoyuaI/AAAAAAAAAHU/oi9-Q8RgHT8/s320/IM000821.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5193000293326043554" /></a></p><br /><br /><p>When you've transferred all the left side spokes, you will end up with this. If you welded these rims together, you could make a monster "dualie" mountain bike!<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBE_ZMoyubI/AAAAAAAAAHc/n8e-Eo1eOlc/s1600-h/IM000826.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBE_ZMoyubI/AAAAAAAAAHc/n8e-Eo1eOlc/s320/IM000826.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5193001547456494002" /></a></p><br /><br /><p>Now work around the wheel and transfer the remaining right side spokes one by one. Except this time, transfer the one that crosses under first, so it will reach, then do the one that crossed over.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBFBG8oyucI/AAAAAAAAAHk/6rnk6E6ZrBs/s1600-h/IM000833.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBFBG8oyucI/AAAAAAAAAHk/6rnk6E6ZrBs/s320/IM000833.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5193003432947136962" /></a></p><br /><br /><p>Ta-da! Now the old rim is free, and the spokes are all in the new rim. Yet you never undid more than one spoke at a time. Magic!<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBFBrcoyudI/AAAAAAAAAHs/fH1p5JiY85U/s1600-h/IM000838.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBFBrcoyudI/AAAAAAAAAHs/fH1p5JiY85U/s320/IM000838.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5193004060012362194" /></a></p><br /><br /><p>Don't try to ride it yet! You still need to true the wheel. I'll explain in another post the technique I came up with to true my wheels without special equipment.</p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com2tag:blogger.com,1999:blog-6897130125864772151.post-74664323519674876242008-04-24T19:43:00.002-05:002008-04-24T19:55:36.694-05:00cheaphack.netJust wanted to extend a little link-love out to Nick Johnson's <a href="http://www.cheaphack.net/">cheaphack.net.</a> When I first started reading his blog, I expected it to really take off, so I've been surprised by how few comments I've seen around there. If you enjoy reading about electronics projects, building things on the cheap, and the occasional post about bicycles, then you'll really enjoy <a href="http://www.cheaphack.net/">cheaphack.net</a>. Check it out, and leave a message if you like it! That's how we know whether or not anyone reads the stuff we write.Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com1tag:blogger.com,1999:blog-6897130125864772151.post-61265535671205120242008-04-24T18:35:00.005-05:002008-04-24T19:16:22.285-05:00Bicycle Shop<p>In March I finally cleaned out my basement so I'd have a place where I can work on my bicycles. I have an alcove that's just right for parking one or two bikes by the door so I can easily wheel them outside.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/R93jD1j2wXI/AAAAAAAAAFo/3Y3OIcQXRqw/s1600-h/bicycle+shop.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_s7k3i46yEG0/R93jD1j2wXI/AAAAAAAAAFo/3Y3OIcQXRqw/s320/bicycle+shop.JPG" alt="" id="BLOGGER_PHOTO_ID_5178544801602519410" border="0" /></a></p><br /><br /><p>I even have a cool sign!<br />(Disclaimer: I do not run a real bicycle shop!)<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBEga8oyuUI/AAAAAAAAAGk/rawZIrxZkG0/s1600-h/IM000854.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBEga8oyuUI/AAAAAAAAAGk/rawZIrxZkG0/s320/IM000854.JPG" alt="" id="BLOGGER_PHOTO_ID_5192967492660803906" border="0" /></a><br /></p><br /><br /><p>Since clearing this shop space I've already completed 1 1/2 bicycle projects! I'll post about them soon.</p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com0tag:blogger.com,1999:blog-6897130125864772151.post-80469863058444691022008-04-24T13:38:00.008-05:002008-04-24T14:09:36.099-05:00Let's Do The Time Warp Again<p>This morning it was 7 o'clock three times in a row! Wow!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_s7k3i46yEG0/SBDYjsoyuPI/AAAAAAAAAF8/q1WrFPmbpi0/s1600-h/Seven.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_s7k3i46yEG0/SBDYjsoyuPI/AAAAAAAAAF8/q1WrFPmbpi0/s320/Seven.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5192888478147459314" /></a></p><br /><br /><p>Clearly I must be caught in a Time Loop! So I did what any sensible person should do when they're caught in a time loop; I went back to sleep!</p><br /><br /><p>Later I discovered this switch on the top of my clock. It was on "alarm set".<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_s7k3i46yEG0/SBDY9MoyuQI/AAAAAAAAAGE/3k7n7KlDSL8/s1600-h/switch.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_s7k3i46yEG0/SBDY9MoyuQI/AAAAAAAAAGE/3k7n7KlDSL8/s320/switch.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5192888916234123522" /></a></p><br /><br /><p>D'Oh!<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_s7k3i46yEG0/SBDZEcoyuRI/AAAAAAAAAGM/nxGH-y5OeNo/s1600-h/one+forty-four.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_s7k3i46yEG0/SBDZEcoyuRI/AAAAAAAAAGM/nxGH-y5OeNo/s320/one+forty-four.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5192889040788175122" /></a><br /></p>Dennishttp://www.blogger.com/profile/03601234553344631838noreply@blogger.com1