HDDJ:hard drive as scrollwheel/turtable-like input

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.

you don't happen to have a schematic of how you wired this do you??

Thanks!

Cool idea,
modifying some old HDDs into a Set of Turntables to use with a live VSTi-Scratching PlugIn on a DAW sounds funny...
Schematics would be appreciated...
Thanks!

i don't have schematics handy, though i see how they would help a lot. i'll try to make some soon.

in the meantime, here's a brief description of the easiest way to do it: generally speaking, your taking weak signals from the stepper motor, amplifying them with opamps or one dual opamp, then passing the amplified signal to the arduino's analog inputs.

the stepper motor from the HD platter should have 4 connections. You can put 2 of them to ground and connect the other 2 to the positive or "non-inverting" inputs on a dual opamp like the lm358. put the negative inputs to ground and power the opamp as you normally would (should be a basic schematic in the datasheet). then connect the outputs to the arduino's analog inputs; i used analog pins 0 and 5 in my code.

if that's still confusing, i'll try to get schematics up soon.

Thanks so much!!! So you're not using any resistors?? I would recommend http://fritzing.org/ for creating schematics. I'm going to get some LM386 unless you think to get anything different.

Tanks, Fritzing is pretty cool, though it crashes a lot if I delete many objects. Still, it's really easy to use.

Here's a diagram I made with it. Sorry it took me so long to get around to this; I've been moving and a lot of my stuff has been packed up and hard to find.

Here's the Fritzing file:
http://mattgilbert.net/Indev/hddjarduino/hddjarduino%20diagram.fzz

The caps are .1uF, by the way.

Awesome!! Thanks so much, I really appreciate it. I actually got it set up using a similar wiring as the instructable, but I'm definitely going to test out this setup. I'll let you know how it goes!

i was trying now this , followed all of the schematic and its all as it should be , uploade code etc... however it still doesnt work :....

Is there somethin in particular i have to watch out ? my old hdd has only 2 platters but has 4 pinouts the motor as is should be... dont know why it doesnt work... its a hdd seagate st3491a

i wasn't able to get it working with the schematic shown either. I did though get it working with a lm324 and can post this schematic possibly tomorrow or sometime before the end of the week.

I just noticed that the resistor between pins 1 and 2 isn't wired up right. That little blue wire next to it should connect to the same row as the resistor, much like the resistor between pins 6 and 7.

well, i actually had it fixed like you said before and it still doesnt work... i am just changing the pinouts for the hdd but it isnt working any way :\

EDIT: Ok, now i inserted the LEDS again to see if its turning clock wise or counter clock wise... when i turn either way , the both leds turn on blinking .... i dont understand why he thinks im turning both ways if im only turning only to clock wise or then if i turn counter-clockwise

EDIT2: I also now noticed that the blinking leds of 2 until 8 (the ones that are blue in the video) mine are always lighted up but just the ones in position 1 and 5 , then after i changed the order of the cables to the motor and now the leds on position 2 and 4 were lighted up constantly, however either time i turn the platter on each way they never change and are always the same lighted up(one of them just blinks a lot)...

Hmm - I wonder if this could be made "simpler" by applying a waveform to one of the phases of the HD motor, and then reading the waveform from the other two phases as you turned the shaft (kinda like a weird variable transformer)...? Maybe setting up a PWM output to the phase, and reading the other two phases using analog pins. I kinda understand what the OP's idea is (basically using some form of residual EM in the rotor to generate a voltage that is read after being amplified - this can actually be done as well with larger AC motors to make electricity), but I am wondering if it is possible to eliminate the amplification stage...

EDIT: Ok, now i inserted the LEDS again to see if its turning clock wise or counter clock wise... when i turn either way , the both leds turn on blinking .... i dont understand why he thinks im turning both ways if im only turning only to clock wise or then if i turn counter-clockwise

EDIT2: I also now noticed that the blinking leds of 2 until 8 (the ones that are blue in the video) mine are always lighted up but just the ones in position 1 and 5 , then after i changed the order of the cables to the motor and now the leds on position 2 and 4 were lighted up constantly, however either time i turn the platter on each way they never change and are always the same lighted up(one of them just blinks a lot)...

This sounds like the "assumed_baseline" is off. For me it was 505, but I think I noticed it was different for different hard drives. Comment out the Serial.println's that are in there now (the ones that send MIDI), and insert some that print the values of val0 and/or val1. See what range of values they return as you turn the hard drive, and pick something in the middle. If one or both of them don't change, switch around the wires from the hard drive's stepper motor until you find that they do. Also check that the connections to the motor are good.

I hope this helps. I'm pretty sure it's just that the "assumed_baseline" is off.

Good luck!

Yeah i was trying yesterday night changing both thresholds and its true! i change it to more low and it works!!! i changed like 150+/- and is now more or less sensitive like your video !

Now i am thinking on a way to do a bridge between some music application to use it. you think is needed to build some kind of driver for it ?
If someone has an idea or some information of knowing how to use it with a music editing application that would be great!

Thank you so much for the help!

you can use processing to build a serial to midi or OSC converter which would allow you to use it with basically any application.

Or you can use the SpikenzieLabs converter:
http://www.spikenzielabs.com/SpikenzieLabs/Serial_MIDI.html

well, i am using now SpikenzieLabs converter, so then i convert the signal to MIDI, as i am seeing it looks like its recieving the signal , but to use on a application like MIXX (http://www.mixxx.org/), when im searching for midi devices it doesnt appear, it only lets me select my audio card...

You know if i need to dosomething more besides using the serial 2 midi converter?

well, i ran the software (SpikenzieLabs converter) and each time i turn the disk in the interface of that software it blinks a green icon on Rx, however the music software i was mentioning it isn't detecting the device, i search for MIDI devices and it doesnt detect nothing.... can someone help me why is not detecting ?

This is great, i am going to have one of these on my synth, selectable to any parameter :slight_smile: