Concept Overview
“Sketch and Switch” is a modern take on the Etch-A-Sketch, but with a twist, where the user can draw with random colored lines with mechanical knobs, as this version uses Arduino hardware to control a digital canvas through two potentiometers and a button. The potentiometers allow left/right and up/down movement of the drawing point, and a button press toggles drawing mode while randomly altering the line’s color and thickness.
Project Interaction
Video interaction: https://drive.google.com/file/d/1h1HtV-_-JUEKgieFiu1-NDM2Pb2Thfwr/view?usp=sharing
Interaction Design
Users interact with two potentiometers and a button:
-
- Left Potentiometer: Controls horizontal (X-axis) movement.
- Right Potentiometer: Controls vertical (Y-axis) movement.
- Button: Toggles drawing mode and changes the drawing color randomly.
Arduino Code
const int potX = A0; // Potentiometer for horizontal movement
const int potY = A1; // Potentiometer for vertical movement
const int buttonPin = 2; // Pushbutton for toggling draw mode
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0; // Timestamp of last button state change
unsigned long debounceDelay = 20; // Debounce time to avoid false triggers
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
int xVal = analogRead(potX); // Read horizontal potentiometer value
int yVal = analogRead(potY); // Read vertical potentiometer value
int reading = digitalRead(buttonPin);
int btnState = LOW; // Default button state to not pressed
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
btnState = (reading == LOW) ? 1 : 0; // Set button state (pressed = 1)
}
lastButtonState = reading;
// Send formatted data: x, y, buttonState
Serial.print(xVal);
Serial.print(",");
Serial.print(yVal);
Serial.print(",");
Serial.println(btnState);
delay(20); // Small delay to reduce serial flooding
}
Circuit Schematic
p5.js Code
let port;
let connectButton, disconnectButton, finishButton, startButton, saveButton, statusText;
let xPos = 0;
let yPos = 0;
let drawingEnabled = false;
let isConnected = false;
let prevX, prevY;
let lastButtonState = 0;
let started = false;
let tutorialShown = false;
let currentColor;
let studentImg;
let tutorialButton;
function preload() {
studentImg = loadImage("Shamsa.PNG"); // preload image for the intro screen
}
function setup() {
createCanvas(1280, 720); // fixed landscape canvas size
background("#F5F5DC");
port = createSerial(); // setup WebSerial port
currentColor = color(random(255), random(255), random(255)); // initial random color
// Setup start screen
startButton = createButton("Start");
styleButton(startButton);
positionCenter(startButton, 0, 60);
startButton.mousePressed(() => {
startButton.hide();
tutorialShown = true;
showTutorialScreen(); // go to tutorial screen before drawing
});
statusText = createP("Status: Not connected");
statusText.position(10, 10);
statusText.hide(); // hidden until drawing mode begins
}
function styleButton(btn) {
// Apply consistent style to all buttons
btn.style("background-color", "#CF877D");
btn.style("color", "black");
btn.style("border-radius", "10px");
btn.style("padding", "10px 15px");
btn.style("font-size", "14px");
btn.style("border", "none");
}
function positionCenter(btn, offsetX, offsetY) {
// Center button horizontally/vertically with optional offset
btn.position((width - btn.size().width) / 2 + offsetX, (height - btn.size().height) / 2 + offsetY);
}
function showTutorialScreen() {
clear();
background("#F5F5DC");
// Instructions and disclaimer
textAlign(CENTER);
fill("#a8423d");
textSize(32);
text("Welcome to Sketch & Switch!", width / 2, 80);
textSize(20);
fill(0);
text(
"Disclaimer:\nThe blue knobs may be difficult at first, so twist them slowly and gently.\n" +
"The one on the right moves ↑↓, and the one on the left moves ←→",
width / 2, 160
);
text(
"Instructions:\n1. Press 'Connect' to connect to your drawing device\n2. Twist knobs to move\n" +
"3. Press the button on the board to change color (it will be randomized)\n" +
"4. When finishing the drawing, click 'Finish Drawing' to clear it,\n" +
" or click 'Save as PNG' to download your art.\n\n Tip: Clockwise = ↑ or →, CounterClockwise = ↓ or ←",
width / 2, 320
);
// Begin actual drawing
tutorialButton = createButton("Start Drawing");
styleButton(tutorialButton);
tutorialButton.position(width / 2 - 70, height - 100);
tutorialButton.mousePressed(() => {
tutorialButton.remove();
clear();
background(255);
started = true;
setupDrawingUI(); // load UI controls for drawing
});
}
function setupDrawingUI() {
// Create control buttons
connectButton = createButton("Connect");
connectButton.mousePressed(() => {
if (!port.opened()) {
port.open("Arduino", 115200); // open WebSerial at 115200 baud
}
});
styleButton(connectButton);
disconnectButton = createButton("Disconnect");
disconnectButton.mousePressed(() => {
if (port.opened()) {
port.close(); // safely close serial port
}
});
styleButton(disconnectButton);
finishButton = createButton("Finish Drawing");
finishButton.mousePressed(() => {
background(255); // clear canvas
drawingEnabled = false;
});
styleButton(finishButton);
saveButton = createButton("Save as PNG");
saveButton.mousePressed(() => {
saveCanvas("drawing", "png"); // download current canvas
});
styleButton(saveButton);
positionUI(); // arrange buttons
statusText.show();
}
function positionUI() {
// Align control buttons along the top
let baseX = width / 2 - 250;
let y = 10;
connectButton.position(baseX, y);
disconnectButton.position(baseX + 130, y);
finishButton.position(baseX + 260, y);
saveButton.position(baseX + 420, y);
}
function draw() {
if (!started) {
// Intro screen only if tutorial not yet shown
if (!tutorialShown) {
background("#F5F5DC");
textAlign(CENTER, CENTER);
textSize(48);
fill("#a8423d");
text("Sketch & Switch!", width / 2, height / 2 - 100);
textSize(24);
fill(0);
text("Press Start to Begin", width / 2, height / 2 - 40);
imageMode(CENTER);
image(studentImg, width / 4, height / 2 - 30, studentImg.width / 3, studentImg.height / 3);
}
return;
}
// Serial data handling (reads only once per frame to prevent lag)
if (port.opened()) {
isConnected = true;
statusText.html("Status: Connected");
let data = port.readUntil("\n");
if (data && data.trim().length > 0) {
processSerial(data.trim()); // pass cleaned data to be handled
}
} else {
isConnected = false;
statusText.html("Status: Not connected");
}
// Draw a small dot when not drawing (cursor)
if (!drawingEnabled && isConnected) {
fill(currentColor);
noStroke();
ellipse(xPos, yPos, 6, 6);
}
}
function processSerial(data) {
// Parse "x,y,button" format from Arduino
let parts = data.split(",");
if (parts.length !== 3) return;
let xVal = int(parts[0]);
let yVal = int(parts[1]);
let btn = int(parts[2]);
if (isNaN(xVal) || isNaN(yVal) || isNaN(btn)) return;
// Map potentiometer values to canvas dimensions
xPos = map(xVal, 0, 1023, 0, width);
yPos = map(yVal, 0, 1023, 0, height);
// Toggle drawing mode when button is pressed
if (btn === 1 && lastButtonState === 0) {
drawingEnabled = !drawingEnabled;
currentColor = color(random(255), random(255), random(255));
prevX = xPos;
prevY = yPos;
}
// Draw if in drawing mode
if (drawingEnabled) {
stroke(currentColor);
strokeWeight(2);
line(prevX, prevY, xPos, yPos);
prevX = xPos;
prevY = yPos;
}
lastButtonState = btn; // update for debounce
}
Arduino and p5.js Communication
Communication is established via serial connection:
-
- Arduino: Sends comma-separated values (X, Y, ButtonState) at a set interval.
- p5.js: Reads incoming serial data, parses the values, and updates the drawing accordingly.
Highlights
I’m proud of the fact that the push button consistently functions to toggle between the drawing modes of randomized thickness and color. Moreover, with optimal baud rate adjustment and data handling, the potentiometers also function with minimal lag, showing smoother and finger movement.
In addition, the project also has clear on-screen instructions and simple0 controls to allow users across any age range to easily become involved, whether they are experts or complete newbies to physical computing.
Areas for Future Improvement
While Sketch & Switch functions smoothly, there’s still plenty of room to build on its foundations:
-
- Add a feature where it allow users to position the drawing point before enabling drawing mode, giving them more control over line placement.
- Adding a color wheel and thickness slider in the UI so users can manually choose colors and line widths, rather than relying solely on randomness.
- Add an undo button to let users correct mistakes without having to clear the entire canvas.
- Replace the current components with larger potentiometers and a larger push button for improved tactile feedback and easier control.








