An etch-a-sketch draws with two knobs, one for left and right and one for up and down. A joystick does both at once. In this lesson the UNO reads the joystick module and sends its position to your computer about 50 times a second. A free program called Processing turns it into a drawing pen: push the stick and the pen moves, faster the further you push. Press the stick down to change colour, hold it for a second to start a new picture, and press S on the keyboard to save your drawing as a picture.
What you'll learn
- How a joystick measures position with two potentiometers
- How the UNO sends numbers to a computer over USB
- How to draw with lines in Processing
- How to tell a short press from a long press
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- Joystick module (45-in-1 Sensor Kit)
- 5 female-to-male jumper wires
- A computer with the free Processing program (Windows, macOS or Linux)
- The printed parts from the 3D printing box below (joystick console), or the cardboard version described there
- Breadboard and jumper wires (UNO R3 Starter Kit)
Wiring

| From | To |
|---|---|
| Joystick GND | GND |
| Joystick +5V | 5V |
| Joystick VRx | UNO pin A0 |
| Joystick VRy | UNO pin A1 |
| Joystick SW | UNO pin 2 |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
The UNO sketch
The UNO only reads the joystick and sends three numbers per line: left-right, up-down and the button.
const int X_PIN = A0, Y_PIN = A1, BUTTON_PIN = 2;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP); // the stick's button connects SW to GND
}
void loop() {
Serial.print(analogRead(X_PIN)); // 0 to 1023, about 512 in the middle
Serial.print(',');
Serial.print(analogRead(Y_PIN));
Serial.print(',');
Serial.println(digitalRead(BUTTON_PIN) == LOW ? 1 : 0);
delay(20); // about 50 lines a second
}Upload it and open the Serial Monitor at 9600 baud: move the stick and watch the numbers change. Then close the Serial Monitor.
The drawing program
- Download Processing 4 for free from processing.org, unzip it and start it. It looks a lot like the Arduino IDE.
- Paste the sketch below into a new Processing window and save it.
- Make sure the Arduino IDE's Serial Monitor is closed (only one program can use the port), then press the round Run button.
- The console at the bottom lists your computer's ports, numbered from 0. If nothing happens or you get an error, change
PORT_INDEXto the number of the UNO's port and run it again.
import processing.serial.*;
final int PORT_INDEX = 0; // which port in the list is the UNO
final boolean INVERT_Y = false; // true if pushing up draws down
final float SPEED = 6; // how fast the pen moves
Serial port;
PGraphics paper; // the drawing, kept separate from the pen marker
float penX, penY;
int stickX = 512, stickY = 512, button = 0, lastButton = 0, pressStart = 0;
color[] COLOURS = {#1B3A7B, #DE544A, #2ECC71, #F2C94C, #7B4FD0, #111111};
int colour = 0;
void setup() {
size(900, 700);
printArray(Serial.list());
port = new Serial(this, Serial.list()[PORT_INDEX], 9600);
paper = createGraphics(width, height - 60);
clearPaper();
textFont(createFont("Arial", 18));
}
void clearPaper() {
paper.beginDraw();
paper.background(255);
paper.endDraw();
penX = paper.width / 2;
penY = paper.height / 2;
}
void draw() {
while (port.available() > 0) { // read every line the UNO has sent
String line = port.readStringUntil('\n');
if (line == null) break;
String[] v = split(trim(line), ',');
if (v.length == 3) {
stickX = int(v[0]);
stickY = int(v[1]);
button = int(v[2]);
}
}
// button: short press = next colour, hold for 1 s = new picture
if (button == 1 && lastButton == 0) pressStart = millis();
if (button == 0 && lastButton == 1) {
if (millis() - pressStart > 1000) clearPaper();
else colour = (colour + 1) % COLOURS.length;
}
lastButton = button;
// the further you push, the faster the pen moves; ignore tiny wobbles round the middle
float dx = (stickX - 512) / 512.0, dy = (stickY - 512) / 512.0;
if (abs(dx) < 0.08) dx = 0;
if (abs(dy) < 0.08) dy = 0;
if (INVERT_Y) dy = -dy;
float newX = constrain(penX + dx * SPEED, 0, paper.width);
float newY = constrain(penY + dy * SPEED, 0, paper.height);
paper.beginDraw();
paper.stroke(COLOURS[colour]);
paper.strokeWeight(6);
paper.line(penX, penY, newX, newY);
paper.endDraw();
penX = newX;
penY = newY;
background(240);
image(paper, 0, 0);
noFill(); // the pen marker
stroke(0, 120);
strokeWeight(2);
ellipse(penX, penY, 16, 16);
fill(COLOURS[colour]); // the bar at the bottom
noStroke();
rect(20, height - 45, 30, 30, 6);
fill(60);
text("Press: next colour Hold: new picture S key: save", 70, height - 24);
}
void keyPressed() {
if (key == 's' || key == 'S') {
saveFrame("sketch-####.png"); // saved in the sketch's folder
println("Saved!");
}
}Draw
- Run the Processing sketch. A white page appears with a small circle in the middle: that is your pen.
- Push the stick: the pen draws a line. Push a little for slow, careful lines, and all the way for fast ones.
- Press the stick down to change colour. Hold it down for a second to start again.
- Press S on the keyboard to save your picture. Open the sketch folder (Sketch → Show Sketch Folder) to find it.
How it works
Inside the joystick are two potentiometers, one for each direction, turned by the stick. In the middle each one gives about half the voltage, which analogRead() turns into about 512. All the way to one side it reads 0, to the other 1023.
The UNO sends the two numbers and the button as one line of text, separated by commas, like 700,512,0. Processing splits the line at the commas with split() and turns the pieces back into numbers.
Subtracting 512 and dividing by 512 gives a number from −1 to 1: how far and which way the stick is pushed. The pen moves by that amount times SPEED every frame, so the stick sets the speed, not the position. A joystick never rests at exactly 512, so small values are ignored: that is called a dead zone.
The drawing goes onto a separate PGraphics page, so the round pen marker can be drawn on top without leaving marks.
Try this next
- Make the line thicker the longer you hold the stick in one direction.
- Add a rainbow colour that changes a little with every step.
- Use a second joystick or the potentiometer to change the pen size.
Troubleshooting
-
Processing says "Port busy" or nothing moves: close the Arduino IDE's Serial Monitor and check
PORT_INDEX. - The pen moves on its own: your joystick rests a bit away from 512. Make the dead zone bigger, for example 0.15.
-
Up and down are swapped: set
INVERT_Ytotrue. - The button never changes colour: check SW on pin 2. Press the stick straight down until it clicks.
- A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.