In this video I will show you how to detect rotational movement using two photo sensors. That rotary encoder will be used to turn conventional DC motors into stepper motors. The sensors I am using detect light with a phototransistor. The resistance of that device is some kiloohms as long as it is not illuminated. As soon as light hits the phototransistor, the resistance drops to just some ohms. A voltage divider composed of a constant 2 kiloohms resistor and the phototransistor is connected to a 5V dc voltage source by what the varying resistance of the photo transistor is turned into a varying voltage. The emitter pin of the phototransistor, usually marked with a "D" is connected to the negative terminal of the voltage source. The second pin of the phototransistor is usually marked with a "+" and it is connected to +5V trough a 2 kiloohms series resistor. As long as the photo transistor is not exposed to light, the resistance of it's emitter-collector line is clearly higher than that of the 2 kiloohms resistor. Consequently almost all of the 5V input voltage is detected across the phototransistor. But wait - the phototransistor is exposed to bright light right now! Why doesn't its resistance drop to just some ohms? Well, the sensitivity of the phototransistor is limited to certain wave lengths. The sensitivity of the photo transistor used here is highest at infrared light. The neon tubes in my video studio emit only a low fraction of infrared light which is why the sensor doesn't detect that environmental light. That's why the photoelectric sensor has an infrared LED: To turn that device "on", the cathode of the diode which is marked with an "E", has to be connected to the negative terminal of the voltage source, the anode marked with a "+" has to be connected to +5V through a 180 ohms resistor used to limit the current. Same as human eyes, the camera can't detect infrared light However as soon as the LED is brought near to the phototransistor, the resistance of the sensor drops to just some ohms. Consequently the voltage across the emitter collector line drops to almost zero volts. Note that the light emitted by the filament of a bulb has a high portion of infrared light! If the phototransistor is exposed to the light of the filament bulb, the voltage drops to zero, too. Same is for bright sunlight. That's why the photoelectric sensors eventually have to be covered when operating in bright environmental light. In the sensor unit, the infrared LED faces the phototransistor. If the unit is powered, the voltage across the phototransistor drops to almost zero volts. The light of the infrared LED has to be blocked to make the voltage step up to almost 5V. Here I am using a metal sheet cut from a can. Paper doesn't block all of the infrared light by what the voltage doesn't exceed 3.7V. With a toothed metal disc, a microcotroller can detect rotational movement: The terminal marked with the "+" at the phototransistor has to be connected to an input pin of the Arduino, minus of the sensor unit must be connected to the ground pin. The sensor disc has 4 teeth. In the initial state, a tooth blocks the infrared light by what +5V can be detected at the input pin of the Arduino which is called HIGH signal. With an additional pin, switched to output mode and connected to a resistor LED combination, the Arduino displays the HIGH signal at the pin of the photo transistor - the LED is lighted up. If the disc is turned clockwise until a gap allows the infrared light to pass the detector, the voltage at the Arduino drops to almost 0V, which is called LOW signal. Thats displayed by turning the red LED off. Whenever a transition from HIGH to LOW or from LOW to HIGH is detected, the microcontroller increases a variable by 1 which can be seen on the LCD display. With a full turn, the input changes four times from HIGH to LOW and of course four times from LOW back to HIGH signal - consequently 8 transitions were counted. Between a HIGH to LOW and a LOW to HIGH transition, the disc has been turned by 45 degrees. The disc has been turned by another 45 degrees if the signal falls back to LOW. The signal also changes from LOW to HIGH or HGH to LOW when turning the disc counterclockwise. In order to detect the direction of rotation with the microcontroller, a second photo sensor is needed that has to be connected to another digital input. Both detectors are arranged side by side. Teeth and gaps of the sensor disc must be wide enough to block or let pass the infrared light of both sensors simultaneously. Accordingly both inputs of the Arduino are on HIGH... ...or LOW level. If the disc is turned in such a way that only one of the sensors is illuminated, there is a LOW singal at the according input and a HIGH signal at the other pin of the microcontroller. In total we get 4 different states considering both inputs. Whenever the disc rotates, only one input changes its state at a time - the other input keeps it's status. Let's number the different input conditions from 0 to 3. If the disc is turned clockwise, we go from 0 to 1... ...from 1 to 2... ...from 2 to 3... ....and finally from 3 back to 0. When turning the disc counterclockwise, we go from 0 to 3... ...from 3 to 2.... ...from 2 to 1... ...and from 1 back to 0. Whenever the state at one of the inputs changes, the microcontroller can detect whether the disc was spinning clockwise... ...or counterclockwise. The variable is increased by one whenever the microcontroller detects clockwise rotation. The variable is decreased by one whenever a counterclockwise rotation is detected. If the status at one of the input pins changes, the disc has been spinning for one "step". For a full turn, the cycle from 0 to 3 is processed four times, the input signals are changing 16 times - thus a full rotation is divided into 16 steps and the rotation can be measured with a resolution of 22.5 degrees. Using a disc with only 2 teeth, we get 8 steps for a full turn, thus 45 degrees per step. Teeth and gaps are larger than the distance between both photo sensors, by what the rotation is not divided into equal steps. You can turn the sensor disc a couple degrees without triggering a change at the inputs of the microcontroller. With the very rough resolution of this two teeth disc, the resulting uncertainty is around 45 degrees. 6 Teeth result in 24 steps for a full turn and so we get approximately 15 degrees per step. The more teeth, the higher the resolution of the rotational encoder - keep in mind that the teeth and gaps must be wide enough to cover both sensors simultaneously. Let's attach the sensor disc to the output shaft of a geared motor. The motor is connected to the output terminals of an H bridge. That H bridge can be controlled by the Arduino using 2 of the four input pins of the double bridge shown here. The inputs of the H bridge have to be connected to 2 output pins of the microcontroller. Ground, thus the negative terminal of the H bridge has to be joined with the ground pin of the Arduino. As long as both output pins of the Arduino are turned OFF, the motor doesn't spin. As soon as digital output 7 of the Arduino is turned ON, we can detect 5V at that pin and the motor spins clockwise. If output pin 7 is turned OFF again, the motor stops spinning. If output pin 6 is turned ON, the motor spins counterclockwise. As soon as that output is turned OFF again, the motor stops spinning. Using that principle, the Arduino can initiate the rotation of the motor and read the true rotation with the sensor disc. By software, the motor can be turned on until the sensor disc has been rotating for one step. If the motor starts spinning continuously, the polarity might be wrong: After swapping the terminals at the output of the H bridge we get what we expected from our control loop - the motor spins stepwise. As you can see, the rotation is not divided into equal steps. That's once more caused by the fact that teeth and gaps of the sensor disc are larger than the distance between the two photo transistors. After 16 steps the motor has done a 360 degrees turn. The direction of rotation can be changed by software. With the microcontroller and the sensor disc, the DC motor operates as stepper motor. Number and direction of steps is commanded through the USB interface from a computer. If 16 steps are transmitted with a single command, the motor does a full turn without a break. Commanding 8 steps causes a smooth 180 degrees rotation. If the motor is stopped by hand, the motor is kept energized. Not until the motor is released and all 8 steps are processed the Arduino turns the motor off. What happens if I turn the motor some more degrees by hand? Now, the microcontroller detects that the motor was spinning for too far. With the H bridge, the motor is controlled in such a way that is starts spinning into the opposite direction until the sensor disc reaches the specified position. The set point is permanently compared to the actual position of the sensor disc and whenever there is a variation, the motor is controlled in such a way that the error gets minimized. Setpoint and actual point are set to zero whenever the Arduino is turned ON. If the sensor disc rotates clockwise for one step, the variable storing the actual position is increased by 1. If the sensor disc spins counterclockwise for a step, that variable is decreased by 1. If a rotation of 16 steps is commanded through the USB interface, the setpoint is increased by 16 so that the difference between setpoint and actual point is 16 at the beginning of the rotation. As soon as the motor starts spinning, the difference between setpoint and actual point is lowered with each step. As soon as that difference becomes zero, the motor is turned off. If a counterclockwise rotation of 16 steps is commanded, the setpoint is lowered by 16 so that the difference between setpoint and actual point becomes minus 16. The motor starts spinning counterclockwise by what the actual point is decreased with each step until the difference becomes zero again. Caused by inertia, a high power motor won't stop spinning as soon as the current is cut off. If the microcontroller detects that overshooting the motor gets powered with reverse polarity and full power until the actual point meets the setpoint again. Once more inertia causes the drive to overshoot, now into the opposite direction. The motor oscillates around the setpoint. To prevent the drive from oscillations, the power forwarded to the motor is reduced as soon as the setpoint is reached for the first time. That power is controlled by pulse-width modulation. With a duty cycle of 20 percent the motor spins much slower than before. So if the power is reduced to just 20 percent as soon as the setpoint is reached, the motor spins back slowly whenever the microcontroller detects overshooting. The rotation stops as soon as the setpoint is reached for the second time. With a proportional controller those oscillations are eliminated in a much better way: Whenever there is a large difference between setpoint and actual point, the motor is turned fully on. The duty cycle is lowered the smaller that difference between setpoint and actual point becomes. A variable in the source code defines the proportion of the duty cycle in relation to the absolute difference between setpoint and actual point. That variable must be high to make the motor spin powerful, but not too high to avoid overshooting. You can learn more about control loops in my video about the Arduino Uno. How fast can the Arduino process the data of the control loop? The clock speed of the microcontroller is 16MHz. Multiple clock cycles are needed to read the signals of the photosensors and to calculate the control signal for the motor. Furthermore the program is interrupted for many cycles whenever the Arduino receives commands through the USB interface. I have added one lines of code to toggle a pins each time the control loop is executed. The periodical time of the resulting square wave signal is approximately 30ms, thus 15ms are needed for a single run of the loop. Here I have disabled the refreshing procedure of the LCD display, because many clock cycles are needed to generate the output. The time for a single run of the loop is decreasing to just 60 microseconds while data is constantly received through the USB interface. Multiplying that time by 10 gives 600 microseconds, thus 1600 loop runs per second which is the highest number of pulses that can reliably be processed by the Arduino in one second. Here you can see a motor without transmission being controlled by the Arduino The oscilloscope plot displays the signal at one of the photo sensors by what the revolution speed can be calculated. Even with a sensordisc having four teeth and a revolution speed of up to 5000 rpm the control circuit works fine. As you can see, the disc always stops with the arrow pointing to the photo sensors which is an evidence that no pulses are skipped. What type of DC motor can be used? Well, that's mainly a matter of the used H bridge. This is a board with a double H bridge based on an chip type L298N with a maximum continuous current of 2A. You need a digital multimeter to measure the current flowing through a motor. Dial the highest range for current measurement - which is 10A for this multimeter - and switch it in series to the motor. If the motor runs in idle mode, it consumes 60mA at 5V... ...and 70mA at 12V. What we need is the maximum current whenever the motor stops under load. Now, the current is increasing to almost 300mA at 5v... ...and 700mA at 12V by what that motor can be used without harming the H bridge. As mentioned before, the angular resolution can be increased by using a sensor disc with more teeth. You can also attach the sensor disc to a gear wheel of the transmission instead of using the output shaft. The gear with the sensor unit turns with an average angle of 22.5 degrees per step when using a disc with 4 teeth. With the transmission of 13:1 from the sensor wheel to the output shaft we get just 1.7 degrees per step. Note that there is always clearance caused by a transmission which lowers that academical value. You get a very precisely controlled digital servo whose maximum angle of rotation only depends on software parameters. It can be approximately 180 degrees... ...or a full turn of 360 degrees. Whenever that servo is turned on, the Arduino has to find the actual position of the servo lever. A limit switch is needed. I am using another photo sensor. After being turned on, the Arduino moves the servohorn slowly in one direction until the infrared light of the photosensor is blocked. That's the zero point for the software. After initialization the servo is ready for use, which is indicated by the green status LED. Let's have a look at an oscilloscope plot of the voltages applied to the two input pins of the Arduino while turning the sensordisc with constant speed. We get two square wave signals jumping between zero and 5V. The periodical time of the signal is approximately 72ms, by what we get a frequency of 14 Hertz. The lower curve is shifted by 12ms compared to the upper one. There is just one transition of the input signals at a time. As mentioned before, the widths of teeth and gaps doesn't correlate exactly to the distance between the photo sensors at this hand made sensor disc. In theory we should get a phase shift of 18ms which is one quarter of the periodical time and the time span of the LOW signal should meet that of the HIGH signal. Here you can see commercially available encoders: The left type is a mechanical encoder, the right one uses light signals to detect rotational movement. Again we get square wave signals when connecting the optical encoder to the inputs of the oscilloscope and turning the sensor by an electric motor with constant speed. The phase shift is 3.5ms, while we would expect to get 3.9ms which is a quarter of the periodical time of 15.5ms. Same as with our hand made sensor, the light detectors are not perfectly arranged in this encoder. At the upper curve there is a transition from LOW to HIGH or from HIGH to LOW when ever the lower curve is on constant LOW or HIGH signal. With the mechanical encoder we get a clear signal, too. When reducing the time base, we can see multiple spikes at the edges of the square wave signal that are caused by contact bounce. Despite those interferences the Arduino can control the motor with ease, because the signal changes only at one of the inputs at a time while the second input stays on LOW or HIGH level. Whenever contact bounce occurs, the error equals one step which is 10 degrees at this encoder with 36 steps per revolution. Not only because of contact bounce but mainly because of wear, those mechanical encoders should not be used to detect rotational movement of a motor. Use non mechanical encoders for that kind of control loop. Here you can see the motor of an old printer being controlled by the Arduino. The sensor disc has approximately 3000 very thin lines. The photo sensors used before in this video can't resolve that fine pattern. Thus I am using the sensors of the printer. You can get more information about how to wire those encoders on the project page. Caused by the fine line pattern, we get too many pulses at the inputs of the Arduino at high revolution speeds of the sensor disc. At one revolution per second we get 12000 transitions at the inputs each second. As demonstrated before, the Arduino can't process that large amount of input data with the software used so far. Thus I have written a new, more efficient sketch using interrupts. Nonetheless the revolution speed of the printer motor had to be reduced by pulse-width modulation to avoid skipping pulses. Let's go back to our hand made encoders: For my CNC machines I use threaded rods to create linear movement along the axes. This geared motor is from an old optical drive - it usually opens and closes the tray. The sensor disc is attached to the threaded rod, by what the clearance caused by the plastics gear can be widely ignored. By the threaded rod, the rotational movement of the geared motor is turned into linear movement. This motor from an old printer is more powerful - here it's driven with 5V. At 12V, torque and so motor speed are increasing clearly. What about really strong motors like this windscreen wiper motor? This one draws 10A at 12V operating voltage in idle mode, thus an H bridge with a clearly higher current rating is needed. The type shown here can be operated with a continuous current of up to 43A. The sensor disc with 4 teeth is attached directly to the rear end of the motor shaft. When turning on the Arduino, the lever of that homebuild servo rotates until a third photo sensor transmits a HIGH signal to the microcontroller. The worm gear has a transmission of 120:1, by what we get approximately 0.2 degrees per step in theory. Note that clearance reduces that academical precision. You get a very powerful and precise digital servo. To get the maximum speed and torque you have to adapt some software parameters of the control loop in the source code of the Arduino. Besides the proportional controller, a softstart function is implemented to avoid current peaks whenever the servo starts spinning. The setpoint of the servo is commanded through the USB interface. The software on the host computer runs in a Linux terminal. That's all about rotational encoders for now - you can find the schematics and some machines using the drives shown in this video on the project page. Thanks for watching and: "I'll be back!"