xy-kao.com: projects and experiments of Xiaoyang Kao http://xy-kao.com New articles from xy-kao.com. Custom rss.php JOURNAL: Lessons learned solo bike touring

This past month I went on a bicycle tour along the central California coast from Monterey Bay to Santa Barbara. Having a week-long Thanksgiving break and nothing to do in Champaign, I decided to head out to warm California for an adventure. Seven days, 320 miles, and some incredible people met later, here are some things I learned and took out of the trip:

Follow the solar schedule

Something I very quickly realized was how important sunlight was when out touring. On the first night, I was five miles out from Pfeiffer State Park where I was going to set up camp when it became dark. Cycling down highway 1 at night with no camp set up yet, no food, no cell service, and cars driving by in as much of a rush as I was was no fun. Make note of when sunset is, and then subtract an hour from that. Make it to camp before then.

Food, shelter, water, fire

These things quickly became top priorities for me as soon as I left the Monterey-Carmel area. Food didn’t end up becoming as big of a problem as I thought (there were general stores every 30 miles or so along the route), but getting properly hydrated and preparing for the next segment water-wise was something I had to be actively aware of.

Time of year

Summer is the prime season for California bicycle touring, but I still met quite a few cycle tourists along the route (a lot of whom were doing longer tours and were passing through). Going during late November was nice because there was no problem looking for open campsites and there was less traffic in general, but the extra ~two hours of sunlight if I went in the summer would have been nice to have.

Solo vs group

I made it a point to go out solo because I wanted to be self-sufficient. It was also nice to be able to more or less completely isolate from the world for a week and just have time to think. When the sun set, all I could really do is read, journal, listen to music, sleep, or talk to fellow campers. By the end of it, I loved having time alone to do whatever I wanted with no distractions.

Things to bring, things not needed

By the second day I had a big list of things I did not need to bring:

  •           I didn’t need to bring so many t-shirts
  •           DSLR camera bag stayed at the bottom of my right pannier from start to finish
  •           18-55mm lens wasn’t used much, the wide Tokina 11-18 was enough for most shots
  •           Stove and cup - water and food was more available than I thought
  •           Four books - I didn’t end up reading much at all and instead journalled
  •           Water filtration system
  •           So many spare electronics - the power bank lasted much longer than expected and I was able to recharge on the sixth night

The list of things I wished I brought was thankfully very short:

  •           Tent light - headlamp isn’t very useful in lighting the entire tent
  •           Damp-Rid - it got down to 35F some nights so a moisture absorber to stop condensation on the inside of the tent would have been much welcomed
  •           Bluetooth speakers - earphones do the job but I had one ear open most of the time to listen for cars
  •           Shoe covers for the cleats - toes get cold real quick in the wind

Favorite day?

Its got to be the third day from Plaskett Creek to San Simeon State Park. As soon as I left camp, it began to pour so I had to take a hour long break at the top of the hill. Had a nice sandwich (first real food in two days) and met a European couple who were halfway through their Alaska-Argentina bicycle adventure. Two big climbs and descents later, the clouds finally cleared out, revealing the most beautiful stretch of highway along the coast. The tailwind was gigantic too so I managed to make it to San Simeon SP before it became pitch black. The tent sites at San Simeon are far away from the RV sites, there was nobody else around, and there was zero cell service, so I had the entire night to myself. Went through a couple albums and did some night photography.

Manage time

You’d think I would have learned my lesson after the first night, but nope. The fifth night headed to Santa Maria, there was a stretch of rolling hills that I wasn’t expecting that really took the energy out of me. I didn’t make it to camp until a full hour after it went dark.. not fun.

Prepare for COLD and wet weather

It got down to almost freezing temperatures in the mornings, which I wasn’t prepared for. Didn’t end up leaving the tent most days until 9 when it got warm enough. I didn’t bring a rain jacket either so the third day was pretty miserable. Stuff didn’t dry until next morning too because it rained that night was well.

Cereal, bananas, granola bars, and beef jerky are your friends

I left Monterey with two bags of beef jerky, a few Clif bars, and a few granola bars. That kept me going until the third day at Plaskett Creek, where I picked up some cereal and dried mangoes. The mangoes and granola bars supplied the carbohydrates, cereal provided vitamins, and beef jerky provided protein. That along with water was enough.

Stretch at night

The first night wasn’t very fun. Stretch or you will feel it the next day.

Take it easy and don’t make it a race

Something that is pretty common in the bicycling community is losing interest in cycling. It definitely happened to me, and a big reason for that is over-obsession with the numbers: kilometers ridden, speed, elevation gain, watts put down, etc. Lesson learned: don’t make it a race and enjoy the surroundings. I didn’t bring a speedometer, had my phone on airplane mode when I was riding, and didn’t look at Strava until after the trip. By the end of the trip I felt really good on the bike for the first time in a long while.

People at campsites are some of the friendliest people

The second night at Plaskett Creek, a couple from San Luis Obispo offered me to join them as I was setting up my tent. We ended up talking for a few hours and they gave me food, water, and a campfire to warm myself up around. Incredibly nice people.
Plaskett Creek campsite was marked as full on the sign as I biked in, but another family immediately offered to let me set up my tent next to their RV - super friendly!!
Fourth night at Montana De Oro, a family who camps there every Thanksgiving weekend invited me to join them. Talked to them for a few hours too and they gave me food and everything!

Drivers are generally nice to bike tourists

Majority of the cars literally drove into the oncoming lane to make room for me, even though I was on the shoulder of the road. The one near miss that I remember was going down the hill after Bixby Bridge, when a Jeep came very close at 35 mph.

Budget more time to explore the local area

There were several roads along the way that went uphill inland that I would’ve liked to explore but didn’t have time to. Next time I will set out from camp before 12 and spend more time exploring the local area.

Be less prepared

Most of the campsites have hike and bike tent sites for backpackers and bike tourists, so there was no need to spend $30 to reserve a site in advance every day. Only risk in that is that it may be full, but even if it is, people will offer a tent spot like a family did at Plaskett Creek

Have a SD card backup plan

Or don’t try to save money and use five different cards of questionable quality. Lost one full of night-time long-exposures and then lost another one when it fell from my bike and cracked.

How to keep warm on the bike

Beanie under helmet -> arm warmers -> leg warmers -> gloves, in that order. If I had brought shoe covers it would slot in right after the beanie.

Equipment and bike handling

I borrowed the bike, panniers, and racks from Central Coast Outdoors. Bike was an aluminum Norco Valence A3 touring bike with a carbon fork and a 9-speed Sora groupset. Another gear would have been nice but the Sora kit was enough to get over those hills with 10 kilos of gear strapped onto the back.
Tires were Continental Gatorskins - didn’t have a problem with them.
With the extra loaded weight on the rear rack, handling was funny at first but I got used to it very quickly. Red lights are tricky because lean it the wrong way and the bike will tip over.

Taut line hitch is also your friend

Used this knot a few times to secure the tent. Also made a make-shift DSLR chest mount.

Next goals

Europe seems especially appealing with its bicycle culture and massive hills. Some at the top of the list:
- Seattle - San Diego
- Norwegian west coast
- Iceland

Trip itinerary and Strava routes

320 miles, six nights, seven days.

Monterey - Pfeiffer Big Sur State Park (47.0 mi)
Pfeiffer Big Sur State Park - Plaskett Creek (34.0 mi)
Plaskett Creek - Hearst San Simeon State Park (37.5 mi)
Hearst San Simeon State Park - Montana De Oro State Park (42.1 mi)
Montana De Oro State Park - Santa Maria Pines RV Park (58.4 mi)
Santa Maria Pines RV Park - Buellton (48.1 mi)
Buellton - Santa Barbara (45.7 mi)

http://xy-kao.com/journals/lessons-learned-solo-bike-touring/ http://xy-kao.com/journals/lessons-learned-solo-bike-touring/journals/lessons-learned-solo-bike-touring/ Fri, 11 Dec 2015 00:00:00 +0000
Projection design for Les Misérables

Visual projections were a key element of last year’s fall production of Les Miserables. Projected set pieces and animations were used to add another dimension throughout the show. With over 30 text, image, and animated elements between the two acts, most of the time there were projections visible on stage.

Visual design

A majority of the elements were Victor Hugo’s original artwork with modifications to match our stage and set. The show opens with Victor Hugo’s artwork, then transitions into the first scene on the ship with Jean Valjean.

One of the cues was a transition from day to night inside a building, which was done with QLab’s internal color correction controls. A gamma and exposure correction was enough to achieve the effect.

The splashing water effect had to be cued to live stage action, so two video layers were used. The background was a simple wave simulation rendering done in Cinema4D, then the front layer is a rendered splash. QLab doesn’t have any internal overlay effects like dissolve or darken, so a video codec with alpha channel support like ProRes 4444 had to be used. The wave simulation was by Helge Kiehl using the HOT4D plugin.

One thing that became apparent was that what looked good on the computer screen does not always translate to the stage - a better projector setup with more brightness will help but it is something to be aware of when designing.

A couple of the cues had the actors walking from upstage to downstage with a projected city street background. To achieve the effect that the street buildings were moving along with the actors, the source image was split into the four geometric sides (ground, left buildings, right buildings, and sky) then animated in After Effects with the vanishing point effect.

And then a couple more animated cues for intermission and for the opening scene:

Technical specifications

Our school has a large-format Panasonic PT-EX12KE venue projector with 13,000 lumens of output power. At the max resolution and the throw distance to the stage from the control booth, each pixel was roughly a centimeter square, which is not great up close but it was acceptable from the closest front-row seats.

Cues were delivered with QLab. The third version of QLab has image-adjust features that allowed us to quickly match the color of the animated elements to match the set and mood. Animations were done in After Effects, Cinema4D, and Photoshop, with final geometric alignments to the stage done in QLab.

Projectors don’t project ‘black’, or complete darkness, when the input signal is black. This is called ‘video black’, and the small amount of light that is emitted becomes very visible during a total blackout and in darker parts of the stage. To compensate for this, we manually closed the shutter during longer parts of projection blackout and also used paper to block parts of the projection space.

http://xy-kao.com/projects/projection-design-for-les-miserables/ http://xy-kao.com/projects/projection-design-for-les-miserables/projects/projection-design-for-les-miserables/ Mon, 07 Dec 2015 00:00:00 +0000
Sealing methods for underwater enclosures

As part of our ROV underwater robot design, we've gone through several iterations of waterproof enclosures meant for sealing electronics down to 10m deep water. I reckon the method we have right now is bulletproof for a few hundred meters of water as long as there are no cable connectors.

Submersible containers have a ton of uses from underwater DSLR photography to research to ROV vehicles, so a reliable design that can be fabricated easily was something we have tried a long while to come up with. We began with regular lockandlock food containers, but they were made of flimsy and opaque plastic which leaked several times. The next version was with a IP67 rated electronics enclosure, but that had problems with hairline fractures, which let water in. At water depths of 10m where water is pushing with an atmosphere of force, any tiny crack is magnified and becomes a leaking hole.

This year we've gone with a 'capsule' based design. Two gaskets and two end caps held together with threaded rods combine to seal a tube. Advantages of this design are:

  • Very easy to fabricate and replace parts
  • No special tools required
  • Easily modified in terms of tube diameter
  • The deeper the water, the greater the pressure on the gasket seals


We're using this design for a 15cm diameter control tube and a 7cm diameter camera tube, both of which haven't leaked yet from the gasket seals. Considerations for electrical connectors are more important as we've found those have a tendency to leak easily. The holes in the middle of the acrylic caps are for M12 PG7 threaded cable glands. A plasma-cut aluminum 'washer' plate is used to spread the force the threaded rods provide. 

http://xy-kao.com/sandbox/sealing-methods-for-underwater-enclosures/ http://xy-kao.com/sandbox/sealing-methods-for-underwater-enclosures/sandbox/sealing-methods-for-underwater-enclosures/ Sat, 20 Jun 2015 00:00:00 +0000
Graphene based super capacitors Here is a copy of the paper I wrote for my research in physics class, which is a year-long introductory course for physics based research in a lab. In the end, my project was more of research in chemistry than physics, but I got close to a functional capacitor.



Batteries are currently the limiting factor behind many electric powered devices. Low capacity and slow charging times are both problems being faced every day, but battery technology has largely stagnated since the introduction of lithium-ion batteries. Improved batteries with faster charge rates and greater capacity has implications in consumer electronics, the automotive industry, and our reliance on fossil fuels.

Ever since the discovery of graphene, scientists have been attempting to find practical applications for the material in everyday life. Due to the unique electrical properties of single-layer graphene sheets, some of the most promising areas of research are in energy storage and microelectronics. Semiconductors made of graphene has been shown to exceed existing silicon transistor switching speeds significantly, and since the single-layer carbon structure strongly interacts with photons, there are more possibilities past the realm of electronics. With a high theoretical surface area and conductivity, graphene has the potential to be used in supercapacitors, with power density and energy density far beyond what is possible with existing lithium-ion battery technology (El-Kady, MF, et al. 2013).

From a materials point of view, carbon is the most abundant element on Earth and is not harmful to the environment compared to existing capacitor and supercapacitor materials. However, one of many limiting factors in widespread graphene supercapacitor use is the difficulty of fabrication at a large scale. Small runs of graphene supercapacitors are reproducible in the context of a research lab, but fabrication techniques that allow for high-volume production must be figured out before the capacitors can become practical in everyday electronic devices. Attempts to create graphene-based supercapacitors using a DVD laser have been successful (Marcano, et al. 2010), and this paper outlines an alternative method for scribing using a commercial desktop laser engraver capable of higher-volume fabrication.

It was discovered that graphite oxide exhibits an unusual photo-thermal effect when exposed to high intensity light (Cote, et al. 2009). When exposed, graphite oxide is reduced to graphene, allowing for new possibilities in graphene production especially in the context of microelectronics.)


To begin the process of creating graphene supercapacitors, a graphene oxide (GO) solution must be synthesized. GO was synthesized by oxidizing flake graphite with an acid mixture. The traditional Hummers method (Hummers et al. 1958)is relatively dangerous as it creates highly toxic waste gas, so a modified method was followed instead. The flake graphite was added to a mixture of sulfuric and phosphoric acid and stirred under heat for twelve hours. The heat and stirring process oxidizes the graphite flakes, turning it into yellow solution GO. An extensive wash process with a centrifuge was done to fully exfoliate the GO solution.

Flake graphite was obtained from an online graphite supplier. The graphite flake particles have an average thickness of 5 nm, with a diameter of less than 10 um. The particles have a specified surface area of over 200m^2g^-}, with over 99.5% purity. Concentrated sulfuric acid (98%) and phosphoric acid (85%) were carefully mixed and let cool to room temperature. Potassium permanagnate (KMnO4) and the graphite flakes were dry mixed. An ice bath was prepared to keep the mixture of acid under the threshold temperature for thermal runaway. While magnetically stirring the acid mixture, the mixture of potassium permanganate and graphite flakes were slowly added. The solution transformed color from transparent to opaque dark-green. The solution was maintained at 50C while left to stir for twelve hours. A lid was kept above the container to avoid excessive evaporation over the twelve hour stir period.

At the end of the stirring period, the solution transformed to a brown color, indicating proper graphite oxidation. The solution was let cool to room temperature and hydrogen peroxide (30%) was added to stop the oxidation process. At this point, the solution transformed into a bright yellow-orange color.

Small amounts of the solution were transferred to centrifuge tubes and then centrifuged in a three step process. Between each centrifuge cycle, the supernatant was discarded, and deionized water was added and mixed. At the end of three cycles, the graphene oxide is brown in color with a thick paste-like consistency. The purpose of centrifugation is to purify the graphene oxide by reduce the acid concentration. Each centrifugation cycle dilutes the solution, and after three cycles there is little acid left in the GO.

The remaining liquid GO was poured into a petri dish and let dry under ambient conditions overnight. The dried GO was collected and then dispersed in the appropriate concentration (2.8 mg/mL) in deionized water for drop cast coating and laser scribing.

The dispersed GO solution was coated on a standard glass microscope slide (25 mm * 75 mm, 18.75 cm^2) using a drop casting technique. Prior to coating, the slide was cleaned of impurities and dust particles in an ultrasonic bath. An appropriate amount of GO solution (0.14 mL/cm^2) was used to maintain an even thickness across the entire microscope slide. Using a pipette, the GO solution was spread evenly across the slide and let dry on a hot plate at 40C. Since the amount of solution will overflow the edge of the slide, the drop casting was done three times on the same slide with drying time in between.

Potential failure points in the modified Hummers method (Marcano, et al. 2010) are thermal runaway and having incorrect temperatures. The acid solution must be kept cool in an ice bath while potassium permanganate (KMnO4) and graphite mixture is added, or toxic chlorine gas and manganese heptoxide will be produced explosively. The solution must also be let cool to room temperature prior to adding hydrogen peroxide, or no reaction will occur.


Graphene oxide synthesis with the modified Hummers method

Existing research with the modified Hummers method of synthesizing graphene oxide has given an yield of approximately 27% from the original potassium permanganate and graphite mixture. Starting with 1.0 g of flake graphite and 6.0 g of potassium permanganate, 1.65 g of dried graphene oxide was collected following the centrifugation cleaning process. This is a yield of 24%, demonstrating that the modified Hummers method can be replicated relatively easily in the lab.

Sources of the slightly lower yield are technique based rather than an incorrect implementation of the method, as small traces of GO were left on the pipette, the centrifugation tube, the drying dish, and the supernatant that was discarded. However, further research to improve synthesis time and safety must be considered before scalable fabrication can become a reality.

Interdigitated geometry

The geometry of the pattern was chosen to allow for the smallest separation between the two electrodes while being efficient with the use of GO material. Minimum gaps and thicknesses of the electrodes are dependent on the spatial resolution of the laser, as unwanted short circuits will compromise the electrodes ability to hold charge. The interdigitated geometry can be scaled to any size and shape, allowing for a wide variety of capacitances and stackup options with any series or parallel combination. Each of the two solid comb-like patterns are individual electrodes. The parallel ends of the electrode were made wider so that there is a good connection to the copper tape.

Laser scribing with an Epilog 40W laser

Laser etchers are commonly found in many workshops and art labs. Others have observed an unusual photo-thermal effect where graphene oxide absorbs high intensity light and is converted to graphene, allowing for the possibility of lasers to be used for creating the capacitor’s interdigitated pattern. Epilog lasers are able to very precisely pattern computer-designed diagrams on to most materials using a CO2 laser. The ease of using a computer controlled laser in comparison to more intensive scribing techniques allows for significantly faster fabrication, with hundreds of interdigitated capacitors of any size being able to be produced. As an example, a small supercapacitor of approximately 10 cm^2 only took two minutes of etching time under the laser at 400 DPI resolution. With an etching capacity of nearly 2000 cm^2, a large banks of capacitors in any series or parallel combination can be fabricated at once on a regular sized desktop etcher.

The printer software provided by Epilog has several adjustable settings that modify the behavior of the laser beam. Raster mode was used instead of vector mode, as vector is used to cut through material. On the raster setting, four settings are available in addition to the grayscale value of the raster file. How the laser is focused also affects how the GO is etched. The settings are DPI, speed, power, and dithering. A combination of all five adjustable settings were tried to determine the best one for GO etching.

Although not all possible combinations of settings were tested due to time constraints, an adequate combination was determined to be 80% grayscale, 500 DPI, 100% speed, 4% power, Stucki mode, and a focus set at -0.075. Below 5% power, the laser does not turn on, and no GO is exposed.

The capacitance of a capacitor is dependent on the surface area of the electrodes, so laser scribed graphene (LSG), having extremely high internal surface area in the order of 1500 m^2/g, is an ideal candidate for use as supercapacitor material. Following laser scribing, the golden brown color of the GO film is converted to black, indicating the reduction of GO to graphene.


Although a graphene based supercapacitor was successfully produced, more testing and experimentation must be done before it can be practically used in a device. At the start of the research process, the goal was to create a 'battery' with multiple supercapacitors in a stack configuration. However, due to time constraints and the difficulty of synthesizing the graphite oxide, that goal was not achieved.

However, what was demonstrated is that a working graphene based supercapacitor is able to be fabricated without any specialized equipment in the context of the TAS research and robotics labs. Future work on this research would include more testing with the laser, characterizing the capacitor even more, and adding an electrolyte to improve the capacitance. 

The 40W Epilog laser is just above what is ideal in terms of power, as on the 5% power and 100% speed mode, the GO is slightly over-exposed (as analyzed under the light and SEM microscope). Other light exposure techniques such as a stencil paired with a photography flash could also be tested.


I am grateful to Dr. Allan Bayntun for providing support, assistance, and motivation throughout the research process, Sean Tsao for help with the lab and lab techniques, Mr. Jude Clapper for his support, Dr. Hartzell and Dr. Hennessey for supporting the research program, and the Friends of TAS for their continued support of all TAS activities.


  1. Daniela C. Marcano, Dmitry V. Kosynkin, Jacob M. Berlin, Alexander Sinitskii, Zhengzong Sun, Alexander Slesarev, Lawrence B. Alemany, Wei Lu, and James M. Tour. Improved Synthesis of Graphene Oxide. ACS Nano 2010 4 (8), 4806-4814
  2. Cote, L. J., Cruz-Silva, R. & Huang, J. Flash reduction and patterning of graphite oxide and its polymer composite. J. Am. Chem. Soc. 131, 11027–11032 (2009).
  3. El-Kady, MF. et al. Scalable fabrication of high-power graphene micro-supercapacitors for flexible and on-chip energy storage. Nat. Commun. 4:1475 doi: 10.1038/ncomms2446 (2013).
  4. William S. Hummers Jr. and Richard E. Offeman. Preparation of Graphitic Oxide. Journal of the American Chemical Society 1958 80 (6), 1339-1339 DOI: 10.1021/ja01539a017
  5. Wang, K. et al. An all-solid-state flexible micro-supercapacitor on a chip. Adv. Energy Mater. 1, 1068–1072 (2011).
  6. Zhu, Y. et al. Carbon-based supercapacitors produced by activation of graphene. Science 332, 1537–1541 (2011).
http://xy-kao.com/projects/graphene-based-super-capacitors/ http://xy-kao.com/projects/graphene-based-super-capacitors/projects/graphene-based-super-capacitors/ Sun, 07 Jun 2015 00:00:00 +0000
First time with the Sony FS7

My school acquired a SONY FS7 camera for their film program and I was able to use it to cover a badminton tournament over a weekend. The camera and Metabones adapter came in the night before the tournament began so I was learning on the spot.

An 85mm and 35mm Canon lens were used for nearly all the shots in the two reels with a couple with the 70-200. All shots were done handheld, as slow motion makes shots a lot more tolerant to small vibrations. The camera is capable of 180fps at full 1080P HD. It would have been nice to have a camera just a little slower than that but with the lighting conditions in the gym the maximum would be about 300 frames a second.

I didnt have much time with it but some quirks I found and improvements that would make it better:

  •           Better immediate footage review - right now a button must be held to quickly review the last recorded clip, which is a little time consuming as it plays back at slow mo speed
  •           Discard unwanted clips - the files take a lot of space so a quick way to delete the last recorded clip which I know is not worth keeping would be useful
  •           Save last n seconds - continuously record until a button is pressed which saves the last 10 seconds of action. Most of the footage I recorded was just waiting for good shot, so this function would be incredibly useful

At the end of the three day tournament, I had 850GB of footage which was edited each night to a highlight reel. Songs used were I Lived by OneRepublic and Hall of Fame by The Script. Basic color grading and speed ramping done in Premiere.


http://xy-kao.com/sandbox/first-time-with-the-sony-fs7/ http://xy-kao.com/sandbox/first-time-with-the-sony-fs7/sandbox/first-time-with-the-sony-fs7/ Mon, 01 Jun 2015 00:00:00 +0000
3D Printed 15mm Film Rod Mounting Blocks

Professional film cameras and accessories are often mounted on 15mm rails. This allows for much greater flexibility in adding parts because everything is made to work with the standardized rod system. Things like follow focuses and lens hoods are made to work with the rails.

For this project I designed a 15mm rail mounting block with holes all around which can be used to add anything with a standard mounting bolt to an existing 15mm film rig.


The nuts have to be embedded within the model so the block was constructed out of two 3D-printed pieces which are superglued together afterwards. PLA bonds together nicely with CA glue, so the block keeps its structural strength.

The bottom piece looks like this:

A total of six ¼ nuts and three ⅜ nuts fit in the bottom piece with spacers. The two slots on the top left and right hold an M4 nut for the thumbscrew.

The spacers stop the smaller ¼ nuts from rattling around.

http://xy-kao.com/sandbox/3d-printed-15mm-film-rod-mounting-blocks/ http://xy-kao.com/sandbox/3d-printed-15mm-film-rod-mounting-blocks/sandbox/3d-printed-15mm-film-rod-mounting-blocks/ Sun, 10 Aug 2014 00:00:00 +0000
Quick 3D Printer Slicer Comparison Ever since I got my 3D printer i’ve been using Slic3r for generating g-code. What a ‘slicer’ does is generate instructions for the printer from your 3D model, telling it where to move and when to extrude plastic. Slic3r was the recommended slicer for reprap-style printers like mine, so I always stuck with that and never tried other ones. What I didn’t know was that a slicer could make a huge difference in print quality, even more so than properly calibrating the printer.

I was very frustrated with the prints coming out of my machine after doing everything that was recommended. I tensioned the belts properly, tightened loose bolts on the frame, calibrated the stepper current levels, and did everything else that people said would help, but I didn’t see much of a difference.

Print samples

Check out these two prints -

KISSlicer on the left, Slic3r on the right

These two were printed on the same calibrated machine with the same Marlin firmware. The only difference was the slicer. With Slic3r, it is pretty obvious that the layers are inconsistent in size (look the walls of the square and circle compared to the KISSlicer print), and there are significant problems with the cone and hemisphere. It also took only nine minutes to print the KISSlicer model - half of the other one.

If you are having problems with print quality and uneven perimeters, try other slicers and see what happens. I’ll be using KISSlicer from now on on my printer.

http://xy-kao.com/sandbox/quick-3d-printer-slicer-comparison/ http://xy-kao.com/sandbox/quick-3d-printer-slicer-comparison/sandbox/quick-3d-printer-slicer-comparison/ Sat, 26 Jul 2014 00:00:00 +0000
Building a Brushless Gimbal for GoPros

As part of my aerial video tricopter project, I built a brushless gimbal for a GoPro camera. What a brushless gimbal does is maintain a steady orientation regardless of how the tricopter moves. Video from a properly tuned brushless gimbal is pretty much indistinguishable from a tripod or crane in terms of stability, and professional ones are increasingly being used for traditional filmmaking.

For the tricopter, I built a two-axis one that stabilizes roll and pitch. This leaves yaw (or pan, in video terms) control under the tricopter. The frame itself was laser-cut from 3mm acrylic and joined together with t-joints.

Brushless motors

The motors I bought were Turnigy 4206 motors from Hobbyking. These have a very wide bell, which allows for slightly more torque than smaller motors. Both of them had to be rewounded with thinner gauge magnet wire to reduce the kV rating, giving more control over a smaller rotational range. I experimented with 0.13 and 0.15mm magnet wire and found the thicker one worked the best.

Control board

There was already a pre-built control board on Hobbyking, so I just used that instead of designing my own.

Tuning and balancing

Brushless gimbals don’t have much torque so they are very sensitive to shifts in weight. Rather than constantly pumping current to the motors to hold a position, the gimbal simply keeps the camera level, so it is very important that the camera is balanced along both rotational axes. The frame I designed has slots that can slide the camera back and forth to make adjustments.

The control board comes with tuning software. Each of the PID parameters had to be tuned for the gimbal to properly work.

Test footage

Some test footage with the gimbal around the school:

http://xy-kao.com/sandbox/building-a-brushless-gimbal-for-gopros/ http://xy-kao.com/sandbox/building-a-brushless-gimbal-for-gopros/sandbox/building-a-brushless-gimbal-for-gopros/ Sun, 27 Jul 2014 00:00:00 +0000
Working Projections on QLab

Our school’s play last year was The Laramie Project, which was quite a bit different from other plays we’ve done in the past. Being the first play ever in the new black box theater, the director wanted to impress everyone with the production - both in the acting and on the technical side. For the play I worked on the projections, which consisted of scene imagery (stuff like bar backdrops, train stations), archival footage, and live video from a camera on the stage.

The black box has an open floorplan with bleachers surrounding the stage on three sides. Three screens were set up, one for each section of bleachers. The primary projector was projected onto a black scrim behind the actors, which was also used for lighting effects.


As our school is all-PC and I couldn’t find a Windows alternative, I borrowed my friend’s Mac to run QLab. Qlab is the standard in tech theater for video and audio cues, so there wasn’t much competition coming from the PC side.

The show ran with about 40 video cues in total, with several grouped loops for the pre-show set and lead-ins to the live camera feed. The cues were planned out already by the director so it wasn’t very difficult. Many of the video cues are clips cut from the Laramie Project documentary, which was filmed on-location.

Live camera

Another component was the live camera. There is a scene in the play where the media crowds around the hospital, with the hospital spokesperson talking to a TV camera. To set this up, during the scene change, a camera was wheeled out on the corner of the stage. The signal was wirelessly transmitted to the control booth. As soon as the spokesperson was ready, I cut to the live feed and keyed a news graphic lower third.

The live camera was also used several other times in the play.

System diagram

Two video sources, one from the Mac running QLab and another from the live camera, was fed into a Sony Anycast mixer. The cue components were done in HD through a HD-SDI converter. The live camera was standard definition composite. The Anycast also superimposed the graphic during the live parts and had a instant fade-to-black button in case anything went wrong (thankfully I never had to use it!).

http://xy-kao.com/sandbox/working-projections-on-qlab/ http://xy-kao.com/sandbox/working-projections-on-qlab/sandbox/working-projections-on-qlab/ Fri, 25 Jul 2014 00:00:00 +0000
Control Boards for a Underwater ROV: Part 1

For this year’s ROV, I designed the on-board control system that controls everything on the ROV itself. Our team participates in the MATE ROV competition, which is an annual event where thirty different teams try to build the best underwater robot that can do different tasks on the seafloor. Tasks normally involve things like picking up objects, deploying sensors, gathering data, and measuring dimensions of sunk ships. Every year our team redesigns both the electrical and mechanical systems for the entire machine from scratch, building and improving what we learned from the previous year. Last year I designed the on-shore control system, but this time i’m doing the on-board one.



  • Much better video performance: last year we had major problems with video signals dropping from the cameras, which we suspect are from the noisy supply lines and cabling
  • Eight channels of motor control: the four vertical thrusters can be controlled individually (in addition to the forward ones), giving the machine roll and pitch control
  • Differential signalling: communication lines are differential RS485
  • Onboard IMU for self-levelling
  • Simplified tether - two eight gauge power lines, and two CAT5s (one for video, one for comms)


Each of the four cameras gets its own 1A LC filter to smooth out any ripples on the 12V line. When the thrusters are fully engaged, noise on the 12V line is around 300mVpp, which is way too much for sensitive cameras.

Each camera also has a balun to convert the 75 ohm video signal to 100. This ensures the signal stays strong after 20 meters of 100 ohm CAT5.

Motors are controlled with 5A MC33886 motor drivers. Each one is individually PWM driven with attiny85s, which also report faults over the I2C bus.

A MAX13432 handles the full-duplex differential comms.


There are three layers inside the control box: primary control, motor driver, and video baluns. All of them are arranged in a 100x100mm grid, with standoffs stacking them up. Layers will be added as needed for sensors that were not planned. 




http://xy-kao.com/projects/control-boards-for-a-underwater-rov/ http://xy-kao.com/projects/control-boards-for-a-underwater-rov/projects/control-boards-for-a-underwater-rov/ Fri, 18 Apr 2014 00:00:00 +0000
3D Matrix Math for CSS Using Sylvester

So recently I've been working on more CSS-based transformations and graphics. One of the problems with the current implementation of transform in webkit is that there is no way to individually assign values with JavaScript, making multi-dimensional animations impossible. This is because all of the transformations (like rotateX, translateZ, and scale) are grouped into a single property: -webkit-transform. For example, if you want to rotate 60 degrees in the X and Y axes, you would apply this piece of CSS:

-webkit-transform: rotateX(60deg) rotateY(60deg);

The problem occurs when you try and modify one or both of the values with JavaScript or JQuery. Since JQuery doesn't support shorthand CSS for the .css() function,  there is no way to change either of them without previously knowing the values. 


Matrix3D( )

The transform property also accepts a 4x4 transformation matrix that is calculated from all seven possible transformations.

matrix3d(0, 1,...15, 16)

Calculating it is pretty math-heavy, so I used a vector math library called Sylvester.js. The function below is heavily based on this tutorial.


The complete function returns a matrix3d value from seven parameters.


			function returnMatrix3D(rX, rY, rZ, scale, tX, tY, tZ) {
				var deg2rad, scale;
				deg2rad = Math.PI / 180; // Degrees to radians constant
				var rotationXMatrix, rotationYMatrix, rotationZMatrix, s, scaleMatrix, transformationMatrix, translationMatrix;
				rotationXMatrix = $M([
					[1, 0, 0, 0],
					[0, Math.cos(rX * deg2rad), Math.sin(-rX * deg2rad), 0],
					[0, Math.sin(rX * deg2rad), Math.cos(rX * deg2rad), 0],
					[0, 0, 0, 1]]);
				rotationYMatrix = $M([
					[Math.cos(rY * deg2rad), 0, Math.sin(rY * deg2rad), 0],
					[0, 1, 0, 0],
					[Math.sin(-rY * deg2rad), 0, Math.cos(rY * deg2rad), 0],
					[0, 0, 0, 1]]);
				rotationZMatrix = $M([
					[Math.cos(rZ * deg2rad), Math.sin(-rZ * deg2rad), 0, 0],
					[Math.sin(rZ * deg2rad), Math.cos(rZ * deg2rad), 0, 0],
					[0, 0, 1, 0],
					[0, 0, 0, 1]]);
				s = scale;
				scaleMatrix = $M([[s, 0, 0, 0], [0, s, 0, 0], [0, 0, s, 0], [0, 0, 0, 1]]);
				transformationMatrix = rotationXMatrix.x(rotationYMatrix).x(rotationZMatrix).x(scaleMatrix);
				transformationMatrix = transformationMatrix.transpose();
				translationMatrix = $M([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [tX, tY, tZ, 1]]);
				transformationMatrix = transformationMatrix.x(translationMatrix); // Apply transformation matrix AFTER transposing rotation and scale
				s = "matrix3d(";
				s += transformationMatrix.e(1, 1).toFixed(5) + "," + transformationMatrix.e(1, 2).toFixed(5) + "," + transformationMatrix.e(1, 3).toFixed(5) + "," + transformationMatrix.e(1, 4).toFixed(5) + ",";
				s += transformationMatrix.e(2, 1).toFixed(5) + "," + transformationMatrix.e(2, 2).toFixed(5) + "," + transformationMatrix.e(2, 3).toFixed(5) + "," + transformationMatrix.e(2, 4).toFixed(5) + ",";
				s += transformationMatrix.e(3, 1).toFixed(5) + "," + transformationMatrix.e(3, 2).toFixed(5) + "," + transformationMatrix.e(3, 3).toFixed(5) + "," + transformationMatrix.e(3, 4).toFixed(5) + ",";
				s += transformationMatrix.e(4, 1).toFixed(5) + "," + transformationMatrix.e(4, 2).toFixed(5) + "," + transformationMatrix.e(4, 3).toFixed(5) + "," + transformationMatrix.e(4, 4).toFixed(5);
				s += ")";
				return s;


Sample Outputs

returnMatrix3D(60, 45, 60, 1, 0, 0, 0) - 60deg in X, 45deg in Y, and 60deg in Z. Scale of 1. The value returned is identical to transform: rotateX(60deg) rotateY(45deg) rotateZ(60deg).




Benchmark ran with jsperf.com. Not sure how accurate this is.

http://xy-kao.com/sandbox/3d-matrix-math-for-css-using-sylvester/ http://xy-kao.com/sandbox/3d-matrix-math-for-css-using-sylvester/sandbox/3d-matrix-math-for-css-using-sylvester/ Fri, 26 Jul 2013 00:00:00 +0000
3D Printed iPhone Dock

One of the few docks available for the iPhone 5 is the Lightning Dock. Apple did not release an official dock for any lightning-capable devices, leaving it for third-party manufacturers to make them. The one I came up with is visually similar to the Lightning Dock, but modified to work with the limitations of the 3D printer.


The connector can be extended higher to accomodate thicker cases. The connector itself is strong enough to hold the phone, so I didn't bother adding back support.


A long M3 bolt holds the connector in place. The slot at the bottom is for holding the dock down to the table.


The way 3D printers work means that all models have ridges between layers. Some people like the look of it, but I don't so I sanded it down with some 120-grit paper. 


Internal structure.

STL Model


Also available on Thingiverse.

http://xy-kao.com/projects/3d-printed-lightning-dock/ http://xy-kao.com/projects/3d-printed-lightning-dock/projects/3d-printed-lightning-dock/ Fri, 19 Jul 2013 00:00:00 +0000
Virtual Lane Graphics for Swimming with CSS3 If you watched any of the Olympic swimming events last year on television, you probably saw something like this:

Sample screencapture from olympics swimming in 2012

Pretty cool stuff. These 'virtual graphics' for sports always intrigue me because there is practically zero time to edit it into the shot. Everything has to be done in real-time. Graphics like this also appear in many other high-profile sporting events like the Super Bowl and the World Series, where the ball is tracked three-dimensionally live. 

Now, my school just happened to be hosting a swimming meet between several other schools. We were going to broadcast and record it anyway, so I thought I might as well try to recreate the graphics. In the end, what I came up with was pretty much visually the same as the one you see in the Olympics.

olympic technology

In a nutshell, the process works by taking the clean feed from the camera and tracking the lane dividers separating the lanes. Graphics are then inserted between, which is what you see up top. The graphics also adapt to the shot, so if the operator pans or zooms, the graphics stay where they are. I don't actually know how they manage to track camera motion in the Olympics, but in the NFL, there are special mechanical rigs attached to the camera that helps the graphics software. 

three dimensional projection

Doing camera tracking would make it a hundred times more complicated, so I didn't bother trying to figure that out. In hindsight, I think it would have been relatively easy to do as long as I had rotary encoders on the tripod feeding data to the renderer. 

I spent many hours trying to pick something to render all the graphics (including the static ones). What renders graphics fast and can update quickly? A browser, of course. The Chrome Skia and V8 engine are heavily optimized for graphics rendering, and HTML5 has matured to a point where you can do advanced graphics like this.

CSS3 has an amazing property called perspective that can transform this:

Unprojected sample of graphics

Into what you see above. 

Imagine a cube with all faces transparent except for the bottom, which composed of the image to the left. Normally, the image would look just like that: looked down from the top face in a birds-eye view. Now imagine the cube rotating on all three axes. This shifts the perspective, and with some educated guesstimation, the image can be projected virtually onto anything. 

3D box model

The red lines are the edges of the imaginary prism surrounding each row. The water surface of the pool can be thought of as the bottom face of the prism.


Sample graphics overlaid on pool.

The graphic overlaid on the school's pool. This is a test image; scroll down for screen captures from an actual race. Play with it in your browser here.


Graphics with chromakey background

For actual keying, the background (meaning everything except the graphic itself) is set to rgb(0,255,0). The production mixer my school has is the Sony Anycast, which takes a VGA signal directly from my laptop. This is keyed over the finish-line camera shot I set up on the balcony above the pool. 

practicality and limitations

The use of a subtractive keying system (removing the green) poses several limitations on the graphics. The most obvious would be when the swimmer dives, the graphics float above the swimmer. Ideally, the swimmer's body would literally 'fly' over the graphics into the water. Another limitation would be dynamic opacity. The Anycast only accepts a single opacity level for each key, so I had to balance it between other static graphics.

Compared to the Olympics, the camera placement is not ideal. It is a lot closer to the pool, so I had to use a wide-angle lens, giving the picture corner distortion. It's not obvious, but each lane had small angular adjustments to account for distortion. 


Experiment and play with the overlay here. Drag the sliders to see how perspective in CSS works. Does not work in IE<10 (edit - works in IE10. Thanks to the commenters who let me know).


Camera placement relative to poolCamera placement relative to the pool. The camera on the left side of the balcony is the primary tracking camera. On the pool deck next to the flag pole is the robotic camera I built. 

Screencapture from an actual race.Screen capture from an actual race. 

Production setup with Anycast mixer

Some of the production equipment. On the far left is the dedicated graphics laptop From right to left: Sony Anycast mixer, computer for streaming and recording, sound mixer, and program monitor.

http://xy-kao.com/projects/virtual-graphics-for-swimming/ http://xy-kao.com/projects/virtual-graphics-for-swimming/projects/virtual-graphics-for-swimming/ Sat, 16 Feb 2013 00:00:00 +0000
Decoding the Daktronics Omnisport 2000 This is an extended version of the README on github.

Daktronics Omnisport 2000 timing console and television graphics.

This project came out of neccessity after a software-based attempt failed. I really wanted to avoid working with hardware on the system because it takes much longer than pure software, but in the end I had to for the sake of simplicity.

timing console

The timing console has three RS232 serial ports: one for the meet manager, one for a venus scoreboard, and another to connect to the PC control software. The PC software from daktronics costs a ton, so I didn't bother trying to work with that. The meet manager port is obviously used for the results, so I couldn't use that either. That left the RTD scoreboard port, which is what is used for this decoder.


The port is for a scoreboard, so logically it should at least have a running-time signal. After looking at it on a serial terminal, I figured out that it sends split times and place data as well.

Raw data from the console looks like this:


It looks like a mess, because it is. Actual data is embedded between keepalive signals, which are then contained within control characters. The periods in the example are not actually ASCII periods (0x2E), but rather control characters that cannot be rendered in the serial terminal. Browsers, however, can render them properly, and this is what a typical data packet looks like:

000000000042100000␂    4.0  C0

The control characters are bolded. Everything between SYN (0x16) and STX (0x02) is irrelevant to the actual data, so it is dropped from the decoded signal. I still haven't figured out what the 0042100000 represents, but it might just be another sync signal like the string of zeroes after SYN. The C0 is probably a checksum, but I didn't bother working it out. 


\n and sequential sorting

first stage

The first stage of sorting applies these filters to all packets:

  1. Remove data between SYN and STX (inclusive)
  2. Remove data between EOT and ETB (inclusive)
  3. Trim leading and trailing whitespace
  4. Add a linefeed and carriage return to the end




secondary stage

The first stage of filtering returns these (names are starred out). Significantly better than the raw data, but still a lot of noise considering all I want is the running time and splits. 

One more filter is applied after the first stage:

  1. Remove packets that do not have a period (ASCII 0x2E)


This cleans out everything except running times and splits.



MAX232 to TTL signal schematic.

Not a lot in terms of hardware for this one.


Out of the 9 pins from the console, only two are used: TX and ground. The signal is fed into the classic MAX232 to   convert it down to TTL logic levels. 







The latest version will always be on github.

String inputString = "";         // a string to hold incoming data
String oldString = "";
char rxbuffer[BUFFER_STRING_SIZE];

void setup() {
  UCSR0A = 1<<U2X0; // async
  UCSR0B = (1<<RXCIE0) | (1<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0); // enable RXTX, register interrupts
  UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); // 8 data bits
  UBRR0L = 103; // 19.2k baud

  DDRB |= (1<<PORTB0); // status LED output
  DDRB |= (0<<PORTB1); // split switch input  
  if((PINB & (1<<PORTB1))) {
    flash_status_led(4, 80);
    while(1) {}; // enter infinite loop

void loop() {
  while(1) {
    while (Serial.available()) {
      if(Serial.read() == 2 && Serial.readBytesUntil((char)4, rxbuffer, BUFFER_STRING_SIZE)) {
          for(int x = 0; x < BUFFER_STRING_SIZE; x++) { // add chars to string
            if((int)rxbuffer[x] != 0) inputString += rxbuffer[x]; // skip null values; add to string
          inputString.trim(); // remove leading and trailing whitespace
          if(inputString.indexOf(".") != -1) { // if string does not include time, skip
            if(inputString.length() <= 7) {
              Serial.print("t"); // t for time
            else if((PINB & (1<<PORTB1)) == 0 && oldString != inputString) { // if split is different from last split transmission
              PORTB = (1<<PORTB0);
              Serial.print("s"); // s for split
              Serial.println(inputString.substring(0,4) + ' ' + inputString.substring(4));
              oldString = inputString;
              PORTB = (0<<PORTB0);
          inputString = "";
          memset(rxbuffer,0, BUFFER_STRING_SIZE); 

void RUN_TEST_MODE(void) {
  for(unsigned int x=0; x<5000; x++) {
    Serial.println(x*0.1, 1);
    if(x == 33) Serial.println("s5 1 3.36 2"); 
    if(x == 45) Serial.println("s3 2 4.52 2"); 
    if(x == 65) Serial.println("s7 3 6.50 2"); 
    if(x == 150) Serial.println("s3 1 15.05 4"); 
    if(x == 165) Serial.println("s5 2 16.54 4"); 
    if(x == 166) Serial.println("s7 3 16.60 4");        

void flash_status_led(byte number_of_flashes, unsigned int milliseconds) {
  for(byte x = 0; x<number_of_flashes; x++) {
    PORTB = (1<<PORTB0);
    PORTB = (0<<PORTB0);


decoded data

There are two types of data packets: running time and splits. Each packet is composed of a prefix (t for running time and s for splits), the packet data, and a carriage return, which serves as the delimiting character.

Typical data packets would look like this:

t1:02.1 - pretty self explanatory

s3 1 1:11.63 2 - four data points, which are ordered as follows:

  1. Lane number
  2. Place
  3. Time (split times are accurate to a hundredth of a second)
  4. Laps of the pool completed

Decoded data is fed into Autobahn with python and then to the browser for graphic rendering. The websockets server and rendering engine is in the IASAS_swimming_2013 repository.


test mode

The decoder can be put into test mode by resetting with the split button set to the OFF position. This mode ignores data from the console and simulates a test race, which is useful for testing the rendering engine.



http://xy-kao.com/projects/decoding-daktronics-omnisport-2000/ http://xy-kao.com/projects/decoding-daktronics-omnisport-2000/projects/decoding-daktronics-omnisport-2000/ Tue, 08 Jan 2013 00:00:00 +0000
Batch Resizing with IRFanView and Python Batch resizing with IRfanview

This is a script I use to quickly compress and resize my photos for the web. Edit the parameters, copy and paste it to the image directory, and run it. The script will create a '/resized' folder for all the processed photos. 

import os

IVIEW32_PATH = 'C:\Program Files (x86)\IrfanView\i_view32.exe'

command = '"%s" '%IVIEW32_PATH + os.getcwd() + r"\*.%s /resize=(%d,%d) /aspectratio /resample /convert="%(SOURCE_FILETYPE,TARGET_WIDTH,TARGET_HEIGHT) + os.getcwd() + r"\resized\*.%s"%TARGET_FILETYPE


Requires IrfanView and python.

 irfanview_resize.py (380B)



http://xy-kao.com/sandbox/batch-resizing-with-irfanview/ http://xy-kao.com/sandbox/batch-resizing-with-irfanview/sandbox/batch-resizing-with-irfanview/ Sun, 06 Jan 2013 00:00:00 +0000
Repairing a Daktronics 7-Segment Scoreboard A segment module from the scoreboard. One of six

The pool at my school has an old-style daktronics LED scoreboard that looks like this:

Sample scoreboard front view

Most of the time the scoreboard is off, but there is an option for it to display the current time like a clock. The time is shown on the second row (in the picture it is at the 15:01.39 time), and over the years of constant operation, many of the leds on that row have reached EOL and died. It didn’t look like a hard fix so I asked the director to remove the digit modules and see if I can fix them.

The first thing anyone should do in this situation is to check the repair manual, so thats what I did. Hidden at the very end of the pdf was this:

Installation schematic
Not too helpful, but I can tell there are 14 LEDs per segment, and 98 per digit. The removed modules confirmed what the manual said. Curiously, each segment has two chains of seven LEDs (this is because if one fails, an incorrect digit wont be displayed).


There are no published specifications for the modules so I probed around and came up with these:

12V input, common anode
9-pin molex square connectors
7 LEDs in series with a 1/2W 150-ohm resistor (I will call these chains)
The stock LEDs have a Vf of about 1.55V (not quite sure how accurate this is)



The modules have a clear conformal coating on the front and back, which was a real pain to work with. The coating meant that the probes didnt make contact properly, so I had to scrape it off. Once I began soldering, the iron melted it away.

New and old broken LEDs

A comparison of the new LEDs and the old. The right segment has not been replaced in this photo.

I broke down replacing LEDs into five steps:

  • Break off the old LEDs with pliers - the old ones were dead, so there is no point in keeping them
  • Remove remaining LED leads from board
  • Wick off the remaining solder still in the via
  • Insert the new LED, solder one leg
  • Position it so it is flush with the board, then solder the other leg and clip the leads




The leads are bent in the factory (presumably to hold it in place).

Pack of new LEDs. 800 5mm LEDs for 30$

Bag of 600 5mm red LEDs. Bought from my local electronics store for $30.

Front side of the board with half of the bulbs removed. The round bits surrounding each pad is the epoxy from the conformal coating.

One of the six boards that were repaired. Red LEDs actually come in different wavelengths, and the one I bought were slightly more orange than the stock ones. 


http://xy-kao.com/sandbox/repairing-a-daktronics-scoreboard/ http://xy-kao.com/sandbox/repairing-a-daktronics-scoreboard/sandbox/repairing-a-daktronics-scoreboard/ Fri, 04 Jan 2013 00:00:00 +0000
Reddit Sort Bookmarklets for Game Threads

The default reddit sort functions apply to all posts you view, and that can get annoying when you are switching between the front-page and smaller, time-sensitive threads. These bookmarklets only apply the sorting to the current thread instead for everything like the dropdown on reddit does. Drag and drop them into your bookmarks bar and click on it when you are in a thread.

Very useful in game threads.

reddit - sort by new

reddit - sort by top

reddit - sort by old

reddit - sort by best

reddit - sort by hot

reddit - sort by controversial


http://xy-kao.com/sandbox/reddit-sort-bookmarklets/ http://xy-kao.com/sandbox/reddit-sort-bookmarklets/sandbox/reddit-sort-bookmarklets/ Tue, 16 Oct 2012 00:00:00 +0000
Eagle Library for Custom Footprints PCB from remote weather logger.


Eagle is the CAD package I use for my schematics and pcbs. Their libraries are probably the most comprehensive of all the free packages out there, but sometimes there are part layouts I need that aren't available. 

This library contains parts that I have used in my projects. Most of them are rather specific and obscure components (like the MBI5026), but i'm going to post it anyway because it might save someone else time. 



J ST-2.54 MM
LTC4054-4.2 SOT23-5



Download XYKlib.lbr on my github page.


http://xy-kao.com/sandbox/eagle-library/ http://xy-kao.com/sandbox/eagle-library/sandbox/eagle-library/ Thu, 02 Aug 2012 00:00:00 +0000
GIFcapture GIFcapture animation.

GIFcapture is a little python script I wrote that captures anything on your screen to a .gif animation. It utilizes the Python Imaging Library for screen capturing and and the image2gif module by Almar Klein for the actual gif generation. This script is Windows only for now until I can find a msvcrt equivalent in Linux. 

Instead of taking a video of the screen, the program captures many screenshots in succession to create frames.  There is a inherent limitation to using this method: the capture rate is restricted by the write speed of the hard drive. To get around this, the program holds the screenshots in RAM until the user ends capturing. 

There is still a lot of work to be done. A nice GUI interface will be added, and the code can be optimized even more. Check out the TODO file for a list of features that will be implemented. 



Requires PIL and python (tested with 2.7, not compatible with 3).
User editable capture size and resize.
Graininess is from the 8-bit color dithering. It is not recommended to turn it off, but you can by adding a dithering=0 parameter to the writeGif function.
Maximum capture speed of ~20fps.
Does NOT support dual monitors at the moment. It will only capture what happens on the primary screen. 



Download GIFcapture version 0.91 here or on github. Updated 8-02.




#! /usr/bin/python

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import shutil
import sys
import time
from PIL import Image
import ImageGrab
import etc.settings as s
from lib.images2gif import writeGif
import msvcrt

img = []
file_location = []
fps = []
time.clock() #reset process timer

program_path = os.path.dirname(sys.argv[0])+'/'
if(os.path.isdir('%stemp'%program_path) is not True): os.mkdir('%stemp'%program_path)
raw_input("\nPress enter to start capture.\n")

while(not msvcrt.kbhit()):
    old_time = time.clock()
    print 'Capturing frame %d'%len(img)

print '\n\n  Captured %d frames in %.3fs'%(len(img), sum(fps))
print '  Frames captured per second: %.2f' %(1/(sum(fps)/len(fps)))
print '\nWriting frames to %s...'%s.GIF_FILE

for x in range(len(img)):
    if(s.RESIZED_DIMENSIONS[0] is not -1): img[x].thumbnail(s.RESIZED_DIMENSIONS, Image.ANTIALIAS) 

PILimages = [Image.open(x) for x in file_location]

writeGif(s.GIF_FILE, PILimages, duration = (sum(fps)/len(fps))) #real time framerate
#for filename in file_location: os.remove(filename)

print "\n\n\nGIF file information:"
print "  Size:             %d KB" %(os.path.getsize(s.GIF_FILE)/1024)
print "  Frames:           %d" %len(img)
print "  Gif frame rate:   %.1f fps" %(1/(sum(fps)/len(fps)))
print "  Gif duration:     %.3fs\n\n" %(len(img)*(sum(fps)/len(fps)))


http://xy-kao.com/projects/gifcapture/ http://xy-kao.com/projects/gifcapture/projects/gifcapture/ Thu, 26 Jul 2012 00:00:00 +0000
New Computer Build for $700 Custom built computer internals.

Over the summer I built a new PC to replace my aging Acer. The specs on my old computer were as follows:


• AMD Athlon 64 x2 CPU (90nm!)
• Nvidia 6750 LE
• 120GB Seagate HDD


It's pretty clear that a computer with those specs could not run the latest software without struggling. The last time I checked, the number of hours the computer was on was approaching 30,000. I haven't had a hardware failure yet, which is miraculous because hard drives typically fail well before that. It was time for an upgrade.

Before I begin I would like to thank r/buildapc, the reddit community who offered advice on part selection. The people there would be happy to help if you ever need anything computer related.


All the parts in their boxes.

Intel i3 2120 - I don't game or do heavy video editing, so an i3 dual core processor is sufficient. 
Radeon R6670 GPU - Once again, I don't game, so I went with something that would still be useful five years down the road. A discrete GPU is good for the light CAD work I do. 
ASUS P8B75-M LE Motherboard - There were many motherboards to pick from, but I went with this one for its native USB 3.0 support and low price. The six SATA ports might be useful if I add an RAID controller later.
Crucial m4 SSD - SSDs are below $1/GB now, and with the recent price hike on hard drives, it made sense to get one. The speed bonuses are incredible as well; I benchmarked the random read speed and it was 26 times faster than my old mechanical hard drive.
8GB Crucial 1333MHz RAM - I spent way too much time debating between getting 4GB or 8GB. Right now as I am writing this, my memory usage is at 41%, so I made the right choice in getting 8 gigabytes.
Western Digital Caviar Blue 500GB HDD - Only 500 gigabytes because I don't have large movies to store. The 120GB in my old computer was really all I need. 
Cooler Master GX400W PSU - 400W is a little overkill, but at least I know I won't have problems. I followed r/buildapc's advice to not skimp on a power supply. 
Cooler Master Elite 431 Case - Nothing special here. Just a case that is compatible and looks nice.

operating system

Windows 7 and Ubuntu are the two operating systems I went with. Dual booting was a pain, but it worked in the end. 


price breakdown

Item Price (USD equivalent)
Intel i3-2120 Sandy Bridge LGA1155 Processor    $119.33
ASUS P8B75-M LE Motherboard $86.33
MSI R6670-MD2GD3 ATI 2GB Graphics Card $83.33
Western Digital Caviar Blue 7200rpm HDD $64.67
Cooler Master Elite 431 ATX Case $49.67
Cooler Master GX400W Power Supply $50.00
Windows 7 64-bit Home Premium OEM  $123.33
Crucial m4 64GB SSD $82.99
Crucial 2*4GB DDR3 1333MHz Memory $47.99
Dual 17" Monitors Free
Keyboard, Mouse, and Speakers Free
Total $707.64




build photos

Build photos are on my Picasa web gallery.

http://xy-kao.com/projects/new-computer-build/ http://xy-kao.com/projects/new-computer-build/projects/new-computer-build/ Tue, 17 Jul 2012 00:00:00 +0000
Remote Weather Data Logger The goal is to make a remote data logger capable of continously collecting environmental data for at least a year.

project requirements

  • self sustained - no external tethered power source allowed
  • collected data will include time, sun luminance, humidity, temperature, and barometric pressure
  • 24h data collection
  • data will be logged to a SD card
  • average microcontroller current should be <1mA
  • As many surface mount components as possible (ideally all SMT)


basic circuit outline

Power from a bank of solar cells will be fed into a LDO linear regulator and then into a single cell lithium ion charger. A second regulator will regulate power from the lithium ion cell for the AVR, which will periodically log data into a SD card.


component selection

Availability was the biggest factor when I chose these parts. Digikey, Mouser, and Farnell were out of the question because of the high postage rates, but luckily many parts were available locally.

A SMPS boost/buck IC designed for energy harvesting would be ideal. Linear Technology does lots of power management stuff, so I started there. The LT3652 is close to perfect, but the input voltage range (4.95+) is too restrictive. The cells will go below that voltage when it is cloudy, and at voltages below ~10V, the efficiency of the IC drops down to 50%.


revision A schematic

The first revision uses 1206 and 0805 SMT components.






Finding and implementing a SD card library was by far the hardest part of this project. The 'standard' library recommended by the members on avrfreaks.com is FatFS by elm-chan, which has pretty much everything you'd ever need. However, the compiled code for the avr example alone is over 64 kilobytes, more than four times what I have on the mega168. I tried reducing the code size by removing functions I did not need (reading, LFNs, and directory access), but it was still way over the limit. 


PetitFS compile size for the atmega328p. Compiled with winAVR

Luckily, elm-chan has another SD library specific for low memory micros. With only read and write capability, PetitFS is a slimmed down version of FatFS that compiles down to 6600 bytes. It is also more efficient with its ram usage, which I have precious little of on the mega168.

SD cards can be accessed with two primary protocols: the proprietary SD bus (which there are actually two versions of) and the serial peripheral interface bus. The SD bus is what all modern consumer devices use now. It allows for very high transfer speeds, but the protocol is so secret that a NDA has to be signed before the specifications can be released. The mega168 has a dedicated hardware SPI controller, and since the SPI protocol is well documented, it was a easy decision to go with SPI. 

PetitFS requires the target SD card to be formatted with the FAT system. File systems are organized into clusters and sectors. Clusters (or allocation units in windows terminology) are groups of 512-byte sectors. The very common NTFS format for computer hard drives uses 4096-byte cluster sizes, with eight sectors in each cluster. A file cannot never be smaller than the cluster size. If you try and create a .txt file with a single letter saved (one byte) on a NTFS formatted hard drive, the 'size-on-disk' size will be one cluster, or 4096 bytes. This sounds counterintuitive, but by organizing sectors into clusters, there are a lot less memory addresses to handle. 

Despite the advantages of organizing sectors into clusters, I won't be able to use it for this project. Clusters can only be appended by holding the original data in ram, adding whatever data to it, then rewriting it completely, and with a paltry 1024 bytes of ram on the mega168, the absolute largest cluster size I can use is 512 bytes (so effectively sectors and clusters are equivalent). This leaves 512 more bytes of ram for system reserves and program variables.




Timing diagram for the TMP102 sensor. Logged with the open logic sniffer.

I2C bus diagram for a slave-transmit operation on the TMP102. The first byte (0x91) contains the device address (0x48) and the read-write direction. The temperature is stored in two eight-bit registers, so two separate bytes are sent by the slave before a NACK command is issued. 

http://xy-kao.com/projects/remote-weather-data-logger/ http://xy-kao.com/projects/remote-weather-data-logger/projects/remote-weather-data-logger/ Sat, 16 Jun 2012 00:00:00 +0000
Laser Cut Project Boxes and T-Slot Joints Screengrab from CAD drawer

Creating a three dimensional object from a flat sheet of material is the idea behind cutting boxes on laser cutters. IKEA does this with their flatpack furniture, which is assembled together by the user. My room-automator project needs a custom enclosure, so I designed a box in Rhino and cut it out on the school laser cutter.


T-slot interlocking joints

To hold the thing together, I used t-slot joints. These are interlocking mortise-and-tenon joints paired with a M5 bolt and a hex nut. M5 bolts were ideal because the thickness of the plywood I used was also 5mm.


Joystick hole


High resolution photos available on Picasa.

http://xy-kao.com/sandbox/laser-cut-project-boxes/ http://xy-kao.com/sandbox/laser-cut-project-boxes/sandbox/laser-cut-project-boxes/ Sun, 10 Jun 2012 00:00:00 +0000
Replicating and Printing an Object in CAD CAD drawing

My DIY slider needs a standard 1/4" bolt to mount, but the one on my tripod was too short so I took some measurements and printed another plate. The plate is a quick-release clamp-on type, which is relatively small and easy to print.

Original object

Normally with art sculptures, the object is scanned with a 3d scanner then cleaned up in a CAD program. The plate however is very geometric and 'boxy', so I modelled it directly. The CAD package I use is Rhinoceros 4 because it is free through my school.


CAD model

CAD outline

Base profile of the plate.


Base profile extruded and the clamp profile drawn.


Side view

Clamp extruded and chamfers added.


printing in ABS

I used ABS for this instead of PLA because it is supposedly better for mechanical parts. What surprised me was how much it shrunk. The whole thing shrunk almost 2mm (~3%), which made it a little loose on the tripod. If you are designing something for ABS, remember to calibrate your skeinforge settings or scale your stl file before you print.

Printed object

Finished print off the printer.


Comparison between old and new


High resolution images available here on Picasa.

http://xy-kao.com/sandbox/replicating-an-object/ http://xy-kao.com/sandbox/replicating-an-object/sandbox/replicating-an-object/ Sat, 09 Jun 2012 00:00:00 +0000
100 Micron Resolution on a 3D Printer 100 micron resolution with 1mm spaced calipers.

My MakerGear Mosaic 3d printer comes with a stock 0.35mm nozzle, meaning that it extrudes a 0.35mm stream of plastic. This doesn't mean that the layer height has to be the same because as the nozzle moves, it can squish down on the extruded plastic. In fact, the recommended layer height for my 0.35mm nozzle is 0.3mm. Squishing the plastic down is actually beneficial because it allows for better contact with the layer below.


Default layer setting

The width of the caliper is set to 1mm. With the default resolution of 0.3mm, you can see that there are roughly three layers (marked in blue) between the red lines.


The characteristic 'ridges' created by the layers become less obvious as layer heights decrease, giving a smoother finish. With a stock 0.35mm nozzle, I managed to print at a layer height of 100 microns, or 0.1mm. At this resolution the ridges are barely detectable with a finger, but the downside is that it takes three times as long to print. The cover photo is of a print with a layer height of 0.1mm.


0.2mm resolution

This is a print at a layer height of 0.2mm. This resolution has a good balance between print speed and surface smoothness.


Full gallery with high-resolution photos here.

http://xy-kao.com/sandbox/layer-heights-on-the-3d-printer/ http://xy-kao.com/sandbox/layer-heights-on-the-3d-printer/sandbox/layer-heights-on-the-3d-printer/ Wed, 06 Jun 2012 00:00:00 +0000
Unboxing the Mosaic 3D Printer Completely assembled Mosaic sitting in my closet

The MakerGear Mosaic is one of many DIY 3d printers available. A lot of 3d printers are at the sub-$1000 mark now, making them very affordable for hobbyists like myself. The big name in 3d printing is the MakerBot, but the print size was too small for me so I went with the Mosaic.

Full gallery with high-resolution photos here.


USPS box

Shipping box. Very expensive postage because I am not in the US.


First thing opened: inventory note and goodies

Packing list and invoice. She even handwrote a message and included chocolate :). Very nice.


PCB heater plate

Heated build platform. The heater board is secured between two aluminum plates with binder clips.


Partially assembled laser cut parts

Laser cut parts. The z-assembly is preassembled with linear bearings and a nut for the leadscrew.


Laser cut parts

Laser cut frame. The frame uses M3 t-slots with square nuts. Assembling this took about half an hour.


Driver control and cabling

Hot end and the filament drive stepper. The hot end heats up to 180C for PLA and 230C for ABS plastic.


Included tools

A set of tools and kapton tape. The allen key is for the M3 bolts, and the kapton tape is for printing with ABS.


Stepper motors

Z stepper and screw. The x and y axes are belt driven, and the Z is screw driven. The white thing in the bag is a 3d printed knob for manual z control.


More drive system components

X and y assemblies and endstops. The endstops let the software know where to start printing.


12V power supply for electronics

Power supplies. There is one 12V power supply for the fan, the extruder, and the motors, and another switch mode 24V supply for the heated build platform.


1.75mm reel of green PLA filament

Included 1kg spool of PLA plastic from Ultimachine. PLA warps a lot less than ABS, so it is better to start printing with.



http://xy-kao.com/projects/unboxing-the-mosaic/ http://xy-kao.com/projects/unboxing-the-mosaic/projects/unboxing-the-mosaic/ Wed, 06 Jun 2012 00:00:00 +0000
Portable Audio Amp Completed audio amp

I wanted something louder than a mini-external speaker, so I disassembled my old speakers and put it into a project box with a battery power supply. In addition to the portable battery mod, I added RCA jacks that could be used as inputs or pass-through connectors.


Closeup of amp speakers and cutout in box.

The hardest part was cutting the holes for the speakers. This project box is a lot thicker than the Radioshack one I used in the turing alarm, so my nibbling tool didnt work. A tip for cutting project boxes with a dremel: cut a few millimeters from the actual line with a cutoff wheel, then sand it and heat treat it.


Amp internals.

The original volume adjustment pot was desoldered then mounted on the box. The original audio cable was split between a 3.5mm jack and a RCA jack, which is useful because one of them can be used as a pass-through connector.



Amp internals + battery.

The original speaker was powered from 5V USB, so I used a 7805 to regulate power from five AA batteries.


Full gallery with photos here.

http://xy-kao.com/projects/portable-audio-amp/ http://xy-kao.com/projects/portable-audio-amp/projects/portable-audio-amp/ Wed, 06 Jun 2012 00:00:00 +0000
Controlling LED Matrices with the MBI5026 Driver header image

Matrices are one of many interesting applications for LEDs. When multiple matrices are linked together into a ‘display’, scrolling text and even images could be projected.

Schematic for multiplexing

In a regular single-color 8x8 matrix, 64 LEDs are arranged in a square with eight on each side. Multicolor red-green-blue matrices are also available, but the complexity increases dramatically because there are three times the number of LEDs.

If you think about it, every LED in the 8x8 matrix would need a cathode and anode to control (a total of 128 pins), right? It makes sense if you think about 64 of them in a line. In a matrix, however, the LEDs are in rows and columns. By connecting all the anodes in each row and all the cathodes in each column, every single LED could be controlled with 16 pins. This introduces another problem: it is not possible to control individual LEDs separately at the same time. To get around this, I will use the technique of multiplexing.



Multiplexing is a common technique used to control large LED matrices and displays. Multiplexed displays only have a single row on at any time. When a row is on, the driver IC tells the columns which LEDs in that row to light up. The cycle repeats for every row in the system one after the other, forming a image to the human eye. Depending on the microcontroller, the speed at which it repeats ranges from microseconds to milliseconds. From my experimenting, anything above a refresh rate of 30ms for a regular 8x8 display (~3.5ms between row) becomes noticeable to the eye, and flickering will occur.


persistence of vision

persistence of vision animation

Early movies used persistence-of-vision to animate objects.

An interesting thing about the human eye is that it cannot detect changes faster than around 40 milliseconds. This oversimplified example explains it pretty well: the AC power going into the lights in your house runs at 50 or 60 hertz, depending on where you are in the world. With a high-speed camera, you can actually see the filament flashing on and off at that frequency. Your eyes, however, cannot see that fast, so it interprets it as a continuous light source. Multiplexing takes advantage of this phenomenon. This is also the underlying principle behind pulse-width modulation.

Now that i’m done with the theory of operation, we can get to picking parts and drawing circuits. My final display will have 12 matrices in a 4*3 arrangement, so I picked parts based on that. The 16-bit parts can still be used to control a single matrix, however.





Since my eventual 4x3 display will have 24 rows of 36 LEDs, I picked this 16-bit multiplexer to control the rows. Don’t confuse multiplexer and multiplexing: the 74HC154 multiplexer turns on a specified output pin out of a bank of 16 based on a 4-bit binary input (A0-A3), whereas multiplexing is the technique used to control all the LEDs. For example, if 0101 is sent to the four binary inputs (A0-A3), the fifth output pin would be enabled because 0101 is 5 in decimal form. The 74HC154 is ‘active-low’, meaning the specified output pin goes LOW and the rest HIGH when assigned by the 4-bit input. This sounds counterintuitive, but it guards against all the rows turning on and killing the power supply if the multiplexer fails. Nonetheless, it is not really relevant in our case because we will be using PNP transistors. Two of these will allow control of up to 32 rows.


2N5401 PNP transistor

Speaking of transistors, I will be using 2N5401s to supply power to the rows. The 74HC154 is not meant for supplying large amounts of current, which is what we need to power all the rows. Why not the more common 2N3906? The 2N3906 has a maximum current rating of 200mA, whereas the 5401 can handle 600mA. My display will have 36 LEDs per row, and 200mA is not enough to power all of them at full brightness. 24 transistors will be needed; one for each row. Every one of these will be connected to separate output pins on the multiplexer. Since these are PNP transistors, they will be OFF when there is current at the base pin. They will only turn ON and allow current to flow through the row of LEDs when there is NO current at the base. The 74HC154 is active LOW, so the PNP transistors will only turn ON when assigned through the 4-bit input.


MBI5026 16-bit Constant-current sink LED driver


The LED driver is the most important part of controlling the display. The MBI5026 is a current-sink, meaning it allows current to pass to ground. I picked the MBI5026 to drive the columns for three reasons: it has 16 output pins, there is a constant current feature, and because it is readily available where I live. The constant-current feature means that a current-limiting resistor for each LED is not required at all. The current for all the output pins is set by an external resistor. The MBI5026 acts like a shift-register: data is shifted into three data pins, and multiple chips can be chained together for more output lines. A practically unlimited amount of pins can be controlled with only three inputs. An example with one of these: 0000000000000001, a 16-bit binary number, is shifted into the chip. All outputs will not allow current to flow except the first pin, so the first LED will be lit. The Arduino shiftOut() function doesn’t support 16-bit shift registers, so two separate bytes of data (one for 8-15, one for 0-7) will be sent before the data is latched. With two of them I can control all 32 columns of the display.


With these three primary components, all rows can be multiplexed. A row-transistor is turned on with the 74HC154 (not necessarily lit), allowing current to flow. The MBI5026 picks which LEDs in the row to turn on, completing the circuit and lighting the specified LED.

For now I will only use one 8x8 matrix because I don’t have more breadboards available :).




Eight 2N5401s: one for each row in the matrix. The three pins are as follows from left to right: emitter, base, collector.


2n5401 with base transistors

510 ohm base current resistors for each transistor. The collectors of each transistor are tied to the supply voltage.


base resistors with IC

MBI5026, 74HC154 with supporting circuitry. The resistor is used to set the constant current level in the driver.


The outputs on the multiplexer tied to each transistor.


The LED driver is connected (yellow and one blue) to the column pins of the matrix, and the multiplexer to the rows (green and blue).


The LED driver is connected to pins 2-4, and the multiplexer to pins 9-13. In my case, pin 2 is the data pin, pin 3 is the clock, and pin 4 is the latch.


1/1000s exposure shows lag

This photo illustrates the multiplexing effect very well. The photo was taken with an exposure of 1/1000s, equivalent to the refresh rate I set the display to. When I took the photo, to the eye it looked like the entire display was on at the same time. However, the multiplexer was actually lighting each row for 1ms, then turning it off and lighting the next one. The human eye cannot detect motion this fast, but the camera did.

Full Picasa web album with more detailed photos here. Code is available on my github page.

http://xy-kao.com/sandbox/led-matrix/ http://xy-kao.com/sandbox/led-matrix/sandbox/led-matrix/ Thu, 17 May 2012 00:00:00 +0000
Turing Alarm: A Mathematical Alarm Clock The Turing Alarm. Based on Nick Johnson's PIC

The arduino turing alarm is an adaptation of Nick Johnsons PIC-based one. At the time, I found that the PIC chip he used was a little too advanced for me, so I decided to use the Arduino microcontroller. All credits for the idea goes to Nick.

The turing alarm forces you to solve math problems when you wake up. If you get the math problem correct, the alarm stops, and if you don’t, you will have to solve another one. My version also includes a 12V light dimmer for the strip lights above my bed. A DS1307 real time clock (RTC) keeps track of the time and the menus are controlled with five buttons.


Code and circuit diagrams are on my github page. High resolution photos and other images are on my Picasa web album


tools and materials

Arduino board - I used the Uno board for testing and the Pro Mini for the final project
DS1307 RTC - You can use the DIP version; I used the breakout from SparkFun
SparkFun Serial LCD 16×2  - This is much easier to interface with than a parallel LCD
Small 12mm buzzer (2.048 kHz)
• 5 SPST panel mount momentary switches
10k pull-down resistors - You will need seven of these
• 1 DC jack panel mount (two if you want light control)
Project box - I used a 6 x 3 x 2″ project box from Radioshack
Mounting screws and nuts (4-40 ½ inch) - Mount LCD and slide potentiometer
• 10K slide potentiometer - Only if you want light control
N-channel MOSFET - Only if you want light control



Sparkfun RTC module   Sparkfun serial lcd module

The RTC module uses the Wire I2C interface to communicate with the Arduino on A4 and A5. The data line (SDA) is on A4, and the clock line (SCL) is on A5. With the coin-cell battery on the module, the RTC can run for up to 17 years without an outside power source. 

To set the time I used ladyada’s example code from her RTC library and tutorial. Her code sets the time using the local time on your computer. Make sure to uncomment this line of code:

          RTC.adjust(DateTime(__DATE__, __TIME__));

A serial LCD is easier to use for this project because it only uses one data line (TX). For beginners like me SparkFun’s serial LCD is very easy to interface and use. Only three pins are needed, whereas a parallel LCD requires more than ten. To change a setting on the LCD like cursor position and backlight brightness, send a command line followed by the instruction, as outlined in the datasheet. For example, to clear the LCD you send this block:

          Serial.print(0xFE, BYTE); // command line

          Serial.print(0x01, BYTE); // instruction

For the turing alarm I used four commands: clear LCD, move to line 1, move to line 2, and set brightness. I wrote the ones used commonly into functions so it can be easily accessed. You can read more about the LCD and the protocol on the datasheet.


libraries and layout

I used three libraries for this project: the RTC library from ladyada, the Wire library for I2C, and the debounce (bounce) library from Thomas Fredericks. You can download them here:

RTClib: Ladyada’s github page
Bounce: Arduino.cc playground
Wire: Already included in IDE; go to Sketch > Import Library > Wire

Basic schematic. made with fritzing

The turing alarm uses seven digital pins and two analog pins. The two analog pins are for I2C communication on the RTC and the digital pins are for the LCD, buttons, and the buzzer.



The code was written way back when I first learned the language. I realize that it is incredibly inefficient, but it worked at the time so I went with it. If I have time later, it will be rewritten and pushed on my github page. 

The code uses seven different while loops for each menu. Within each of those while loops are if statements and display commands. The seven menus are:

• Main menu
• Choose set alarm, brightness, or IO monitor
• Set alarm time
• IO monitor
• Brightness control
• Alarm is on; turn off?
• Alarm math menu (this one is the menu when the alarm goes off)

When the the device is powered up, this function loops:


This function gets the time from the RTC and writes it to the LCD screen in a two-line configuration. The date is displayed centered on line 1 and the time is centered on line two.

When the OK button is pressed, the time is set and this line of code runs:

          if (okDebounce == HIGH) {
          alarmSetting = 1;
          timePosition = 0;
          mathValOne = random(11, 20);
          mathValTwo = random(9, 15);
          mathValThree = random(20, 150);
          MenuPosition = 7;

alarmSetting stores whether the alarm is on or off with a boolean variable: 1 for on, and 0 for off. This is used in other parts of the code to check if the alarm is on or not.

timePosition is used to store which time value is being changed (second, minute or time). This resets it to 0, or second. (0 for second, 1 for minute, and 2 for hour).

The next three lines of code determines the math problem. It picks a random value between the values shown based on a seed from randomSeed(analogRead(2)) in the setup.

inputAnswer stores what the user inputs as an answer. The line of code shown simply sets the variable to a value that is close to the actual answer.

The next five lines of code clears the LCD and changes the menu.

After the alarm time is set, the loop constantly checks if the alarm time is equal to the real time with this line of code:

          if(alarmSetting == 1 && alarmSecond == now.second() && alarmMinute ==                     now.minute() && alarmHour == now.hour() )

The problem with this line is that it doesn’t check for date, so the alarm goes off within 24 hours. It is adequate for myself, but if you need to set alarms for more than a day later add a set date function.

When the alarm goes off, this block of code runs:

          realAnswer = mathValOne * mathValTwo + mathValThree;
          Serial.print(” Hello!”);      // wakeup message

          Serial.print(” = “);
          Serial.print(” ?”);

          if(debounceIncrease == HIGH) {
          if(debounceDecrease == HIGH) {

AlarmNoise on is a tone function that beeps the buzzer in a familiar 'alarm' pattern. realAnswer stores the actual answer that will turn off the alarm. The last two functions check if the up or down buttons have been pressed.

When the OK button is pressed, the code checks if the input answer is equal to the actual answer. If it is, noTone is called (turns off the buzzer) and all the variables are reset. A wakeup message is displayed for five seconds then the alarm returns to the main time menu.

          alarmSetting = 0;
          Serial.print(” Good Morning!”);
          MenuPosition = 0;
          mathValOne = 0;
          mathValTwo = 0;
          mathValThree = 0;
          alarmSecond = 0;
          alarmMinute = 0;
          alarmHour = 0;

If the input answer is not equal to the actual answer, then the math values are reset to a different random value, giving the user another problem to solve.



Eagle PCB layout capture   Custom etched PCB with photoresist

I also drew a PCB design in EagleCAD for those who are too lazy to solder on a perfboard. The double-sided one is very densely populated, and is meant for a board-house to make. All the parts are squeezed in to a 5cm square to keep the price low ($9.90 at Seeed). There is also a schematic that comes with the PCB layout.

If you would rather etch your own circuit board, use the single layer version that is much bigger (6*10 cm) and easier to etch. The picture is of the board I etched. Note that there is one jumper that you will need to connect with hookup wire; it is located at the top center of the board.


mounting parts

Internals.  Underside of the front panel

All of the parts except for the buttons and the jack are mounted with 4-40 screws and nuts. The buttons and jacks are already threaded with a nut, so a 1/4 inch hole is all you need. For the 4-40 screws, I used a ~2.5 mm hole.

The LCD has four mounting holes, one on each corner. The LCD itself does not sit flush with the board, so you will need to use spacers on each hole. I found that two 4-40 nuts work well as spacers. You will need 12 nuts in total for the LCD: 8 for spacing, and 4 for securing.

The slide potentiometer is a little tricky because many spacers are needed. When the knob is attached, it sits much higher than where the mounting holes are. Just keep on adding spacers until the knob sits relatively flush on the box.

Mark where to drill the holes and mount the components. If you need measurements, open the CorelDRAW file and use the ruler tool. You can also submit this file to a laser-cutting service (Pololu, for example) and have it laser etched and cut.



The serial LCD is displaying a black line/random text/nothing.
I got this problem very often when working with the LCD. Most of the time the problem fixes itself when you cycle the power or adjust the contrast. To prevent this from happening again, remove the serial wire from the Arduino when uploading code. Sometimes it sends a random serial message that could change the settings on the LCD or display random text. If cycling power does not fix the problem, upload and run Reset_Serial_LCD.pde attached below.

The time stays at 00:00:00 or doesn’t change.
Sometimes the RTC stops itself when debugging. Rerun the set-time sketch and you should be fine.

http://xy-kao.com/projects/turing-alarm/ http://xy-kao.com/projects/turing-alarm/projects/turing-alarm/ Sat, 28 Apr 2012 00:00:00 +0000