Project Title

Double Transducer

Video and Photos

Our completed double transducer with labels.

Input IR sensor to detect linear distance.

DC motor with IR sensor below to detect fan rotation speed.

Output speaker to produce pitch at different sound volumes.

Overall physical layout of our model.

Simple Narrative Description

There is a sensor on the side that tells a motor to start spinning faster once it detects when something is moving closer towards it. Another sensor reads in the speed of the motor’s rotation and tells a speaker to decrease its volume in response to faster rotation.

Progress Photos

We began by trying to figure out the wiring for the IR photosensor to read in distance values.

We tested out the DC motor at varying speeds depending on amount of voltage passed through.

We tested out the LCD display with varying sensor value inputs.

Discussion

To build our project, it was difficult to first approach all these new components we’d never worked with before. This project went through several iterations before we finally settled on our current design. We had considered using rotation angle as our intermediary step since we could use the hobby servo motor, which we were already familiar with. However, in the end we decided to go with rotation speed because although less familiar, it seemed to be a fun challenge.

Surprisingly the smaller mistakes often caused us the most trouble. For a long time we couldn’t figure out why the speaker wasn’t producing noise, and it turned out the speaker pin was just defined as the wrong number. The wiring for the IR proximity sensor also wasn’t working before we realized it was because we were just missing the pull down resistor at the side. For later components, we noted it was important to wire things carefully and pay attention to all the details of a schematic. In addition, mapping the values caused issues because we were giving the incorrect ranges. We realized it would be much easier to tackle this project one component at a time rather than a bit of everything at once as it would help isolate where errors were occurring.

One of the biggest challenges to tackle for this project was figuring out a way to measure rotation speed. Because there was no component which could directly read in speed, we had to get creative with our options. The Internet was mostly a useful resource as there were online tutorials to help us navigate through working with unfamiliar libraries and parts. But in this case, we over complicated things by trying to follow confusing online tachometer tutorials. In the end, we decided it would be better to take our own approach. We used an IR sensor and distance calculations to track rpm. It was a much easier solution as we got to reuse the same component, just repurposed as a tachometer.

For future improvements, we could try cleaning up the appearance of the physical model, and it might be nice to build a container to hide the messy wires. Despite all our setbacks, we were able to put everything together and get a successful transducer working. We learned not to overcomplicate simple tasks and to tackle future projects with the bigger picture in mind. Overall, this project was a good learning experience as we learned how to use new parts and apply creative problem solving.

Schematic

Code Submission

  1. <span class="com">/*
  2. * Project Title: Double Transducer
  3. *
  4. * Description: This code reads change in linear distance through
  5. * an IR sensor. A motor's fan spins with a faster speed in response
  6. * to closer distances and a slower speed in response to further
  7. * distances. Another IR sensor acts as a tachometer by reading in
  8. * the rotation speed of the fan by tracking # rotations per second.
  9. * An output speaker's volume decreases in response to faster fan
  10. * rotation speeds and increases with slower speeds. An LCD screen
  11. * displays updated status of these sensor & actuator states.
  12. *
  13. * Pin mapping:
  14. *
  15. * pin | mode | description
  16. * ------|--------|------------
  17. * A4 input IR sensor (input)
  18. * A0 input IR sensor (tachometer)
  19. * 9 output sound speaker pin
  20. * 6 output motor pin
  21. *
  22. * Credit: Incorporated timer-based periodic update code
  23. * from the course website:
  24. * https://courses.ideate.cmu.edu/60-223/s2020/reference/class-log
  25. *
  26. */</span><span class="pln">
  27. </span><span class="com">#include</span><span class="pln"> </span><span class="str"><NewPing.h></span><span class="pln">
  28. </span><span class="com">#include</span><span class="pln"> </span><span class="str"><Servo.h></span><span class="pln">
  29. </span><span class="com">#include</span><span class="pln"> </span><span class="str"><Wire.h></span><span class="pln">
  30. </span><span class="com">#include</span><span class="pln"> </span><span class="str"><LiquidCrystal_I2C.h></span><span class="pln">
  31. </span><span class="com">#include</span><span class="pln"> </span><span class="str">"Volume3.h"</span><span class="pln">
  32. </span><span class="com">#define</span><span class="pln"> PHOTOPIN1 A4 </span><span class="com">// input IR sensor</span><span class="pln">
  33. </span><span class="com">#define</span><span class="pln"> PHOTOPIN2 A0 </span><span class="com">// rpm measurement IR sensor </span><span class="pln">
  34. </span><span class="com">#define</span><span class="pln"> SPEAKER_PIN </span><span class="lit">9</span><span class="pln"> </span><span class="com">// sound speaker</span><span class="pln">
  35. </span><span class="com">#define</span><span class="pln"> MOTORPIN </span><span class="lit">6</span><span class="pln"> </span><span class="com">// DC motor pin</span><span class="pln">
  36. </span><span class="com">#define</span><span class="pln"> FREQUENCY </span><span class="lit">440</span><span class="pln"> </span><span class="com">// pitch for speaker to play</span><span class="pln">
  37. </span><span class="typ">Servo</span><span class="pln"> steeringMotor</span><span class="pun">;</span><span class="pln"> </span><span class="com">// create motor object</span><span class="pln">
  38. </span><span class="typ">LiquidCrystal_I2C</span><span class="pln"> screen</span><span class="pun">(</span><span class="lit">0x27</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// create LCD display object</span><span class="pln">
  39. </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> timer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// variable for timing LCD</span><span class="pln">
  40. </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> timer2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// variable for timing rpm</span><span class="pln">
  41. </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> INTERVAL </span><span class="pun">=</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln"> </span><span class="com">// milliseconds between LCD updates</span><span class="pln">
  42. </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> INTERVAL2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">;</span><span class="pln"> </span><span class="com">// milliseconds between rps updates</span><span class="pln">
  43. </span><span class="typ">uint16_t</span><span class="pln"> frequency </span><span class="pun">=</span><span class="pln"> </span><span class="lit">440</span><span class="pun">;</span><span class="pln"> </span><span class="com">// speaker tone frequency</span><span class="pln">
  44. </span><span class="com">// val to store previous distance in rpm sensor</span><span class="pln">
  45. </span><span class="kwd">int</span><span class="pln"> photoVal2prev </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  46. </span><span class="kwd">int</span><span class="pln"> rotations </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  47. </span><span class="kwd">int</span><span class="pln"> rps </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// how many rotations per sec</span><span class="pln">
  48. </span><span class="kwd">int</span><span class="pln"> lastCycle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  49. </span><span class="com">// update display of sensor & actuator states (4-10x per sec)</span><span class="pln">
  50. </span><span class="kwd">void</span><span class="pln"> updateScreen</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> m1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> m2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> o</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  51. </span><span class="com">// map states within 0-99 range</span><span class="pln">
  52. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  53. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">800</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print input</span><span class="pln">
  54. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  55. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print m1</span><span class="pln">
  56. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  57. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print m2</span><span class="pln">
  58. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  59. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">90</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print output</span><span class="pln">
  60. </span><span class="pun">}</span><span class="pln">
  61. </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  62. </span><span class="typ">Serial</span><span class="pun">.</span><span class="kwd">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln"> </span><span class="com">// open serial monitor at 9600 baud </span><span class="pln">
  63. pinMode</span><span class="pun">(</span><span class="pln">PHOTOPIN1</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// input IR sensor</span><span class="pln">
  64. pinMode</span><span class="pun">(</span><span class="pln">PHOTOPIN2</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// tachometer IR sensor</span><span class="pln">
  65. pinMode</span><span class="pun">(</span><span class="pln">MOTORPIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// DC motor</span><span class="pln">
  66. pinMode</span><span class="pun">(</span><span class="pln">SPEAKER_PIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// sound speaker</span><span class="pln">
  67. </span><span class="com">// start screen and print value labels</span><span class="pln">
  68. screen</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln">
  69. screen</span><span class="pun">.</span><span class="pln">backlight</span><span class="pun">();</span><span class="pln">
  70. screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
  71. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"i:"</span><span class="pun">);</span><span class="pln">
  72. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  73. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"m:"</span><span class="pun">);</span><span class="pln">
  74. screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  75. screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"o:"</span><span class="pun">);</span><span class="pln">
  76. </span><span class="pun">}</span><span class="pln">
  77. </span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  78. </span><span class="com">// sense linear distance from IR sensors</span><span class="pln">
  79. </span><span class="kwd">int</span><span class="pln"> photoVal1 </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">PHOTOPIN1</span><span class="pun">);</span><span class="pln">
  80. </span><span class="kwd">int</span><span class="pln"> photoVal2 </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">PHOTOPIN2</span><span class="pun">);</span><span class="pln">
  81. </span><span class="com">// set rotation speed (spin faster at closer distance)</span><span class="pln">
  82. </span><span class="kwd">int</span><span class="pln"> motorSpeed </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">photoVal1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">800</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">);</span><span class="pln">
  83. analogWrite</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> motorSpeed</span><span class="pun">);</span><span class="pln">
  84. </span><span class="com">// measure motor fan rotation speed</span><span class="pln">
  85. </span><span class="kwd">int</span><span class="pln"> difference </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  86. </span><span class="com">// check change in distance </span><span class="pln">
  87. </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">photoVal2prev </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  88. difference </span><span class="pun">=</span><span class="pln"> photoVal2 </span><span class="pun">-</span><span class="pln"> photoVal2prev</span><span class="pun">;</span><span class="pln">
  89. </span><span class="com">// when gap is detected, one full cycle completed</span><span class="pln">
  90. </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">difference </span><span class="pun">></span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  91. </span><span class="com">// increment rotations</span><span class="pln">
  92. rotations</span><span class="pun">++;</span><span class="pln">
  93. </span><span class="pun">}</span><span class="pln">
  94. photoVal2prev </span><span class="pun">=</span><span class="pln"> photoVal2</span><span class="pun">;</span><span class="pln">
  95. </span><span class="com">// update value for rotations per second</span><span class="pln">
  96. </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> timer2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  97. rps </span><span class="pun">=</span><span class="pln"> rotations</span><span class="pun">;</span><span class="pln">
  98. rotations </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  99. timer2 </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> INTERVAL2</span><span class="pun">;</span><span class="pln"> </span><span class="com">// update timer</span><span class="pln">
  100. </span><span class="pun">}</span><span class="pln">
  101. </span><span class="com">// generate sound volume in response to rps</span><span class="pln">
  102. </span><span class="kwd">int</span><span class="pln"> volume </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">rps</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln"> </span><span class="lit">600</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  103. vol</span><span class="pun">.</span><span class="pln">tone</span><span class="pun">(</span><span class="pln">SPEAKER_PIN</span><span class="pun">,</span><span class="pln"> FREQUENCY</span><span class="pun">,</span><span class="pln"> volume</span><span class="pun">);</span><span class="pln">
  104. </span><span class="com">// update LCD screen display</span><span class="pln">
  105. </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> timer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  106. updateScreen</span><span class="pun">(</span><span class="pln">photoVal1</span><span class="pun">,</span><span class="pln"> motorSpeed</span><span class="pun">,</span><span class="pln"> rps</span><span class="pun">,</span><span class="pln"> volume</span><span class="pun">);</span><span class="pln">
  107. timer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> INTERVAL</span><span class="pun">;</span><span class="pln"> </span><span class="com">// update timer</span><span class="pln">
  108. </span><span class="pun">}</span><span class="pln">
  109. </span><span class="pun">}</span>
<span class="com">/*
 * Project Title: Double Transducer
 * 
 * Description: This code reads change in linear distance through 
 * an IR sensor. A motor's fan spins with a faster speed in response 
 * to closer distances and a slower speed in response to further 
 * distances. Another IR sensor acts as a tachometer by reading in 
 * the rotation speed of the fan by tracking # rotations per second.
 * An output speaker's volume decreases in response to faster fan 
 * rotation speeds and increases with slower speeds. An LCD screen 
 * displays updated status of these sensor & actuator states.
 * 
 * Pin mapping:
 * 
 * pin   | mode   | description
 * ------|--------|------------
 * A4      input     IR sensor (input)
 * A0      input     IR sensor (tachometer)
 *  9      output    sound speaker pin
 *  6      output    motor pin
 * 
 * Credit: Incorporated timer-based periodic update code 
 * from the course website: 
 * https://courses.ideate.cmu.edu/60-223/s2020/reference/class-log
 * 
 */</span><span class="pln">

</span><span class="com">#include</span><span class="pln"> </span><span class="str"><NewPing.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><Servo.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><Wire.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><LiquidCrystal_I2C.h></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">"Volume3.h"</span><span class="pln">

</span><span class="com">#define</span><span class="pln"> PHOTOPIN1 A4 </span><span class="com">// input IR sensor</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> PHOTOPIN2 A0 </span><span class="com">// rpm measurement IR sensor </span><span class="pln">
</span><span class="com">#define</span><span class="pln"> SPEAKER_PIN </span><span class="lit">9</span><span class="pln"> </span><span class="com">// sound speaker</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> MOTORPIN </span><span class="lit">6</span><span class="pln"> </span><span class="com">// DC motor pin</span><span class="pln">
</span><span class="com">#define</span><span class="pln"> FREQUENCY </span><span class="lit">440</span><span class="pln"> </span><span class="com">// pitch for speaker to play</span><span class="pln">

</span><span class="typ">Servo</span><span class="pln"> steeringMotor</span><span class="pun">;</span><span class="pln"> </span><span class="com">// create motor object</span><span class="pln">
</span><span class="typ">LiquidCrystal_I2C</span><span class="pln"> screen</span><span class="pun">(</span><span class="lit">0x27</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// create LCD display object</span><span class="pln">

</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> timer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// variable for timing LCD</span><span class="pln">
</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> timer2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// variable for timing rpm</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> INTERVAL </span><span class="pun">=</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln"> </span><span class="com">// milliseconds between LCD updates</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> INTERVAL2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">;</span><span class="pln"> </span><span class="com">// milliseconds between rps updates</span><span class="pln">
</span><span class="typ">uint16_t</span><span class="pln"> frequency </span><span class="pun">=</span><span class="pln"> </span><span class="lit">440</span><span class="pun">;</span><span class="pln"> </span><span class="com">// speaker tone frequency</span><span class="pln">

</span><span class="com">// val to store previous distance in rpm sensor</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> photoVal2prev </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> rotations </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> rps </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// how many rotations per sec</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> lastCycle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com">// update display of sensor & actuator states (4-10x per sec)</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> updateScreen</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> m1</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> m2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> o</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// map states within 0-99 range</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">800</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print input</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print m1</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print m2</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">map</span><span class="pun">(</span><span class="pln">m2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">90</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">));</span><span class="pln"> </span><span class="com">// print output</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Serial</span><span class="pun">.</span><span class="kwd">begin</span><span class="pun">(</span><span class="lit">9600</span><span class="pun">);</span><span class="pln"> </span><span class="com">// open serial monitor at 9600 baud </span><span class="pln">
  
  pinMode</span><span class="pun">(</span><span class="pln">PHOTOPIN1</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// input IR sensor</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">PHOTOPIN2</span><span class="pun">,</span><span class="pln"> INPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// tachometer IR sensor</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">MOTORPIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// DC motor</span><span class="pln">
  pinMode</span><span class="pun">(</span><span class="pln">SPEAKER_PIN</span><span class="pun">,</span><span class="pln"> OUTPUT</span><span class="pun">);</span><span class="pln"> </span><span class="com">// sound speaker</span><span class="pln">

  </span><span class="com">// start screen and print value labels</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">backlight</span><span class="pun">();</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">home</span><span class="pun">();</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"i:"</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"m:"</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="pln">setCursor</span><span class="pun">(</span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  screen</span><span class="pun">.</span><span class="kwd">print</span><span class="pun">(</span><span class="str">"o:"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> loop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// sense linear distance from IR sensors</span><span class="pln">
  </span><span class="kwd">int</span><span class="pln"> photoVal1 </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">PHOTOPIN1</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">int</span><span class="pln"> photoVal2 </span><span class="pun">=</span><span class="pln"> analogRead</span><span class="pun">(</span><span class="pln">PHOTOPIN2</span><span class="pun">);</span><span class="pln">
  
  </span><span class="com">// set rotation speed (spin faster at closer distance)</span><span class="pln">
  </span><span class="kwd">int</span><span class="pln"> motorSpeed </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">photoVal1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">800</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">);</span><span class="pln"> 
  analogWrite</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> motorSpeed</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// measure motor fan rotation speed</span><span class="pln">
  </span><span class="kwd">int</span><span class="pln"> difference </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="com">// check change in distance </span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">photoVal2prev </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
    difference </span><span class="pun">=</span><span class="pln"> photoVal2 </span><span class="pun">-</span><span class="pln"> photoVal2prev</span><span class="pun">;</span><span class="pln">
    
  </span><span class="com">// when gap is detected, one full cycle completed</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">difference </span><span class="pun">></span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// increment rotations</span><span class="pln">
    rotations</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  photoVal2prev </span><span class="pun">=</span><span class="pln"> photoVal2</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// update value for rotations per second</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> timer2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    rps </span><span class="pun">=</span><span class="pln"> rotations</span><span class="pun">;</span><span class="pln">
    rotations </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    timer2 </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> INTERVAL2</span><span class="pun">;</span><span class="pln"> </span><span class="com">// update timer</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// generate sound volume in response to rps</span><span class="pln">
  </span><span class="kwd">int</span><span class="pln"> volume </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">rps</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln"> </span><span class="lit">600</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  vol</span><span class="pun">.</span><span class="pln">tone</span><span class="pun">(</span><span class="pln">SPEAKER_PIN</span><span class="pun">,</span><span class="pln"> FREQUENCY</span><span class="pun">,</span><span class="pln"> volume</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// update LCD screen display</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> timer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    updateScreen</span><span class="pun">(</span><span class="pln">photoVal1</span><span class="pun">,</span><span class="pln"> motorSpeed</span><span class="pun">,</span><span class="pln"> rps</span><span class="pun">,</span><span class="pln"> volume</span><span class="pun">);</span><span class="pln">
    timer </span><span class="pun">=</span><span class="pln"> millis</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> INTERVAL</span><span class="pun">;</span><span class="pln"> </span><span class="com">// update timer</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span>