골판지 로봇 팔 만들기 – 아두이노와 서보로 쉽게 DIY
필요한 부품 및 소모품
| 부품 |
수량 |
| 아두이노 우노 (Arduino UNO) |
1 |
| 일반 크기 서보 (Normal Sized Servo) |
3 |
| SG90 마이크로 서보 모터 |
1 |
| 브레드보드 (Breadboard) |
1 |
| 5V 전원 공급 장치 |
1 |
필요한 도구
앱 및 온라인 서비스
- 아두이노 IDE (Arduino IDE)
- 파이썬 (Python)
프로젝트 소개
이 프로젝트는 위치를 기록하고 재생할 수 있는 간단한 로봇 팔입니다. 골판지와 글루건 같이 쉽게 구할 수 있는 재료로 제작되어 누구나 만들기 쉽습니다.
컴퓨터의 그래픽 인터페이스로 팔을 제어하며, 이 인터페이스는 아두이노로 데이터를 전송해 서보를 제어합니다. 각 서보를 조절하는 슬라이더와 위치를 기록·재생하는 버튼이 있으며, 녹화 내용을 저장하고 불러올 수도 있습니다.
제작 방법
- 페이지 하단의 'Custom Parts and Enclosures' 섹션에 있는 골판지 커팅 템플릿을 다운로드해 출력한 뒤, 골판지를 잘라 부품을 만듭니다.
- 영상(0:22부터 시작)을 참고해 로봇 팔을 조립합니다.
- 페이지 하단의 회로도를 참고해 회로를 구성합니다.
- 'Robot Arm Arduino Code'를 다운로드해 아두이노에 업로드합니다.
- 'Python User Interface' 코드를 다운로드합니다. 파이썬이 설치되어 있어야 하며(python.org에서 다운로드), PySerial 라이브러리도 필요합니다(
pip install pyserial로 설치).
- 로봇 팔을 연결하고 파이썬 코드를 실행한 뒤, 아두이노의 COM 포트(윈도우의 장치 관리자에서 확인 가능)를 입력하면 사용 준비가 완료됩니다.
문제 해결 팁: 작동하지 않으면 파이썬 코드 20번째 줄의 time.sleep(0.15) 값을 0.2나 0.3으로 늘려보세요.
코드
파이썬 사용자 인터페이스 (Python)
from tkinter import *
from tkinter import filedialog
import serial
import time
port_opened = False
def set_port():
global port_opened, arduino
com_port = port_input.get()
arduino = serial.Serial(com_port, 9600)
port_opened = True
print("COM port set to: " + com_port)
def send_positions(position):
message = "{0:0=3d}".format(position[0]) + "{0:0=3d}".format(position[1]) + \
"{0:0=3d}".format(position[2]) + "{0:0=3d}".format(position[3]) + \
"{0:0=3d}".format(position[4]) + "\n"
arduino.write(str.encode(message))
print(message, end='')
time.sleep(0.2)
saved_positions = []
def save_positions():
saved_positions.append([servo1_slider.get(), servo2_slider.get(),
servo3_slider.get(), servo4_slider.get(), servo5_slider.get()])
print("saved positions: " + str(saved_positions))
def play_positions():
for position in saved_positions:
print("playing: " + str(position))
send_positions(position)
time.sleep(1)
def clear_all_positions():
global saved_positions
saved_positions = []
print("cleared all positions")
def clear_last_positions():
global saved_positions
removed = saved_positions.pop()
print("removed: " + str(removed))
print("saved positions: " + str(saved_positions))
def open_file():
global saved_positions
filename = filedialog.askopenfilename(initialdir="/", title="Select a File",
filetypes=(("Text files", "*.txt*"), ("all files", "*.*")))
file = open(filename, "r")
data = file.read()
saved_positions = eval(data)
file.close()
print("opened: " + filename)
def save_file():
save_file = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
save_file.write(str(saved_positions))
save_file.close()
print("saved file")
def instructions():
print("1.) 아두이노의 COM 포트를 설정하고 Enter를 누르세요. (윈도우 장치 관리자에서 확인 가능)")
print("2.) 슬라이더로 각 서보를 움직이세요")
print("3.) 위치를 기록하려면 'Record Position'을 클릭하세요")
print("4.) 기록된 위치를 재생하려면 'Replay Positions'을 클릭하세요")
print("\n기록을 저장하려면 File > Save File")
print("저장된 파일을 열려면 File > Open File")
window = Tk()
window.title("Robot Arm Controller 2")
window.minsize(355, 300)
port_label = Label(window, text="Set Port:")
port_label.place(x=10, y=10)
port_input = Entry(window)
port_input.place(x=10, y=35)
port_button = Button(window, text="Enter", command=set_port)
port_button.place(x=135, y=32)
servo1_slider = Scale(window, from_=180, to=0)
servo1_slider.place(x=0, y=100)
servo1_label = Label(window, text="Servo 1")
servo1_label.place(x=10, y=80)
servo2_slider = Scale(window, from_=180, to=0)
servo2_slider.place(x=70, y=100)
servo2_label = Label(window, text="Servo 2")
servo2_label.place(x=80, y=80)
servo3_slider = Scale(window, from_=180, to=0)
servo3_slider.place(x=140, y=100)
servo3_label = Label(window, text="Servo 3")
servo3_label.place(x=150, y=80)
servo4_slider = Scale(window, from_=180, to=0)
servo4_slider.place(x=210, y=100)
servo4_label = Label(window, text="Servo 4")
servo4_label.place(x=220, y=80)
servo5_slider = Scale(window, from_=180, to=0)
servo5_slider.place(x=280, y=100)
servo5_label = Label(window, text="Servo 5")
servo5_label.place(x=290, y=80)
save_button = Button(window, text="Record Position", command=save_positions)
save_button.place(x=10, y=220)
clear_button = Button(window, text="Clear Last Position", command=clear_last_positions)
clear_button.place(x=120, y=220)
clear_button = Button(window, text="Clear All Positions", command=clear_all_positions)
clear_button.place(x=120, y=255)
play_button = Button(window, text="Replay Positions", command=play_positions, height=3)
play_button.place(x=250, y=220)
menubar = Menu(window)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Open File", command=open_file)
filemenu.add_command(label="Save File", command=save_file)
menubar.add_cascade(label="File", menu=filemenu)
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="Clear last position", command=clear_last_positions)
editmenu.add_command(label="Clear all positions", command=clear_all_positions)
menubar.add_cascade(label="Edit", menu=editmenu)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label="How to use (printed in console)", command=instructions)
menubar.add_cascade(label="Help", menu=helpmenu)
window.config(menu=menubar)
while True:
window.update()
if port_opened:
send_positions([servo1_slider.get(), servo2_slider.get(),
servo3_slider.get(), servo4_slider.get(), servo5_slider.get()])
로봇 팔 아두이노 코드 (Arduino)
#include
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;
int servoPositions[5];
void setup() {
Serial.begin(9600);
servo1.attach(3);
servo2.attach(5);
servo3.attach(6);
servo4.attach(9);
servo5.attach(10);
}
void loop() {
while (Serial.available()) {
String input = Serial.readStringUntil('\n');
servoPositions[0] = input.substring(0, 3).toInt();
servoPositions[1] = input.substring(3, 6).toInt();
servoPositions[2] = input.substring(6, 9).toInt();
servoPositions[3] = input.substring(9, 12).toInt();
servoPositions[4] = input.substring(12, 15).toInt();
}
servo1.write(servoPositions[0]);
servo2.write(servoPositions[1]);
servo3.write(servoPositions[2]);
servo4.write(servoPositions[3]);
servo5.write(servoPositions[4]);
delay(500);
}
회로도
페이지 하단의 회로도 이미지를 참고하세요.