픽잇 (Pickit) 비전 시스템 통합 예제
픽잇 비전과의 연동 프로그램은 IndyDCP 를 통해 명령을 전달합니다. 따라서 IndyDCP 를 이용하여 indy 객체를 생성합니다. 여기서 추가적으로 Pickit 클라이언트 모듈과 JsonProgramComponent 모듈을 임포트 하면 픽잇을 연결하여 사용할 수 있습니다. 이 때, 픽잇, 로봇, 호스트 PC 는 같은 네트워크로 구성하여야 합니다. 모듈 파일과 예제 노트북 파일은 아래 링크를 클릭하여 다운받을 수 있습니다.
indy_utils/indydcp_client.py 와 vision_clients/indydcp_client.py 는 Python 모듈 소스 파일이며 Pickit_Program.ipynb 는 픽잇 사용 예제와 이에 대한 상세 내용이 기술된 주피터 노트북 파일입니다. 첨부 된 주피터 노트북을 통해 아래 예제들의 실행이 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | from indy_utils import indydcp_client as client
from indy_utils.indy_program_maker import JsonProgramComponent
from vision_clients import pickit_client as p_client
from time import sleep
import json
from threading import Lock
import threading
robot_ip = "192.168.0.3" # 예시 CB IP 주소
robot_name = "NRMK-Indy7" # IndyRP2의 경우 "NRMK-IndyRP2"
# 로봇 연결
indy = client.IndyDCPClient(robot_ip, robot_name)
indy.connect()
|
| # 픽잇 연결
bind_ip = "192.168.0.199" # 예시 Host-PC IP 주소
pickit_addr = "192.168.0.2" # 예시 픽잇 컨트롤러 IP 주소
pickit = p_client.PickitClient(bind_ip, pickit_addr)
pickit.connect()
|
픽잇은 일정 주기마다 로봇으로부터 로봇 자세를 수신합니다. 아래 함수를 실행하면 픽잇 UI 상에서 로봇 연결 표시를 확인하실 수 있으며, 정상적으로 연결 표시가 나타난 후 다음 단계를 진행하시길 바랍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | PERIOD_STOP = False
TERMINATE_THREADS = False
def periodic_send():
while not PERIOD_STOP:
sleep(0.1)
pickit.periodic(list(indy.get_task_pos().astype('float16')))
if TERMINATE_THREADS:
print('periodic_send finished')
break
# 'periodic send' 쓰레드 생성
th2 = threading.Thread(target=periodic_send)
th2.start()
|
툴 오프셋 획득
로봇을 픽잇과 연결한 후에는 프로그램에 사용 할 툴 오프셋과 경유점을 교시하여 파일로 저장해주어야 합니다. 여기서 툴이란 픽잇 연동을 통해 픽 앤 플레이스 작업에 사용될 툴을 지칭합니다.
먼저, 픽에 사용될 물체를 하나만 상자에 올려둔 후 픽잇 UI 에서 Enable Robot mode 를 실행하고 아래 명령어를 실행합니다. 그러면 현재 물체 위치 좌표를 획득할 수 있습니다.
| # 툴 티칭 1
obj_pos, obj_remaning, status = pickit.get_object_pos(indy)
obj_next_pos = pickit.get_next_object_pos(indy)[0]
print(list(obj_pos))
print(list(obj_next_pos))
pickit.check_object_found(status)
|
그런 다음, 직접 교시 또는 조그를 이용하여 툴이 장착 된 로봇을 픽 위치로 이동시킨 후 아래 명령어를 실행합니다. 이를 통해 픽잇으로부터 인식된 물체 위치 대비 툴의 위치 오프셋을 계산하고 저장하게 됩니다.
| # 툴 티칭 2
pickit.set_tool_offset(indy, obj_pos)
|
경유점 교시
다음은 경유점 교시 및 저장 단계입니다. 먼저, 아래 명령어들을 이용하면 로봇의 현재 관절 위치 또는 작업 위치를 출력할 수 있습니다.
| print(list(indy.get_joint_pos().astype('float16'))) # Angle of each axis in degrees
print(list(indy.get_task_pos().astype('float16'))) # Each value of X, Y, Z, U, V, W in meters
|
따라서, 픽 앤 플레이스 작업의 각 단계별 위치로 로봇을 움직인 후 아래 명령어를 실행하여 로봇 위치를 획득함과 동시에 파일로 저장합니다. 이 때, 조인트 무브 또는 태스크 무브인지에 따라 두 명령어 중 하나를 택하여 실행할 수 있도록 하며, 구분을 위해 경유점 이름 지정 시 j_ 또는 t_ 를 붙여 저장하는 것을 권장드립니다.
| # 조인트 무브 교시점 추가
indy.update_teaching_data(file_name='teaching/teach_config.json', wp_name='j_detect', j_pos=indy.get_joint_pos())
|
| # 태스크 무브 교시점 추가
indy.update_teaching_data(file_name='teaching/teach_config.json', wp_name='t_prepick', j_pos=indy.get_task_pos())
|
| # 추가한 교시점 삭제
indy.del_teaching_data(file_name='teaching/teach_config.json', wp_name='j_detect')
|
모든 구성 옵션 저장이 완료되면, 아래와 같이 파일에서 모든 데이터를 불러옵니다.
| # Load teaching data
with open('./teaching/teach_config.json') as json_file:
teach_config = json.load(json_file)
print(teach_config)
|
| # Load teaching data
with open('./teaching/tool_config.json') as json_file:
tool_config = json.load(json_file)
print(tool_config)
|
빈 피킹 예제 프로그램
앞서 설정한 툴 오프셋과 교시점을 토대로 빈 피킹 예제 프로그램에 대해 설명합니다. 그리퍼를 장착한 로봇이 빈에 쌓여있는 시편을 픽잇을 통해 인식하고, 시편을 그리퍼로 잡아 설정한 위치에 놓는 픽 앤 플레이스 작업을 수행합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | BIN_PICKING_ON = False
def bin_picking(vel=1, pick_height=0.03): # 로봇 속도 및 픽 직전 높이 설정
while True:
if TERMINATE_THREADS:
print('bin_picking finished')
break
if BIN_PICKING_ON:
# 픽잇으로부터 현재 로봇 위치 대비 픽 위치 획득
pick_pos, pick_above, objects_remaining, status = pickit.get_pickit_pos(indy, pick_height)
# 1회 반복 후 'Place' 프로그램 종료까지 대기
indy.wait_for_program_finish()
# 'Pick' 프로그램 시작 전 픽 가능한 물체 여부 및 픽잇 구동 상태 확인
if pickit.check_object_found(status) and pickit.check_mode(indy) and indy.set_workspace(pick_pos):
print('Detect! Move to pick!')
# Pick
prog = JsonProgramComponent(policy=0, resume_time=2) # 프로그램 초기화
prog.add_tool_command(tool_id=0, command=3) # 그리퍼 Release
prog.add_joint_move_to(teach_config['j_home'], vel=vel, blend=20) # 조인트 무브로 'j_home' 교시점까지 이동
prog.add_joint_move_to(teach_config['j_pre_entry'], vel=vel, blend=20) # 조인트 무브로 'j_pre_entry' 교시점까지 이동
prog.add_task_move_to(teach_config['t_entry'], vel=vel) # 태스크 무브로 't_entry' 교시점까지 이동
# 픽 위치 높이가 진입점 높이보다 낮은 지 확인
if pick_above[2] <= teach_config['t_entry'][2]:
# 태스크 무브로 픽 위치 이동
prog.add_task_move_to(list(pick_above), vel=vel, blend=0.1)
prog.add_task_move_to(list(pick_pos), vel=vel, blend=0.1)
prog.add_tool_command(tool_id=0, command=2) # 그리퍼 Hold
# 진입 위치로 재이동
prog.add_task_move_to(teach_config['t_entry'], vel=vel, blend=0.1)
prog.add_joint_move_to(teach_config['j_pre_entry'], vel=vel)
indy.set_and_start_json_program(prog.program_done()) # 프로그램 완성 및 실행
indy.wait_for_program_finish() # 'Pick' 프로그램 종료 시까지 대기
# Place
prog = JsonProgramComponent(policy=0, resume_time=2)
prog.add_task_move_to(teach_config['t_place1'], vel=vel, blend=0.1)
prog.add_task_move_to(teach_config['t_place2'], vel=vel, blend=0.1)
prog.add_tool_command(tool_id=0, command=3)
prog.add_joint_move_to(teach_config['j_home'], vel=vel)
indy.set_and_start_json_program(prog.program_done())
else:
print('No object is detected')
# 'bin picking program' 쓰레드 생성
th1 = threading.Thread(target=bin_picking)
th1.start()
|
프로그램 실행은 아래 명령어로 할 수 있으며, 비상 정지를 해야할 경우에는 그 다음 명령어들을 통해 즉시 종료할 수 있습니다.
| # 프로그램 실행
BIN_PICKING_ON = True
|
| # 프로그램 비상 정지 및 로봇 모션 종료
indy.stop_motion()
BIN_PICKING_ON = False
TERMINATE_THREADS = True
|
모든 프로그램을 종료하고 더 이상 실행시키시지 않을 경우에는 아래 명령어를 통해 로봇과의 연결을 정상적으로 해제하여야 합니다.