Introduction
I had gotten a joystick a while ago and wanted to do something different and interesting with it. After coming up with and discarding a bunch of other ideas, I came up with the Arduino Sketcher. The ideas was to make something similar to an Etch-a-Sketch but uses the joystick instead of two dials. The computer would serve as the sketching pad while to Arduino relayed all the commands sent by the user. This project uses both Arduino and Python and turned out to be fairly simple to implement.
Schematic
Below is the schematic of the Arduino Sketcher.
The sketcher allows the user to click on various parts of the canvas to determine where the lines start out. This allows for disconnected lines. It uses the joystick to determine where to draw the line and how quickly. The more the user shifts the joystick, the faster it draws lines. When the user holds the joystick down, the button triggers and a circle will be drawn on the canvas. The longer the button is held down, the larger the circle is. The buttons next to the joystick allow the user to select various colors indicated by the wire. There are buttons available that are colored and can be used to indicate color.
Code
Arduino Code
Below is the code on the Arduino side. The Arduino is mostly used to translate the controller and send commands to the Python side.
/**************************** Controller for Sketcher Jennifer Case 13/06/2013 ****************************/ //Declare pins int redPin = 7; int yelPin = 6; int grnPin = 5; int bluPin = 4; int blkPin = 3; int verPin = A0; int horPin = A1; int circlePin = 8; int lastColor = 4; long previousMillis = 0; long interval = 200; float numClicks = 0; void setup() { Serial.begin(38400); pinMode(redPin, INPUT); pinMode(yelPin, INPUT); pinMode(grnPin, INPUT); pinMode(bluPin, INPUT); pinMode(blkPin, INPUT); pinMode(circlePin, INPUT); digitalWrite(circlePin, HIGH); } void loop() { //read values from color buttons int redBtn = digitalRead(redPin); int yelBtn = digitalRead(yelPin); int grnBtn = digitalRead(grnPin); int bluBtn = digitalRead(bluPin); int blkBtn = digitalRead(blkPin); //read and normalize values from the potentiameters float verPos = (analogRead(verPin)-504.0)/504.0; float horPos = (496.0-analogRead(horPin))/496.0; //read value of button boolean circleBtn = digitalRead(circlePin); //if either normalized value from the joystick is //essentially zero, make it equal zero if (verPos < 0.01 && verPos > -0.01) {verPos = 0;} if (horPos < 0.01 && horPos > -0.01) {horPos = 0;} unsigned long currentMillis = millis(); char charBuf[5]; //if enough time has passed and either potentiameter is not zero, //print out commands for both axes if(currentMillis - previousMillis > interval && (verPos != 0 || horPos != 0)) { Serial.print("X,"); dtostrf(verPos, 4, 2, charBuf); //turn float to string Serial.println(charBuf); Serial.print("Y,"); dtostrf(horPos, 4, 2, charBuf); //turn float to string Serial.println(charBuf); previousMillis = currentMillis; //reset the interval } //determine color and print it to sketcher if it was not the last color if (redBtn && lastColor != 0) { Serial.println("C,R"); //print command lastColor = 0; } else if (yelBtn && lastColor != 1) { Serial.println("C,Y"); //print command lastColor = 1; } else if (grnBtn && lastColor != 2) { Serial.println("C,G"); //print command lastColor = 2; } else if (bluBtn && lastColor != 3) { Serial.println("C,B"); //print command lastColor = 3; } else if (blkBtn && lastColor != 4) { Serial.println("C,K"); //print command lastColor = 4; } //while button on joystick is clicked, while (!circleBtn) { numClicks++; //increase counter circleBtn = digitalRead(circlePin); //read the button again } //if numClicks is more than zero, if (numClicks > 0) { Serial.print("O,"); //start printing command numClicks = numClicks/20000.0; //normalize the numClicks dtostrf(numClicks, 4, 2, charBuf); //int to string Serial.println(charBuf); //print the rest of the command numClicks = 0; //reset numClicks } }
Python Code
Below is the Python code. It just translates the commands from the Arduino side and draws the appropriate lines on the canvas. It should be noted that this was coded for Python 3.
#! /usr/bin/python from serial import * from tkinter import * import time #Serial ser = Serial("COM9",38400,timeout=0,writeTimeout=0) time.sleep(1) #initialize positions xPos = 500 yPos = 300 #function for making a circle def drawcircle(canv,x,y,rad,color): canv.create_oval(x-rad,y-rad,x+rad,y+rad,width=0,fill=color) #function for mouse click def goToClick(event): global xPos global yPos xPos = event.x yPos = event.y #Main window root = Tk() #Tk is a function that makes a class root.wm_title("Canvas Sketch") root.config(bg="#8D8A8A", bd="0") #make the sketcher canvas sketcher = Canvas(root, width=1000, height=600, bg='white') sketcher.grid(row=0, column=0) sketcher.bind('<Button-1>', goToClick) #log = Text(root, width=50, height=8, takefocus=0) #log.grid(row=1, column=0, padx=2, pady=2) #initializations color = 'black' verPos = 0 horPos = 0 def runLoop(event=0): ln = ser.readline() #get command lineStr = ln.decode(encoding='UTF-8') #log.insert('0.0',lineStr) #print(lineStr) #initializations Xline = 0 Yline = 0 circline = 0 newLine = 0 #other neccessary variables global verPos global horPos global xPos global yPos global color #determine selected color if "C" in lineStr: for line in lineStr.split(','): if "R" in line: color = 'red' if "Y" in line: color = 'yellow' if "G" in line: color = 'green' if "B" in line: color = 'blue' if "K" in line: color = 'black' #get X value elif "X" in lineStr: if len(lineStr) > 6: #make sure length is appropriate for line in lineStr.split(','): if Xline == 1: #take value from lineStr verPos = float(line.strip("\n \r"))*-1 #fix direction #print(verPos) Xline = 0 elif Xline == 0: Xline = 1 #get Y value elif "Y" in lineStr: for line in lineStr.split(','): if Yline == 1: #take value from lineStr horPos = float(line.strip("\n \r")) #print(horPos) Yline = 0 newLine = 1 #indicates that a line is ready to be drawn elif Yline == 0: Yline = 1 #draw circle elif "O" in lineStr: if len(lineStr) > 4: #checks length for line in lineStr.split(','): if circline == 1: #gets value circDiam = float(line.strip("\n \r")) #draw circle drawcircle(sketcher,xPos,yPos,5*circDiam,color) circline = 0 elif circline == 0: circline = 1 if newLine == 1: newY = yPos+5*verPos #finds new end position newX = xPos+5*horPos #finds new end position sketcher.create_line(xPos, yPos, newX, newY, fill=color, width = 2) xPos = newX #adjusts end position yPos = newY #adjusts end position root.after(10, runLoop) runLoop() root.mainloop()