Sunday, June 16, 2013

PS2 mouse and optimouse Arduino projects

Once I had the Frankenprinter carriage working, I got interested in making it move according to some way other than issuing step or acceleration commands.  And since I'd been interested in how the H-P printer was using a barcode-style mechanism for movement feedback, I went down the path of getting a mouse for input.

Here are a few pictures of the H-P barcode strip that inspired this mini-project.  This is a plastic strip held under tension and mounted parallel to the printer carriage rod.  The barcode chip's sensor is mounted to the ink cartridge holder, and its optosensor shines light through the strip to a sensor on its opposite side.


The band looks like a gray bar to the naked eye...
But under magnification , you can see the individual stripes that the barcode-reading sensor sees.

HP printer ink cartridge "barcode" board optosensor with plastic positioning strip
6/18/13 update: found this link
http://www.iceinspace.com.au/forum/archive/index.php/t-74481.html
as a result of tearing apart an old H-P 720 inkjet printer.  The chip on the image above appears to be a 9866, where the one I got from the 720 is a Q9863.  Very intriguing.  That page links to this:
http://www.mindspring.com/~tom2000/Delphi/Codewheel.html#Optical%20Encoders
which is also very cool.  Add that back to the future project list!
Considering Jameco part 1991475, all of $0.25, for the Schmitt (Schmidt?) NAND gate to get square waves, then tie output to triggers on Arduino, and see what happens.  But once I get there, I'll also have to keep in mind the digitalFastWrite/Read approach
http://www.hessmer.org/blog/2011/01/30/quadrature-encoder-too-fast-for-arduino/

I picked up two old mice.  One was an old-school ball mouse on a PS/2 serial port, and the other was a USB optical mouse.  I also got a few things at Weird Stuff that made wiring it easier.  They were the interface ports from PC housings that allowed me to plug in each mouse, and use the wire outputs on the other end.
Ball-type mouse with convenient PS/2 connector that gives me access to pins
Ball-type mouse with cover removed.

The PS/2 serial mouse was easy to set up.  There were several example implementations available online that amounted to sending signals to the data and clock lines with appropriate delays, and roughly obeying ACK and NACK sequences.  For the online code I saw, it didn't really obey the full sequence of the PS/2 serial protocol, but it was good enough for me to mess around with the data.  Once I had it going, I had a basis for accumulating X and Y positions, and if I wanted them, button press and Z axis (wheel) values.
Ref: http://playground.arduino.cc/componentLib/Ps2mouse
Ref: http://www.computer-engineering.org/ps2mouse/

The innards of the PS/2 mouse were really cool.  They use spinning wheels with slots cut out -- so it sort of looks like a black sunflower -- and then the wheel's edge is running through an optosensor of some sort.  The mouse ball, through friction, rotates the spindle which is the stem of the black sunflower.  The optosensor is fancier than a plain old optosensor, though, because it must be able to detect forward and backward motion.
Ball-type mouse innards.  The black and clear pieces are the optosensor and diode.

But what's hack-unfriendly is that the optical sensor and light blockage system requires precise placement of parts in order to work.  You can kind of fake the function by slotting something other than a black sunflower plastic piece in there, and sliding that through the optosensor gap, but it has to be maintained at the right location (distance above optosensor base, distance from LED and/or photo detectors) to work.  Plus, the system may have dual blockage detection, so a bar-type block strip might not work.  It might depend on the shape of the device that blocks the light.



One thing that I found along the way as inspiration was a YouTube video of a guy who'd connected up a robotic arm, and set up combinations of mouse gestures to define what the arm should do.
Ref: http://www.circuitsathome.com/mcu/controlling-robotic-arm-with-arduino-and-usb-mouse
And you can get some robotic arm kits for about $50 now.  Yet another item for the future project list.  I think it'd actually be neat to record the movement gestures of a human, and also record eye tracking, so that a computer could play it back and understand what a human is looking at in order to know why certain movements are being made.

I then coded up the Arduino to move the carriage head according to mouse movements.  But there was a general problem: collecting mouse movement info via PS/2 using existing libraries was not interrupt-driven, and relied on repeated polling.  So, while the motor was moving, it was easy to lose mouse motion information.  And, I think, making it interrupt-driven would eat up the few interrupt pins available on the Arduino Uno R3.

The initial code structure would pick up a movement made by the mouse, and then immediately would try to move the motors based on that data.  It was a frequent sample-move-sample-move kind of operation.  But, these resulted in having many very small mouse movements, and with more frequent polling, it'd get smaller steps.  Short distances meant low likelihood of running the full acceleration sequence, resulting in very jerky motion by the motor.  There was no look-ahead.

I tried an alternate implementation that blended in the Arduino "smooth" code, thus averaging the last n mouse moves, and combined that with a "stopped" detection (last m mouse positions are the same).  That was a bit better, because it'd wait a bit until I'd stopped moving the mouse, and then move the carriage head a longer distance.  But from a usability standpoint, it felt less satisfying when handling rapid direction reversals, because those would just get averaged out.

For a second attempt, I pulled apart the optical mouse that had a USB connection.  Before going there, I'd hoped to read USB directly, but that required running the Arduino Uno R3 as a virtual USB host, and I didn't have the motivation to do all of that.  If I'd had a later Arduino, I could have done it, since other Arduinos have USB ports built in.

I followed examples online to rewire the optimouse.
Ref: http://www.martijnthe.nl/2009/07/interfacing-an-optical-mouse-sensor-to-your-arduino/
I found it was a little tricky at the part where you're removing the black piece that covered the chip, and I wanted to do that to try to identify the chip.  It was connected to the LED that lights up the area that is being viewed by the chip, so getting the black piece up off the sensor chip required some bending of LED leads.

Once past that, I found that the chip didn't exactly look like the ones referenced on the page, but some came close.  I did a fairly poor job at soldering directly to the chip, but eventually figured it out.  The good thing is that the mouse's innards for an optimouse are a lot more spacious, because the physical form factor isn't stuffed with the mouse ball and black sunflowers.  So, I took the soldered wires, connected them to the four wires of the original USB wire, and stuffed it all back into the original mouse housing.  I'd effectively circumvented the USB circuitry, which also meant that I ended up with no button or Z axis data.  (Note in the picture below how the chip-soldered wires go to the white connector and out to the USB cable, and the white connector is no longer plugged into its housing on the board.)
Innards of optical mouse, rewired, connected via USB port to 0.1"-separated pins for direct breadboard connection


So at this point, I had a not-really-USB optical mouse sending data through a USB cable, then that connected to a PC housing's USB ports, yielding four wires on the inside that I could use.  I then wired and coded according to the Martijn The web site, and through some experimentation, determined that I could use either the PAN3101 or ADNS2051 specifications.  I ended up having a second mouse that I could use for controlling printer movements.  I haven't tried using the full ADNS2051 register set to see if I could get image data from the built-in 16x16 camera, and I'm not sure if it would even obey that command set, so that's another project for the future.

More recently, I've picked up an optical mouse that runs through a PS/2 serial interface, so if I ever want to use it, I should be able to use the PS/2 serial mouse code and go with it.  The original idea was that I would be able to attach the mouse itself to something driven by the motor, and use the mouse data to tell me where things are, but that's not needed now that I have precise stepper motion in the Frankenplotter.

I did have some project thoughts along the way with this.  The one that would seem fun would be having the mouse act as a tail to some kind of wheeled robot, thus providing position feedback to the robot -- kind of like a chariot, where the mouse is that chariot behind some horses.  But, the mouse doesn't convey rotational movement around the Z axis (yaw)  so unless I could sense that, it wouldn't really work.  But, having two mice orthogonal to each other and having that at the end of a rigid tail... now that might be interesting.

[ Edit 7/3/13 ]
I felt it important that I reference this article from here.  Without someone having invented the mouse, I couldn't hack a mouse.
http://blog.sfgate.com/techchron/2013/07/03/doug-englebart-a-computing-giant-passes-away/

No comments:

Post a Comment