Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

424 lines
14 KiB

  1. It is fun to find an interesting use for old technology. Being someone who has
  2. tons of old floppy drives and loves music, I decided to turn my old floppy
  3. drives into an orchestra. I’m not sure where I first learned about musical
  4. floppy drives, however, there are thousands of videos on YouTube.
  5. This project first started over a year ago when I connected two floppy drives to
  6. a Raspberry Pi to play the Star Wars theme.
  7. <iframe width="100%" height="315" src="https://www.youtube.com/embed/wcnUvPMpqjA" frameborder="0" allow="autoplay;
  8. encrypted-media" allowfullscreen></iframe>
  9. Although this was fun, there was hardly any software for playing different music
  10. on the Raspberry Pi. I managed to hack the software to also play Jingle Bells,
  11. however, that took hours to input just a single song.
  12. A half a year ago I got an Arduino board and built a new and improved floppy
  13. drive orchestra.
  14. <iframe width="100%" height="315"
  15. src="https://www.youtube.com/embed/qwbcrR-6dTU" frameborder="0" allow="autoplay;
  16. encrypted-media" allowfullscreen></iframe>
  17. What is nice about using an Arduino, is that the software used is more
  18. developed. Unlike the program I used with the Raspberry Pi, the software used
  19. with the Arduino allows the songs to be loaded via a MIDI file.
  20. That brings us up to the present. My previous 8 floppy drive orchestra was not
  21. transportable and took up a ton of space. When I decided to present this project
  22. at Imagine RIT with RITLUG, I knew I had to rebuild my orchestra to be portable
  23. and compact.
  24. There are plenty of tutorials online demonstrating how to build floppy
  25. orchestras, but, many of them are incomplete. Since this was my third time
  26. building a floppy orchestra, I decided to log my process and make a complete
  27. tutorial for my blog.
  28. Hardware
  29. ========
  30. - 10 Floppy Drives
  31. - Arduino Uno
  32. - LOTS of Ribbon Cables
  33. - 1 Old Power Supply
  34. - Hot Glue
  35. - Solder
  36. In in addition to these materials, you will also want something to mount your
  37. floppy drives to. I decided to use 2x2’s and half inch screws because they are
  38. cheep and I had some laying around my house.
  39. Assembly
  40. ========
  41. The first thing you should do is secure your floppy drives.
  42. ![Floppy Drives](media/f8802f1f71cb433274d265fc81e36fc6.jpg)
  43. Now, it is time to power the floppy drives and turn them on. To make the floppy
  44. drives turn on, you need to connect pins 11 and 12 on your floppy drives
  45. together. You can easily do this with a single ribbon cable.
  46. ![Floppy Drives pin configuration](media/5b7a15fd7b5da2939f4e27eae4ceada3.jpg)
  47. ![Floppy drives connected together](media/09bce0ed13f28db38a141bd10bb096c8.jpg)
  48. You can use an old power supply for this project. Since we are only using the
  49. stepper motor in the floppy drives, you only need to supply 5v. Each floppy
  50. drive has four power connectors, the middle two pins are ground, and the right
  51. pin is 5v and the left pin 12v. Since I had ten floppy drives to power, I used a
  52. bread board to avoid excessive soldering.
  53. To turn on a power supply you simply connect the green wire to any ground wire.
  54. If you want to get fancy, you can solder on a switch, however, must people just
  55. jam a paper clip into the motherboard connector.
  56. FWI: The red wires in your power supply are 5v and the black wires are ground.
  57. **Warning**: Do not draw all your power from the power supply via a single
  58. ribbon cable, it will melt. Ribbon cables have low gauge and are not meant for
  59. high wattages. It is good idea to use multiple 5v lines from your power supply
  60. and make sure that nowhere in your wiring is all the voltage going through a
  61. single ribbon cable.
  62. ![Musical floppy drives wired together](media/5ebac37ad45784c31219451d6e4c4504.jpg)
  63. If you have done everything correct up to this point, you will see the green
  64. lights on the floppy drives turn on when the power supply is running.
  65. Now we need to connect the pins of the floppy drive to the Arduino.
  66. Personally, I started by connecting pin 19 on the floppy drive to the ground pin
  67. on the Arduino. Again, I used a bread board to make the connections easier.
  68. ![Floppy drives pin io](media/d0888a3222fa328c291629fac491e268.jpg)
  69. ![Floppy drives connected to uno](media/463f2aa188466da8f47309235039250c.jpg)
  70. Next, we need to wire the step and direction pins of the floppy drives to the
  71. Arduino.
  72. ![Floppy drives pin diagram](media/81ffef0249da3c1fc077d114fb6beecb.jpg)
  73. Connect direction pin 18 on the floppy drive to pin 3 of the Arduino and step
  74. pin 20 to pin 2 of the Arduino. For additional floppy drives you follow the same
  75. pattern. For example, the next drive would be floppy pin 18 to Arduino pin 5 and
  76. floppy pin 20 to Arduino pin 4. If you are using something other than an Arduino
  77. Uno board this will potentially be different. We are using these specific pins
  78. on the Arduino because they correspond to this specific program.
  79. ![Floppy drives wired together with power supply](media/50dc96254f26b730e842134db98c9966.jpg)
  80. While making this, I had 4 sets of pins (8 total) connected to the Arduino,
  81. however, I have 10 floppy drives in total. I wired two sets of three drives and
  82. two sets of two drives together on the same Arduino “channel”. This makes the
  83. wiring easier and makes the sound better. Not all floppy drives sound the same,
  84. by pairing drives together you get a richer sound. Since I want to present this
  85. live, it also makes it louder for the audience.
  86. This is a ton of wiring! After you verify that the drives are working properly,
  87. I would strongly recommend using hot glue to secure ribbon cables to the drives.
  88. That’s it. Now your floppy drives should be good to go.
  89. Software
  90. ========
  91. This is the section where most other tutorials fall short. Please follow along
  92. carefully. First, have the following installed on your computer.
  93. - Arduino Software
  94. - NetBeans
  95. - JDK 1.8 – or higher
  96. Next download
  97. [timer1](https://code.google.com/archive/p/arduino-timerone/downloads) and
  98. [Moppy](https://github.com/SammyIAm/Moppy). Install timer one by extracting the
  99. files and copying the folder timer1 into the libraries folder under your root
  100. Arduino directory.
  101. Open up your Arduino software and paste the following code in the editor:
  102. ```
  103. #include <TimerOne.h>
  104. #define RESOLUTION1 40
  105. boolean firstRun = true; // Used for one-run-only stuffs;
  106. //First pin being used for floppies, and the last pin. Used for looping over all pins.
  107. const byte FIRST_PIN = 2;
  108. const byte PIN_MAX = 17;
  109. /*NOTE: Many of the arrays below contain unused indexes. This is
  110. to prevent the Arduino from having to convert a pin input to an alternate
  111. array index and save as many cycles as possible. In other words information
  112. for pin 2 will be stored in index 2, and information for pin 4 will be
  113. stored in index 4.*/
  114. /*An array of maximum track positions for each step-control pin. Even pins
  115. are used for control, so only even numbers need a value here. 3.5" Floppies have
  116. 80 tracks, 5.25" have 50. These should be doubled, because each tick is now
  117. half a position (use 158 and 98).
  118. */
  119. byte MAX_POSITION[] = {
  120. 0,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0};
  121. //Array to track the current position of each floppy head. (Only even indexes (i.e. 2,4,6...) are used)
  122. byte currentPosition[] = {
  123. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  124. /*Array to keep track of state of each pin. Even indexes track the control-pins for toggle purposes. Odd indexes
  125. track direction-pins. LOW = forward, HIGH=reverse
  126. */
  127. int currentState[] = {
  128. 0,0,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW
  129. };
  130. //Current period assigned to each pin. 0 = off. Each period is of the length specified by the RESOLUTION1
  131. //variable above. i.e. A period of 10 is (RESOLUTION1 x 10) microseconds long.
  132. unsigned int currentPeriod[] = {
  133. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  134. };
  135. //Current tick
  136. unsigned int currentTick[] = {
  137. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  138. };
  139. //Setup pins (Even-odd pairs for step control and direction
  140. void setup(){
  141. pinMode(13, OUTPUT);// Pin 13 has an LED connected on most Arduino boards
  142. pinMode(2, OUTPUT); // Step control 1
  143. pinMode(3, OUTPUT); // Direction 1
  144. pinMode(4, OUTPUT); // Step control 2
  145. pinMode(5, OUTPUT); // Direction 2
  146. pinMode(6, OUTPUT); // Step control 3
  147. pinMode(7, OUTPUT); // Direction 3
  148. pinMode(8, OUTPUT); // Step control 4
  149. pinMode(9, OUTPUT); // Direction 4
  150. pinMode(10, OUTPUT); // Step control 5
  151. pinMode(11, OUTPUT); // Direction 5
  152. pinMode(12, OUTPUT); // Step control 6
  153. pinMode(13, OUTPUT); // Direction 6
  154. pinMode(14, OUTPUT); // Step control 7
  155. pinMode(15, OUTPUT); // Direction 7
  156. pinMode(16, OUTPUT); // Step control 8
  157. pinMode(17, OUTPUT); // Direction 8
  158. Timer1.initialize(RESOLUTION1); // Set up a timer at the defined resolution
  159. Timer1.attachInterrupt(tick); // Attach the tick function
  160. Serial.begin(9600);
  161. }
  162. void loop(){
  163. //The first loop, reset all the drives, and wait 2 seconds...
  164. if (firstRun)
  165. {
  166. firstRun = false;
  167. resetAll();
  168. delay(2000);
  169. }
  170. //Only read if we have
  171. if (Serial.available() > 2){
  172. //Watch for special 100-message to reset the drives
  173. if (Serial.peek() == 100) {
  174. resetAll();
  175. //Flush any remaining messages.
  176. while(Serial.available() > 0){
  177. Serial.read();
  178. }
  179. }
  180. else{
  181. currentPeriod[Serial.read()] = (Serial.read() << 8) | Serial.read();
  182. }
  183. }
  184. }
  185. /*
  186. Called by the timer inturrupt at the specified resolution.
  187. */
  188. void tick()
  189. {
  190. /*
  191. If there is a period set for control pin 2, count the number of
  192. ticks that pass, and toggle the pin if the current period is reached.
  193. */
  194. if (currentPeriod[2]>0){
  195. currentTick[2]++;
  196. if (currentTick[2] >= currentPeriod[2]){
  197. togglePin(2,3);
  198. currentTick[2]=0;
  199. }
  200. }
  201. if (currentPeriod[4]>0){
  202. currentTick[4]++;
  203. if (currentTick[4] >= currentPeriod[4]){
  204. togglePin(4,5);
  205. currentTick[4]=0;
  206. }
  207. }
  208. if (currentPeriod[6]>0){
  209. currentTick[6]++;
  210. if (currentTick[6] >= currentPeriod[6]){
  211. togglePin(6,7);
  212. currentTick[6]=0;
  213. }
  214. }
  215. if (currentPeriod[8]>0){
  216. currentTick[8]++;
  217. if (currentTick[8] >= currentPeriod[8]){
  218. togglePin(8,9);
  219. currentTick[8]=0;
  220. }
  221. }
  222. if (currentPeriod[10]>0){
  223. currentTick[10]++;
  224. if (currentTick[10] >= currentPeriod[10]){
  225. togglePin(10,11);
  226. currentTick[10]=0;
  227. }
  228. }
  229. if (currentPeriod[12]>0){
  230. currentTick[12]++;
  231. if (currentTick[12] >= currentPeriod[12]){
  232. togglePin(12,13);
  233. currentTick[12]=0;
  234. }
  235. }
  236. if (currentPeriod[14]>0){
  237. currentTick[14]++;
  238. if (currentTick[14] >= currentPeriod[14]){
  239. togglePin(14,15);
  240. currentTick[14]=0;
  241. }
  242. }
  243. if (currentPeriod[16]>0){
  244. currentTick[16]++;
  245. if (currentTick[16] >= currentPeriod[16]){
  246. togglePin(16,17);
  247. currentTick[16]=0;
  248. }
  249. }
  250. }
  251. void togglePin(byte pin, byte direction_pin) {
  252. //Switch directions if end has been reached
  253. if (currentPosition[pin] >= MAX_POSITION[pin]) {
  254. currentState[direction_pin] = HIGH;
  255. digitalWrite(direction_pin,HIGH);
  256. }
  257. else if (currentPosition[pin] <= 0) {
  258. currentState[direction_pin] = LOW;
  259. digitalWrite(direction_pin,LOW);
  260. }
  261. //Update currentPosition
  262. if (currentState[direction_pin] == HIGH){
  263. currentPosition[pin]--;
  264. }
  265. else {
  266. currentPosition[pin]++;
  267. }
  268. //Pulse the control pin
  269. digitalWrite(pin,currentState[pin]);
  270. currentState[pin] = ~currentState[pin];
  271. }
  272. //
  273. //// UTILITY FUNCTIONS
  274. //
  275. //Not used now, but good for debugging...
  276. void blinkLED(){
  277. digitalWrite(13, HIGH); // set the LED on
  278. delay(250); // wait for a second
  279. digitalWrite(13, LOW);
  280. }
  281. //For a given controller pin, runs the read-head all the way back to 0
  282. void reset(byte pin)
  283. {
  284. digitalWrite(pin+1,HIGH); // Go in reverse
  285. for (byte s=0;s<MAX_POSITION[pin];s+=2){ //Half max because we're stepping directly (no toggle)
  286. digitalWrite(pin,HIGH);
  287. digitalWrite(pin,LOW);
  288. delay(5);
  289. }
  290. currentPosition[pin] = 0; // We're reset.
  291. digitalWrite(pin+1,LOW);
  292. currentPosition[pin+1] = 0; // Ready to go forward.
  293. }
  294. //Resets all the pins
  295. void resetAll(){
  296. // Old one-at-a-time reset
  297. //for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
  298. // reset(p);
  299. //}
  300. // New all-at-once reset
  301. for (byte s=0;s<80;s++){ // For max drive's position
  302. for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
  303. digitalWrite(p+1,HIGH); // Go in reverse
  304. digitalWrite(p,HIGH);
  305. digitalWrite(p,LOW);
  306. }
  307. delay(5);
  308. }
  309. for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
  310. currentPosition[p] = 0; // We're reset.
  311. digitalWrite(p+1,LOW);
  312. currentState[p+1] = 0; // Ready to go forward.
  313. }
  314. }
  315. ```
  316. ![Arduino program screenshot](media/23c6ad380e3224fbcd0c8d28cbecac23.png)
  317. Now you can upload this script to your Arduino.
  318. ![Arduino Uno serial COM settings](media/0b9d25d56269d39f60177b6b29a882da.png)
  319. If you get any errors about your COM port, make sure that your Arduino is set to
  320. listen on COM1 under the Device manager –Windows only.
  321. If that works, you can now open Moppy through Netbeans and start playing with
  322. your musical floppy drives.
  323. ![Moppy control application](media/161edc628257e8a2f92086c5987dcf0f.png)
  324. For a great package of MIDI music to use check out
  325. [MrSolidSnake](https://github.com/coon42/Floppy-Music--midis-). Not all MIDI
  326. songs work well with floppy drives. Songs with too many tracks obviously won’t
  327. work well. Songs with high notes will sound terrible on floppy drives since they
  328. will grind their motors. Also, long notes don’t sound good because the floppy
  329. drives just spin back and forth. MrSolidSnake did a wonderful job at compiling a
  330. bunch of MIDI files that work’s well with floppy drives.
  331. I hope that this tutorial was helpful.
  332. <iframe width="100%" height="315" src="https://www.youtube.com/embed/X0FeJPFKpQw" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>