Skip to main content

Conversion of cheap optical mouse to robot odometer

For a small robot project I'm working on I needed a way to measure the robot's progress across the floor. There are various possibilities, such as: use stepper motors (expensive and am recycling some old continuous run servos), add an encoder to the wheels (would need to go buy some parts for that), or use the optical sensor for a mouse.

I had a really old PS/2 optical mouse lying around which contains an MCS-12085 optical sensor that has a rather simple serial interface suitable for connection to a microcontroller. Inside there are two separate areas of components. On the right in the picture above is the PS/2 interface chips and four nice extras that I desoldered for later use (three microswitches and a quadrature encoder). On the left is the red LED that illuminates the surface and the 8 pin square MCS-12085 that has the camera.

The only description of the chip was for a related optical sensor, the MCS-12086. The difference between the two appears to be that the MCS-12085 requires an external oscillator. A quick comparison of one of the designs in the datasheet and the PCB reveals the simple circuit that runs the chip:

Here's a marked up picture of the mouse internals:
The reverse side shows that there's a nice clean separation between the optical sensor side and the PS/2 interface.
So, after taking a hacksaw to the PCB and case, exposing some copper tracks with sand-paper and drilling four holes for +5V, GND, SDIO and SCLK it was possible to attach a small piece of the PS/2 cable and some connecting pins to have a stand-alone optical sensor unit for my robot.
Then it's just a question of software. For this project I'm using an Arduino Uno which can easily supply the 5V that the sensor needs and two digital pins can be used to generate the clock and I/O signals to read the movement of the sensor. I've created a small Arduino code module called mcs12085 that reads the delta-X and delta-Y values from the sensor as it moves.
Each call to mcs12085_dx() and mcs12085_dy() gives the distance the sensor has moved in the X and Y directions in dots with the range -128 to 127. Note that the sensor has a default accuracy of 1,000 dpi so it will overflow in either direction if the sensor moves more than 3.2mm in any direction.
The code uses one digital pin to act as the clock and generates the relevant clock signal, and another pin to read and write from the sensor.
Before I dismantled it I used a Salae Logic analyzer to observe what the PS/2 interface chip was doing to communicate with the sensor. Here's a screen shot of the complete cycle. The top shows the clock signal and the bottom the data.
It clocks in 8 bits of data corresponding to 0x02 (this is the read DX register command), pauses and reads out 8 bits (in this example the read bits were all 0). Then it clocks in 0x03 (the read DY register command), pauses and reads out 8 bits.
More details of the commands possible are in this document. At some point I'll add some of them to the project.


x said…
The ADNS 2060 looks like an equivalent part to the MCS 12085:
Thanks for that Ron. It looks similar although the commands seem to be slightly different (e.g. read delta X is 0x42 on that device and 0x02 on the one I have).

Zaid Pirwani said…
I would love to see these in action on a bot, measuring distance travelled...

I myself have been thinking about doing something like this for long [I have gathered about 4 old mice for the purpose]... maybe now I will do it.... thanks for the simple explanation and code example.
Unknown said…
What is the max speed that the sensor can track?

I had a similar idea and just used software to track "raw mouse" movements - but once the mouse was moving faster then 4 (maybe it was 8) MPH it couldn't keep up any longer. I was looking for a solution to track at least 25mph and was hopeful for something up to 30+ so I abandoned the approach.

Nice write up!

Anonymous said…
By the way, you seem to have uploaded your mcs-12085.h with the same text as your .cpp file on Github.
Thanks for pointing that out John. Bizarre situation, but I've pushed the correct file to github now.
aodhan said…
I hacked apart an old ps2 mouse I had lying around and tried to get your hack up and running. I wasn't getting anything useful from the mouse until I added a delay of 100ms between "mcs12085_dx()" calls. I am now getting meaningful data from the mouse, however this delay means I can only get 10 updates a second from the mouse. Any thoughts on speeding this up, or is this delay due to the crunch time it takes the mouse to calculate its dx,dy movements?
Unknown said…
I like this and I wana try this ASAP.... But I would like to know the commands? For example how were u able to differentiate between ADNS2620 and MCS 12085 in ur comments??
Anonymous said…
@aodhan I found out in the data sheet that the chip needs a small delay to complete the setup (~40 ms). You can try 100 ms just to be safe. After that you should be able to poll it at the full 1500 fps. I was able to run it at 100 fps without any problems.

I have uploaded my code here:

Thanks to John Graham-Cumming for providing an excellent library!
Rick Bruderick said…
Thanks for sharing this, John!

I've found a few optical mice to hack, but none with the MCS-12085/6 chip.
Instead, I've found the MX8733 and MX8731A chips.…d-SOC-mouse/MX8733_Spec_V1.2.pdf…min/Product20/MX8731 SPEC V1_1.pdf
They are PS2 and seem quite like the MCS-12085/6. But when I connect them to the Arduino UNO and run your code, the x and y always equal -1. I don't have a scope to look at the DATA and CLK signals.
Did you ever just see -1 as the x and y outputs? Any clue as to what I'm not doing right?


Popular posts from this blog

Your last name contains invalid characters

My last name is "Graham-Cumming". But here's a typical form response when I enter it:

Does the web site have any idea how rude it is to claim that my last name contains invalid characters? Clearly not. What they actually meant is: our web site will not accept that hyphen in your last name. But do they say that? No, of course not. They decide to shove in my face the claim that there's something wrong with my name.

There's nothing wrong with my name, just as there's nothing wrong with someone whose first name is Jean-Marie, or someone whose last name is O'Reilly.

What is wrong is that way this is being handled. If the system can't cope with non-letters and spaces it needs to say that. How about the following error message:

Our system is unable to process last names that contain non-letters, please replace them with spaces.

Don't blame me for having a last name that your system doesn't like, whose fault is that? Saying "Your last name …

All the symmetrical watch faces (and code to generate them)

If you ever look at pictures of clocks and watches in advertising they are set to roughly 10:10 which is meant to be the most attractive (smiling!) position for the hands. They are actually set to 10:09.14 if the hands are truly symmetrical. CC BY 2.0image by Shinji
I wanted to know what all the possible symmetrical watch faces are and so I wrote some code using Processing. Here's the output (there's one watch face missing, 00:00 or 12:00, because it's very boring):

The key to writing this is to figure out the relationship between the hour and minute hands when the watch face is symmetrical. In an hour the minute hand moves through 360° and the hour hand moves through 30° (12 hours are shown on the watch face and 360/12 = 30).
The core loop inside the program is this:   for (int h = 0; h <= 12; h++) {
    float m = (360-30*float(h))*2/13;
    int s = round(60*(m-floor(m)));
    int col = h%6;
    int row = floor(h/6);
    draw_clock((r+f)*(2*col+1), (r+f)*(row*2+1), r, h, floor(m…

Importing an existing SSL key/certificate pair into a Java keystore

I'm writing this blog post in case anyone else has to Google that. In Java 6 keytool has been improved so that it now becomes possible to import an existing key and certificate (say one you generated outside of the Java world) into a keystore.

You need: Java 6 and openssl.

1. Suppose you have a certificate and key in PEM format. The key is named host.key and the certificate host.crt.

2. The first step is to convert them into a single PKCS12 file using the command: openssl pkcs12 -export -in host.crt -inkey host.key > host.p12. You will be asked for various passwords (the password to access the key (if set) and then the password for the PKCS12 file being created).

3. Then import the PKCS12 file into a keystore using the command: keytool -importkeystore -srckeystore host.p12 -destkeystore host.jks -srcstoretype pkcs12. You now have a keystore named host.jks containing the certificate/key you need.

For the sake of completeness here's the output of a full session I performe…