Friday, February 21, 2014

Revitalizing old hard drive motors using Arduino

Hard drives use brushless motors (BLDC motors) 

Brushless motors are more durable than ordinary carbon brush motors because they lack a commutator (which is a brush rubbing a pair of cyclic magnets to reverse the direction of current)

For brushless motors they use electronic switches to reverse the current.
In BLDC motors the coils are wrapped on the stator, while the rotor has a permanent magnet attached to it.

However, it should be noted that a brushless motor cannot be driven by ordinary Direct Current.

This article tries to demonstrate how to run a Hard drive scraped BLDC motors by using a microcontroller/ rapid prototyping board Arduino.

This method is based on this video
http://www.youtube.com/watch?v=CMz2DYpos8w

Principles

Use Arduino sends pulses to Darlington Transistors.
There are 3 phases in the motor. Each phase is controlled by one Arduino Pin. 
For example, 

---------time---------------->
phase1pin:100100100
phase2pin:010010010
phase3pin:001001001
Fig 1

where 1 = High signal in Arduino pin, causing Darlington Transistor to supply current to the motor.

Scraping hard drive motors

You need:

Torx screw drivers (especially T8)
common screw drivers

Technique: No special attentions needed. Just unscrew them all. Some screws may be hidden under the label.


(There is a ribbon connected to the drive; DO NOT PULL it off because there are very thin wires which are connected to the coils of the motor inside. I suggest soldering additional wires like the photo above)

Testing which lead is common

Fig 2
Usually a hard disk BLDC is a 3-phase BLDC, which has 3 phases + 1 common = 4 wires

Use a multimeter to test for resistance on those 4 points:

A common lead + coil = 1x ohm
A coil + a coil = 2x ohm (Fig.2)

Then solder extending wires. In Fig. 1, the common wire is in black color.

Connecting to Arduino

Arduino:
- We need 3 digital pins to send the signal, say pin 2,3,4

Breadboard components:
- 1k ohm resistors *3
- TIP122 darlington pairs *3
- diode 1N4004 *3
- battery power 5 to 12V

Connect them as shown in Fig. 3 and Fig 4

Fig 3


Fig 4




Coding Arduino

Simple switching


const int phase1pin = 2;
const int phase2pin = 3;
const int phase3pin = 4;
const int delayTime = 6000; // microsecs

void setup(){
  Serial.begin(9600);
  pinMode(phase1pin, OUTPUT);
  pinMode(phase2pin, OUTPUT);
  pinMode(phase3pin, OUTPUT);
}

void loop(){
  switchStep(1);
  switchStep(2);
  switchStep(3);
}

void switchStep(int stage){
  switch(stage){
    case 1:
      digitalWrite(phase1pin, HIGH);
      digitalWrite(phase2pin, LOW);
      digitalWrite(phase3pin, LOW);
      delayMicroseconds(delayTime);
      break;
    case 2:
      digitalWrite(phase1pin, LOW);
      digitalWrite(phase2pin, HIGH);
      digitalWrite(phase3pin, LOW);
      delayMicroseconds(delayTime);
      break;
    case 3:
      digitalWrite(phase1pin, LOW);
      digitalWrite(phase2pin, LOW);
      digitalWrite(phase3pin, HIGH);
      delayMicroseconds(delayTime);
      break;
  }
}

Improved version

The phases overlap with the previous phase by 1/4 cycle to improve the rotation transition.
In this version the motor is slowly accelerating to the max speed.

Improved switching



const int phase1pin = 2;
const int phase2pin = 3;
const int phase3pin = 4;
float holdTime = 50000; // microsecs
const unsigned long minHoldTime = 1300;

unsigned long p1start,
              p1end,
              p2start,
              p2end,
              p3start,
              p3end;

void setup(){
  Serial.begin(9600);
  pinMode(phase1pin, OUTPUT);
  pinMode(phase2pin, OUTPUT);
  pinMode(phase3pin, OUTPUT);
  p1start = micros();
  digitalWrite(phase1pin, HIGH);
}


void chkP1(){
  unsigned long currentTime = micros();
  unsigned long td = currentTime - p1start;
  unsigned long refractory = 2.25*holdTime;
  if(digitalRead(phase1pin)){
    if(td > holdTime){
      digitalWrite(phase1pin, LOW);
      p1end = currentTime;
    }
  }else if(td > refractory){
    digitalWrite(phase1pin, HIGH);
    p1start = currentTime;
  }
}

void chkP2(){
  unsigned long currentTime = micros();
  unsigned long td = currentTime - p1start;
  if(digitalRead(phase2pin)){
    if(td > 1.75*holdTime || td < 0.75*holdTime){
      digitalWrite(phase2pin, LOW);
      p2end = currentTime;
    }
  }else if(td > 0.75*holdTime && td < 1.75*holdTime){
    digitalWrite(phase2pin, HIGH);
    p2start = currentTime;
  }
}

void chkP3(){
  unsigned long currentTime = micros();
  unsigned long td = currentTime - p1start;
  if(digitalRead(phase3pin)){
    if(td > 0.25*holdTime && p3start < p1start){
      digitalWrite(phase3pin, LOW);
      p3end = currentTime;
    }
  }else if(td > 1.5*holdTime){
    digitalWrite(phase3pin, HIGH);
    p3start = currentTime;
  }
}

void loop(){
  chkP1();
  chkP2();
  chkP3();
  delayMicroseconds(100);
  if(holdTime >= minHoldTime){
    holdTime -= 0.5;
  }
}


That's it.

For my 5400rpm hard disk motor, I used 3.7*3 = 11.1V
The min cycle period = 1.3ms
i.e. it takes about 1.3*2.25*2 = 5.85ms for 1 rev
=> about 10k rpm

Any further decrease in cycle period leads to an halt.

Increasing voltage allows shorter cycle period (prabably due to a stronger torque => higher rotation speed)

Addition info:

I dismantled / disassembled one of the BLDC motor, shown below:
The 4 wires were accidentally broken by me. So I punched the center of the axle to separate the rotor   
              

Please ignore the bearing in the middle. It is totally irrelevant and it belongs to my other projects.

29 comments:

  1. Hello, I was looking how to run old HDD stepper motor. Yesterday I found your article, build up the circuit, but something going wrong after 20 sec. Stepper motor stops spinning and I don't know what to do. Also stepper motor works only with second code. I wonder can you help me, because I don't know where to look for a problem.

    ReplyDelete
    Replies
    1. Hey, I tried the second code (the first code needs some modification to work) and i got the same errors and u did. The motor got locked after some 20s. To correct this this, like Hermann MK said, we have to determine the "optimum signal interval" (Kudos! Hermann MK for the article). To do that try increasing the value of "minHoldTime", until your motor starts running smoothly without locking. (in my case it was 2400us).

      Furthermore, if you want to increase/decrease the acceleration to reach the optimum speed, you can increase/decrease the signal hold interval shortening time. That is the final section of the code.
      E.g ( holdTime -=1; shortens the signal hold interval by 1us for every loop of 100us).

      Delete
  2. Hi. The second code is actually instructing the motor to spin faster and faster
    (as you can see in the main Loop, holdTime -= 0.5; i.e. For every 100us loop, the signal hold interval shortens by 0.5us).

    However, there are different limits for different motors. Since we dont have a hall sensor, we cant sense the position of the rotor. If the signal pulses are given too fast but the rotor cannot keep up with the speen, it will be stuck. So I think we have to determine the "optimum signal interval" by experience.

    ReplyDelete
  3. Stepper motors have usually a critical speed (or more than one) that resonate mechanically. At that speed the motor can stop with very small resistant couple, or even stop without any mechanical load connected. I guess this is not a problem for an HD cause they run at fixed speed, but for other uses this can be a problem

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. good job dude... and thanks for explaining everything :)

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Hello, but ir you use a push pull output stage obtain better response, you don't need center star coil connection, if you want use it center star use dual symmetrical power supply for power push pull stage and the center of star connected to GND power l, it improve full power at motor start better acceleration.

    ReplyDelete
    Replies
    1. Could you please send a link to Fritzing diagram of your solution?

      Thanks in advance,

      Kamil

      Delete
    2. I tried the Push Pull (complete electronics Noob here, understanding things slowly as I learn from the net)
      Example: 3 TIP127 (High Side) (triggered on off by 3 TIP122) 3 TIP 122 Low Side. Used the proper sequence after testing the motor. Commutations are A-B, B-C, C-A. Applied the same through Arduino code. Doesn't work.
      Could you please elaborate your concept.

      Delete
  8. Hi ... Motor how many KV ? How many rpm ?

    ReplyDelete
  9. http://www.pilottr.com/urun/iflight-ibm1811-13-2000kv-model-motor.html?srt=UP This engine is okay to use , is that it works with arduino code ?

    ReplyDelete
  10. I took out the motor out of a 14 year old Seagate Barracuda (7200rpm/blown up SMOOTH controller). It has only 3 wires (no center tap). I tried this circuit a month ago. Didn't Work. Had been banging my head for the entire month. Got a 30A ESC and Servo Tester. The Motor only WALTZed no matter what settings I tried. Even tried 3 TIP127 High Side Switches (controlled through 3 TIP122) coupled with 3 TIP122 Low Side Switches (through Arduino UNO).Didn't Work. Yesterday I decided to give this circuit another go. After Watching the video carefully, I connected one extra wire from Positive Rail directly to one of the leads of the motor. Now, the first code works but with slow speed. The second Shorts out as someone said, 20 seconds in.
    SO i used the code in the video (http://bartvenneker.nl/schemas/Code_arduino_hdd.txt) and kept on adjusting the "minStepLength". With the platter on, motor speeds up and maintains speed if value is above 4000. With no load, I could go down to 1600 with really good high rpm (supply of 12V).
    Problem: This is just a temporary solution and the TIP122 to whose Outgoing lead the Positive input is connected gets hot and is hotter than the other two. It still hasn't blown up though. Plus with this configuration I can hear a ticking sound from the motor. Most probably because it is not meant to be run this way and I think it will damage the windings in the long run.
    Can someone please, please suggest a work around??!!

    ReplyDelete
    Replies
    1. Based on the measurements I took on one I have with a 3-pin motor, I believe it's 3 coils and no common pin. I don't know that this design will work without the common lead.

      I'm no electrical engineer, but it looks like the power for the motor is carried on the common pin and then flows through the coils as each transistor is pulled to ground.

      Based on that, I think you'd have to run power to each of the 3 pins and not just to the one pin you had it wired to.

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. Hi, can i use a flip flop like 4047b with 3 different square waves to spin the motor?

    ReplyDelete
  14. Hi can anyone write that code to a pic in mikroc pro please

    ReplyDelete
  15. Hi, Im having the same problem as an above user. I only have 3 pins and no ground, suggestions? both codes are giving vibrations or very jerky motor movement

    ReplyDelete
  16. I'm curious about something before I go to try any build this myself.... What are the 1K resistors between the Arduino and the bases on the transistors?

    ReplyDelete
  17. I tried running a 5400rpm motor with the same circuit as you gave and the improved code but the motor is heating up like hell! i tried running it at lesser rpm also, but still the motor keeps heating up. Can you help me out?

    ReplyDelete
  18. I am currently working on a spin coater and stumbled across this blog. Using a wall plug as a 12v source instead of the batteries will work right? I would think they would be the same since they are both 12V DC source?

    ReplyDelete
  19. I have just disassembled a HDD to see if I can use the motor as a generator. But reading the comments above I have my doubts. But my real comment is to consider the coils as being in Delta format, not star. That would only require 3 pins. But each pin would have dual roles. If I was going further with this i would try and reverse engineer teh PC board that attached to the motor.

    ReplyDelete
  20. hello , nice work what the name is those specific transistors ?
    and if so what is there name or the number on it ?

    ReplyDelete
  21. any TTL level mosfet over 5 amps will do the job, I used overkill IRLZ44 but any IRL series MOSFET will work... then I acheived x2 speed with a smoother accel with this code :
    void loop(){
    chkP1();
    chkP2();
    chkP3();
    //delayMicroseconds(50);
    if(holdTime >= minHoldTime){
    if (previousup+200<micros()){
    previousup=micros();
    holdTime -= 0.5;
    if(holdTime< 2400){previousup +=20000; holdTime += 0.25;}

    // Serial.println(holdTime);
    }
    }
    }
    cheer's!

    ReplyDelete
    Replies
    1. sorry here is the full code :
      const int phase1pin = 2;
      const int phase2pin = 3;
      const int phase3pin = 4;
      float holdTime = 50000; // microsecs
      const unsigned long minHoldTime = 1600;//1300;

      unsigned long p1start,
      p1end,
      p2start,
      p2end,
      p3start,
      p3end;

      unsigned long previousup=0;

      void setup(){
      Serial.begin(9600);
      pinMode(phase1pin, OUTPUT);
      pinMode(phase2pin, OUTPUT);
      pinMode(phase3pin, OUTPUT);
      p1start = micros();
      digitalWrite(phase1pin, HIGH);
      }


      void chkP1(){
      unsigned long currentTime = micros();
      unsigned long td = currentTime - p1start;
      unsigned long refractory = 2.25*holdTime;
      if(digitalRead(phase1pin)){
      if(td > holdTime){
      digitalWrite(phase1pin, LOW);
      p1end = currentTime;
      }
      }else if(td > refractory){
      digitalWrite(phase1pin, HIGH);
      p1start = currentTime;
      }
      }

      void chkP2(){
      unsigned long currentTime = micros();
      unsigned long td = currentTime - p1start;
      if(digitalRead(phase2pin)){
      if(td > 1.75*holdTime || td < 0.75*holdTime){
      digitalWrite(phase2pin, LOW);
      p2end = currentTime;
      }
      }else if(td > 0.75*holdTime && td < 1.75*holdTime){
      digitalWrite(phase2pin, HIGH);
      p2start = currentTime;
      }
      }

      void chkP3(){
      unsigned long currentTime = micros();
      unsigned long td = currentTime - p1start;
      if(digitalRead(phase3pin)){
      if(td > 0.25*holdTime && p3start < p1start){
      digitalWrite(phase3pin, LOW);
      p3end = currentTime;
      }
      }else if(td > 1.5*holdTime){
      digitalWrite(phase3pin, HIGH);
      p3start = currentTime;
      }
      }

      void loop(){
      chkP1();
      chkP2();
      chkP3();
      //delayMicroseconds(50);
      if(holdTime >= minHoldTime){
      if (previousup+200<micros()){
      previousup=micros();
      holdTime -= 0.5;
      if(holdTime< 2400){previousup +=20000; holdTime += 0.25;}

      // Serial.println(holdTime);
      }
      }
      }

      Delete
  22. The facts confirm that fenced in areas were accessible at the time, however for reasons unknown buyers were not utilizing them all the time. A few walled in areas can be extremely hard to utilize in light of the fact that they expect screws to be loosened before a drive is even embedded. Discuss badly designed.Best hdd docks

    ReplyDelete
  23. Merkur 37C Progress Double Edge Safety Razor - deccasino.com
    Merkur 37C Progress Double Edge Safety Razor. The 제왕 카지노 Merkur Classic 1904 Double Edge Safety Razor features a chrome finished, chrome finished deccasino handle that  Rating: 4.7 · ‎5 reviews 카지노

    ReplyDelete
  24. I want to use this phase stepper motor for per degree revolution or microstepping. please suggest the way I prooceed.

    ReplyDelete