Tuesday, February 28, 2012

Remapping Zoom on the Microsoft Natural Keyboard 4000 - Mac OS X

The Microsoft Natural Keyboard 4000 is pretty great, but the "Zoom" slider in the middle never seemed very useful to me - how often do I need to zoom in or out? I scroll much more often than I need to zoom, so it would be nice to remap to scroll instead.
 
Although Microsoft's control panel lets you remap the special function keys, it doesn't let you change the Zoom slider function. Luckily for Windows users there's a fairly simple xml file that you can edit to change the mapping (and there are plenty of explanations: SuperUser, Josh Highland, Joel Bennett, etc).

Unfortunately, the "commands.xml" config file doesn't exist on Mac OS X. Instead, there's a binary file for the configuration, which makes it tough to modify:
/Users/YOUR_NAME/Library/Preferences/com.microsoft.keyboard.pref

After a bit of reverse-engineering, I was able to remap the Zoom slider to the UP and DOWN keys (sadly, using the SCROLL mapping doesn't auto-repeat, so UP/DOWN was the best I could do).

Scrolling Instead of Zooming - The Easy Way:
The easiest way to get scrolling instead of zooming is to replace your com.microsoft.keyboard.pref file with a modified version:
  1. Make sure System Preferences is closed
  2. Download the modified pref file: com.microsoft.keyboard.pref
  3. Navigate to /Users/YOUR_NAME/Library/Preferences/
  4. Back up the com.microsoft.keyboard.pref file (e.g. rename it to com.microsoft.keyboard.pref.old)
  5. Move the modified pref file into that folder
  6. Open System Preferences, and open the Microsoft Keyboard preference panel (this causes the pref file to be reloaded)
If you're interested to see how the file was modified (or want to map the Zoom slider to something other than UP/DOWN), keep reading...

How to reverse-engineer the preferences: 
Since com.microsoft.keyboard.pref is a binary file, opening it with TextEdit or vim isn't going to be very useful. Instead, take a hex dump of the original configuration:

cd /Users/YOUR_NAME/Library/Preferences
xxd com.microsoft.keyboard.pref > prefsOrig.hex

Now we'll make some key mapping changes and see what parts of the pref file change. I changed the Open and Close buttons to do nothing.

Now we'll take another hex dump and compare the two:

xxd com.microsoft.keyboard.pref > prefMod.hex
diff prefOrig.hex prefMod.hex

which outputs:

182,183c182,183
< 0000b50: 0000 0000 0000 0000 0000 0000 0000 5400
< 0000b60: 0000 0000 0000 0000 0000 0000 0000 0000
---
> 0000b50: 0000 0000 0000 0000 0000 0000 0000 0000
> 0000b60: 0000 ff00 0000 0000 0000 0000 0000 0000
185c185
< 0000b80: 0000 0000 0000 5500 0000 0000 0000 0000
---
> 0000b80: 0000 0000 0000 0000 0000 ff00 0000 0000

Notice the changes:
  1. At 0x0000b5e, value 0x5400000000 becomes 0x00000000ff
  2. At 0x0000b86, value 0x5500000000 becomes 0x00000000ff
It looks like the 0xff signifies "None" mode, whereas the 0x54 and 0x55 probably specified the Open and Close functions that used to be there.

You can play around with this technique to figure out how the byte values change with different mappings. For example, let's make Open and Close map to zooming in and zooming out. The pref file diff now looks like:

182,183c182,183
< 0000b50: 0000 0000 0000 0000 0000 0000 0000 5400
< 0000b60: 0000 0000 0000 0000 0000 0000 0000 0000
---
> 0000b50: 0000 0000 0000 0000 0000 0000 0000 0800
> 0000b60: 0000 ff00 0000 0000 0000 0000 0000 0000
185c185
< 0000b80: 0000 0000 0000 5500 0000 0000 0000 0000
---
> 0000b80: 0000 0000 0000 0900 0000 ff00 0000 0000

The changes:
  1. At 0x0000b5e, value 0x5400000000 changes to 0x08000000ff
  2. At 0x0000b86, value 0x5500000000 changes to 0x09000000ff.

The next issue is figuring out which bytes correspond to the Zoom slider's key-mappings. The only control that the GUI provides is enable/disable, zoom speed, and zoom acceleration, so we can mess with those.



If you toggle "Enable zooming" you get a hex diff that looks like:

82,83c82,83
< 0000510: 0000 0000 0000 0000 0000 0000 0000 0800
< 0000520: 0000 0000 0000 0000 0000 0000 0000 0000
---
> 0000510: 0000 0000 0000 0000 0000 0000 0000 0000
> 0000520: 0000 ff00 0000 0000 0000 0000 0000 0000
85c85
< 0000540: 0000 0000 0000 0900 0000 0000 0000 0000
---
> 0000540: 0000 0000 0000 0000 0000 ff00 0000 0000

Notice the similarities to the diff when we changed Open/Close to None:
  1. At 0x000051e, the value 0x0800000000 changes to 0x00000000ff
  2. At 0x0000546, the value 0x0900000000 changes to 0x00000000ff
So it looks like disabling zooming is actually just switching 2 key mappings to None (0x00000000ff) - and now we know where the key mappings for the Zoom buttons are located (0x51e and 0x546)!
Again, we can play around with some other key mappings to figure out the byte values to map keys to the UP and DOWN actions (0x030000007e and 0x030000007d). Now, just apply these values to the prefOrig.hex file, at the addresses we found for the Zoom slider's mappings (0x51e and 0x546):

0000510: 0000 0000 0000 0000 0000 0000 0000 0300
0000520: 0000 7e00 0000 0000 0000 0000 0000 0000
0000530: 0000 0000 0000 0000 0000 0000 0000 0000
0000540: 0000 0000 0000 0300 0000 7d00 0000 0000

(If you want to make your Zoom slider do something other than UP/DOWN, you can replace 0x030000007e and 0x030000007d with different key mappings)

Finally, convert the modified hex dump back into a binary preference file:
xxd -r prefOrig.hex > com.microsoft.keyboard.pref

Now open the Microsoft Keyboard settings panel within System Preferences to get the driver to reload the pref file, and you're all done!

Wednesday, February 15, 2012

Running 6.270 Robotics Competition

This past January I organized and ran MIT's 26th annual 6.270 Autonomous Lego Robotics Competition. Basically groups of 2 or 3 students are given a box with Lego, a microcontroller, motors, and sensors, and they have just 3 weeks to put together and program a fully autonomous robot to compete in a game.

Here's the first part of the final competition video:

MIT Tech TV

Part 2 is on MIT TechTV


This year's game was about capturing territories and gathering resources, on a hexagonal playing field:
The organizing team with the playing field


Robots had to spin a gearbox to capture a territory:



Then they could collect ping pong balls by pulling a lever:



And then dump them on their half of the center:



One of the robots actually shot the ping pong balls into the center:



But the really cool part is that 6.270 is entirely student-run - the organizing team that I led had about 8 core members that took care of everything from ordering Lego, motors, and electronics, to developing lectures and labs to teach the basics of autonomous systems to the ~60 students enrolled in the class. We also design the game itself (playing field, scoring, etc), and interact with companies to get sponsorship for the competition.

We were really ambitious this year, making a hexagonal playing field rather than the usual rectangular one. One of the organizers was able to CNC-cut the plywood:

I did all the electronics in the playing field - programming a microcontroller to read the quadrature encoders on all 6 of the gearboxes, sensing the breakbeams attached to each lever, and controlling the 6 servos that dispensed the ping pong balls. This interfaced with the "vision positioning system" computer that wirelessly transmits each robot's location along with the score, who owns each territory, and how many balls are remaining in each territory - which the robots could use to make decisions.

We also integrated LED lighting in the table to indicate which team owned each territory (using my friend Joe's ACRIS LED controllers):


When we weren't giving lectures or helping contestants with their robots, the organizers had time to build a robot of our own. One of the cooler robot drive systems is omni-drive - each of the wheels are actually compound wheels, made out of a bunch of smaller wheels around the circumference. The smaller wheels are placed perpendicular to the drive direction of the large "wheel", so that it can roll sideways. This allows the robot to strafe in any direction and rotate in place (or both simultaneously). Here's one of the LEGO omni-wheels I designed:

And here's a video of the omnibot in action:




Running 6.270 was a really fun & rewarding experience - I got experience lecturing to a large group of students, learned about the HappyBoard's embedded software, hardware, etc, learned how to do basic PCB layout work on the HappyBoard, taught myself OpenCV to create the vision positioning system, utilized my 6.111 knowledge to do some FPGA programming, interacted with reps from Apple, Oracle, Dropbox, and more!


(My girlfriend made me a LEGO cake after the final competition was over!)



That's all for now. You should watch the final competition video - there were some really amazing robots this year!