驴友花雕 发表于 前天 16:15

【Arduino 动手做】LittleArm:Arduino 机械臂

LittleArm 是一款 3D 打印可训练 Arduino 机械臂,适合 STEM 学生和制造商。

这是LittleArm网站,您可以在此找到其他购买 Littlearm 套件或获取文件、教程和其他资源来构建您自己的套件。

LittleArm 最初是由 Slant 创始人 Gabe Bentz 的一个周末项目发起的。Gabe 当时正在寻找一款低成本的 3D 打印机械臂来配合 Arduino 进行实验。由于找不到合适的,他便用自己的 3D 打印机制作了 LittleArm 的第一个原型。

朋友和老师们不断请加布为他们制作工具,以便他们能组装这只假肢。从那时起,它就成了Slant的一个项目。

如今,LittleArm 由一支热爱科技的设计师团队提供支持。用户可以免费下载所有软件,开始训练他们的 LittleArm。拥有 3D 打印机的用户可以下载 STL 文件,没有打印机的用户则可以购买套件。

Slant 团队非常热爱 LittleArm 的设计。它是市面上少数几个需要 3D 打印的设计之一,而且其他任何制造工艺都无法实现。







驴友花雕 发表于 前天 16:16

【Arduino 动手做】LittleArm:Arduino 机械臂

项目代码

#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:
         
            print p
            ser = serial.Serial(p, 9600, timeout = .5)
            checker = 1
            break
                       
      if "Arduino" in p:
            print "hello1"
            ser = serial.Serial(p, 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()

驴友花雕 发表于 前天 16:20

【Arduino 动手做】LittleArm:Arduino 机械臂

附录
【Arduino 动手做】LittleArm:Arduino 机械臂
项目链接:https://www.hackster.io/slantconcepts/littlearm-arduino-robot-arm-401fe2
项目作者:Slant Concepts

项目视频 :
https://www.youtube.com/watch?v=RSenq1iEZ_M
https://www.youtube.com/watch?v=xU3S6d1WIh4
项目代码:
https://www.hackster.io/code_files/82889/download
LittleArm 图形用户界面:
https://github.com/slantconcepts/LittleArmOne-Desktop-GUI



页: [1]
查看完整版本: 【Arduino 动手做】LittleArm:Arduino 机械臂