I just came up with a very simple, easy to implement, and very cheap way to monitor the RPM of brushed DC motors. It would also work on brushless motors but there are better ways for them (counting phase changes) so I'd only recommend this for motors that otherwise have no means of determining speed.
In my case, I'm using two brushed DC motors with gearboxes that were taken from Harbor Freight cordless 18V drills. I want to use them as drive motors for a 2-wheeled robot, but of course they need to be speed-matched so the robot goes straight. I considered several different options (optical encoder wrapped around the shaft and magnetic sensor) and decided that magnetic sensor would work well.
Step 1: Parts List
This design uses very few components, and you can pick up enough to do many motors for under $5 on eBay. I paid more for the SparkFun optical sensors than I did for 10 magnetic sensors and 20 magnets. You will need the following:
- Small round neodymium rare-earth magnet (1) that fits on the end of the motor shaft
- Hall effect sensor
- 2-part epoxy
- Motor with exposed rear shaft
If you want to build a protective cover, you will also need:
- Plastic bottle cap
- Hot glue (epoxy works too, but hot glue is easier to remove if necessary)
- Spray paint (optional, if you don't like the color of the bottle cap you have)
For the cap, you will also need a rotary tool (Dremel) to cut slots in the cap for wires, and you will need a hot glue gun for the hot glue as well.
Step 2: Assemble the Magnet
The build process couldn't be easier. Mix up a drop or two of epoxy (you don't need much!) and dab a tiny blob on the tip of the rear motor shaft. You don't want it running down the shaft and into the bearings so be careful! It might be best to wait a few minutes and let the epoxy thicken up to ensure it doesn't run. After the blob is applied, simply place your magnet sideways (rounded edge touching motor shaft, both flat faces exposed) and gently tap it until it is centered. Let the epoxy cure for several hours before continuing.
Step 3: Assemble the Sensor
After the magnet is firmly epoxied into place, begin epoxying the sensor. You will need to find a way to point the hall effect sensor at the magnet, preferably at the same height off the motor as the magnet. My motor had a protruding metal lip holding the bearing that was perfect, but if yours doesn't have this you can epoxy a plastic riser in place and then epoxy the sensor to that. Make sure you get the sensor oriented correctly. The side with the angled corners and the label is the front. I pointed it at the magnet. Again, be super careful with the epoxy, I had to scrape some off the bearing. Go easy on the first application, as long as the sensor is sticking you can go back later and fill in the gaps when you're not moving the sensor around. Unlike the magnet, you'll have to either hold the sensor or find a way to keep it held in position. My sensor already had wires soldered so I used the wires to support it.
Step 4: Testing...
Hook the sensor up. From the front, the pinout on my sensor is 1: Vcc (5V), 2: GND, 3: Open-drain output. Yours may be different, but this pinout is common for many hall sensors. The output is open drain, so you need to add a pull-up resistor to Vcc, I used 1K Ohm. Now hook up a frequency counter or oscilloscope and start spinning the motor. You should see a pulse for each rotation of the motor. If you know the gear ratio of your gearbox, you can easily determine the speed of your final output by multiplying the frequency and the gear ratio, then multiplying by 60 to account for RPM vs. RPS. Note that there is both one rising and one falling edge per revolution, as it transitions approximately every 180 degrees when the magnet flips around.
Step 5: Build the cover
If you're going to be using the motor in an open area where it is subject to environmental debris (such as on the bottom of a robotics platform like I'm doing) it would be wise to protect the sensor from being knocked off. Epoxy is strong, but a solid hit from a bouncing rock could easily crack it, sending your sensor flying away from the magnet, losing feedback, and possibly allowing your feedback loop to develop huge error and send the motor into a speeding frenzy. This is bad.
To protect the sensor, I found that a plastic bottle cap off of a 2 liter soda bottle fit the back of the motor just about perfectly, so I bought some delicious soda and saved the caps. Line up the cap with the terminals on the motor. If you already have wires soldered in place, it is easiest to just cut notches out of the cap, otherwise you could drill holes and leave the cap wall intact. I used a rotary tool with a cut-off wheel for this job and it turned out nicely. Then, use a thin grinding bit to cut a slot in the top of the cap, slightly off-center, for the hall sensor wires to exit through. Try to line up the slot with where the sensor is.
Next, if you care about it looking decent, use some spray paint to cover up the unsightly bright colors of the plastic cap. I used black since it matched the color of the motor's gearbox. Use some spray-on clear coat afterwards to protect the color.
Finally, after soldering all your wires on to the motor and sensor, slip the cap over the wires, align it in place being careful not to damage the sensor's epoxy base or knock the magnet off, and use hot glue to hold it in place. Finally, use the hot glue to seal the wires in place, making sure to build up a nice thick wire protector around the hall sensor wires to relieve stress on the sensor and epoxy below.
Step 6: Additional thoughts...
This sensor only gives two measurable events per revolution, so if you have a low gear ratio this may not be an ideal sensor for you. In my case, the drill gearbox is a fairly high reduction so a low resolution on the motor shaft still gives a fair resolution on the output. You may consider adding an additional hall sensor offset by 90 degrees. I haven't tested this yet, but I assume it would give you a quadrature output from which you could get additional resolution as well as be able to read the rotational direction. It means more processing on your microcontroller but could yield better results.
As for the code, there are many ways to do a motor speed feedback loop. The one I'm testing is a simple error correction loop that determines the difference between actual speed (measured in Hz) and desired speed. The error is multiplied by a scalar (0.05, chosen for a slower, less aggressive response) and added to a floating-point speed value which is then converted into a uint8 type and set into OCR0A/OCR0B on the AVR's timer to adjust the PWM output. This works as expected. Grab the motor shaft and grip it tightly to apply a load and the speed will decrease, but will quickly ramp up power to correct it. Let go and it will briefly spin over speed as it decreases power until the speed settles back at the desired level. Disconnect the sensor and the error continuously accumulates, ramping up power to the limit where it will stay until a speed signal is reconnected. I'm using timer/counter 1 in input-capture mode to measure the motor speed with fast update rates. This is better than counting pulses per second as it gives you much finer resolution and much faster updates. Experiment with various mathematical filters if you want an average RPM value taken over some set amount of time.