I got an old hard drive working as a rotary input for the arduino (controlling a shoddy max patch at the moment):
Based on this instructable:
http://www.instructables.com/id/HDDJ_Turning_an_old_hard_disk_drive_into_a_rotary/
Basically, turning a stepper motor like the one that spins an HD platter creates nice sine-wave pulses out of phase from each other. Once amplified (with LM386's in my case), they can be used as analog inputs. By comparing the pulses you can figure out which direction the platter is being turned. I then used that info to send MIDI commands over usb using this serial/midi converter:
http://www.spikenzielabs.com/SpikenzieLabs/Serial_MIDI.html
and a quick max patch i threw together. MIDI note "0" means a counter-clockwise turn, MIDI note "1" means a clockwise turn.
There's more details on getting the signals from the hard drive motor on the instructable, although I only needed 2 sine waves and I think they used 3. Here's the arduino code:
/*********************************************************************************************/
//
// HDDJ with an Arduino
// by: Matt Gilbert
// Thanks nvillar for the Instructable that got me started:
// http://www.instructables.com/id/HDDJ_Turning_an_old_hard_disk_drive_into_a_rotary/
//
/*********************************************************************************************/
#define LEDNUMBER 7
#define LINEINPIN0 0
#define LINEINPIN1 5
#define CWLED 11 //clockwise indicator led
#define CCWLED 12 //counter clockwise indicator led
int threshold_offset = 8; // Fix this to be a little bit above zero.
// Too close to the baseline makes noise interfere. Too far
// away from the baseline and it works, but you have to spin the
// platter faster to get a signal.
//
// If it behaves erratically, raise this value a bit. If it isn't
// sensitive enough, lower it.
int assumed_baseline = 505;// For me the baseline was arround 505.
int threshold = assumed_baseline + threshold_offset;
int threshold2 = assumed_baseline - threshold_offset;
int state_changes = 0;
int state = 0;
int state_changes_per_tick = 1;
int val0 = 0; // Variable to store the analogRead() value.
int val1 = 0; // Variable to store the analogRead() value.
int ledPins[] = { 2, 3, 4, 5, 6, 7, 8 }; // You can change the Pins here ;)
void setup() {
Serial.begin(57600);
for (int thisLed = 0; thisLed < LEDNUMBER; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT);
}
pinMode(CWLED, OUTPUT);
pinMode(CCWLED, OUTPUT);
}
int ticks = 0;
void loop() {
// We will find the current state and
// by comparing that to the previous state, we can find the direction of the rotation.
int this_state = 0;
int direction = 0;
// read the analog values from 2 of the stepper motor coils
val0 = analogRead(LINEINPIN0);
val1 = analogRead(LINEINPIN1);
// get the magnitude of the difference between the 2 inputs. might be useful.
int d_val = abs(val1 - val0);
// Now that we've read the values of the coils, we can detect the "state"
// of the hard disk's rotation. From there we can find the direction of turn.
//
// The coils make sine waves that are a little out of phase, meaning
// one rises before the other, they are both high for a moment, then
// the same one falls before the other as well. Using that rhythm, we
// can define several states (This would be easier to explain graphically):
// : both coils near baseline (do nothing)
// 0: one above +threshold, one near baseline
// 1: both above +threshold, the first higher than the second
// 2: both above +threshold, the second higher than the first
// 3: one near baseline again, the other above +threshold
// : both coils near baseline again (do nothing, since we cant distinguish this state with the first one)
// 4: one below -threshold, one near baseline
// 5: both below -threshold, one lower than the other
// 6: both below -threshold, one higher than the other
// 7: one near baseline, the other below -threshold
// (back to the beginning)
//
if( val0 < threshold && val0 > threshold2
&& val1 < threshold && val1 > threshold2){
// don't change anything, since it could be several states, and noise wouldbe very bad anyway.
} else if( val0 < threshold && val0 > threshold2
&& val1 >= threshold){
this_state = 0;
} else if( val0 >= threshold && val1 >= threshold){
if(val1 > val0){
this_state = 1;
} else {
this_state = 2;
}
} else if( val0 >= threshold
&& val1 < threshold && val1 >= threshold2){
this_state = 3;
} else if( val0 < threshold && val0 > threshold2 // going below the baseline now
&& val1 <= threshold2){
this_state = 4;
} else if( val0 <= threshold2 && val1 <= threshold2){
if(val1 < val0){
this_state = 5;
} else {
this_state = 6;
}
} else if( val0 <= threshold2
&& val1 < threshold && val1 >= threshold2){
this_state = 7;
}
// Now that we know this state and the previous state, we can compare them
// to find the direction of rotation. For example, if the previous state was
// "2" and this one is "3", that one direction, say clockwise, or 1. If the previous state was "3"
// and this state is "2", that's the opposite direction, counter-clockwise, -1. If direction
// remains 0, we assume there was no movement.
if(this_state != state){
if(this_state == state+1 || (this_state == 0 && state == 7)){
state_changes++;
}
if(this_state == state-1 || (this_state == 7 && state == 0)){
state_changes--;
}
state = this_state;
}
if(state_changes > state_changes_per_tick){
direction = 1;
state_changes=0;
} else if(state_changes < -state_changes_per_tick){
direction = -1;
state_changes = 0;
}
// Now do something with the direction, whatever you like really.
// I'm sending serial/MIDI notes, 1 meaning a clockwise step and
// 0 meaning a counter-clockwise step.
// I'm also incrementing a value, "ticks" then displaying it by lighting 1 of 4 LEDs
// and showing clockwise and counter-clockwise on 2 other LEDs
if(direction == 1){
Serial.print(144, BYTE); // NOTE ON
Serial.print(1, BYTE); // note byte. 1 means clockwise step.
Serial.print(127, BYTE); // velocity (not used at the moment);
ticks += 1;
if(ticks > 4){
ticks = 0;
}
} else if(direction == -1){
Serial.print(144, BYTE); // NOTE ON
Serial.print(0, BYTE); // note byte. 0 means counter-clockwise step
Serial.print(127, BYTE); // velocity (not used at the moment);
ticks -= 1;
if(ticks < 0){
ticks = 4;
}
}
if(ticks == 0){
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
} else if(ticks == 1){
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
} else if(ticks == 2){
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
} else if(ticks == 3){
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
} else if(ticks == 4){
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
}
// clockwise and counter-clockwise indicator LEDs
if(direction == -1){
digitalWrite(CWLED, HIGH);
digitalWrite(CCWLED, LOW);
} else if(direction == 0){
digitalWrite(CWLED, LOW);
digitalWrite(CCWLED, LOW);
} else if(direction == 1){
digitalWrite(CCWLED, HIGH);
digitalWrite(CWLED, LOW);
}
}
By the way, if you do this I highly recommend removing the read/write arm and anything else unnecessary, or you might cut your finger like I did if you get into it.