Project showcase
LittleArm: Arduino Robot Arm

LittleArm: Arduino Robot Arm © CC BY-SA

LittleArm is a 3D printed trainable Arduino robot arm for STEM students and makers.

  • 16,728 views
  • 1 comment
  • 75 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)

Apps and online services

About this project

Here is the LittleArm website where you can find other purchase the Littlearm kit or get files, tutorials, and other resources to build your own.

The LittleArm started as a weekend project by the founder of Slant, Gabe Bentz. Gabe was searching for a low cost 3D printed robot arm to experiment with the Arduino. Finding none he put his 3D printer to work to create the first prototype of the LittleArm.

Friends and teachers continued to ask Gabe to make kits for them so they could build the arm. That was when it became a project at Slant.

Today the LittleArm is supported by a team of designers who love technology. Users can download all of the software for free and start training their LittleArm. Those with 3D printers can download the STL's and those without can purchase the kit.

We at Slant love working with the LittleArm. It is one of the few designs out there that requires 3D printing, and really would not work with any other manufacturing process.

Code

Python Basics for WindowsPython
#This program has a complete set of commands for most behaviors
#an improvement to the software would be for the arduino to wait until completion of the execution of the command before sending a ready signal

from Tkinter import *
import tkFileDialog
import tkMessageBox
import time
import serial
import serial.tools.list_ports
import copy

#+++++++++++++Global Variables+++++++++++++++++++++

currentSequence = "motion_recording.txt"	#the file name of recording prei-intialized to the default
currentDirectoy = "/"						#defines the working directory of the user

loopStartStop = False

#This line of code is a manual alternative should the Arduino search function below fault
#To use Comment out the below While loop and change the COM# to the port the arduino is connected to based on the Device Mananger
#ser = serial.Serial('COM3', 9600, timeout = .1)

checker = 0  #Loop control
while checker == 0:
    #Find the serial port that the arduino is connected to
    ports = list(serial.tools.list_ports.comports())
    print ports
	
    for p in ports:
        
        print "Searching for Port ..."
        
        if "CH340"  in p[1]:
           
            print p[1]
            ser = serial.Serial(p[0], 9600, timeout = .5)
            checker = 1
            break
			
        if "Arduino" in p[1]:
            print "hello1"
            ser = serial.Serial(p[0], 9600, timeout = .5)
            checker = 1
            #print "Found the Arduino"
             		
        else:
	        print ("No Arduino Device was found connected to the computer")

#++++++++++++++++Functions+++++++++++++++++++++++

colors = {
    "spacer": "black",
    "background": "black",
    "frame": "black",
    "label": "gray",
    "speed": "#3366ff",
    "arm": "#00b300",
    "gripper": "red"
}

if sys.platform != "win32": 
    colors["spacer"] = "black"
    colors["background"] = "white"
    colors["frame"] = "white"

def move_it(aCommand):
    #this function sends the command of joint angles to the arduino to move the servos to the desired positions in real time with the GUI
    
    aCommand = 0  #unused holder to allow function to work live with scale bar

    ser.flushInput()
    ser.flushOutput()
    command = str(base.get()) + ',' + str(shoulder.get()) +   ',' + str(elbow.get())+','+ str(gripper.get())+','+ str(21 - theSpeed.get()) + '\n'
    print command
    ser.write(command)

    #wait until a repsonse if found from the arduino
    OK = 'no'
    while (OK != 'd'):
        OK = ser.read(1)
    
def recordArmPos():
    #This function records the current positions of the GUI and places them in a TXT file in the same directory as this program
    readPosCommand = str(base.get()) + ',' + str(shoulder.get()) +   ',' + str(elbow.get())+','+ str(gripper.get()) +','+ str(21 -theSpeed.get())+'\n'
    recordFile = open(currentSequence, 'a')
    print (currentSequence)
    recordFile.write(readPosCommand)
    recordFile.close()

def recordPause():
    #This function records the current positions of the GUI and places them in a TXT file in the same directory as this program
    pauseCommand = "pause" + '\n'
    recordFile = open(currentSequence, 'a')
    recordFile.write(pauseCommand)
    recordFile.close()    

def playback():
   #This function reads the record file created in recordArmPos() and send the commands to the arm so that a sequence may be repeated.
   recordFile = open(currentSequence, 'r')
   Count = 1
   for line in recordFile:
       Count = Count + 1
       recordedCommand = line

       #send the command to the arduino using another function
       sendCommand(recordedCommand)
   print ('Done')
   recordFile.close()

def sendCommand(anotherCommand):
    #this is a basic command function. It recieves the generic command in the form base,shoulder,elbow,effector\n and send it to the arduino and then waits to recieve confirmations that the arduino has processed it.
	#this function is a variation of move_it for the playback function
    ser.flushInput()
    ser.flushOutput()
    theCommand = anotherCommand 
    print theCommand

    if theCommand == "pause\n":
        time.sleep(1)
        return
    
    ser.write(theCommand)

    #wait until a repsonse if found from the arduino
    OK = 'no'
    while (OK != 'd'):
        OK = ser.read(1)
			
def goHome():
    #This function returns the robot to its initial positions and changed the GUI positions to match
    homePos = str(108) + ',' + str(154) + ',' + str(30)+ ',' + str(10) + ',' + str(4) + '\n'
    base.set(108)
    shoulder.set(154)
    elbow.set(30)
	
    sendCommand(homePos)
	
def clearFile():
    #this clears the file for a new sequence
    open(currentSequence, 'w').close()
	
def saveFileAs():
    #This function is called by the menubar
    #this function opens the current set of commands in the file motion_recording.txt and saves the contents to a new
    print "Saving a File I see"
    global currentSequence			#aacess the gloabl value of the current sequence
	
	#open the current file and copy its contents
    file = open(currentSequence, 'r')   
    textoutput = file.readlines()
    file.close()
	
	#open the new files and insert the contents
    theNewFile = tkFileDialog.asksaveasfilename(initialfile='Untitled.txt',defaultextension=".txt",filetypes=[("All Files","*.*"),("Text Documents","*.txt")])

    file = open(theNewFile, 'w')
    file.writelines(textoutput)		#not the writelines. write does not enter the data correctly from readlines
    file.close()
	
	#update the working file
    currentSequence = theNewFile	#update the file that is being used universally

def openFile():
    #this function sets the file that is being edited and recorded into
    global currentSequence
    currentSequence = tkFileDialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("txt files","*.txt"),("all files","*.*")))
    print (currentSequence)
	
def newFile():
    #this function created a new .txt file to hold imput commands
    global currentSequence
	
	#open a new fle 
    theNewFile = tkFileDialog.asksaveasfilename(initialfile='Untitled.txt',defaultextension=".txt",filetypes=[("All Files","*.*"),("Text Documents","*.txt")])	#names the file and sets the location
    file = open(theNewFile, 'a')   #creates the file
    file.close()
    
    currentSequence = theNewFile	#update the file that is being used universally

def looper( ):
    #this function loops through a the current sequence repeatedly.
    #startStop is the boolean bit that stats looping
    if loopStartStop == 1:
        playback()
    root.after(1000, looper)	

def startLooper():
    global loopStartStop
    loopStartStop = 1

def stopLooper():
    global loopStartStop	
    loopStartStop = 0
	
#++++++++++++++++++++The GUI++++++++++++++++++++++
root = Tk()
root.wm_title("LittleArm")
root.configure(background = colors["background"])

#++++++++++++++++++Menu+++++++++++++++++++++++++
menubar = Menu(root)

filemenu = Menu(menubar, tearoff = 0)

filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Open", command=openFile)
filemenu.add_command(label= "New Sequence", command=newFile)

filemenu.add_command(label="Save Sequence As", command=saveFileAs)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.quit)
menubar.add_cascade(label="File", menu=filemenu)

# display the menu
root.config(menu=menubar)

#+++++++++++++++++++++++spacer frame++++++++++++++++++++++++++++++++++
spacerFrameLeft = Frame(root, bg = colors["frame"])
spacerFrameLeft.grid(row = 0, column = 0 )


spacerLabel6 = Label(spacerFrameLeft,  bg = colors["spacer"], padx = 10)
spacerLabel6.grid(row = 0, column = 0 )

#+++++++++++++++++ARM+++++++++++++++++++++++++

# The scroll bars
armControl = Frame(root, background = colors["frame"])
armControl.grid(row = 0, column = 1 )

#armLabel = Label(armControl, text = "Arm Components", font = ("ARIAL", 24),relief = GROOVE, padx = 100)
#armLabel.pack()

spacerLabel = Label(armControl,  bg = colors["spacer"], padx = 100)
spacerLabel.grid(row = 1, column = 1 )

#++++++++++++++++++++++++BASE+++++++++++++++++++++++++++

baseLabel = Label(armControl, text = "Base", font = ("ARIAL", 16), relief = GROOVE, padx = 100, width = 9, bg = colors["arm"])
baseLabel.grid(row = 2, column = 1 )

base = Scale(armControl, from_= 5, to = 175, length = 306, orient = HORIZONTAL, troughcolor = colors["arm"], showvalue = 0, command = move_it)
base.set(108)
base.grid(row = 3, column = 1 )

#++++++++++++++++++++++++Shoulder+++++++++++++++++++++++++

shoulderLabel = Label(armControl, text = "Shoulder", font = ("ARIAL", 16),relief = GROOVE, padx = 100, width = 9, bg = colors["arm"])
shoulderLabel.grid(row = 4, column = 1 )

shoulder = Scale(armControl, from_= 5, to = 175, length = 306, orient = HORIZONTAL, troughcolor = colors["arm"], showvalue = 0,command = move_it)
shoulder.set(100)
shoulder.grid(row = 5, column = 1 )

#++++++++++++++++++++++ELBOW++++++++++++++++++++++++++++

elbowLabel = Label(armControl, text = "Elbow",font = ("ARIAL", 16), relief = GROOVE, padx = 100, width = 9, bg = colors["arm"])
elbowLabel.grid(row = 6, column = 1 )

elbow = Scale(armControl, from_= 5, to = 175, length = 306, orient = HORIZONTAL,troughcolor = colors["arm"], showvalue = 0, command = move_it)
elbow.set(30)
elbow.grid(row = 7, column = 1 )

#++++++++++++++++++++++++++++Gripper+++++++++++++++++++

gripperLabel = Label(armControl, text = "Gripper",font = ("ARIAL", 16), relief = GROOVE, padx = 100, width = 9, bg = colors["gripper"])
gripperLabel.grid(row = 8, column = 1 )

gripper = Scale(armControl, from_= 5, to = 75, length = 306, orient = HORIZONTAL, troughcolor = colors["gripper"], showvalue = 0,  command = move_it)
gripper.grid(row = 9, column = 1 )

#++++++++++++++++++++++++++Speed++++++++++++++++++++++++

spacerLabel2 = Label(armControl,  bg = colors["spacer"], padx = 100)
spacerLabel2.grid(row = 10, column = 1 )

speedLabel = Label(armControl, bg = colors["speed"], font = ("Arial", 16), text = "Speed", relief = GROOVE, padx = 100, width = 9)
speedLabel.grid(row = 11, column = 1 )

theSpeed = Scale(armControl, from_= 3, to = 20, length = 306, orient = HORIZONTAL, troughcolor = colors["speed"] ,command = move_it)
theSpeed.grid(row = 12, column = 1 )


spacerLabel3 = Label(armControl,  bg = colors["spacer"], padx = 100)
spacerLabel3.grid(row = 13, column = 1 )

pauseButton = Button(armControl, font = ("ARIAL", 16), text= "Pause for 1 Sec", width = 20, command = recordPause)
pauseButton.grid(row = 14, column = 1 )

homeButton = Button(armControl, font = ("ARIAL", 16), text= "Go Home", width = 20, command = goHome)
homeButton.grid(row = 15, column = 1 )

spacerLabel8 = Label(armControl,  bg = colors["spacer"], padx = 100)
spacerLabel8.grid(row = 16, column = 1 )

#+++++++++++++++++++++++space frame++++++++++++++++++++++++++++++++++

spacerFrame = Frame(root, bg = colors["frame"])
spacerFrame.grid(row = 0, column = 2 )

spacerLabel6 = Label(spacerFrame,  bg = colors["spacer"], padx = 20)
spacerLabel6.grid(row = 0, column = 0 )

#+++++++++++++++++++++++RECORD++++++++++++++++++++++++++++
recordButtons = Frame(root, bg = colors["frame"])
recordButtons.grid(row = 0, column = 3 )

spacerLabel4 = Label(recordButtons,  bg = colors["spacer"], padx = 100)
spacerLabel4.grid(row = 1, column = 2 )

recordButton = Button(recordButtons, font = ("ARIAL", 16),text = "Record Position", width = 20, command = recordArmPos)
recordButton.grid(row = 2, column = 2 )

spacerLabel9 = Label(recordButtons,  bg = colors["spacer"], padx = 100)
spacerLabel9.grid(row = 3, column = 2 )

playButton = Button(recordButtons, font = ("ARIAL", 16), text = "Play Sequence", width = 20, command = playback)
playButton.grid(row = 4, column = 2 )

clearButton = Button(recordButtons, font = ("ARIAL", 16), text = "Clear Sequence", width = 20, command = clearFile)
clearButton.grid(row = 5, column = 2 )

spacerLabel5 = Label(recordButtons,  bg = colors["spacer"], padx = 100)
spacerLabel5.grid(row = 6, column = 2 )

#++++++++Looping+++++++++++++++++++

loopStartButton = Button(recordButtons, font = ("ARIAL", 16), text = "Start Loop", width = 20, command = startLooper)
loopStartButton.grid(row = 7, column = 2 )
loopStopButton = Button(recordButtons, font = ("ARIAL", 16), text = "Stop Loop", width = 20, command = stopLooper)
loopStopButton.grid(row = 8, column = 2 )

#+++++++++++++++++++++++space frame++++++++++++++++++++++++++++++++++

spacerFrameRight = Frame(root, bg = colors["frame"])
spacerFrameRight.grid(row = 0, column = 4 )

spacerLabel7 = Label(spacerFrameRight,  bg = colors["spacer"], padx = 10)
spacerLabel7.grid(row = 0, column = 0 )

#+++++++++++++++++++++++++++Primary Loop+++++++++++++++++

root.after(1000, looper)
root.mainloop()

Schematics

Basic Wiring
M3k1tvxraxwemoqtxj7q

Comments

Similar projects you might like

Littlearm 2C: Build a 3D Printed Arduino Robot Arm

Project tutorial by Slant Concepts

  • 4,404 views
  • 1 comment
  • 32 respects

Control Arduino Robot Arm with Android App

Project tutorial by Slant Concepts

  • 9,004 views
  • 7 comments
  • 26 respects

MeArm Robot Arm - Your Robot - V1.0

Project tutorial by Benjamin Gray

  • 19,423 views
  • 3 comments
  • 35 respects

"Waldo" Motion Capture with LittleArm

Project showcase by Slant Concepts

  • 3,894 views
  • 3 comments
  • 29 respects
Add projectSign up / Login