");return this;};/* ----------------------------------------------------------------------Format dates*/$.fn.fmtShortDate = function(d) {if (_.isNumber(d)) d = new Date(d);function pad(n) {if (n ");var eml = this.find(".errorMessageLoc");if (eml.length) {eml.append(em);} else {this.append(em);}}if (_.isString(err)) {em.html(err);}else if (!err) {em.html("");}else {em.html("Unknown error " + err.result);}em.show();return em;};$.fn.clearErrorMessage = function() {this.find(".errorMessage").hide();this.find(".errorMessageLoc").empty().hide();return this;};$.fn.fmtSuccessMessage = function(msg, specials) {this.clearSpinner();this.clearErrorMessage();var sm = this.find(".successMessage");if (!sm.length) sm = this.find(".successBox");if (!sm) {sm = $("span class="successMessage">");this.append("").append(sm);}if (_.isString(msg)) {sm.html(msg);}else if (specials && specials.hasOwnProperty(msg.result)) {sm.html("Success! " + specials[msg.result] + "");}else {sm.html("Success! " + msg.result);}sm.show();return sm;};$.fn.clearSuccessMessage = function() {this.find(".successMessage").empty();return this;};var flashErrorMessageTimeout = null;$.flashErrorMessage = function(msg) {var fem = $("#flashErrorMessage");if (fem.length === 0) {fem = $("").appendTo(document.body);var sw = $(window).width();var fw = fem.width();fem.css({left: Math.floor((sw-fw)/2 - 30).toString() + "px"});}var em = $("");fem.append(em).show();fem.fmtErrorMessage(msg);if (flashErrorMessageTimeout) {clearTimeout(flashErrorMessageTimeout);}flashErrorMessageTimeout = setTimeout(function() {fem.fadeOut(500, function() {$(this).empty();});}, 2000);};/* ----------------------------------------------------------------------DOM structure utilities*/$.fn.findOrCreate = function(sel, constructor) {var findSel = this.find(sel);if (findSel.length) {return findSel;} else {this.append(constructor);return this.find(sel);}};$.fn.toplevel = function() {return this.closest("body"); // might change when we have sub-panels};$.fn.syncChildren = function(newItems, options) {var top = this;if (top.length === 0) return;if (top.length > 1) return top.first().syncChildren(newItems, options);var domKey = options.domKey || "syncDomChildren";var domClass = options.domClass || "syncDomChildren";var removeEl = options.removeEl || function(name) {top.fadeOut(500, function() { $(this).empty(); });};var createEl = options.createEl || function(name) {return $("");};var setupEl = options.setupEl || function() {};var updateEl = options.updateEl || function() {};// Find all contained dom elements with domClass, index them by domKeyvar oldEls = {};_.each(top.children(), function(oldEl) {var name = $(oldEl).data(domKey);if (name !== undefined) {oldEls[name] = oldEl;}});// Index newItems by namevar itemToIndex = {};_.each(newItems, function(name, itemi) {itemToIndex[name] = itemi;});// Remove orphaned elems (in oldEls but not in itemToIndex)_.each(oldEls, function(name) {if (!itemToIndex.hasOwnProperty(name)) {removeEl.call($(oldEls[name]), name);}});// Insert new elems into domvar afterEl = null;_.each(newItems, function(name, itemi) {if (oldEls.hasOwnProperty(name)) {afterEl = oldEls[name];} else {var newEl = createEl(name);if (!newEl) return;if (newEl.length) newEl = newEl[0]; // unwrap if already wrapped in jquery$(newEl).data(domKey, name);oldEls[name] = newEl;if (afterEl) {$(afterEl).after(newEl);afterEl = newEl;} else {top.prepend(newEl);afterEl = newEl;}setupEl.call($(newEl), name);}/*If calcSignature is supplied, we use it to avoid updates when nothing has changed.It should be a signature across everything that matters for the content*/if (options.calcSignature) {var signature = options.calcSignature(name);var oldSignature = $(oldEls[name]).attr("signature");if (signature !== oldSignature) {$(oldEls[name]).attr("signature", signature);updateEl.call($(oldEls[name]), name);}} else {updateEl.call($(oldEls[name]), name);}});// Return map of old & new elementsreturn oldEls;};/* ----------------------------------------------------------------------Animation*/// Polyfill for browsers with no requestAnimationFrame(function() {var lastTime = 0;var vendors = ["ms", "moz", "webkit", "o"];for (var x = 0; x = maxTicks) {nticks = maxTicks;}else {nticks = curtick - lasttick;}lasttick = curtick;if (nticks > 0) {f.call(self, nticks);}window.requestAnimationFrame(wrap);} else {if (console) console.log(self, "disconnected");}}};/*Arrange for a model to be used in animating the DOM efficiently.Instead of just callingm.on("changed", function() { ... draw stuff ... })do this:top.animation2(m);m.on("animate", function() { ... draw stuff ... });We use requestAnimationFrame to turn multiple "changed" notifications into a single "animate"notification per screen refresh.As well as emitting the "animate" signal, it calls m.animate(dt) where dt is the time (in seconds) elapsed sincethe last call, limited to reasonable bounds to provide smooth animation.It also checks on each animation whether the the dom element is still in the document, and shutsdown when not.*/$.fn.animation2 = function(m) {var top = this;var lastTime = 0;var mChangeCounter = 0;var vChangeCounter = 0;var afActive = false;m.on("changed", function() {if (mChangeCounter === vChangeCounter) mChangeCounter++;if (!afActive) {afActive = true;lastTime = 0;window.requestAnimationFrame(wrap);}});return;function wrap(curTime) {if (top.closest("body").length === 0) {if (console) console.log(top, "disconnected");return; // leaving afActive true, so we shouldn"t get called any more}if (vChangeCounter !== mChangeCounter) {vChangeCounter = mChangeCounter;var dt = (lastTime ? Math.min(curTime - lastTime, 200) : 20) * 0.001;lastTime = curTime;if (m.animate) m.animate(dt);m.emit("animate");window.requestAnimationFrame(wrap);} else {afActive = false;}}};/*Super-simple layout helper for drawing in canvases.If you want to create a sub-box, do something like:lo.child({boxL: (lo.boxL+lo.boxR)/2})Use .snap or .snap5 to snap a coordinate to the corner or center of a device pixel*/function BoxLayout(t, r, b, l, pixelRatio) {this.boxT = this.canvasT = t;this.boxR = this.canvasR = r;this.boxB = this.canvasB = b;this.boxL = this.canvasL = l;this.pixelRatio = pixelRatio;this.thinWidth = 1 / pixelRatio;if (pixelRatio >= 2) {this.lrgFont = "20px Arial";this.medFont = "10px Arial";this.smlFont = "9px Arial";this.tinyFont = "7px Arial"} else {this.lrgFont = "25px Arial";this.medFont = "12px Arial";this.smlFont = "10px Arial"this.tinyFont = "8px Arial"}}BoxLayout.prototype.snap = function(x) {return Math.round(x * this.pixelRatio) / this.pixelRatio;};BoxLayout.prototype.snap5 = function(x) {return (Math.round(x * this.pixelRatio - 0.5) + 0.5) / this.pixelRatio;};BoxLayout.prototype.child = function(changes) {if (changes) {return _.extend(Object.create(this), changes);} else {return Object.create(this);}};BoxLayout.prototype.toString = function() {return "box(" + this.boxL.toFixed(1) + "," + this.boxT.toFixed(1) + "," + this.boxR.toFixed(1) + "," + this.boxB.toFixed(1) + ")";};BoxLayout.prototype.childBox = function(t, r, b, l) {var ret = Object.create(this);ret.boxT = t;ret.boxR = r;ret.boxB = b;ret.boxL = l;return ret;};/*Animate a canvas based on a model.Call on a pre-existing canvas dom node.This calls drawFunc with (m, ctx, hd, lo, o), where:m is a provided model (with .emit and .on)ctx is a 2d rendering context on the canvashd is a HitDetector, persisistent between callslo is a BoxLayout filled in with the canvas dimensions.o is the provided options objectIt captures most mouse events on the canvas:wheel, mousedown, mousemove, mouseup.These can be acted on by adding callbacks to hd inside drawFuncConvention is for drawFunc to add properties to lo as it works out the geometry of what it"s drawing, and pass it around to subordinate drawing functions.On a Retina or similar screen, this arranges to double the pixel size of the canvas andscale it back down, so you get sharp results. It will scale the drawing context so drawFunc canthink in css pixels, including for mouse hit detection.lo.canvas[LTRB] are always the (css-pixel) canvas dimensionslo.box[LTRB] start out as the canvas dimensions, but could be If you want to snap to device pixels to get super-crisp 1-pixel lines do this:ctx.lineWidth = lo.thinWidth;ctx.moveTo(lo.snap5(x), y1);ctx.lineTo(lo.snap5(x), y2);lo.snactx gets some extra properties added, like .tooltipLayer which adds its argument to a deferredqueue to be rendered after the rest of rendering is done. Usage:ctx.tooltipLayer(function() {drawTooltip(ctx, ...);})There"s also .textLayer, .cursorLayer, .buttonLayer and .curLayer, which calls its argumentimmediately*/$.fn.mkAnimatedCanvas = function(m, drawFunc, o) {var top = this;top.maximizeCanvasResolution();var canvas = top[0];var avgTime = null;var drawCount = 0;var hd = new HitDetector(); // Persistent// Isn"t this what jQuery is supposed to do for me?// http://stackoverflow.com/questions/12704686/html5-with-jquery-e-offsetx-is-undefined-in-firefoxfunction eventOffsets(ev) {if (ev.offsetX !== undefined) {return {x: ev.offsetX, y: ev.offsetY};}// Firefox doesn"t have offsetX, you have to work from page coordinatesif (ev.pageX !== undefined) {return {x: ev.pageX - top.offset().left,y: ev.pageY - top.offset().top};}// jQuery doesn"t copy pageX when the event is "wheel"if (ev.originalEvent.pageX !== undefined) {return {x: ev.originalEvent.pageX - top.offset().left,y: ev.originalEvent.pageY - top.offset().top};}return null;}function eventDeltas(ev) {if (ev.deltaX !== undefined) {return {x: ev.deltaX, y: ev.deltaY};}if (ev.originalEvent && ev.originalEvent.layerX !== undefined) {return {x: ev.originalEvent.deltaX, y: ev.originalEvent.deltaY};}return {x:0, y: 0};}top.on("wheel", function(ev) {var md = eventOffsets(ev);if (!md) return;var action = hd.findScroll(md.x, md.y);if (action && action.onScroll) {var deltas = eventDeltas(ev);if (deltas) {action.onScroll(deltas.x, deltas.y);m.emit("changed");}return false;}});top.on("mousedown", function(ev) {var md = eventOffsets(ev);var action = hd.find(md.x, md.y) || hd.defaultActions;if (action) {if (action.onDown || action.onClick || action.onUp) {hd.buttonDown = true;hd.mdX = md.x;hd.mdY = md.y;if (action.onDown) {action.onDown(hd.mdX, hd.mdY, ev);if (hd.dragging && hd.dragCursor) {// see https://developer.mozilla.org/en-US/docs/Web/CSS/cursor?redirectlocale=en-US&redirectslug=CSS%2Fcursor// Grab not supported on IE or Chrome/Windowstop.css("cursor", hd.dragCursor);}}}}m.emit("changed");return false;});top.on("mousemove", function(ev) {var md = eventOffsets(ev);var action = hd.find(md.x, md.y);if (hd.buttonDown || hd.hoverActive || hd.dragging || (action && action.onHover)) {hd.mdX = md.x;hd.mdY = md.y;if (hd.dragging) {hd.dragging(hd.mdX, hd.mdY);}m.emit("changed");}});top.on("mouseup", function(ev) {hd.mdX = hd.mdY = null;hd.buttonDown = false;var md = eventOffsets(ev);var action = hd.find(md.x, md.y);if (action && action.onClick) {action.onClick();}if (action && action.onUp) {action.onUp();}if (hd.dragging && hd.dragCursor) {top.css("cursor", "default");hd.dragCursor = null;}hd.dragging = null;m.emit("changed");return false;});m.on("animate", function() {var t0 = Date.now();drawCount++;var ctx = canvas.getContext(o.contextStyle || "2d");var pixelRatio = canvas.pixelRatio || 1;ctx.save();ctx.scale(pixelRatio, pixelRatio);ctx.curLayer = function(f) { return f(); };ctx.textLayer = mkDeferQ();ctx.buttonLayer = mkDeferQ();ctx.cursorLayer = mkDeferQ();ctx.tooltipLayer = mkDeferQ();hd.beginDrawing(ctx);var cw = canvas.width / pixelRatio;var ch = canvas.height / pixelRatio;var lo = new BoxLayout(0, cw, ch, 0, pixelRatio);ctx.clearRect(0, 0, cw, ch);ctx.lineWidth = 1.0;ctx.strokeStyle = "#000000";ctx.fillStyle = "#000000";drawFunc(m, ctx, hd, lo, o);ctx.textLayer.now();ctx.buttonLayer.now();ctx.cursorLayer.now();ctx.tooltipLayer.now();ctx.textLayer = ctx.buttonLayer = ctx.cursorLayer = ctx.tooltipLayer = ctx.curLayer = undefined; // GC paranoiaif (m.uiDebug >= 1) {var t1 = Date.now();if (avgTime === null) {avgTime = t1 - t0;} else {avgTime += (t1 - t0 - avgTime)*0.05;}ctx.fillStyle = "#888888";ctx.font = lo.tinyFont;ctx.textAlign = "right";ctx.textBaseline = "top";ctx.fillText(drawCount.toString() + " " + avgTime.toFixed(2), lo.boxR - 5, lo.boxT + 1);}hd.endDrawing();ctx.restore();});};/* ----------------------------------------------------------------------Track all key events within a document object. The hash (down) keeps track of what keys are down, and (changed) is called whenever anything changes.*/$.fn.trackKeys = function(down, changed) {$(window).on("keydown", function(ev) {var keyChar = String.fromCharCode(ev.which);down[keyChar] = true;if (changed) changed();});$(window).on("keyup", function(ev) {var keyChar = String.fromCharCode(ev.which);down[keyChar] = false;if (changed) changed();});};/* ----------------------------------------------------------------------On some browsers on retina devices, the canvas is at css pixel resolution. This converts it to device pixel resolution.*/$.fn.maximizeCanvasResolution = function() {this.find("canvas").each(function(index, canvas) {var ctx = canvas.getContext("2d");var devicePixelRatio = window.devicePixelRatio || 1;var backingStoreRatio = (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio ||ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);if (devicePixelRatio !== backingStoreRatio) {var ratio = devicePixelRatio / backingStoreRatio;var oldWidth = canvas.width;var oldHeight = canvas.height;canvas.pixelRatio = ratio;canvas.width = oldWidth * ratio;canvas.height = oldHeight * ratio;canvas.style.width = oldWidth + "px";canvas.style.height = oldHeight + "px";} else {canvas.pixelRatio = 1;}});return this;};/*mkDeferQ is a way of deferring drawing some elements on a canvas so they can be layered on top.Usage: ctx.textLayer = mkContextLayer();...ctx.textLayer(function() { // the closure is queuedctx.fillText(...);});...ctx.textLayer.now(); // the fillText gets executed*/function mkDeferQ() {var q = [];function defer(f) {q.push(f);}defer.now = function() {for (var i=0; i");el.prop("href", path);var url = el.prop("href");var wsUrl = url.replace(/http/, "ws");// WRITEME: detect vendor-prefixed WebSocket.// WRITEME: Give some appropriately dire error message if websocket not found or fails to connectvar wsc = new WebSocket(wsUrl);return WebSocketBrowser.mkWebSocketRpc(wsc, handlers);}/* ----------------------------------------------------------------------Called from web page setup code (search for pageSetupFromHash in Provider.js)*/function pageSetupFromHash(reloadKey) {setupConsole(reloadKey);setupClicks();gotoCurrentHash();startHistoryPoll();}"use strict";function HitDetector() {var hd = this;hd.hits = [];hd.scrolls = [];hd.defaultActions = null;hd.buttonDown = false;hd.mdX = hd.mdY = null;hd.ctx = null;hd.hoverActive = false;hd.dragging = null;}HitDetector.prototype.clear = function() {var hd = this;hd.hits = null;hd.scrolls = null;hd.defaultActions = null;hd.ctx = null;hd.hoverActive = false;hd.dragging = null;};HitDetector.prototype.beginDrawing = function(ctx) {var hd = this;hd.ctx = ctx;hd.hits.length = 0;hd.scrolls.length = 0;hd.defaultActions = null;hd.hoverActive = false;};HitDetector.prototype.endDrawing = function(ctx) {var hd = this;hd.ctx = null;};HitDetector.prototype.mouseIn = function(t, r, b, l) {var hd = this;return hd.mdX >= l && hd.mdX = t && hd.mdY = hit.l && x = hit.t && y = scroll.l && x = scroll.t && y lo.boxR - 10 - textW) {x = lo.boxR - 10 - textW;}var ttL = x - 6;var ttR = x + 6 + textW;var ttT = y - textH/2;var ttB = y + textH/2 + 2;ctx.beginPath();ctx.moveTo(ttL, ttT);ctx.lineTo(ttR, ttT);ctx.lineTo(ttR, ttB);ctx.lineTo(ttL, ttB);ctx.closePath();ctx.fillStyle = "rgba(255,255,202,0.9)";ctx.fill();ctx.fillStyle = "#000023";_.each(lines, function(line, lineIndex) {ctx.fillText(line, x, ttT + 10 + lineH * lineIndex);});});}function mkShinyPattern(ctx, butT, butR, butB, butL, loCol, hiCol) {var cX = (butL + butR)/2;var skew = 0;var pat = ctx.createLinearGradient(cX-skew, butT, cX+skew, butB); // verticalpat.addColorStop(0.125, "#e5e5e5");pat.addColorStop(0.250, loCol);pat.addColorStop(0.375, hiCol);pat.addColorStop(0.875, "#e5e5e5");pat.addColorStop(1.000, "#e5e5e5");return pat;}function drawRountangle(ctx, t, r, b, l, rad) {ctx.moveTo(l+rad, t);ctx.lineTo(r-rad, t);ctx.arc(r-rad, t+rad, rad, -Math.PI/2, 0);ctx.lineTo(r, b-rad);ctx.arc(r-rad, b-rad, rad, 0, Math.PI/2);ctx.lineTo(l+rad, b);ctx.arc(l+rad, b-rad, rad, Math.PI/2, Math.PI);ctx.lineTo(l, t+rad);ctx.arc(l+rad, t+rad, rad, Math.PI, Math.PI*3/2);}function drawSpinner(ctx, spinnerX, spinnerY, spinnerSize, phase) {var dotSize = 0.15 * spinnerSize;for (var i=0; iNot FoundNot Found. Go to Front page.");};$.defPage("", function(o) {document.title = "Trevor Blackwell";this.html("Trevor BlackwellAbout meY CombinatorUmbrella ResearchBlogA self-balancing electric unicycleA self-balancing two-wheeled scooterFree software I\"ve writtenPictures on FlickrResearch PapersFrequently Asked Questions");this.find(".footer").fmtTlbFooter(o);});$.fn.fmtTlbFooter = function(o) {this.html("Copyright 2014 Trevor Blackwell. Home");};$.defPage("aboutMe", function(o) {document.title = "About Trevor Blackwell";this.html("About MeI\"m a partner in Y Combinator, a new kind of venture firm specializing in early stage startups. We have funded and helped more than 600 startup companies.I founded Umbrella Research in 2001. We developed the Anybots brand of telepresence robots, now operating as a separate company. We also developed research robots including Monty, a teleoperated robot with arms and Dexter, a human-sized two-legged walking robot.Before that (1995-2001) I was a co-founder of Viaweb, which made easy end-user e-commerce software. I developed the merchant order processing and statistics systems. We were acquired by Yahoo, and our product became Yahoo Store.As a grad student at Harvard (1993-1998) I worked on randomized network protocols, randomized compiler optimizations, and other random things. I published in the proceedings of ACM SIGCOMM, IEEE Infocom, and Usenix. Download the papers.I\"ve also done a number of recreational hacking projects and published the results on the web, such as the balancing scooter, improved keyboard, and ultra-realistic Apple ][ mode for xscreensaver.");this.find(".footer").fmtTlbFooter(o);});$.defPage("software", function(o) {document.title = "tlb: Publicly Available Software";this.html("Publicly Available SoftwareThese days I put it all on Github, but these are some older projectsCheat DetectorDetects similiarities in source code. Handles hundreds of students\" submissions in seconds. Handles most languages.Sourceforge ProjectApple II mode for X ScreensaverJamie Zawinski\"s X11 Screensaver has a nice \"bsod\" mode, which shows the Blue Screen of Death and crash graphics from a few other operating systems. I added an Apple II mode, which faithfully emulates the distortions and color reproduction on a late-70s analog television set. Ah, the good old days of 40x24 pages of uppercase text.Patch from release 4.09. Note: this is now included in 4.10.");this.find(".footer").fmtTlbFooter(o);});$.defPage("faq", function(o) {document.title = "tlb: FAQ";this.html("Frequently Asked QuestionsAre you the Trevor Blackwell I met at X?Here are some times and places you might have met me: Saskatoon, (1969-1985), Ottawa (1985-1993), Gloucester High School (1985-1988), Carleton Unversity, B.Eng (1988-1992), BNR/Nortel, Ottawa (1988-1993), Harvard University, Ph.D in Computer Science (1993-1998), Viaweb (1995-1998), Los Altos, CA (1998-2005), Yahoo (1998-2001), Mountain View, CA (2005-), Anybots (2001-), Y Combinator (2005-).You might have seen me talk at: Stanford University (2003, 2004), Harvard University (1993-1998), Carnegie Mellon University (2004), IEEE Infocom (1996), ACM Sigcomm (1994, 1996), The Hackers Conference (2003-2006), USENIX (1995, 2006). I\"ve also been at: the International Physics Olypiad (1988), the ACM Programming contest (1993), the Spam Conference (2003), RoboNexus (2004), IROS (2002, 2004), Burning Man (2001, 2005). I\"ve vacationed in Hawaii (1999, 2000, 2003), Istanbul (2005), Iceland (2004), France (1996), England (1984), Munich (1997). I\"ve been at the Homebrew Robotics Club in Mountain View (2001-).Can I have the source code for your balancing scooter?You can download the source code for the electric unicycle. All the hard parts are the same; it\"s just missing the steering control.Some of your predictions are wrong!I\"ll let history be the judge. Only send me your arguments if you think I\"m unlikely to have heard that point of view before.You say spam cannot be stopped, but I have a foolproof plan to stop spam.Well, get to work on it then.Will you invest in my company?Y Combinator, in which I\"m a partner, invests and helps early-stage startups find their market. We do two funding cycles per year.What programming language should I learn?Start with Python. It\"s clean, powerful, aesthetically pleasing, and simple to learn. Squeak, a modern version of Smalltalk, is also excellent, but it\"s out of the mainstream. You\"ll need to learn C at some point, but you\"ll write better programs if you think in terms of the high-level abstractions provided by Python and translate to C as you type. At some point, you should learn Lisp.Besides their intrinsic characteristics, languages define commmunities of programmers. You want to choose one that lets you communicate with good programmers, because you\"ll learn from them. They tend to prefer powerful languages like Python, Lisp, and C++. So for example, although Visual Basic is actually a powerful and complete language, few good programmers use it. C++, on the other hand, is a poorly designed language, but for historical reasons a lot of smart people use it so at least you\"ll be in good company.The principle applies to operating systems too. Although Windows 2000 and its successors are perfectly reasonable operating systems, few of the good programmers use them, so if you do, most of your colleagues will be mediocre. FreeBSD or Linux have much better communities around them.How should I become a better programmer?Spend time reading other people\"s well-written programs. Sadly, a lot of Linux and Gnome open source is poorly written. Good code bases that I know of include:The kernel and utilities for FreeBSD.Bittorrent, an elegant Python program with both serious algorithms and good UI.Squeak, which is written in itself. It includes the complete source to its powerful GUI system, and is the only GUI toolkit I know of that is clean, readable, and hackable.Python, both the interpreter (in C) and libraries (in Python.)LCC, the lightweight C compiler along with the excellent book documenting it: A Retargetable C Compiler: Design and Implementation by David R. Hanson. It\"s worth reading even if you have no interest in writing compilers.I\"m an expert programmer. Can you recommend good books?Algorithms by Cormen, Leiserson and Rivest; The Structure and Interpretation of Computer Programs by Abelson and Sussman; On Lisp by Paul Graham (whether or not you use Lisp); all of Don Knuth\"s books, though you\"ll have to buckle down to get through them. Some good books on specific topics include: Unix Network Programming by Stevens; Garbage Collection by Jones and Lin; A Retargetable C Compiler: Design and Implementation by Fraser & Hanson.I want to get into robotics. How should I start?Get a robot kit you can program from a PC, and start making it do interesting things. I think the best one is the Bioloid, a kit that can make anything from a humanoid to a snake and has a usable programming interface from the PC. Their actuators are much more smooth and reliable than the hobby servos that people used to build such robots out of.Robotics is a huge, multidisciplinary field. Anything you learn in mechanical engineering, electronics, real-time software, machine vision, or learning or planning techniques will be useful.I just got my Bachelor\"s degree in CS. Should I get a Ph.D.?I did, and I value the experience greatly. It was much more satisfying and more fun than my undergrad degree. I learned something from taking classes, something from writing papers and grant applications, and a measure of self-discipline from having to actually produce a thesis. But the best part was interacting with all the smart people there. I learned a lot from them, and met people who became important friends and business partners.On the other hand, many smart and successful people I\"ve known in industry didn\"t have any degree at all. Programming courses aren\"t the place to learn programming -- you can only learn it by doing. (However, grad school is an excellent time and place to work on cool extracurricular programming projects with friends.)If you have a longer time horizon, I think the most promising fields are robotics and biotechnology.");this.find(".footer").fmtTlbFooter(o);});$.defPage("predictions", function(o) {document.title = "tlb: Predictions";this.html("Predictions O God, grant me today my daily idea, and forgive me yesterday\"s. -- Bernard Berenson These are some predictions I have made over the years. Many of them are already proven wrong, some right.I\"m not going to erase any predictions; if I change my mind I\"ll add an updated prediction. An excellent site for major predictions (often with significant wagers) is Long Bets. Technology June, 2004: Spam email will never be greatly reduced by any technological fix. See my essay for more detail. July, 2002: Moore\"s law will run out of steam by 2012. Moore\"s law suggests that computers in 2022 will have 10000x the power of todays (say, 30 TIPS) but I think they will have no more than 100x (say, 300 GIPS). [Opposing views: Sheldon Renan] July, 2002: Robot butlers, capable of cooking, cleaning, and interacting in fairly natural ways will become available by 2010 and common by 2020. July, 2002: CDs and DVDs compatible with today\"s will remain the most common way to buy or rent music or video through 2020. July, 2002: Word processors, spreadsheets, web browsers, and email will have substantially the same features in 2020 as today. July, 2002: In 2030, most people will communicate over telephones much like today\"s, and telephones will still be dialed like they are today. Videoconferencing will remain an exotic feature. July, 2002: In 2075, most fiction will be read in paper book form. July, 2002: In 2050, most people will still drive to work in a car with a gasoline engine getting less than 60 MPG. The real price of gasoline in the US will not rise by more than a factor of 3. July, 2002: Computers available to consumers will have hardware controls to prevent copying of CDs and DVDs by 2020. Only a few hobbyists will be able to copy digital media. July, 2002: Most consumers will watch NTSC analog television through 2020; digital or HDTV television will remain a curiosity for audiophiles. July, 2002: Video on demand will not supplant video store rentals before 2020. July, 2002: Voice recognition will not supplant keyboards for tasks such as word processing before 2050. July, 2002: Less than 5% of US homes will have internet connections of more than 500 kbits by 2010. July, 2002: Supersonic air travel will account for only a tiny fraction of all air travel in 2100. Airport delays will continue to add more than an hour to most trips. July, 2002: No person will set foot on the moon or another planet between now and 2100. [Opposing views: Hemant Sharma] Economy July, 2002: The NASDAQ index will drop below 900 and the DOW below 6000 before the end of 2003. [WRONG: it climbed back to about 2000 at the end of 2003.]July, 2002: At least 5 more Fortune-100 companies (after Enron and Worldcom) will declare bankruptcy before 2005; accounting tricks will have hidden their large losses until their collapse. July, 2002: By 2100, most developing countries except those in sub-Saharan Africa will enjoy a standard of living comparable to today\"s in the western world. The exceptions will be due to political repression, not fundamental limits. July, 2002: The US will remain the world\"s largest economy through 2100. July, 2002: Russia will not become a technological leader by 2020. It will have a per-capita GDP lower than China\"s in 2050. [Opposing views: Esther Dyson] World July, 2002: There will not be a nuclear weapon detonated in anger before 2100. July, 2002: Taiwan will still be an effectively independent country in 2050; China will still deny their independence. July, 2002: There will not be an effective world government before 2100. [Opposing view: Colin R. Glassey] July, 2002: The population of the world will not exceed 10 billion before 2100. Medicine July, 2002: AIDS will cause 100 million deaths before being eradicated. July, 2002: Before 2050 a new disease, not due to biotechnology but simply a naturally evolved virus, will cause at least 100 million deaths. July, 2002: Prion-borne diseases (as Creutzfeldt-Jakob disease) will not cause more than 3000 human deaths before 2100. July, 2002: No disease epidemic will ever again wipe out more than 1/4 of mankind. July, 2002: By 2100, most Americans will live to be over 120 years old. [Opposing view: S. Jay Olshansky] Aug, 2002: By 2030, most forms of cancer will be found to be viral in origin. ");this.find(".footer").fmtTlbFooter(o);});$.defPage("papers", function(o) {document.title = "tlb: Papers";this.html("PapersT. Blackwell. Applications of Randomness in System Performance Measurement.Ph.D. Thesis, Harvard University, 1998.Postscript VersionT. Blackwell. Fast Decoding of Tagged Message Formats.In Proceedings of IEEE/ACM INFOCOM \"96Postscript VersionT. Blackwell. Speeding up Protocols for Small Messages.In Proceedings of ACM SIGCOMM \"96Postscript VersionNikolas Gloy, Trevor Blackwell, Michael D. Smith, and Brad Calder. Procedure Placement using Temporal Ordering Information.In Proceedings of the 30th Annual IEEE/ACM International Symposium on Microarchitecture, pp 303-313, December 1997Postscript VersionT. Blackwell, J. Harris, M. Seltzer. Heuristic Cleaning Algorithms in Log-Structured File Systems.In Proceeding of the Winter 1995 Usenix Conference.Postscript VersionT. Blackwell, K. Chan, K. Chang, T. Charuhas, J. Gwertzman, B. Karp, H.T. Kung, W.D. Li, D. Lin, R. Morris, R. Polansky, D. Tang, C. Young, J. Zao. Secure Short-Cut Routing for Mobile IP.Conference Proceedings of Usenix Summer 1994 Technical Conference. pp305-316Postscript VersionT. Blackwell, K. Chan, K. Chang, T. Charuhas, B. Karp, H.T. Kung, D. Lin, R. Morris, M. Seltzer, M. Smith, C. Young, O. Bhagat, M. Chaar, A. Chapman, G. Depelteau, K. Grimble, S. Huang, P. Hung, M. Kemp, I. Mahna, J. McLaughlin, M.T. Ng, J. Vincent, J. Watchorn. An Experimental Flow-Controlled Multicast ATM Switch.Proceedings of the First Annual Conference on Telecommunications in Massachussetts.Postscript VersionT. Blackwell, K. Chang, H.T. Kung, D. Lin. Credit-Based Flow Control for ATM Networks.Proceedings of the First Annual Conference on Telecommunications in MassachussettsPostscript VersionH. T. Kung, T. Blackwell, A. Chapman. Credit-Based Flow Control for ATM Networks.Proceedings of SIGCOMM \"94Postscript VersionH. T. Kung, T. Blackwell, A. Chapman. Adaptive Credit Allocation for Flow-Controlled VCs.ATM Forum Contribution, March 1994Postscript Version");this.find(".footer").fmtTlbFooter(o);});$.defPage("eunicycle", function(o) {document.title = "tlb: Electric Unicycle";this.html("The Electric UnicycleRiding a unicycle is the most useless thing you can do. -- Ricky Gervais. Some time ago I built a self-balancing two-wheeled scooter. Since then I realized that two wheels are redundant, and only a single wheel is needed to make a ridable vehicle. A vehicle with a single wheel is much smaller and lighter. It weighs under 30 lbs and is easily carried with one hand when going up stairs or on public transportation. MPEG Video [4.2 MB] The Electric Unicycle\"s only control is the on-off switch. The rider controls everything else by shifting his weight. You lean forward to accelerate, lean backwards to brake, and gyrate your arms wildly to turn. With a little practice you can get more graceful and keep your arms mostly by your side.The unicycle balances itself using a simple feedback loop between a solid-state gyroscope and the wheel motor. When it detects itself tilting forward, it runs the wheel forward to keep it vertical. When it detects itself tilting backwards it runs the wheel backwards. It does this so rapidly (200 updates per second) that it feels perfectly smooth. This is really the same thing that a conventional unicycle rider does with his legs.Although I could have reused the electronics for my balancing scooter, I designed a better system, partly to lower cost and partly to improve performance. Version 1 of the scooter used a RoboteQ motor controller, which takes tens of milliseconds to respond to motor speed commands. The unicycle uses an OSMC motor controller which takes a PWM drive signal directly from the microcontroller, reducing delay to less than a millisecond. The result is a smoother, stiffer feel with less wobble. It\"s also smaller, lighter, and cheaper.Building your own Update:: This instructables project is an easier place to start.Want to look more eccentric as you cruise the neighborhood? Build your own electric unicycle!You need the parts listed below, some welding, fabrication, electronics, programming, and control skills, some physical skill, and some bravery. My code is downloadable below, but you\"ll probably need to tweak it a bit for your exact electronics and hardware configuration. Or better yet, build something else and tell me about it! There are lots of possibilities for balancing vehicles that haven\"t been explored.What I said about safety for the two wheel scooter applies, but there is a major difference. While the 2-wheeled scooter is easy to ride (I\"ve let maybe 100 people ride it without a single fatality) the Electric Unicycle takes a good deal of practice. You don\"t want to be learning how to control such a vehicle at the same time as debugging it, so you really need to learn to ride a regular unicycle first. I got a "United 24-inch Trainer for Adults" from Unicycle.com and spent a couple months learning to ride it before I built the electric version.Components All together the components, in single unit retail quantities, cost about $1500. They are: A microcontroller board from BDMicro featuring the Atmel AVR Mega 128. $125. A gyroscope and acceleromoter by Rotomotion. $149. The OSMC motor controller by Robot Power. $199. 40 NIMH cells, made into nice packs by Robot Marketplace. $218. A Magmotor S28-150. $299 The Whyachi TWM3M gearbox. $345. A 16-inch bicycle rim with spokes. $35 from your local bike shop. I use a 100 psi tire, which makes turning slightly easier. A custom-machined hub. A GT2 5 mm pitch belt, and 28 and 72-tooth pulleys. $21, $26 and $14. Some 1" diameter tubing, TIG-welded together. $40 A guard for the upper pulley, machined from black Acetal plastic. Some spacer bushings to center the wheel. A combination dead man\"s switch and key. $12. A unicycle seat. $24. The component I would most like to replace is the Whyachi gearbox. It makes a very loud gear whirring sound, which is fine for battlebots but undermines the graceful gliding look.DownloadsYou can download the complete software here. The mechanical fabrication drawings are available in Postscript (use the Ghostscript viewer) and as an eDrawing (use the eDrawing viewer.)Links The Einrad-Fahrzeug is another self-balancing unicycle. It has a wide wheel to make it laterally stable.The eniCycle has a steering mechanism that might make side-to-side balancing easier.");this.find(".footer").fmtTlbFooter(o);});$.defPage("scooter2", function(o) {document.title = "tlb: Balancing Scooter 2";this.html("Balancing Scooter Version 2The original balancing scooter I made in late 2002 had some shortcomings, so in January 2005 I set out to make a better one. Version 2 is faster, lighter, smoother, and has more range. It has 3 inches more ground clearance, it\"s an inch narrower so it fits through doorways better, and it has a much better steering system.Version 1Segway i-SeriesVersion 2Speed9 MPH12.5 MPH15 MPHWeight90 lb80 lb70 lbSteeringtouch padstwist griphandlebarsI was prodded to build version 2 when Chris Johnson brought over his two Segways and we went for a ride. (I had never ridden one any distance before.) The Segway was faster and smoother than my machine. The gauntlet was thrown! I had to surpass it. As usual, I followed my personal rule for building projects: only use parts that can be ordered over the internet without talking to anyone. Wheels Some punk riding it The first change was larger, lighter, smoother wheels. The original wheels were 14" diameter foam-filled trailer tires. They had fairly high rolling resistance, and one of them had started to make a skrupp-skrupp sound every time it went around where the foam was peeling away from the rubber inside.I decided to change to bicycle tires. They are lighter and have less rolling resistance than the trailer tires, and the narrower width helps it fit through doorways. To do this, I bought a pair of 20 inch diameter bicycle wheels (rim, hub and spokes) and machined a new hub to bolt onto the output shafts of my motors. I started with a 3.5" diameter by 3" long cylinder of steel, machined the mounting faces, removed 80% of the material to reduce weight, and then drilled 36 holes around the rim to fit the spokes. The diameter of the hub is larger than the original hub to get maximum torsional stiffness of the wheel. After the tedious job of stringing, tightening, and adjusting the spokes for even tension and no wheel wobble, I put on 100 PSI snake belly tires. The 20" wheels propel the scooter 43% faster for a given motor speed than the 14" wheels and give 3" more ground clearance. They also look much better, especially with the all-black smooth tires. The narrower wheels reduce the width by about an inch, making it much easier to get through doorways. Segway Polo I may make a second set of wheels and outfit them with knobby mountain bike tires, for playing Segway Polo on grass. Electronics I also replaced all the electronics. Version 1\"s electronics were chosen for maximum convenience. Version 2\"s electronics are designed for performance. I replaced the dual-channel RoboteQ motor controller with two OSMC controllers. While the RoboteQ is fine for many applications, its use of a 9600 baud serial link for control added too much delay to the feedback loop for good performance. The OSMC controllers take a PWM signal directly from the microcontroller. I also get more precision in the PWM control: 9 bits instead of 7. Most important of all is how the OSMC lets me precisely control motor voltage, regardless of the condition of the batteries. In the RoboteQ system I couldn\"t measure battery voltage fast enough to include in the feedback loop, so the gain in the balance feedback loop depended on the resistance in the batteries, which increases as they run down. Fresh off the charger the gain was so high it would start oscillating if you didn\"t hold the handlebar firmly, and after 3 miles it would start feeling mushy and unstable at high speeds. In the new system an analog-digital converter in the microcontroller measures battery voltage 2000 times per second, so I can adjust the PWM controller to get a desired motor voltage. It turns out that most of the "clunk" the old one produced as the motors changed direction was due to the electronics, not the gearboxes. The new version feels perfectly smooth. I also changed the gyro and accelerometer. I had been using a Tokin gyro that came on a board from RotoMotion. It had some performance problems: it would occasionally glitch (causing the scooter to jump), and it was susceptible to vibration (causing the tilt angle to wander at some speeds.) I changed to the CRS03-02 gyro from Silicon Sensing Systems. Noise is lower and it seems completely immune to vibration. I\"m also using the ADXL105 accelerometer instead of the ADXL102. The difference is that it has a higher saturation threshold (5 Gs of acceleration instead of 2) so it\"s less likely to saturate on bumpy roads. The new gyro and electronics have a much faster response, allowing tighter control of balance. While version 1 required a firm hand on the handlebar at all times, the new version can be controlled entirely with the feet, even at high speed. You can lean it up against a wall and it will remain almost motionless. (The old one had a tendency to start whacking the wall.) The new gyro also has less drift, so the handle angle of the scooter doesn\"t wander as much. Batteries I also installed better batteries. Version 1 started with 120 cells worth of cheap off-brand NiMH batteries. One bank of 30 caught fire because the fragile plastic shell wore through, and one seems to have a dead cell that won\"t accept a charge. Version 2 uses 60 HHR-6500 D cells from Panasonic. Digikey part P019-ND. These are high-quality cells with low internal resistance (typically 2 milliohms -- theoretical short circuit current = 600 amps!) I wired them in two parallel strings of 30 for a nominal voltage of 36 volts, able to deliver 200 amps at 30 volts. This works out to 8 horsepower peak. Those pedestrians better get out of my way! In the original scooter I used a diode bridge to parallel the batteries while allowing some voltage difference between them. In the new version I use a relay to connect both batteries simultaneously when the power is on. This reduces power supply impedance and gives smoother control. Also, the relay disconnects the batteries from each other during charging so I can charge the packs separately. There are two charging jacks on the console. Remote Control The scooter is now Bluetooth-equipped. Using a Bluetooth wireless connection, I can can change parameters, download logs, and even drive it using my laptop. I got a pair of serial port extenders from Free 2 Move which look like DB-9 connectors with no wire coming out of them. Within 100 meters range, they provide a transparent serial port connection. Then I wrote a GTK application that lets you drive it around without a rider. I can now leave my scooter parked somewhere and use my laptop to have it come and get me, thus saving valuable steps. All I need now is to make it run on one of those Linux wristwatches, and I\"d have the complete James Bond remote control system. (Or at least a yuppie techno-geek version of it.) Battery Monitoring The old version would let you know that the batteries were getting low when the balance feedback would get mushy. The new version measures and compensates for battery voltage and resistance, which is great except that the rider has no way of knowing when the batteries might let him down. So version 2 monitors battery state by doing a least-squares fit between battery voltage and current draw. It calculates the maximum speed at which it would have enough torque to balance properly, and limits the rider to that speed by tilting back. It also has a beeper which sounds when the motor drives are nearly maxed out, or the battery voltage drops below a threshold, or the battery current exceeds the battery fuse rating, or a few other exceptional conditions. Steering The Segway uses a twist grip on the left handlebar to control steering. My version 0 used a potentiometer conveninently located where my pants would brush against it and send me into a spin. Version 1 used a pressure sensitive touch pad with left and right sides. This was all right, but required careful finger positioning and wasn\"t very intuitive for others to learn. Version 2 uses handlebars which you twist. The handlebars don\"t actually move when you twist them; they sense the torque applied using four strain gauges which measure the slight change in resistance of a thin wire bonded to a piece of metal when the metal bends. Just to make sure it can outperform Segways in every way, I increased the steering control so it can spin in place much faster than a Segway. It goes around 1 revolution per second. It\"s pretty terrifying to be on, actually. I\"m going to have to add a mode switch: normal (for me), beginner (for letting other people try it) and yee-haw (for proving that it can beat Segways.) Chassis To protect the batteries against damage, I added a stainless steel plate around the bottom. It also looks better than the mishmash of wires, plastic sheet, and fiber tape that held the old undercarriage together. The steering column, formerly 1.5" square aluminum extrusion, is now 2" square tubing which is lighter and stiffer, and looks cleaner. Also, all the wires and switches can be mounted internally sticking out the side. To improve chassis stiffness, some metal bars are bolted onto the front and back of the main plate. It still isn\"t a very well engineered chassis, but it handle the usual urban terrain (jumping off curbs) pretty well. Controls The new version adds a few controls, since I had space for them on the steering column. First is an on-off switch in addition to the kill switch on version 1. That way I can leave the kill switch key on it so it won\"t get lost, and I don\"t need to fiddle with the key when I\"m parking it. I also added a beeper to indicate dangerous battery/speed combinations, and a knob which I can use to adjust whatever parameter I like.Styling Segway owners report being yelled at by people in pickup trucks (and I\"ve gotten this a number of times,) usually something to the effect of "Too lazy to walk, you f***ing homo?" Objectively, it\"s less lazy to ride the scooter than drive a car. It also uses less fuel, and pollutes the air less. The people yelling from inside their truck aren\"t walking either. At least I\"m standing up. But, like, whatever. I dismiss this part of their criticism. However, I think something can be done about the "homo" part (not that there\"s anything wrong with that.) It reflects the not-so-masculine soft plastic styling of the Segway. I\"d like to see if I can tweak the styling of mine so I don\"t get yelled at as much. At least mine is metal, but it still looks spindly. I\"d like to give it a muscular look with lots of chrome tubing and polished metal surfaces. The new wheels are a step in the right direction. After I put them on, the first comment I got on the street was from a hip-hop-looking guy in a Mustang who pulled up and told me, "Dude! That\"s tight!" Later at the office, I checked Urban Dictionary and found that "tight" means "stylish, cool, having everything together," "dude" means "male person," and "that\"s" means "that is." So he liked it! By the way, it\"s not just any new form of motorized transportation that attracts hostility. I often ride my electric unicycle around, and I\"ve never gotten a negative comment. Futures How fast can a scooter like this go? There\"s no fundamental limit. A bigger, heavier one could go highway speed. The danger, of course, is that if something fails it\"d be a serious accident. Under 10 mph the rider can probably land on his feet if it falls over, but at higher speed you\"d want more protection. Also, the differential steering might be iffy at high speed, and hitting a pothole without any suspension might be hazardous. Someone else with no fear of death should experiment with this. ");this.find(".footer").fmtTlbFooter(o);});$.defPage("scooter", function(o) {document.title = "tlb: Balancing Scooter";this.html("Building a Balancing Scooter Two wheels are more than you need! See myself-balancing electric unicycle. Also see Version 2 of the scooter. Short MPEG Video [1.0 MB] Self-balancing scooters, like the Segway™ are often thought to be technological miracles, but it is not actually very hard to build one. I built the one described here in about a week using off-the-shelf parts. I spent another week tweaking the high-speed stability, improving the steering control, and writing about it. Although the Segway has several exotic components, mine is built from common low-tech parts like wheelchair motors and RC car batteries. The parts, even at small quantity retail prices, cost less than half of a genuine Segway. It also doesn\"t need complex or high-performance software. The first version was written in Python and used serial ports to talk to the gyroscope and motor controller. The current software, now in C running in an onboard 8-bit microcontroller, is only 500 lines of code. Riding the scooter is definitely fun. Things I like about it are: It\"s easy, when riding down the street, to stop and chat. Somehow on a bicycle or a regular scooter, it\"s a huge nuisance to stop. But on this scooter, it seems very natural to pull up and chat while standing on it. It\"s pretty easy to drive around inside the office. The low-speed maneuverability makes it easy to go through doors. Things I don\"t like are: It\"s fairly tiring to ride. Standing still on a hard, bouncing platform makes my feet tired. Not as bad as rollerblading, but a somewhat similar feeling. The body is really evolved to be in constant motion, and the combination of static posture (even more static than standing normally, since you try to keep your weight centered) and being jolted by bumps is probably bad for your spine. I feel like a total techno-dweeb riding it around. It just screams "Silicon Valley nerd," even more than having 3 cellphones and a PDA strapped to your belt. OK, I am in fact a Silicon Valley nerd, but I don\"t want everyone to know it. I get stopped every few blocks by someone ask about how it works. I don\"t mind telling people about it, but it does take an awfully long time to get to the coffee shop and back in the morning. And I can\"t quite drink a cup of coffee on it while moving at any speed, so the net result is that I arrive back at the office, 30 minutes later than if I\"d just walked, with a cold coffee. A small sacrifice for Science. Its speed and terrain handling is an uncomfortable middle ground between walking and bicycling. When walking, I usually go in pretty straight lines, over grass and curbs. Biking is fast enough that I don\"t mind going around on the road. But the scooter is neither fast enough to make going the long way round feel right, nor maneuverable enough to go up and down a lot of curbs. It\"s not relaxing and conducive to having deep thoughts the way walking is. Riding it is fun but tense. Rolls Royce vs Model T The Segway is made with quite high-quality, high-tech, and expensive components. Overall, the components I used are a lot lower-tech and cheaper than the ones in the Segway. Yet, mine seems to ride just fine. It suggests that there\"s room for a Henry Ford of balancing scooters to develop and sell a low-cost everyman\"s version. Here\"s a quick comparison. Quotes below are from segway.com. SegwayMy Scooter Motors Brushless servo motors with neodymium magnets. "The highest-power motors for their size and weight ever put into mass production". Conventional DC motors with gearbox, widely used in powered wheelchairs. $286each from National Power Chair or from Robot MarketPlace. Gearbox "Like a precision Swiss watch". Engineers designed the "meshes in the gearbox to produce sound exactly two musical octaves apart." Part of the wheelchair motor above. When going up a ramp, they sound kind of like the starter motor on my old Dodge Dart. Rrrrr-rrrr-rrrr-rrrr. Batteries 2, 60-cell custom-designed NiMH packs producing 72 volts. "the highest power of any currently available chemistry". 20, 6-cell NiMH packs made for RC cars. They have "IDEAL SOLUTION FOR RC TOY" printed on them. $15 each from Powerizer. Wheels Wheels are "sophisticated engineering-grade thermoplastic." Tires by Michelin, with a "unique tread compound (a silica-based compound instead of traditional carbon-based materials)". Wheels are stamped steel. I think they\"re made for utility trailers. Tires made by Cheng Shin tire works. They make startlingly loud squelching sounds on tile floors. Tire and wheel are $79 each from NPC, and hubs are $20 each. Controller "Sophisticated controller boards from Delphi Electronics" with "Texas Instruments digital signal processor, monitoring the entire Segway HT system and checking 100 times per second." An 8-bit microcontroller from Atmel, running code written in C using floating point arithmetic. It sends speed control commands out the serial port at 9600 baud in ASCII to the motor driver. $10 from Digikey. Motor Driver "a set of 12 high-power, high-voltage field-effect transistors (FETs)". The controller has 16 MOSFETs and can handle way more current than my batteries can supply. Made by RoboteQ, it\"s $485 from Robot MarketPlace. It\"s a popular part for use in Battlebots. Gyroscope "packed with five solid-state, vibrating-ring, angular-rate sensors" One ceramic rate gyro, of the same kind that\"s in your camcorder (to detect your hand jiggling and stabilize the video) or RC helicopter (to stabilize the tail), and a 2-axis accelerometer to correct for drift. $149 from Rotomotion complete with the Atmel microcontroller. Structure Plastic and aluminum in smooth swooping shapes. "Chassis withstands 7 tons of force." Two pieces of aluminum plate with holes drilled in them, and a standard aluminum extrusion for the handle. Safety features Everything is dual redundant. For example, "in the unlikely event of a battery failure, the system is designed to use the second battery to operate the machine and allow it to continue balancing until it is brought to a safe stop." There is no redundancy or backup system. It is not even robustly made. Loose wires literally dangle out the bottom. In the fairly likely event of the software crashing, a wire coming loose, a component failing, or the batteries running low, the wheels will stop and the entire kinetic energy of the system will be used to accelerate my head toward the ground. Despite being able to build my own, I\"m still impressed with the Segway™ and with the courage it takes to bring such a product to market. Like with cars, it\"s pretty easy to put together a motor and wheels and make it go. But building a safe, comfortable vehicle is a serious effort. Warning There is one very important difference between what can be built as an experiment and the commercial Segway: The commercial one has a lot of safety features, redundancy and fool-proofing. Mine has none whatsoever (Well, it does have a kill switch so it doesn\"t go zooming away if I fall off, and it does shut down if it finds itself tipped more than 45 degrees.) Those details are kind of important, and you should think about them carefully before considering building such a thing yourself. With a scooter like this, if it stops working for any reason (software crash, hardware failure, low battery) you will fall, hard, and probably on your face. Imagine zipping along at 10 MPH, and suddenly the platform you\"re standing on stops dead. Oh, and there\"s a T-bar in front of you to trip you up if you start to run. So you really shouldn\"t try to replicate this experiment, and I can\"t be responsible for what happens if you read this and try to build something. A scooter that you ride on is not the best place to learn how to build a two-wheeled balancing device. Getting them working properly is quite subtle, so you should really start with a two-wheeled balancing robot and then scale up. See my notes on safety if you\"re considering trying to build something. Construction The mechanical construction is incredibly simple. Just a plate to stand on bolted to the tops of the motors, a support across the bottom, and a handle. Hanging from the foot plate are two pieces of hand-bent sheet metal to support the batteries. The batteries are just taped and cable-tied to the sheet metal. Mechanically it\"s much simpler than any other kind of vehicle. With only two wheels side-by-side, there is very little structure. With no steering it doesn\"t need complicated pivots and linkages. It is literally just two motors bolted to a frame and a stick to hold. The electronics and footrest all fit entirely within the 14" wheel diameter. Without the handle, it can roll end over end. But the ground clearance is pretty small. I should go up to 16" wheels, hopefully a bit lighter than the big tires I\"ve got now. Currently it weighs about 90 lbs with its full load of batteries. The wheels alone must account for 20 lbs of this. Dashboard The dashboard is an electronics chassis box with knobs for steering and balance feedback loop gain. This shows the early version of the dead man\"s switch, which really is not adequate. I found this out when I fell off, but the wire pulled apart instead of yanking out the connector. When it pulled apart, the exposed strands ended up touching to complete the circuit and keep it going. Fortunately, a safety feature in the software shut it down before it ran over my head. Power The motors I used are made for wheelchairs where they are driven from a 24 volt battery. I want a little more speed, so I drive them from 36 volts. My wheels are also a bit larger than the wheelchair\"s. It should reach 15 MPH flat out. I got 36 volts by putting 5 standard 7.2 volt RC car battery packs in series. The batteries are rated for 30 amps discharge and I wanted over 100, so I put 4 strings of 5 in parallel for a total of 20 packs or 120 cells. There is a a complication with multiple NiMH batteries in parallel. You want to avoid current flowing between them when their voltages are a bit different. So there is a bridge rectifier for every pair of batteries, with both + and - terminals connected to the motor driver. That way the voltage on the 4 strings of batteries can differ by up to 1.5 volts without current flowing. The batteries can be disconnected by the 4-way connector for safety, and for charging. I use an Astroflight model 112 charger, which delivers 5 amps charge current at the 40 volt charging voltage. See schematic diagram.The system pumps energy back into the batteries when it\"s decelerating or doing downhill. I had worried about the frequent current reversals harming the batteries, but I\"m assured by a number of people who\"ve had experience doing this with NiMH batteries that it works well. There might be some extreme case, like starting at the top of Pike\"s Peak and riding all the way down, where it could overcharge and destroy the batteries.Balance and Control Balancing is easy. Just keep the wheels under the center of gravity. It\"s just like when you pick up a stick and balance it resting on the palm of your hand. Actually, there are some complications. You don\"t know where the center of gravity is. You don\"t know exactly which way up is. And you may not be able to move the wheels fast enough to keep under it. I discuss knowing which way is up under "Gyroscope" below, but for now assume it\"s known. Technically what it knows is the angle between the scooter\"s chassis and the direction of gravity. And instead of keeping the wheels below the center of gravity, it keeps the stick vertical (ie, the angle equal to zero.) With the stick vertical, if you stand in just the right position, the center of gravity will be right over the wheels and the scooter will be stable. But if you lean forward, the center of gravity will be in front of the wheels and the scooter will start tipping forward. The computer senses this and moves the wheels to keep the stick vertical. But by then it has fallen some more, and it needs to move the wheels faster. The net result is that when you lean forward, the scooter accelerates forward and when you lean back it accelerates back. It\"s surprisingly intuitive. Most people find they can control it within seconds of getting on it. If you\"re used to riding busses or subways, you\"re used to leaning forward when the bus is about to accelerate. Well, this scooter follows your lean instead of you having to follow it. There is another complication. What happens if you keep leaning forward until the scooter is going so fast that the wheels can\"t keep up? It has to change the tilt of the scooter so instead of keeping the bar vertical, it tilts back. The bar is at waist level, so it pushes you back until the center of gravity is no longer in front of the wheels and it stops accelerating. If you lean farther forward it keeps tilting back in order to keep the speed down. In order to be able to tilt the scooter back it needs to speed up the wheels and get them out in front, so the speed limiter needs to kick in before the motors are maxed out. I currently have the limit set to 50% of maximum speed. Keeping the Stick Vertical Keeping the stick vertical is easy. If it tilts forward, it runs the wheels forward until the bottom of the stick is under the top. Here too there are complications. It has to move the wheels just the right amount forward. Too much and it\"ll have to move them back, then forth, until the thing is bucking widly. This is pretty much the default thing that happens until you get it tuned just right. It needs to know both the angle of the stick and how fast it\"s changing. Knowing how fast it\"s changing lets it slow down before it overshoots the mark. Technically this is known as a PD loop. The amount of drive it sends to the wheels is proportional (P) to the error in angle, and also to the derivative (D) of the error. I mentioned above that when it\"s going too fast it needs to tilt the stick back. This is tricky to do, because in order to tilt back it needs to accelerate the wheels forward to get them a few inches out in front. It then seems like it\"s going even faster, and it tries to tilt even farther back. This is called "positive feedback" and it\"s a recipe for uncontrollable oscillation. Making this stable was the trickiest part of the whole project, and the fact that it can only be tested at high speed resulted in several moments of terror and a few bruises before I got it right. Wheels and Steering Steering is done by making one wheel go faster than the other. Because all the mass is centered between the wheels, it can spin around quite quickly. When not moving, maximum turning corresponds to having one wheel at about 10% forward and the other at 10% reverse. This spins it around pretty fast. You wouldn\"t want to turn this fast at high speed because it would tip sideways, so it reduces the maximum turning speed as the forward speed increases. The wheels have 0.5 degrees of toe-in, meaning that they are both angled slightly inwards. The front wheels of most cars have a similar amount of toe-in. Pneumatic tires are inherently flexible sideways, and it makes it more stable to have them always flexed slightly. I don\"t know if 0.5 degrees is the right amount and I haven\"t tested any alternatives. But the steering is quite stable despite not having any active correction in software. Putting it all together What takes many paragraphs to explain is surprisingly simple to code. Here is the basic pseudocode of the balance algorithm, complete with the numbers which made my scooter feel stable and responsive. Inputs angle, angle_rate: the tilt angle of the scooter in radians and its derivative in radians/sec steer_knob: the reading from the steering knob, between -1 and +1. Balance balance_torque = 5.0 * (angle - rest_angle) + 0.4 * angle_rate Limit top speed by tilting back overspeed = max(0, cur_speed - 0.5) if (overspeed > 0) { overspeed_integral = min(0.4, overspeed_integral + min(0.2, overspeed+0.05) * dt) } else { overspeed_integral = max(0, overspeed_integral - 0.04*dt) } rest_angle = 0.4*overspeed + 0.7*overspeed_integral Steer. Decrease steering rate at high speed steer_cmd = 0.07/(0.3+abs(cur_speed)) * steer_knob Track current speed cur_speed += 1.2 * balance_torque * dt Differential steering left_motor_pwm = balance_torque + cur_speed + steer_cmd right_motor_pwm = balance_torque + cur_speed - steer_cmd Outputs left_motor_pwm and right_motor_pwm directly set the duty cycle of the pulse width modulator for the wheel controller, and range from -1 to +1 (+1 is 100% forward, -1 is 100% reverse.) Gyroscope In order to keep the handle vertical, it needs to know which way is up. Humans, other mammals, and even lobsters have a nifty little sensor in the inner ear which does this, and it\"s possible to do something similar mechanically. The simplest way to know which way is up is with a pendulum. A pendulum at rest points down. Unfortunately, the scooter is not at rest. If it\"s accelerating forwards a pendulum will swing backwards. It may also get swinging back and forth. It needs a much more stable notion of up. A gyroscope made from a spinning wheel is the classical solution to keeping a vertical reference. They are still used in airplanes to remind pilots which way is up when they\"re in the clouds. But having an actual spinning flywheel is clumsy. They take time to spin up, they need expensive precision bearings and lubrication and use a lot of power, and occasionally the flywheel explodes (they have to spin pretty fast) and sends little bits of shrapnel into the rest of the system. Although it\"s hard to visualize, it turns out that if you have a tuning fork vibrating and rotate it, it will cause a measurable vibration in the perpendicular direction. By measuring the vibration you can tell which way it is rotating and how fast. The scooter uses a very small ceramic tuning fork in just this way. They are a standard electronic product called a piezoelectric rate gyro, used in handheld camcorders to detect your hand jiggling and subtract out the motion from the picture to make it stable. One of the first successful applications of nanotechnology, they\"re a vital enabling technology for TV shows like C.O.P.S. Unfortunately, these rate gyros are not perfect. They tend to report a small rate of rotation even when they\"re perfectly still. And if the balancing software integrates this small rate for long enough, it\"ll think it has rotated a lot. So it needs to compensate for that, and it does it with a pendulum. While a pendulum may swing around and wobble back and forth in the short term, the long-term average of its position is straight down. Again, it doesn\"t use an actual pendulum. It uses a "micromachined silicon accelerometer", a silicon chip with a sort of diving board etched into it. This diving board bends a tiny amount in the direction of gravity, and some electronics detect how much it bends. With two of these arranged perpendicular to each other, it can compute the angle of gravity by computing the arctangent of the ratio of the bending measurements. And unlike a pendulum they don\"t get swinging around. So now it has to combine the short-term reading of the rate gyro and the long-term reading of the pendulum. There is a theoretically optimal way to combine these pieces of information into a good estimate of actual tilt angle. This is called a Kalman filter. Such a filter was a good place to start, but I found I got better results with a hand-tuned feedback loop. Sound complicated? It\"s not as bad as it sounds. In fact, the whole code, including stuff to read ADCs and manage serial communication is about 500 lines. Microcontrollers All the software needs somewhere to run. Not so long ago this task would have required more computer than you could lift, but now it runs in a tiny chip costing $10. The one I used is from Atmel. They\"re fast and very easy to write software for; I wrote the code in C using floating point arithmetic and trigonometric functions, and it has plenty of speed for this kind of application. The Atmel chip I\"m using has built in analog data converters to interface with the gyroscopes and steering controls so it\"s a nearly complete solution. There are only about 5 chips in the whole scooter. Motor driver The software needs to exert precise control over the speed and torque of the motors. Under worst-case conditions, like going fast up a steep ramp, the motors need to work very hard to keep up and can consume a tremendous amount of power doing so, as much as 5000 watts. The torque generated by the motor is directly related to the current flowing through the motor. The current is controlled by alternately switching the motor across the full battery voltage, then short circuiting it. If it did this slowly it would do just what you\"d think: alternate full speed, then full stop. But it alternates very fast, about 4000 times per second, and this produces a smooth output from the motor. If it spends 37% of the time with the motor connected to the battery, the motor runs about 37% of full speed. The scooter uses a device made by RoboteQ to switch all this power around. It\"s a popular unit among Battlebot builders since it\"s small and handles a lot of power. It receives commands from the microcontroller over a serial port, such as "left motor 37% forward, right motor 35% forward" (but in a compact binary format) and it gives the motors that much power. This command would correspond to going about 5 mph in a gentle right turn. Limits In theory, balancing is quite simple. Just keep the support under the center of gravity. Where it gets complicated is in handing the limitations of the motor & battery system. The simple control strategy may require much more power than the motors and battery can deliver. If it lets the scooter get into a situation where the wheels can\"t keep up with the center of gravity, the rider will be thrown. If you\"re going fast and then run into something like a ramp or speed bump, it may require a lot of power for a short time to keep the wheels going up the ramp. As batteries get low and motors get warm, the amount of available power goes down. It\"s hard to predict exactly when it doesn\"t have enough to run safely. There\"s certainly a large gap between when it couldn\"t handle hitting a speed bump at 10 MPH and when the batteries actually run down. I plan to experiment with using a bank of capacitors to provide enough short-term oomph to handle hitting a major bump at high speed. It\"s much easier to calculate the amount of energy needed to handle a bump safely than the maximum speed for a given battery condition. It just needs enough to get the wheels out ahead of the center of gravity, so it can slow down. My back-of-the-envelope calculations suggest about 2500 Joules delivered in 0.5 seconds. The new carbon aerogel ultracapacitors (not to be confused with mere supercapacitors) can store this much power in small 4" x 4" x 2" package costing about $250. Or, I could just stick a wheel in front of it. But that would seem like something of a compromise. Performance and Testing When I first built this, I had never been on a Segway or even seen one close up. You\"d think with all my geeky friends I\"d know someone with one, but I didn\"t. I tuned the system according to how I thought it should work. A few days after I put up this page, I got to try a genuine Segway and I realized two things: it felt better to have a stiffer feedback loop so the handle didn\"t move back and forth so much, and that it should limit maximum speed by tilting back. I changed both, and it feels much better now. These videos are from the original version: Current Problems These are the things that are currently bad about my prototype. The ground clearance is very low. Even large acorns get stuck under it. Using larger wheels is one solution, and I think with more clever mounting of batteries I could get them at least 1.5" higher. If I make the wheels much larger, I\"ll want to find a way of getting the foot plate below the center of the wheel since I\"m already 8" off the ground. It should detect when I\"ve stepped off it, so it doesn\"t simply zoom away with no rider. My big worry is that I\"ll shift my feet around and it will erroneously detect me having stepped off. At high speed, this could be Really Bad. It really should give some indication of battery charge, other than by falling over when it gets too low. The voltage of NiMH batteries isn\"t a good indication of charge, so there\"s no easy way to do it. It doesn\"t detect when the wheels are off the ground or slipping. Once when leading it down a curb, I got it twisted a bit and it hung up on the battery supports. With the wheels free, they started spinning very quickly and it gave a huge lurch when it got back on the ground. I don\"t know what the general solution is. Probably it should limit the speed to 1 MPH when the rider is off. Things Learned You don\"t need high-tech low-inertia motors for adequate responsiveness. Regular old copper-wound motors work pretty well even though they have a lot of rotating mass that acts like a flywheel. This might actually help with handling a bump, as the inertia helps keep the wheels spinning up the incline. You don\"t need low-backlash gearboxes either. The conventional non-precision spur gear units give about 1/8" backlash at the wheel diameter. You can feel a tiny clunk sometimes when the torque reverses, but it\"s hardly noticeable. They do make some gear whirring noise which is noticeable indoors. It\"d probably be quieter if they weren\"t bolted to a big aluminum sounding board. I didn\"t need any feedback in yaw (left-right steering) to keep it heading straight. I just give equal motor drive voltages, and it keeps nice and straight even on slopes or going over bumps. Future Work Things I\"d like to try, if I had more time: I can take both hands off the control bar and control with my feet, at least at low speeds. Handy when going through doors. I wonder if I could learn to control it without a handlebar at all. Perhaps with some sort of ski boots and bindings for greater control. Put the vertical handle bar off to the side, instead of in front, and hold it with one hand. Make wacky new vehicles on the same principle. Why not go for coffee in a miniature dragster, doing a wheelie all the way? Or in a greco-roman chariot, without the horses? You could also make improbably tall vehicles, like a phone booth that zoomed around upright. Take a regular 3-wheeled "mobility scooter," and make it do wheelies all the time. You might even be able to use its original motor driver, and just add a gyroscope and feedback controller. Seeing one of those 3-wheeled scooters, normally associated with geriatric mall cruisers, doing a wheelie would really surprise people. And if it fell, you\"d at least have a wheel to land on. The ideal vehicle might be something that rides like a motorized recumbent 3-wheeled bike on roads, but tilts back to balance on sidewalks. You\"d have to get off to change modes. Build one with a small gas engine and generator instead of batteries to power the electric motors. It\"d probably need a substantial capacitor bank to smooth out the power demand. The engine and alternator might even be lighter than the batteries, and it\"d have tremendous range. It might go faster too. Build a balancing scooter without any batteries at all, but instead control the braking force on the wheels to keep it balanced. It would only work going down a hill. You could use the same motors and dump their power into a bank of big resistors. Mountain boarders might dig this. Build a real experimental platform with 20 or so knobs to control each of the feedback parameters. It\"s very interesting to adjust a parameter and feel the difference in real time under your feet. It\"d need to have some fail-safe scheme for returning to a reasonable set of parameters if the user adjusts them too far. Links Ben Smither\"s self-balancing one-wheeled scooter.nBot, a 2-wheel balancing robot. A much better place to start if you want to build something that balances. Good collection of links.Ted Larson\"s balancing robot. Mesmerizing to watch.LegWay, a balancing robot made from Lego.A Japanese version of the Segway. Smaller and more fuel-efficient.Equibot, a balancing robot without gyroscopes. Probably the easiest and lowest-cost balancing machine you can build if you want to build something. The disadvantage is that it only works on flat floors.A simple and elegant experiment in dynamic balanceFrancisco Lobo built a balancing robot using similar technology.Some students in British Columbia built one. Their report includes working code and schematics.The Brilliant Pebbles project has a useful wiki for programming Atmel microcontrollers.Bay Area Segway Enthusiasts Group, who let me try a genuine Segway.Steve Wozniak\"s Segway Page.The Robot Marketplace sells most of the parts I used; they also sell higher quality battery packs.Ugh. You knew it had to happen.Maddox has an even simpler idea for making your own.A FIRST robotics team built a balancing scooter in 2002.Segway LLC.Self-balancing Skateboard by the UBC Electric Bike Club.");this.find(".footer").fmtTlbFooter(o);});$.defPage("scooterSafety", function(o) {document.title = "tlb: Balancing Scooter Safety";this.html("Balancing Scooter SafetyIf you\"re developing a balancing scooter, you will fall quite a few times. I didn\"t fall or get hurt at all testing at low speeds, but testing at high speeds earned me a few bruises. Testing such a scooter is not for timid, frail, or un-coordinated folks. Segways look and feel quite safe, but if you build your own balancing scooter, until the software is tuned perfectly it is very likely to lurch violently and throw you off. Controlling and/or leaping off a wildy lurching scooter requires a lot of physical strength and agility and is inherently hazardous. I would rate it more hazardous than skateboarding, but less than racing motocross bikes. Skateboarders fall a lot, but at least they don\"t have an 80 lb thing under them with spinning tires.For initial testing at low speed, the most important things are a very handy kill-switch, sturdy shoes and shin guards. Mine, at 80 lbs, isn\"t heavy enough to hurt much running over your toes, but if you\"re standing behind it and it backs into you the bare metal plate can really bruise your shins. You also want to make sure to limit the maximum motor speed, so you don\"t find yourself suddenly testing at high speed.Unless you have the feedback loop parameters just right, it will start oscillating back and forth out of control when you turn it on. You\"ll want to shut it down quickly, and the right kind of kill switch is essential. I made a mistake here that you should avoid. I first used a circular power jack of the same kind that most wall transformers use as a combination kill-switch and dead-man\"s switch. (Terminology: a kill switch is something you press. A dead-man\"s switch is something that is triggered when you fall off.) I connected the wires together and tied the wire to my belt. Completing the circuit through the power jack turned on the scooter. This is unsafe. When I fell off, it pulled at an angle and ended up ripping the wire instead of pulling out the jack. The exposed ends ofwire touched, and it kept going.Then I changed to a proper combination dead-man\"s- and kill-switch made for snowmobiles and jet skis. It can handle being yanked out in any direction, and it has a big red button to press to shut it down manually.Testing at high speed is scarier. The dynamics of limiting speed are quite complicated and hard to get right, and it\"s really frightening when it starts lurching around near maximum speed. Ideally you\"d test on some kind of springy surface, like a rubberized jogging track. I didn\"t have one handy, so I tested in a parking lot. It can fail either by tipping forwards or backwards . When it tipped forwards at high speed, I ended up straddling the vertical bar, still holding the handlbars, with my feet on the ground. Once it tips that far the software locks up the rear wheels, so I was able to bring it and myself to a stop without losing balance. In this case, it\"s better to hang on to the handlebars and use the scooter to keep your balance than to try to get your legs over the bar and risk getting tripped up or run over. You want sturdy shoes for this: real running shoes, tightly laced, or they\"ll come off.Tipping backwards is actually worse. One time it started oscillating at medium speed and zoomed out from under me. I landed on my butt and elbows. You really want to be wearing elbow pads when this happens.I should point out here that I while I was testing experimental software, the motor driver was a solid, reliable product. Testing a motor driver of your own design is much more dangerous. Motor drivers have a tendency to fail in full-on mode when they get overloaded. Imagine getting up near top speed and all of a sudden one of the wheels goes full forward or full reverse. In most designs, not even the kill switch will shut it down. Please, use a dependable motor controller, and test it under some a heavy simulated load before using it.I never had much trouble with steering and steering control on mine, and never felt in danger of tipping sideways. I don\"t know what I\"d do if a software problem caused a major steering change. In general, you never want more than 7% differential speed between the wheels.If it turns too fast and you tip off sideways, you need to let the scooter go rather than get yanked around by it. You\"re more likely to let it go if there aren\"t cars parked all around. So you really want to find the biggest possible space you can so you\"ll feel free to just let the scooter go if it goes crazy. If the kill switch is working properly, it should stop pretty quickly.I haven\"t gone fast on a slippery surface and skidded out, but I imagine this would be pretty scary. This is the sort of thing that the Segway folks have probably put a lot of R&D into, but isn\"t practical for an amateur to figure out.I mention various wacky vehicle ideas on my page. Don\"t start with them. For one, count on crashing it a dozen times before it finally works. So start with basic metal pieces. Also, it\"s really important that you can leap off quickly when things go wrong. Something enclosed, like a Roman chariot, would be a lot more dangerous.The testing cycle is roughly like:wheel it out to the test rangestart it up, get goingit starts lurching violently and you wipe outbring it back to your computeredit the code, tweak a parameter or twohook it up to the serial port of your computer and download the new programYou\"re likely to have to repeat the cycle 50 times or more to get it working well. In order to make it most convenient, you should really have a laptop you can take with you outside, rather than dragging it up and down the basement stairs dozens of times.To summarize, you\"d really be a fool to test with less than the following. For low speed:sturdy shoesshin guardsan open area at least 20\"x30\"easily reached kill switchand for high speed:helmetsturdy shoeselbow padsshin guardsseveral acres of empty parking loteasily reached kill switchdead man\"s switch");this.find(".footer").fmtTlbFooter(o);});$.defPage("keyboardChop", function(o) {document.title = "tlb: Chopping the Numeric Keypad off a Microsoft Natural Keyboard";this.html("Chopping the Numeric Keypad off a Microsoft Natural KeyboardIt\"s always bothered me to have the numeric keypad on a keyboard. I write programs and prose, but I never enter in columns of numbers. Are there still people who do this? I thought computers were supposed to liberate us from that sort of thing. Anyway, this vestige of adding machines had to go! It forces the mouse to be about 3 inches farther away from where I\"m typing than it needs to be, which adds up to a lot of unnecessary arm movement over the years. So I set about to chop the numeric keypad off the otherwise excellent Microsoft Natural Keyboard. It worked well (on my second try) and took about two hours.BeforeAfterUnfortunately, you can\"t just saw the right side off because a number of wires run around the outside edge of the big circuit board under the keys. On my first attempt, I cut all the components on the right side and about 1/3 of the keys didn\"t work afterwards.Modern keyboards have a sandwich of 2 flexible mylar sheets with wiring printed on them, and a third layer of thicker plastic between. The middle layer has holes punched where the keys go. The keys press down on the top layer and bulge it down slightly to contact the bottom one, setting off a long chain of events that result in a letter appearing on the screen.The good news is that the mylar circuits are flexible and can be bent back behind the keyboard rather than cut. So, get out your tools, unplug your keyboard, and let\"s begin. You might want to make sure you have a spare keyboard around in case it doesn\"t work.Step-by-step instructionsYou first have to disassemble the keyboard. Take the bottom off by removing several screws.Remove all the layers of mylar. In my keyboard, they were held on by some plastic posts going through holes in the mylar. The posts had been squashed down by a hot tool. I was able to wiggle the mylar off the head of the post, but you might need to trim the mushroomed plastic off using a knife.Now remove the keys. In mine, there were 3 separate key units: left hand, right hand, and the direction/editing/numeric keys. They came out quite easily.Do you sit there all day eating crackers and scratching your dandruff over your keyboard? Take this opportunity to clean it up.Now, the fun part! Reassemble the top and bottom halves without the keys or mylar circuits. Then run it right through a bandsaw. I marked the path with a flexible ruler and pencil, then went for it. Remember, all the wiring is removed.I\"m sure you could also do this with a hacksaw. The plastic is very easy to cut. If you\"re cutting the top and bottom separately, make sure to mark the cutting line clearly on both before you start.Ta-dah! The right side is gone.The cut you get is fairly rough, so you should clean it up. I used an exacto knife to trim the burrs from the edge, and then a file to smooth it out and round off the corners. Then trim the burrs again.Rounding the corners adds a lot to the appearance. Just a few strokes with a file will do it.On the second keyboard I modified, I removed the 3 banks of keys and cut the right side key group separately. I wanted to cut this exactly to avoid cutting off the pins which hold the springy sheet in place.The springy rubber sheet also has to be cut separately, with very sharp scissors.The offending part has been removed. As a special bonus, the manufacturer\"s logo goes with it.Now, reassemble the whole thing. Since you haven\"t cut the mylar printed circuits, they\"ll stick out on the right.To get them out of the way, I bent them back under the bottom of the keyboard. I found that the middle sheet was fairly thick and hard to bend, so I cut it away. But the wiring on the outer sheets cannot be allowed to touch, so I applied a layer of scotch tape to the bottom side of the top circuit board in order to insulate them.I was worried about having all kinds of ugly wires dangling out of the side, but the result is fairly clean looking.The Final ResultI\"m now trying to retrain my hands to keep the mouse closer. I find that I naturally end up keeping the mouse in about the same place as always, far to the right of the keyboard.This, though, is way cooler");this.find(".footer").fmtTlbFooter(o);});//]]>setTimeout(function() {pageSetupFromHash("/tlb/");});
follow
" + url + "