Skip to content

픽잇 (Pickit) 비전 시스템 통합 예제

픽잇 비전과의 연동 프로그램은 IndyDCP 를 통해 명령을 전달합니다. 따라서 IndyDCP 를 이용하여 indy 객체를 생성합니다. 여기서 추가적으로 Pickit 클라이언트 모듈과 JsonProgramComponent 모듈을 임포트 하면 픽잇을 연결하여 사용할 수 있습니다. 이 때, 픽잇, 로봇, 호스트 PC 는 같은 네트워크로 구성하여야 합니다. 모듈 파일과 예제 노트북 파일은 아래 링크를 클릭하여 다운받을 수 있습니다.

indy_utils/indydcp_client.pyvision_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()
1
2
3
4
5
6
# 픽잇 연결
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
2
3
4
5
6
7
# 툴 티칭 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)

그런 다음, 직접 교시 또는 조그를 이용하여 툴이 장착 된 로봇을 픽 위치로 이동시킨 후 아래 명령어를 실행합니다. 이를 통해 픽잇으로부터 인식된 물체 위치 대비 툴의 위치 오프셋을 계산하고 저장하게 됩니다.

1
2
# 툴 티칭 2
pickit.set_tool_offset(indy, obj_pos)

경유점 교시

다음은 경유점 교시 및 저장 단계입니다. 먼저, 아래 명령어들을 이용하면 로봇의 현재 관절 위치 또는 작업 위치를 출력할 수 있습니다.

1
2
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_ 를 붙여 저장하는 것을 권장드립니다.

1
2
# 조인트 무브 교시점 추가
indy.update_teaching_data(file_name='teaching/teach_config.json', wp_name='j_detect', j_pos=indy.get_joint_pos())
1
2
# 태스크 무브 교시점 추가
indy.update_teaching_data(file_name='teaching/teach_config.json', wp_name='t_prepick', j_pos=indy.get_task_pos())
1
2
# 추가한 교시점 삭제
indy.del_teaching_data(file_name='teaching/teach_config.json', wp_name='j_detect')

모든 구성 옵션 저장이 완료되면, 아래와 같이 파일에서 모든 데이터를 불러옵니다.

1
2
3
4
# Load teaching data
with open('./teaching/teach_config.json') as json_file:
    teach_config = json.load(json_file)
    print(teach_config)
1
2
3
4
# 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()

프로그램 실행은 아래 명령어로 할 수 있으며, 비상 정지를 해야할 경우에는 그 다음 명령어들을 통해 즉시 종료할 수 있습니다.

1
2
# 프로그램 실행
BIN_PICKING_ON = True
1
2
3
4
# 프로그램 비상 정지 및 로봇 모션 종료
indy.stop_motion()
BIN_PICKING_ON = False
TERMINATE_THREADS = True

모든 프로그램을 종료하고 더 이상 실행시키시지 않을 경우에는 아래 명령어를 통해 로봇과의 연결을 정상적으로 해제하여야 합니다.

1
indy.disconnect()