Friday, March 30, 2012

Using the SEN0038 wheel encoders, the Arduino, and interrupts

Now that I got the ultrasonic sensor to work and the MEGA board on the robot, it is time to tackle the wheel encoders. The ROB0025 comes with the SEN0038 wheel encoder. The first step is to get the encoders mounted on the robot. This was a little challenging given how small the screws were. Plus getting them spaced right so the spinning wheel was centered between the diode took a little trial-and-error with the right set of washers.

First up, the parts list. The parts from previous projects were needed, plus the new encoders

  1. MegaShield: http://store.nkcelectronics.com/megashield-kit.html
  2. Arduino Mega: http://arduino.cc/en/Main/ArduinoBoardMega
  3. Jumper wires
  4. ROB0025: http://www.dfrobot.com/ 
  5. AdaFruit motor drive shield: https://www.adafruit.com/products/81
  6. Wheel encoders: http://www.dfrobot.com/index.php?route=product/product&filter_tag=encoder&product_id=98
After I wired everything up, I started looking around for some documentation on how to use them. First, here is a picture of the encoders connected.


Then some googling to learn more about the model and product. This turned up several threads about how these encoders do not work. Luckily I traced down a thread which had answers and code about how to make them work (item #3 below).
  1. http://www.dfrobot.com/wiki/images/b/b9/FIT0029_Encoder_Schematics.png
  2. http://dfrobot.com/wiki/index.php?title=Wheel_Encoders_for_DFRobot_3PA_and_4WD_Rovers_(SKU:SEN0038)
  3. http://www.dfrobot.com/forum/index.php?topic=354.0
  4. http://www.dfrobot.com/index.php?route=product/product&product_id=98
To get the encoders to work properly, interrupts need to be used. I spent some time reading up on the best way to do this. Interrupts are used to ensure that all transitions of the wheel are caught. If we were to use polling we would probably miss half the transitions. Reading up on encoders though, they will probably not be all that accurate anyways. Here are a few of the noteworthy links:

  1. http://arduinomega.blogspot.com/2011/05/external-interrupts-buttons-for.html
  2. http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/
  3. http://www.codeproject.com/Articles/61023/Arduino-Platform-Interrupts-Introduction
  4. http://www.me.ucsb.edu/~me170c/Code/How_to_Enable_Interrupts_on_ANY_pin.pdf
  5. http://arduino.cc/en/Hacking/PinMapping2560
Getting the interrupt to work properly turned out to be much more challenging than I expected. Many hours were spent trying to figure out what exactly was wrong. I originally hooked up the encoders to use interrupts 2 & 3 (pins 21 and 20). No matter what I tried, I would not get back reasonable results. Most of the time I would get a reasonable count (robot setting with wheels off the table spinning for a second). Usually one wheel would work well, but the other would return nonsensical values in the 1000s. 

More googling turned up this thread, and a pointer to the pololu encoders and library.
Using these posts, I gave up using the Arduino interrupt abstraction and used the AVR library directly. I put the encoders on pins 50 and 51. This worked much better. I am not sure exactly why the Arduino interrupt library did not work with the Mega and the encoders. I checked with the multimeter and the encoders were not fluctuating in voltage when the wheel was not spinning. I did notice that the AdaFruit motor shield was causing subtle power fluctuations that could explain the interrupts misfiring. I did an experiment where I disconnected the motor shield, put the encoders on pins 20 and 21, and spun the wheels by hand. This worked perfectly. So the only thing I can conclude is that it is some combination of trying to use pins 20 and 21 with the configuration I had.

At any rate, hooking the encoders up to pins 50 and 51, and then coding directly to the AVR library for the interrupts seems to have solved my problems. Again the code is located at:
https://github.com/mark-r-stevens/Ardadv/tree/master/device/sensors/encoders
There is an encoders class that abstracts the messy interrupt code (with the global variables) and a simple unit test that spins the left wheel, stops it, then the right wheel and stops it. Wheel encoders counts are made when only one wheel is spinning. This enables me to check that the right encoder is being used when the right wheel is spinning. Here is a plot showing the two wheels.



Next, here is a histogram of the two. Note that in this case, I had the right wheel spin at a speed of 200 and the left wheel spin at a speed of 150. This can be seen from the plot that more values were recorded when the motor was spinning faster (good sanity check).



I will need to convert these to meters based on wheel diameter. However, it was a lot of work to figure out the interrupt problem, so that will need to wait until next time.

No comments:

Post a Comment