Thursday, September 13, 2012

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.


Ron Harwood said...

The ADNS 2060 looks like an equivalent part to the MCS 12085:

John Graham-Cumming said...

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).

Muhamamd 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.

Christopher Fowler 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.

John Graham-Cumming said...

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?


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?