Rotary Encoder Generator

Outputs angle as gray code using desired number of bits.

by Santiago J

HTML

<img id="encoder">

JavaScript

// Important parameters
var nbits = 7; // number of bits used by the encoder
var radius = 100; // radius of circle in pixels
var startAt = 1 / nbits; // fraction of radius that defines inner radius
var padding = 20; // padding between circumference and edge of canvas

// "validation"
startAt = Math.min(Math.max(startAt, 0), 1); // startAt must be between 0 and 1
nbits = Math.max(nbits, 1); // nbits must be positive

// Canvas and variables
var canvas = document.createElement("canvas");
var img = document.querySelector("#encoder");
var ctx = canvas.getContext("2d");
var xyc = radius + padding;
var n = 1 << nbits;
var K = 2 * Math.PI / n;
var HOLE_COLOR = "#fff";
var NOHOLE_COLOR = "#000";

// Get m-th of n-th number in Gray Code sequence
function isHigh(n,m) {
    return Math.floor(n / (1 << (m+1)) - 0.5) % 2 == 0;
}

// Paint background
canvas.width = canvas.height = 2 * xyc;
ctx.fillStyle = HOLE_COLOR;
ctx.fillRect(0, 0, 2*xyc, 2*xyc);

// Pre-fill circle
ctx.fillStyle = NOHOLE_COLOR;
ctx.beginPath();
ctx.arc(xyc, xyc, radius, 0, 2*Math.PI, false);
ctx.fill();

// Draw code
ctx.fillStyle = ctx.strokeStyle = HOLE_COLOR;
for (var i = 0; i < n; i++) {
    for (var j = 0; j < nbits; j++) {
        if (isHigh(i,j)) {
            ctx.beginPath();
            ctx.arc(xyc, xyc,
                    (startAt + (1 - startAt) * (1 - (j+1) / nbits)) * radius,
                    i*K, (i+1)*K, false);
            ctx.arc(xyc, xyc,
                    (startAt + (1 - startAt) * (1 - j / nbits)) * radius,
                    (i+1)*K, i*K, true);
            ctx.fill();
            ctx.stroke();
        }
    }
}

// Draw lines between bits for clarity
ctx.strokeStyle = NOHOLE_COLOR;
ctx.lineWidth = 3;
for (var j = 0; j <= nbits; j++) {
    ctx.beginPath();
    ctx.arc(xyc, xyc,
            (startAt + (1 - startAt) * j / nbits) * radius,
            0, 2*Math.PI, false);
    ctx.stroke();
}

img.src = canvas.toDataURL("image/png");