Saturday, November 5, 2011

Yogurt Maker Part 1

We started building this yogurt maker.

We've completed the TTL controlled power switch and that seems like a pretty useful project by itself. Of course we had to hack the hack and redesign Chris Reilly's implementation to suit our needs and the parts we had on hand. We roughed out the design on paper. As great as CAD is, nothing beats a sheet of quad paper, a mechanical pencil, and a big eraser for your first few design iterations.

Next I went to a big box home supply store - there are no more hardware stores in our neighborhood - and found parts such as a junction box, a power socket and a cable clamp. Since it wasn't exactly what I needed, yet another design iteration was called for. The result was this:

And on the outside it looks like this. The cable plugs into the wall and that powers up the outlet on top. We'll plug the power supply for our microcontroller into that outlet. The microcontroller's ground, 5V power, and signal lines will plug into the connector on the left. The amber LED on top indicates 5V power. The red LED indicates that the signal line is high, and that the outlet on the bottom should be energized.
In the next installment I'll write about the microcontroller and sensors.

Tuesday, August 2, 2011

Taiko Synth - Phase 9 - Waveforms

Until now, the taiko drum pad was a simple piece of masonite on a stack of packing foam with some mouse mats on top. A single strike resulted in multiple signals and I suspected it was because of either the masonite resonating, or all the pieces bouncing up and down. I needed some instrumentation.

The first step was to tie the drum pad together in an attempt to hold all the pieces together. I cut a circular base from plywood, then used a hacksaw to cut the foam to match. The foam looks terribly jagged - I think it needed some kind of hot-wire cutter for that. I got some 1/4" shock-cord (at REI, this is what they call this bungee cord) and cord-stoppers (clips used to close up back-packs, etc), then I cut holes in the drum head, foam, and base through which to thread the shock-cord. The hardest part was punching holes in the foam and threading the cord through it. The drill won't cut; the foam just got all wrapped around the bit! Forcing a 1/4" rod through the foam worked pretty well, although it was sill nearly impossible to thread the shock cord through the foam. Once the shock cord was threaded and cinched up, I glued some 2x2s to the base so it didn't rock back and forth on the shock-cord and cord-stoppers underneath. I used Gorilla Glue, which is really strange stuff, attach the 2x2s. As it hardens it foams up like polyurethane and can be a big mess if you use too much. The last step was to attach the mouse mats to the top surface of the masonite with silicone rubber glue.

After all that, it was time to hook it up. I connected a mini stereo plug to the drum and plugged that into the input jack of a laptop running XOscope. This is a pretty neat program. The controls are pretty intuitive, but I'm not going to be able to get any useful amplitude data until I figure out some kind of calibration work-flow. The other thing I didn't do which I should have done was to put some protection on the inputs - I could have damaged the PC's audio circuit - or worse. Note to self: next time be more careful!


Here's a trace of a hard DON strike. Right click and open the graph a new tab to enbiggen it sufficiently. The green trace it the drum head and the blue trace is the rim. You can see that the green trace is clipped, but what I was looking for was how long it resonated for. This way I could know when to start listening for the next strike. The graph shows that the signal took about 75 mS to settle down.

The other thing we can determine is that the resonant frequency is 4/0.02125, or 188 Hz

What I see there is that the drum head needs more damping. I want a single bounce - like when you push down on the fender of your car to see if the shocks are shot.


Below is a plot of a softer strike; one that 's not clipped. From it we can obtain the damping coefficient Tau, or the time it takes for the sine wave component to decay to 0.27 times its origin amplitude. It looks like Tau is about 0.017 Seconds.

The other thing I see in this plot is cross-talk. Striking the center of the drum results in a signal on the rim sensors. Cross talk's roughly (0.25/3.5)*100% or 7% and that's not too bad.


Tapping on the rim shows a quite different crosstalk story. Here the cross talk is (0.5/1.2)*100% or 42%. Something will need to be done to improve this. I think I many need to cut a slot in the foam to separate the rim from the drum pad center, but I'm concerned that the remaining foam will be too thin to support the rim. Maybe the foam will need to be replaced by a stiffer elastomer.


From this base-line data, I'll be able to see if changes I make to the construction of the drum pad improve or worsen its performance.

Sunday, July 24, 2011

Ardunino-based AA Battery Tester

I've been a big believer in buying products that use AA rather than proprietary batteries. One advantage of AA batteries is that if you use up all your rechargeable AAs when traveling, you can alway find alkaline batteries in a convenience store. Also, if all you devices use AAs, you only need one charger.

On the other hand, a disadvantage of AAs is that because of NiMH technology, and the shape of the cells, their total energy density is less than Li-ion batteries.

When using NiMH cells, a problem with I've encountered occurs when one of the four cells in the pack is bad. With a fully charged pack in my camera, I've been out of power after only five pictures because of one bad cell. Even if all all cells are good, it's best to match cells with similar characteristics. This was the purpose of this project. Yes, one can buy a battery tester, but its so much more fun to do it yourself!

My goal was not just to test the batteries as a set of four, but to get discharge data from each cell. I've seen some projects in which the battery pack is tested by connecting a power resistor and a clock to the terminals. The idea is that the when the battery is discharged, the clock stops, and you can make a calculation of battery capacity from that. There are two problems with this. One is that the battery isn't discharging at constant current, so you can't accurately compare your results to the battery's capacity rating. The other problem is that fully discharging an NiMH battery below 1 volt per cell will damage it. If you test in this manner, each subsequent test will result in worse performance.

The first step in the project was to do a little research on NiMH Batteries. I found a good reference in Sanyo's Twicell battery manual. Here are some of the more useful facts about NiMH batteries.

If you discharge the battery below 1V/cell, the cell can undergo a polarity reversal (!). This would cause the battery (a battery is a group of cells) voltage to drop suddenly. To give the cells a margin of safety, I limited discharge to 1.1V/cell.

The typical test discharge rate (It) is defined as the current at which the battery would be drained in one hour. Thus, a 2800 mAh (milliAmp-hours) battery can be drained at 2.8 amps. That would dissipate if a lot of power! I decided limit battery drain to 1 amp - a nice even number.

Here's the circuit:

The schematic is a little hard to read in the blog. You can right click it and open it in a new tab to enbiggen it.

Here are the circuit details.

Current is drained through an LM317 three-terminal voltage regulator. It's configured for constant current mode with eight 10 Ohm 1/2 Watt resistors. Since full discharge current passes through these resistors, they must be big enough to dissipate that power. Increasingly higher rates of discharge can be selected as each of the switches are closed.
S1           => 1.2 Volts / (10 Ohms / 2) = 0.24 Amps
S1 + S2 => 1.2 Volts / (10 Ohms / 4) = 0.48 Amps
S1 + S2 + S3 => 1.2 Volts / (10 Ohms / 8) = 0.96 Amps

I only used the maximum discharge rate because any less results in a long test time. At the lowest setting, a full discharge can take ten hours.

One curious thing you may notice about the circuit is 1 ohm, 10 watt resistor. That's there because of the possibility of the maximum battery voltage exceeding 5 volts. Rather than attempting to measure the voltage of all 4 cells directly, the voltage is dropped 1 volt when draining the cells at 1 amp. In this way, the Arduino's maximum analog input is not exceeded. It does make calculation of the cell four's voltage a little strange-looking, though.
VB1 = A0
VB2 = A1 - A0
VB3 = A2 - A1
VB4 = A3 - A2 + (It * 1)

To convert these values to voltages and perform the calculations I imported a floating point library. In this way I was able perform the calculations and format the output directly to so that could be used by a plotting program such as GnuPlot. To use the tester I charged the batteries using the same charger that I travel with. I transferred the batteries from the charger to the tester. The tester was plugged into a laptop running a Putty terminal which logged all the output to a file. When "g" was typed at the keyboard, D7 went high, closing the relay and discharging the cells. If any cell reached less than 4.1 Volts, D7 would go low, stopping the test. From the saved data, a discharge profile could be plotted:

Several problems were encountered with the first version of the battery tester. The first was heat. I didn't expect that I'd need a very large heat sink on the LM317 since it was only dissipating four watts. I was wrong. My rule of thumb is that if a component is so hot that you can't hold your thumb on it, the component needs more cooling. I first tried adding a small 5 volt fan to the heat sink, powering it off the laptop's USB port. This cooled the LM317 sufficiently but made an annoying sound I suspected it was causing electrical noise that was making the battery readings erratic. I clamped ferrites on USB cable, but that didn't improved the accuracy of the measurements, so I removed the small heatsink, and installed the big heatsink you see in the photo. That took care of the temperature, but the measurements were still unstable. It turns out the source of the problem was the instability of the 5 volts supplied from the laptop via USB. A check of the Arduino's Vref pin showed that the voltage was varying all over the place. The solution was to use an external power supply to power up the Arduino, so the Arduino's regulator could provide a stable Vref.

I've not done anything with this project recently, so I wanted to document everything. When I'm ready to start again, I won't have to start from scratch!

Friday, July 15, 2011

Sunday, June 26, 2011

Taiko Synth - Phase 8 - Two Channels


On a taiko drum, in addition to striking the head (ドン) you need to be able to play rim shots (カラ). To make a rim, I cut a gap into the masonite. The rim needed to be as wide as a piezo sensor. I used GE silicone adhesive to fasten the piezo sensors to the drum head and rim, then wired each set in parallel (observing polarity) and then to a connector on the rim. I had to change the Arduino/nunchuck interface a little to handle two channels efficiently. That may be the subject of a later post.

In this new configuration, I seem to have trouble with single hits being detected as multiple. Reducing the number of sensors on the head helped. Also increasing the padding on the head of the drum helped. I bought a bunch of mouse mats for that purpose. Still, I think either the masonite board is resonating, or, more likely the board is bouncing up and down on the foam. The best fix I can think of for this is to glue them together, but if I do that, I will no longer have access to the underside of the head, so making changes is going to be difficult.

Anyway, here's the result:

Saturday, April 9, 2011

Taiko Synth - Phase 7 - Basic Improvements

The volume is now proportional to the hit - although I do need to scale it for better dynamic range. Initially I did the scaling like I would in any software application:
outputValue = inputValue * maxOutput / maxInput
The problem is that Arduino only deals with 16 bit integer math. Anything over 32767 is a negative number. By multiplying first, it went over that value so I was seeing negative volume values when I hit the drum hard. Since maxOutput and maxInput are constants with a ratio of about 5, I re-wrote the formula as follows:
outputValue = inputValue / 5
More work needs to be done on scaling; the detection threshold needs to be lower, a peak indicator LED is needed, and I want to be able to use the nunchuck to adjust the sensitivity. The nunchuck is running out of controls, so I'll try to use the accelerometers.


I'm now running the synthesizer software on an HP 1000 mini running Ubuntu 10.04 LTS off of a bootable flash drive.The latency isn't as bad as before. The little netbook works pretty well. I read that there's a low-latency Linux kernel, so I may try that for fun some day.

I changed the synthesizer software is to FluidSynth (http://sourceforge.net/projects/fluidsynth/). FluidSynth needs a soundfont. It can use the General MIDI instruments which include Taiko (channel 117) and a bird (channel 123 - not so useful, but fun).

Here's where I got the sound font: http://packages.debian.org/search?keywords=fluid-soundfont-gm

Once installed, here's how to start everything.
./ttymidi -s /dev/ttyUSB0&
aconnect -i
aconnect -o
aconnect 129:0 a28:0
fluidsynth -c0 -r0 -r22050 -l -a alsa -o audio.alsa.device=plughw:0 FluidR3_GM.sf2

If you are troubleshooting, there's a -v parameter for verbose, that's helpful.



I installed Jack, a GUI device connector, and experimented with that, but I think it's easier to use Aconnect.

Here's a demo of the results:

Saturday, March 19, 2011

How to Make a Decent Splice



Sometimes you need to shorten an existing cable by removing a section and reconnecting the two ends. Other times you might need to lengthen a cable by adding one or more sections. If you're doing this to a multi conductor cable, it's best to use the "Western Union" splice my grandfather taught me. This type of splice won't short-out (the condition in which conductors touch) if the insulation on your joint fails.

You will want to strip two to three times as much of the outer insulation as you normally would. On one end cut the red wire short, and the white wire long. On the other end cut the red wire long and the white wire short. Cut some heat-shrink tubing to go over the inner conductors. Also cut a larger piece to go over the whole thing, slide it over one or the other of the pieces of cable, and slide it well out of the way. Don't forget to do this, because after you've made the connection, you won't get be able to do get the heat-shrink onto the cable. Now cut some smaller heat-shrink tubing for the inner conductors and slide them over each of the longer wires. Make sure these are far away from the joint so the heat from soldering won't shrink them and prevent them from fitting over the joint.

Twist the wires together facing each other such that the joint isn't much thicker than the original wire. If you twist them facing the same direction (like a zipper), you might not be able to get the heat shrink over them, and if you do, the tubing will look like a python that's swallowed a pig. If the conductor is going to poke through the heat-shrink and cause a short, it's going to be where it's stretched thin over the big solder blob.

Like this:



Not like this:

Apply heat, then solder to the joints. After the joints have cooled, slide the heat shrink over them and apply heat. After that's cooled down, slide the large heat-shrink over the whole thing and apply heat to complete the job.

Sunday, March 13, 2011

Time Lapse Photography - Phase 1

The first step was to get the hardware ready.

To find the power, focus and shutter switches on this old camera, I disassembled it screw-by-screw. I only shocked myself once on the flash capacitor. I thought I'd never get the camera back together. It might have been better to have ground away the buttons with my Dremel tool. The nice thing about this camera is that when connected to and external 3.3 v power supply it never goes to sleep. This way it doesn't lose settings like "no flash" and the lens does not have to be extended for each frame. If make a 10 minute movie, that would be 18,000 frames. I'd guess that's pretty much the life of that mechanism. Now I wonder about the shutter and focus mechanism. How long will it last?

To use the camera, first touch the two "on" button wires together.
To focus, hold the brown and blue wire together.
To snap a frame, touch the white wire to the brown and blue.


This is the board with four relays that I made. It'll control the camera with one relay to spare. I made it generic as possible. I think the Arduino could probably have driven the relays, but I used some 2N2222 transistors anyway. The funny thing about these relays is that they have polarity. I thought maybe they had an internal protection diode, but when I ohmed it out, it was about 120 ohms both ways. I read up on this type of relay, and I think the armature may have a magnet on it to reduce the current requirement. The bad thing about that is if you wire it backwards, the armature is repelled, and the relay won't close. The other thing generic about this board is that I kept the PWM pins in reserve using only the pure digital I/O pins. The pin numbers are going to be numbered funny in the firmware, but this way all the analog outputs are available if needed.

Saturday, March 12, 2011

Taiko Synth - Phase 6 - Sensing the Bachi

I began with this simple code to detect the strikes, assuming that the start of the first negative slope signal the strongest part of the strikes.
void loop()
{
//polarity - white positive
amp = 0;
ampNew = 0;
don = false;
peak = false;
while(!don)
{
ampNew = analogRead(0);
if (ampNew > 25)
{
don = true;
while(!peak)
{
amp = ampNew;
ampNew = analogRead(0);
if ((ampNew + 1) < amp) // plus 10 for noise compensation
{
peak = true;
printSettings();
}
}
}
}



In the above code, I've had to replace all the "greater than" and "less than" symbols with equivalent HTML entity names, and that seems to work fine. I thought anything with in a code block shouldn't have needed that.

Anyway...

This "don detect" algorithm gave some strange results. The first strike didn't seem to even register. Later strikes weren't proportional to the intensity of the hit. To investigate, wrote new code to capture as much data as possible and send it to Putty via USB serial at 115200 bps.
void setup() {
Serial.begin(115200);
}

void loop() {
Serial.println(analogRead(0));
}



Here are 5 strikes growing in amplitude:







Here's a close-up of the 5th strike:









Some interesting observations can be made. I'm not quite sure of the frequency, because I'm not sure of the sample rate, but you can see that the wave form is a truncated decaying sine wave. That's what one might expect from striking a board with a stick. What's a little surprising is that the first peak is not necessarily the greatest. There is also some dc offset at the end of the strike. From this, the lesson is that I need to change the "don detect" algorithm take the first 15 or so points after a strike is detected. Then, use the greatest of those to determine the peak amplitude. This method may trade latency for accuracy so I may need to tweak the final code a little. It may be a good idea to write more test code to capture these points from within the taiko app to make sure sufficient data is gathered to determine the true peak amplitude. This is because the taiko app surely has a different sample rate than the app above. To address the DC offset, I think I need to make sure that the foam is cut away from beneath the piezo sensor.

Monday, February 28, 2011

Smartphone Mount

There are some pretty neat solutions for mounting smartphones on a car dashboard. The mounts make it easy and safe to use a smartphone as a GPS or listen to Pandora on those long trips. Unfortunately it wasn't clear just by looking at pictures on the web that one of these mounts would fit exactly right. I decided to make a custom mount using my old friend, styrene. Styrene is a soft plastic that's really easy to work with. However, with the demise of the neighborhood hobby store, it's gotten hard to find. Fortunately there's a model railroad shop nearby that sill carries styrene sheets and shapes such as angles and I-beams. Plastruct and Evergreen Models seem to be the two major brands.

First I took measurements of the phone and designed a holder on paper. I found that the plastic angle-beams were the most versatile for this application. I bought all the 3/8 angle-beams in the store (about 6). I cut the pieces in a mitre box and then dry-fit them to make sure my calculations were right.

Next I glued the pieces using Testors liquid cement. This stuff actually melts the plastic and forms a great bond. Another advantage is that it's fast-drying. I used alligator clips, a pin-vice, and a hemostat to clamp the pieces while they dried.

I wanted to use the "cubby hole" in the dash to hold the mount. I took measurements and found that it was shaped like a truncated pyramid. What a complex shape! I did my best to measure the inside of the box, and constructed a box to mount the smart phone holder on. When I did my final test fit, I found that the box was too wide to be fully inserted into the cubby hole! The reason was that I had measured the cubby hole at the middle, but the inner edges were rounded so it was just a little narrower where it made contact with my box. Here's the beauty of styrene. I cut the box in half longitudinally, taking out a few millimeters of material. I used more angles to re-connect the now slightly narrower box. This time it fit perfectly. I connected the holder to the mount and put a little piece of velcro at the bottom to keep it steady.

I have yet to paint it. If I paint it, it'll be white because styrene has a tendency to melt in the hot sun.

Sunday, February 27, 2011

Two ways to log temperatures.

With an Arduno, Adafruit's XPort Ethernet shield, and an Internet connection, parameters such a temperature can be logged to the cloud.

When I assembled the Ethernet shield I only connected power, TX and RX. Setup of PPP on the XPort was a little tedious, as a fixed IP address, mask, gateway, and other parameters had to be entered through the Arduino with a terminal app. I connected the output of an LM335 temperature sensor to analog port 0 using the recommended calibration circuit from the data sheet.

Since Arduino can be powered over USB, I used the USB port on the router for power only. This was a neat solution because it needed no additional power supply for the Arduino. The drawback was that power from a USB port isn't always stable or equal to exactly five volts. Measure the voltage of VREF after connecting it to the port. Analog read should be equal to VREF/1023. Hopefully it is stable. One option may be to make a stable 3.75 volt reference circuit, and that would enable any USB port to be use. This would also improve resolution of the A/D reading. With any spare op-amps, the LM335 could be level-shifter and amplified.

For now, I'm just using an external power supply.














The first solution used and HTTP GET to some PHP running on our hosting server. Getting this to send a properly formatted HTTP packet was a little tricky. I ended up using Wireshark and comparing the output of a browser to the output of the XPort. For this I needed a true Ethernet hub, but now switches seem to be replacing hubs, even in the consumer space. In the future I may need a second NIC on my pc, bridged to the main NIC, just so I can solve this kind of problem.


#include
#include
#include
//#define IPADDR "207.58.139.246" //www.ladyada.net
//#define IPADDR "157.166.226.25" //cnn.com
#define IPADDR "---.---.---.---" //www.---.net

#define PORT 80

char linebuffer[256]; // large buffer for storing data
unsigned int value = 77; //fake temperature
int indoorPin = 0;
float fpVal = 0;
int i = 0;
boolean debug = false;

#define XPORT_RXPIN 2
#define XPORT_TXPIN 3
#define XPORT_RESETPIN 4
#define XPORT_DTRPIN 5
#define XPORT_CTSPIN 6
#define XPORT_RTSPIN 7

AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);

void setup() {

Serial.begin(9600);
xport.begin(9600);
xport.reset();
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}

}

void loop()
{
byte ret;

while(true)
{

if(debug){
Serial.println("Reading Temperature...");
}
value = analogRead(indoorPin);
fpVal = float(value);
fpVal = fpVal-52.0;
fpVal = fpVal*500.0/1023.0;
fpVal = fpVal-273.15;
fpVal = fpVal*9.0/5.0+32.0;
value = ((int)fpVal);
if(debug){
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println(value);

Serial.print("Temperature = ");
Serial.println(value);
Serial.print("GET /php/add_temperature.php?temperature=");
Serial.print(value);
Serial.println(" HTTP/1.1");
}

//while(true){}


if(debug){
Serial.println("Connecting...");
}
xport.connect(IPADDR, PORT);
//xport.flush(300);

if(debug){
Serial.println("Getting...");
}
//xport.println("GET /index.html");




//xport.print("GET /savedb.php?value=");
//xport.print("GET /php/add_temperature.php?temperature=12.6 HTTP/1.1");

xport.print("GET /php/add_temperature.php?temperature=");
xport.print(value);
xport.println(" HTTP/1.1");
xport.println("Host: www.---.net");
xport.println("Connection: keep-alive");
xport.println("User-Agent: Arduino/xport\r\n");
//xport.println("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.125 Safari/533.4");
//xport.println("Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
//xport.println("Accept-Encoding: gzip,deflate,sdch");
//xport.println("Accept-Language: en-US,en;q=0.8");
//xport.println("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n");
//note that this has got to end with and extra crlf.

//delay(1000);
//delay(1000);
//delay(1000);

ret=xport.readline_timeout(linebuffer, 255, 3000); // get first line
while(ret!=0){
if(debug){
Serial.print(linebuffer);
}
ret=xport.readline_timeout(linebuffer,255,4000);
}

if(debug){
Serial.print("Readline returned: ");Serial.println(ret,HEX);
}

for (int i=0; i <= 300; i++) { delay(1000);} } }


The PHP code stored the temperatures to a SQL data base, and an app was written to display the latest ten readings.

After we changes hosting services, we didn't have time to reinstall all our PHP application. However, I found and interesting service called pachube. When you sign up, they give you an API key which lets you post data to their site. This site requires an HTTP PUT to post data. The code is slightly different


#include
#include
#include
//#define IPADDR "207.58.139.246" //www.ladyada.net
//#define IPADDR "157.166.226.25" //cnn.com
#define IPADDR "173.203.98.29" //www.pachube.com

#define PORT 80

char linebuffer[256]; // large buffer for storing data
unsigned int value = 77; //fake temperature
int indoorPin = 0;
float fpVal = 0;
int i = 0;
boolean debug = true;
int vref = 500;//fully regulated
//int vref = 469;//cisco
//int vref = 465;//pc

#define XPORT_RXPIN 2
#define XPORT_TXPIN 3
#define XPORT_RESETPIN 4
#define XPORT_DTRPIN 5
#define XPORT_CTSPIN 6
#define XPORT_RTSPIN 7

AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);

void setup() {

Serial.begin(9600);
xport.begin(9600);
xport.reset();
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}

}

void loop()
{
byte ret;

while(true)
{
//reset before each reading - see if that stops it from getting hung up every five days.
xport.reset();
delay(1000);
delay(1000);
delay(1000);
delay(1000);
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}


if(debug){
Serial.println("Reading Temperature...");
}
value = analogRead(indoorPin);
fpVal = float(value);
//if(debug)Serial.println((int)fpVal);
//fpVal = fpVal-52.0;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal*(float)vref/1023.0;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal-273.15;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal*9.0/5.0+32.0;
if(debug)Serial.println((int)fpVal);
value = ((int)fpVal);
if(debug){
Serial.println(value);

Serial.print("Temperature = ");
Serial.println(value);
Serial.print("GET /php/add_temperature.php?temperature=");
Serial.print(value);
Serial.println(" HTTP/1.1");
}

//while(true){}


if(debug){
Serial.println("Connecting...");
}
xport.connect(IPADDR, PORT);
//xport.flush(300);

if(debug){
Serial.println("Getting...");
}
//xport.println("GET /index.html");


xport.print("PUT /v2/feeds/19356.csv HTTP/1.1\n");
xport.print("Host: api.pachube.com\n");
// fill in your Pachube API key here:
xport.print("X-PachubeApiKey: --------------------------------\n");
xport.print("Content-Length: ");

// calculate the length of the sensor reading in bytes:
int thisLength = getLength(value);
//+ id and comma
xport.println(thisLength + 2, DEC);

// last pieces of the HTTP PUT request:
xport.print("Content-Type: text/csv\n");
xport.println("Connection: close\n");

// here's the actual content of the PUT request:
// this wored when I send the value,input1 but it appeared backwards!
// ok, this time it looked like it worked.

xport.print("0,");
xport.println(value, DEC);
xport.println("\n");
/*
xport.print("GET /php/add_temperature.php?temperature=");
xport.print(value);
xport.println(" HTTP/1.1");
xport.println("Host: www.---.net");
xport.println("Connection: keep-alive");
xport.println("User-Agent: Arduino/xport\r\n");
*/
ret=xport.readline_timeout(linebuffer, 255, 3000); // get first line
while(ret!=0){
if(debug){
Serial.print(linebuffer);
}
ret=xport.readline_timeout(linebuffer,255,4000);
}

if(debug){
Serial.print("Readline returned: ");Serial.println(ret,HEX);
}

for (int i=0; i <= 300; i++) { delay(1000);} } } // This method calculates the number of digits in the // sensor reading. Since each digit of the ASCII decimal // representation is a byte, the number of digits equals // the number of bytes: int getLength(int someValue) { // there's at least one byte: int digits = 1; // continually divide the value by ten, // adding one to the digit count for each // time you divide, until you're at 0: int dividend = someValue /10; while (dividend > 0) {
dividend = dividend /10;
digits++;
}
// return the number of digits:
return digits;
}


Pachube's API for displaying data is a little tricky, and I haven't been able to retrieve nice-looking data, but here's their standard API plot showing my indoor temperature data over a 24 hour period.

Saturday, February 26, 2011

Taiko Synth - Phase 5 - Drum Pad

The first drum pad attempt used 24" diameter, 1/8 thick Masonite with four inches of foam below, and mouse pads on top. I tried a good hard hit, and cracked the board! Second try used two layers of Masonite, 18" in diameter, joined with Gorilla Glue.







A length of 26 GA stranded wire was soldered to a 1" piezo disc. You can get an idea of the polarity and a rough idea of the amplitude by using a DC voltmeter and simply squeezing the sensor. The silver part of the sensor is positive, although that doesn't really matter. The cable and the sensor were glued to the drum pad with GE silicone glue. The other end of the cable was connected to the Arduino input(0) with a 1 megaohm resistor and a 4.7 V zener diode in parallel to protect the Arduino inputs.

Taiko Synth - Phase 4

Lots of folks are talking about multiple nunchucks:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230499241

I like the idea of using a couple i2c accelerometers from sparkfun the best, I think.
I could attach them to dowels, Y-axis could detect ドン and X-axis could detect カラ. The question is, what is the frequency response of i2c accelerometers? A spongy mount could be used to trade amplitude for frequency. Detecting the a soft note from a loud note may be a challenge, too. I think I'd keep the nunchuck as a controller.


Now that I can select MIDI channel, voice, and note, I've been able to explore timidity. One change I would like to make to my UI is that the setting should change when the joystick passes the threshold, rather than when it it released from the de-bounce routine. Because if this I find I don't know how far to push the joystick to affect a change.

On channel 0, each voice is a different instrument and note changes the frequency. In this way one could change the size of the drum sound.

Taiko related sounds on channel 0,
0,47 Drum
0,73-76, various flutes.
0,78 Shakuhachi - not there!
0,115 Drum
0,117 Taiko - not there!
0,122 Water

Channel 9 is a set of percussive sounds. Changing voice does nothing. Changing note selects various percussion instruments. So far 64 sounds like the best taiko drum. For the first phase, I just need a center hit and a rim shot. Later a shinofue, suzu, and shime would be good. I'd like to run the accompaniment on the PC while playing drums on Arduino.

Too bad a lot of the sounds I want are missing from Timidiy. Oh well, there are other soft synths to try. I think there are .PAT files that Timidity can use, but the web sites that supply these look a little scary.

Here's a video demonstrating what works so far.

Taiko Synth - Phase 3

We need to see the MIDI settings so they can be matched to the sounds from the Timidiy soft synth.

I used a serial LCD display from sparkfun:

http://www.sparkfun.com/products/9393

This is a great unit, and as a bonus, it can display katakana! Check the datasheet:

http://www.sparkfun.com/datasheets/LCD/st7066.pdf

Use the Arduino softserial library to talk to the display, because the main serial port is being used for MIDI. Lady Ada also has a softserial library, but I just used the one that came with Arduino.

Connect the display to power and to data on digital pin 3.

Explore the syth as follows.


C button: Toggle channel 0/9
Joy stick: up/down: change voice (instrument)
Joy Stick: left/right: change note
Z button: play note


I had considered using the nunchuck's built in accelerometer to trigger the note when playing "air drum" style, however that would encourage weaker hitting of the taiko, as you don't want to hold back when playing. Another option: mount the nunchuck and the stick and trigger on detecting the hits. I like this except I would need two nunchucks, and they both operate on the same i2c channel. This solution might need either two arduinos, figuring out to use the i2c library with two data channels, or changing the nunchuck channel.

Here's the code.



/*
* WiiMIDI --
* a06 display change in value as soon as joystick crosses threshold.
*
*
*
*/

#include
#include
#include
#include "nunchuck_funcs.h"

#define rxPin 2
#define txPin 3

int loop_cnt=0;
byte accx,accy,accz,zbut,cbut,joyx,joyy;
int ledPin = 13;
int note_on = 0;
int voice = 47;
int note = 60;
int channel = 9;

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

int debounce;

void setup()
{
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
midi_program_change(0, voice);

pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);

nunchuck_setpowerpins();
nunchuck_init(); // send the initilization handshake
printSettings();
midi_program_change(0, voice);
}

void loop()
{
delay(1);
nunchuck_get_data();

//accx = nunchuck_accelx(); // ranges from approx 70 - 182
//accy = nunchuck_accely(); // ranges from approx 65 - 173
//accz = nunchuck_accelz();
zbut = nunchuck_zbutton();
cbut = nunchuck_cbutton();
joyx = nunchuck_joyx(); //33L - 133C - 225R
joyy = nunchuck_joyy(); //25B - 128C - 224B

if(cbut == 1)
{
if(channel == 9)
{
channel=0;
//printMsg((char*)"nine");
//printSettings();
}
else
{
channel = 9;
//printMsg((char*)"zero");
//printSettings();
}
while(cbut == 1)
{
delay(100);
nunchuck_get_data();
cbut = nunchuck_cbutton();
//printMsg((char*)"release button");
}
printSettings();
}

if(joyy > 175)
{
voice++;
printSettings();
while(joyy > 150)
{
delay(100); //why does this delay prevent the app from getting hung up?
nunchuck_get_data();
joyy = nunchuck_joyy(); //25B - 128C - 224B
//printMsg((char*)"inc v");
}
midi_program_change(0, voice);
}

if(joyy < joyy =" nunchuck_joyy();"> 175)
{
note++;
printSettings();
while(joyx > 150)
{
delay(100); //why does this delay prevent the app from getting hung up?
nunchuck_get_data();
joyx = nunchuck_joyx(); //33L - 133C - 225R
//printMsg((char*)"inc n");
}
}

if(joyx < joyx =" nunchuck_joyx();" zbut ="="" zbut ="="" zbut =" nunchuck_zbutton();" joyx =" 125;" joyy =" 125;"> 100 )
// { // every 100 msecs get new data
// loop_cnt = 0;
// }
// loop_cnt++;
// delay(100);
}

void printSettings()
{
mySerial.print(0xFE, BYTE);
mySerial.print(0x01, BYTE);
mySerial.print("c:");
mySerial.print(channel);
mySerial.print(" v:");
mySerial.print(voice);
mySerial.print(" n:");
mySerial.print(note);
//delay(1000);
}

void printMsg(char* msg)
{
mySerial.print(0xFE, BYTE);
mySerial.print(0x01, BYTE);
mySerial.print(msg);
delay(1000);
}

Taiko Synth - Phase 2

The sythesizer produces lots of different sounds. I need and easy way to select a sound an listen to it.

There are 127 voices, 127 notes, and 2 different channels.


A Nintendo Wii nunchuck is used to select voices, notes, and channels. It also is used to play the selected sound. An adapter is needed to connect to Arduino.

http://www.sparkfun.com/products/9281

Solder a header to the adapter and plug it into analog inputs 2-5. The "Wire" library will use the use analaog inputs 2 and 3 for power and inputs 4 and 5 as digital i2c I/O.

For a nunchuck libary that makes the interface really easy, here's a link to Todd Kurt's blog.

http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/

Download the Wiichuckdemo. Put the example program and nunchuck_funcs.h in the same sketchbook folder and open them together with the Arduino IDE.

Compile and upload to the Arduino to make sure everything works.

Taiko Synth - Phase I

Taiko drums are quite expensive. I only get to play them in class, but I want to practice at home. Some people just use a large bucket strapped with duct tape, but of course that's not going to sound quite right.

I'm making a variant of the bucket idea, but on top of the bucket with be a soft surface with some kind of piezo or resistive sensor to detect strikes to the head of the drum. Around the edge will be soft plastic tubing (like Tygon), capped at one end and with a small microphone or pressure transducer inserted into the other end. This will be used to detect the カラ hits. An Arduino will detect the hits, and convert them to the appropriate MIDI messages and send them to a PC running a synthesizer application.


The first step is to install the synthesizer onto the PC. I'm running Ubuntu, so I added Timidity from the software archive.

The Arduino is going to need to talk to Timidity through USB serial. Timidity doesn't know about USB serial - it usually receives data from a MIDI controller. Fortunately, Thiago Teixeira has written a excellent tool called ttymidi. It can be downloaded here.

http://www.varal.org/ttymidi/

Grab the whole package. The ardumidi libraray in the package will be useful on for the Arduino part of the system. Extract the ttymidi code and compile it. It's a good idea to read the source code first, just to make sure it's safe. More or less follow the instructions in the readme file.

Copy the ardumidi library folder to the Arduino /libraries folder. Copy the example program to the sketchbook and compile.

Running the Arduino IDE and ttymidi on the same box doesn't seem to work real well because I think they both want to use the same port. It kind of a hassle working on two boxes. I need to look into how to switch back and forth easily.

Now disconnect from you IDE box and connect to the box running Timidity. On my system, Timidity was started automatically so I was able to omit that step.

Start ttymidi.

./ttymidi -s /dev/ttyUSB0 &

It's not always clear what port the Arduino is on, especially if you are disconnecting and reconnecting it. Look in the /dev directory and see how many USB devices there are and try each one if you have to. Also remember process number so you can kill ttymidi when you need to reconnect the Arduino and restart ttymidi.

Now connect ttymidi to Timidity.


aconnect -i
aconnect -o
aconnect 129:0 128:0
or whatever input and output ports are reported respectively.

Restart Arduino and it should start playing notes.