Introduction: Optical Mouse Odometer for (Arduino) Robot
Accurately determining the progress of a wheeled robot can be pretty tricky (and expensive!). Dead reckoning assumes that our motors are perfectly matched, our wheels don't slip and the surface we are running on is perfectly flat: most of these conditions are unattainable and are never guaranteed. Rotary Encoders on the wheels or motors are more accurate, they certainly remove the need for matched motors and can deal with incline changes, however slippage is still an issue. Ultrasonic or Laser range sensors circumvent all of the mechanical issues that plague dead reckoning and encoders but require stationary fixed points of reference, are subject to interference (objects coming between the robot and the reference point) and have issues with regard to range, accuracy and resolution (the more you want, the more it costs!).
Ideally, we want a sensor that can accurately measure positional changes in two dimensions, has a simple interface, has low power requirements, is easily obtainable and cheap into the bargain. The solution: that old optical mouse you have lying around! Computer mice are designed to do just what we want: very accurately track the two dimensional movement of an object in near to real time. They actually have a resolution 1000dpi which means we are able to measure a movement of ~0.03mm in any direction!
We do have to choose our mouse a little carefully however. We need one that either has a PS/2 connector (6 pin mini-DIN) or a USB mouse that is PS/2 compatible (should be stated on the bottom of the mouse somewhere, see picture). This is because the PS/2 protocol is really easy to implement (particularly for microcontrollers) whereas USB is somewhat more difficult!
I happened to have an old Microsoft USB1.1/PS/2 compatible mouse hanging around that I wasn't using, so I decided to sacrifice it to my robotical pursuits in the manner described herein.
Step 1: Tear Down
First things first, we need to open the case and liberate the electronic goodies within. I chose to do this because the mouse is far too big and bulky for my robot. If you don't want to this you just need a USB Type A or PS/2 socket that can be wired to the processor (Arduino in this case) into which the mouse can be plugged without modification, just skip this bit.
So, the process to deconstruct my mouse was as follows (also see pictures):
- Remove rubber adhesive feed covering screws (at the rear) and clips (at the front
- Remove the two screws at the back and then use a small flat bladed screwdriver to push back the clips holding the top and bottom parts of the case together at the front. (This may take a bit of fiddling, I actually inadvertently broke one of the clips in the process.)
- Once the case is open, remove the scroll wheel and then any screws hold the circuit board to the case. There may also be a few small plastic clips that retain the circuit board. The small screwdriver used before and some wiggling should free the circuit board(s) from the case.
- There should be a clear plastic piece under the circuit board (the lens) which will also need, so retain this and the circuit boards, discard (or file!) the rest.
If you plug the mouse into a computer or laptop, ensuring the lens is correctly in place on the bottom, the mouse should work normally when you move it around.
Step 2: Initial Circuit Modifications
Now we've got our hands on the board we need to connect it to our microcontroller. To do this we can either use the existing cable (USB) in my case and wire an appropriate socket or we can replace this wire with some of our own. We also need to determine the function of each of our new wires. This is done simply by using a multimeters continuity setting and working out which connection on the board is connected to which pin on the USB (or PS/2) connector. The original wiring can be seen in the first image above and functions are, left to right, as follows:
- Red: Vcc (USB pin 1)
- White: Data (USB pin 2)
- Green: Clock (USB pin 3)
- Black: Gnd (USB pin 4)
- Black: Shield
I chose to desolder the existing cable form the board and replace it with some wires with Arduino friendly Dupont connectors. I also chose not to connect a wire to the shield connection as its not strictly necessary. We then connect the mouse to our microcontroller of choice, an Arduino Leonardo Nano clone in this case, as follows:
- Mouse Vcc to Arduino Vcc
- Mouse Gnd to Arduino Gnd
- Mouse Clock to to Arduino Pin 6
- Mouse Data to Arduino Pin 5
Step 3: Software
Now we've connected everything up we need some software for the microcontroller. Firstly we need some code that implements the PS/2 protocol. Helpfully there is an Arduino library available for this, however I found it to be a little outdated and I wanted to add some new functionality so I reimplemented and extended it a bit and it can be found here: https://github.com/jazzycamel/PS2Mouse.
The library contains a simple example sketch (PS2Mouse.ino) which requests the mouses status and position delta (the change in X and Y directions since we last asked) and prints it to the serial port once every second. If we program the Arduino, and everything has gone well, the mouse will light up and your favourite terminal application (or the Arduino IDE's serial monitor) will show a stream of status, X and Y deltas once a second. The X and Y data has a (theoretical) range of -255 to +255 and each step (theoretically) represents 0.25mm which means we can (theoretically) measure up to 63.75mm change in any direction (for X positive values are to the right, for Y positive values are forwards).
Note: the above numbers are theoretical for the following a reasons:
- Whilst a mouse can report the range -255 to 255, so far all the mice I've used only return -128 to 127.
- Whilst each step supposedly represents 0.25mm, I've found this to be very dependent on the mouse and the surface its on. Generally the step size seems a lot smaller.
Step 4: Further Modifications and Finishing Up
Once I'd got everything up and running I decided to remove the extra circuit board which has the electronics for the mouses buttons and scroll wheel as I didn't need these features and they were just taking up space. I desoldered both of the ribbon cables, plugged everything in and... nothing. The mouse wouldn't light up and I got nothing from the serial port. A little investigation with the multimeter told me that three of the pins (1,3, and 6) on the rightmost connector (looking from the top) were usually connected together when the button board was connected, so I just shorted them together with some scrap wire as shown in the picture. I then plugged everything back in and Hey Presto! We were back in business!
The final touch was to superglue the clear plastic lens in place on the circuit board to retain it and so I wouldn't lose it.
The next step will be to mount this on my robot and put it to use. I actually intend to cannibalise another mouse in the same way and fit both to the robot so as to be able to accurately determine orientation as well as progress (as described here).
I hope people find this little tutorial useful, please feel free to ask any questions. Thank you.
57 Comments
2 years ago
There must be some error in the initialisation as some days it just starts and works, other days without touching anything same wiring same code, it gets stuck at the start, or very slowly only reads 0 x=84 y=0 (error code?)
I found unplugging and replugging in the mouse after the code starts sometimes gets it through the first part but then it still gives errors.
Question 2 years ago on Step 2
Red - 5V
black - GND
Green - clock - PIN 6
White - data - PIN 5
this is correct right?
It doesn't seem to work with any of the mice I bought. I even got the same model of this example... plus another 3 ps2 mice and all of them work with the pc but don't work with the arduino...
I checked all connections ...
I'm out of ideas of what I might be doing wrong.
Arduino ide 1.8.13
I tried with arduino 1,mega,nano and teensy 3.6, didn't work on any of those.
I did get briefly a response from a mouse once but was never able to replicate it...
2 years ago on Step 2
Adding a pull up resistor on the data/clock lines the LED turns on at least but still doesn't work... stuck at Start
2 years ago on Step 2
I think the library got broken by some arduino update because there is no way I can get this to work... feeling quite stupid with a master in electronics not to be able to get a bloody serial comms to work
I'm forced to use arduino 1.8.7.0
Question 2 years ago on Step 4
Hi,
I gave this a try, with a normal ps2 mouse it didn't work, so I tried buying the same type of mouse and it worked for a little bit then it stopped, I reconnected the mouse to the PC and it still works ok, I tried different boards and micros and it doesn;t work, never get past the setup or rarely get past it and then it just shows zero movement .
I'm trying many different ps2 mice too but nothing...
I tried swapping dat/clk wires and on one mice the light turns on but it's still stuck at the beginning.
Have you had anything similar happen?
Answer 2 years ago
I now got a new mouse, same model again, it just doesn't seem to work.
I'm not sure how the first one managed to work for a couple of minutes then stopped.
I tried exchanging boards too... measured the voltages and it's all working fine.
If I reconnect the mouse to the PC it still works,..
Question 2 years ago
Is there way to make mouse be in 'active' state all the time, with power saving mode off?
3 years ago
Really the info I was looking for. Got it working. However with 2 mice I had the resolution was in sub mm range (0.03-0.06mm/bit) and it did NOT change with PS2 command 0xE8 (also command was positive acknowledged.
As a fruther note I found the standard chip A5020E reads in the datasheet a speed resolution of 20ips (which I interpret as inch per second, 50cm/s). I was looking for something like 10m/s... so it won't work for me...
4 years ago
I wasn't able to find the exact mouse in this article. What's nice about this mouse is the distance between mouse surface and lens is significantly more than new mice. Needed for robots.
Now that I have the mouse connected and working I need to change the focal length to something like 2 cm so it clears the floor and wont collect dirt and dust. See image.
Any suggestions on where to find lenses.
4 years ago on Step 3
Thanks jazzycamel for doing this instructable!
This post may be useful for some. And it may get response that is even more useful.
I was able to easily move the mouse and loose data with the example code provided. It has a 1 second loop delay. Same for 10 ms delay. But not for 1 ms delay.
My robot code loop time is 10 ms maximum including the mouse ps/2 code provided.
I set the loop delay in the provided code to 4 ms to emulated 10 ms loop time. I can easily loose data moving the mouse by hand but I have to move fast. This will work for slower moving objects as described. I'm lucky in that my robot is slow enough this is not an issue. How fast the mouse can go before loosing data can be calculated.
The minimum time to get position data is 5.83 milliseconds (measure in microseconds), 171.8 Hz. If I knew the pixels per inch then it would be straight forward to calculate maximum speed for the mouse and not loose data. Also what is the ability of the detector? It must have a maximum detection time.
To date my robot code loop time is about 2.5 milliseconds maximum. Add the 5.83 ms brings it to a total of 8.33 ms. Leaving ~1.7 ms for higher level control code. Might not be enough. If so I may add an Arduino just to track robot displacement and provide other minor functionality. Divide and conquer. I do hope this is not required.
The next step is to push PS/2 to a higher clock rate and find where it breaks down. jazzycamel may have already determined this. ?
in case anyone is wondering my serial port is set at 1M baud so prints do not interfere much with loop time. Also I measured the 5.83 ms just on the get position command.
Question 4 years ago
HI
fist of all I must say thanks a lot.
I have an issue with it. your code works on some mic but didn't work on many others!!
Do you have any idea what is the problem?
Answer 4 years ago
as i see, the code uses the mouse library , and this one added to keyboard library are just used with mic equipped with a USB transceiver ! like the 32u4
arduino boards like pro micro , leonardo ..
4 years ago
Hi,
First of all I gotta say I am very new to microcontroller arduino programming, I am only familiar with CAD modeling and various simulation. Please teach me and correct me if I am wrong.
Currently, I am using ps2 library for my optical mouse (with MX8733) to retrive x- and y-coordinates. The sample programming is shown below:
#include <ps2.h>
PS2 mouse(6, 5);
void mouse_init()
{
mouse.write(0xff); // reset
mouse.read(); // ack byte
mouse.read(); // blank */
mouse.read(); // blank */
mouse.write(0xf0); // remote mode
mouse.read(); // ack
delayMicroseconds(100);
}
void setup()
{
Serial.begin(9600);
mouse_init();
}
void loop()
{
char mstat;
char mx;
char my;
mouse.write(0xeb); // give me data!
mouse.read(); // ignore ack
mstat = mouse.read();
mx = mouse.read();
my = mouse.read();
/* send the data back up */
Serial.print(mstat, BIN);
Serial.print("\tX=");
Serial.print(mx, DEC);
Serial.print("\tY=");
Serial.print(my, DEC);
Serial.println();
// delay(20); /* twiddle */
}
HOWEVER, it stucks at 'mouse.write(0xff); //reset' and nothing is shown at the serial monitor, or some time (rarely) it shows status=1000 x=0 y=0. I feel like MX8733 is using different protocol, no? Anyway, I can't find any detailed datasheet regarding this sensor, only found this http://www.lizhiic.com/admin/Product20/MX8733_SPEC_V1_0.pdf. Ive also found that ADNS
-2620 is a more common mouse sensor after some time of googling.
So my question is, is ps2 library applicable to all types of optical navigation sensor including this MX8733? If not, any idea to still use this sensor? *because I have bought 2 of them and I don't want to waste my money by leaving them aside doing nothing.
Sincerely, all experts and professionals out there, please help
Question 5 years ago
Hi jazzycamel, good job! Can I get INSTANT value of the sensor's VELOCITY? Sorry, I could miss this point in your description. And how fast (msec) can it be calculated by Arduino?
Question 5 years ago
hey
I tried the same but there is no response in Arduino nut sensor is responding
plz suggest some solution
5 years ago
Thanks for this instruction. I have a question , I can't get negative numbers instead like 65000 is printed. Any tips?
5 years ago
I have a question
Why when we stop moving mouse...the serial monitors show x=0 and y=0, it suppose have reading right ?
Reply 5 years ago
it is completely normal because you have no movement
5 years ago
AWESOME
5 years ago
Thank you for writing this. I am having the issue with being hung on setup. The only theory as to why that I can come up with is that my old (IDK how old) logitech usb mouse does not support USB. The only evidence I have to support this is that there is no mention of PS/2 on the bottom.
I believe that the pins are hooked up correctly because when I connect the green & white one way the mouse LED lights but when I swap those wires the mouse does not light up. Therefore I think I can rule that out. In both cases the serial monitor sits on setup...
Any further troubleshooting recommendations would be appreciated.
Thanks