Rotary Encoder Etch a Sketch
Rotary Encoder Etch a Sketch
What I wanted to learn, and why it interested me: I wanted to learn how to use an Arduino as mouse input because I've only ever used the Arduino to make circuits by itself, but not mainly as an additional tool on a computer.
Final outcome: I used an Arduino Pro Micro to emulate a mouse using two rotary encoders. My goal was to make a digital recreation of the Etch a Sketch toy, which has two knobs that draw a straight line up/down and left/right.
Images of final creative/exploratory output
Breadboard with Arduino and two rotary encoders.
Trying to draw a rectangle on an online sketch website.
Process images from development towards creative/exploratory output
Soldered pins onto the Arduino Pro Micro.
Testing out a single rotary encoder first.
Process and reflection:
The process was less straightforward than I was expecting. Nothing was working at first, and I spent half an hour trying to figure out why my Arduino wouldn't connect to my computer until I realized the Arduino Uno didn't support mouse and keyboard emulation, only the Pro Micro did, which I had to solder pins onto. I first started off with just a single rotary encoder, which was a little confusing to figure out how to wire up. My breadboard was a mess of jumper cables, so I went and cut a ton of wire to make the board and wiring more compact, so it could look kind of like a video game controller. After I got one rotary encoder working, I added the second one. The board works decently well, aside from the fact that the rotary encoders like to jump around a lot, so it's really hard to actually use it to draw on the screen. I could probably use some capacitors to help with the voltage spikes if I decided to improve on the project, but overall I think it's pretty cool.
Technical details
Electrical Schematic. There is no rotary encoder option so the rotary encoder is modeled as a potentiometer combined with a push button.
/*
60-223 Intro to Physical Computing, fall 2025
Domain-specific Skill Building exercise: Rotary Encoder Etch a Sketch
This sketch takes in 2 rotary encoders as input, encoder X controls horizontal mouse
movement as well as the activation button press, and encoder Y controls vertical mouse
movement. There is a stepSize scale factor that allows you to increase or decrease the
distance the mouse moves.
Pin mapping:
Arduino pin | role | details
------------------------------
2 input Rotary encoder X pin A
3 input Rotary encoder X pin B
4 input Rotary encoder X button
7 input Rotary encoder Y pin A
8 input Rotary encoder Y pin B
*/
ChatGPT helped with dealing with rotary encoder values.
#include <Mouse.h>
// Encoder X pins
const int encoderX_A = 2;
const int encoderX_B = 3;
// Encoder Y pins
const int encoderY_A = 7;
const int encoderY_B = 8;
// Button on encoder X
const int buttonPin = 4;
volatile int xPos = 0;
volatile int yPos = 0;
bool mouseEnabled = false;
bool lastButtonState = HIGH;
// scale factor to make mouse move more
const int stepSize = 2;
void setup() {
Serial.begin(9600);
pinMode(encoderX_A, INPUT_PULLUP);
pinMode(encoderX_B, INPUT_PULLUP);
pinMode(encoderY_A, INPUT_PULLUP);
pinMode(encoderY_B, INPUT_PULLUP);
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(encoderX_A), updateEncoderX, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderY_A), updateEncoderY, CHANGE);
}
void loop() {
// Check button press to toggle mouse on/off
bool buttonState = digitalRead(buttonPin);
if (lastButtonState == HIGH && buttonState == LOW) {
mouseEnabled = !mouseEnabled;
if (!mouseEnabled) {
Mouse.release(MOUSE_LEFT); // release when disabled
Mouse.end();
} else {
Mouse.begin();
Mouse.press(MOUSE_LEFT); // hold left button
}
}
lastButtonState = buttonState;
if (mouseEnabled) {
noInterrupts();
int dx = xPos * stepSize; // scale movement
int dy = yPos * stepSize;
xPos = 0;
yPos = 0;
interrupts();
if (dx != 0 || dy != 0) {
Mouse.move(dx, dy, 0);
}
}
}
void updateEncoderX() {
if (digitalRead(encoderX_A) == digitalRead(encoderX_B)) {
xPos++;
} else {
xPos--;
}
}
void updateEncoderY() {
if (digitalRead(encoderY_A) == digitalRead(encoderY_B)) {
yPos++;
} else {
yPos--;
}
}