Skip to content

프로그램 메이커 (Program maker)

프로그램 메이커는 아래 Conty 에서의 프로그램 트리 (Program Tree) 를 Python 코드를 통해 작성하고, 실행할 수 있게 합니다. 이를 통해 복잡한 로직과 멀티 쓰레드, 비동기 프로그램 등을 통해 더 유연하고 복잡한 로봇 작업 공정을 구현할 수 있습니다. 또한 뉴로메카 Conty 에서 지원하는 비전 시스템 (IndyEye, Pickit) 외 상용 비전 시스템과의 통합도 수행할 수 있습니다.

프로그램 메이커는 IndyDCP 를 통해 명령을 전달합니다. 따라서 앞 장에서의 IndyDCP 와 동일한 방법으로 indy 객체를 생성합니다. 여기서 추가적으로 JsonProgramComponent 모듈을 임포트 하면 프로그램 메이커를 사용할 수 있습니다. 또한, 프로그램 메이커에서도 마찬가지로 프로그램 구동 전과 후에 로봇과의 연결 및 해제를 connect(), disconnect() 함수를 이용하여 정상적으로 실행해주어야 합니다.

1
2
3
4
5
6
from indy_utils import indydcp_client as client
from indy_utils.indy_program_maker import JsonProgramComponent

robot_ip = "192.168.0.2"    # 예시 STEP IP 주소
robot_name = "NRMK-Indy7"   # IndyRP2의 경우 "NRMK-IndyRP2"
indy = client.IndyDCPClient(robot_ip, robot_name)  # indy 객체 생성
1
2
indy.connect() # 로봇 연결
indy.disconnect() # 연결 해제

프로그램 메이커 기본 사용법

기본 사용법은 프로그램 초기화 (prog 객체 생성), 프로그램 추가, 프로그램 작성 완료를 하게 되면 JSON 타입의 프로그램을 기술하는 문자열이 출력됩니다. 이 JSON 문자열을 확장 IndyDCP 의 명령을 이용하여 로봇에게 전달하면 로봇은 전달된 프로그램을 실행합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
indy.connect()

indy.set_joint_vel_level(3)

prog = JsonProgramComponent(policy=0, resume_time=2)  # Init. prgoram

prog.add_move_home()
prog.add_move_zero()
prog.add_move_home()

prog_json = prog.program_done()  # Program end

indy.set_and_start_json_program(prog_json)  # Execute program

indy.disconnect()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
indy.connect()

prog = JsonProgramComponent(policy=0, resume_time=2)  # Init. prgoram

prog.add_endtool_do(type=0, value=0)
prog.add_wait(1)
prog.add_endtool_do(type=0, value=1)

prog_json = prog.program_done()   

indy.set_and_start_json_program(prog_json)  # Execute program

indy.disconnect()

로봇 위치 정보 획득 및 교시점 저장

프로그램 트리 상 교시점을 추가하기 위해서는 먼저 해당 교시점에서 로봇의 현재 관절 위치 또는 작업 위치를 획득해야합니다. 로봇을 교시점으로 이동시킨 뒤, 확장 IndyDCP 의 명령을 통해 로봇 위치를 얻고 이를 교시점 파일에 저장합니다.

1
indy.connect()
1
2
print(indy.get_joint_pos())  # Joint angle (degree)
print(indy.get_task_pos())  # Task-space pose (meter and degree)
1
2
3
file_name = 'test.json'
teach_config = indy.update_teaching_data(file_name, 'j_wp1', indy.get_joint_pos())
teach_config = indy.update_teaching_data(file_name, 't_wp1', indy.get_task_pos())
1
2
teach_config = indy.update_teaching_data(file_name, 'j_wp2', indy.get_joint_pos())
teach_config = indy.update_teaching_data(file_name, 't_wp2', indy.get_task_pos())
1
2
teach_config = indy.update_teaching_data(file_name, 'j_wp3', indy.get_joint_pos())
teach_config = indy.update_teaching_data(file_name, 't_wp3', indy.get_task_pos())
1
2
teach_config = indy.update_teaching_data(file_name, 'j_wp4', indy.get_joint_pos())
teach_config = indy.update_teaching_data(file_name, 't_wp4', indy.get_task_pos())
1
indy.disconnect()

로봇 모션 명령

교시한 경유점을 이용하여 프로그램 메이커를 통해 모션 프로그램을 작성할 수 있습니다. 모션 명령에서는 로봇의 속도 레벨과 블렌딩 옵션을 설정하며, 경유점 종류에 따라 조인트 무브와 태스크 무브를 선택할 수 있습니다.

1
2
file_name = 'test.json'
teach_config = indy.load_teaching_data(file_name)
  • Joint Move
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
indy.connect()

vel = 5    # Level 1-9
blend = 20 # Blendig radius 3-27 (degree)

j_wp1 = teach_config['j_wp1']
j_wp2 = teach_config['j_wp2']
j_wp3 = teach_config['j_wp3']
j_wp4 = teach_config['j_wp4']

prog = JsonProgramComponent(policy=0, resume_time=2)                
prog.add_joint_move_to(j_wp1, vel=vel, blend=blend)
prog.add_joint_move_to(j_wp2, vel=vel, blend=blend)
prog.add_joint_move_to(j_wp3, vel=vel, blend=blend)
prog.add_joint_move_to(j_wp4, vel=vel, blend=blend)

prog_json = prog.program_done()
indy.set_and_start_json_program(prog_json)

indy.disconnect()
  • Task Move
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
indy.connect()

vel = 5     # Level 1-9
blend = 0.2 # Blending radius 0.02-0.2 (meter)

t_wp1 = teach_config['t_wp1']
t_wp2 = teach_config['t_wp2']
t_wp3 = teach_config['t_wp3']
t_wp4 = teach_config['t_wp4']

prog = JsonProgramComponent(policy=0, resume_time=2)                
prog.add_task_move_to(t_wp1, vel=vel, blend=blend)
prog.add_task_move_to(t_wp2, vel=vel, blend=blend)
prog.add_task_move_to(t_wp3, vel=vel, blend=blend)
prog.add_task_move_to(t_wp4, vel=vel, blend=blend)

indy.set_and_start_json_program(prog.program_done())

indy.disconnect()

디지털 출력 및 툴 명령

IndyCB 의 디지털 출력 제어와 툴 명령은 아래 예제처럼 실행합니다. 단, 툴 명령은 사용자가 직접 Conty 를 통해 미리 툴 설정을 해두어야 사용 가능합니다.

 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
# Simple example
indy.connect()

vel = 5
j_blend = 20
t_blend = 0.2


prog = JsonProgramComponent(policy=0, resume_time=2)

prog.add_move_home()  
prog.add_joint_move_to(j_wp1, vel=vel) 

# Turns on digital output of port indices from 0 to 7 (0: OFF, 1: ON)
for idx in range(0, 8):
    prog.add_digital_out(idx=idx, val=1)

# Wait for set time
prog.add_wait(1)

# Tool command of tool ID and its command
# Tool should be first set up in Conty Application (Setting - Tool)
# In Conty, add tool and set application (e.g. Pick & Place)
# Edit Hold and Release output and update the tool (Refer the Indy manual)
prog.add_endtool_do(type=0, value=0)
prog.add_wait(1)
prog.add_endtool_do(type=0, value=1)

prog.add_task_move_to(t_wp2, vel=vel, blend=t_blend)
prog.add_task_move_to(t_wp3, vel=vel, blend=t_blend)
prog.add_task_move_to(t_wp4, vel=vel, blend=t_blend)

# Turns off digital output of port indices from 0 to 7 (0: OFF, 1: ON)
for idx in range(0, 8):
    prog.add_digital_out(idx=idx, val=0)

prog.add_stop()  # Stop program

indy.set_and_start_json_program(prog.program_done())

indy.disconnect()

동기/비동기 모션

아래 예제의 wait_for_program_finish() 명령어를 통해 프로그램 간의 동기/비동기 모션을 구성할 수 있습니다. JSON 문자열로 전달된 프로그램 구동이 완료되기 전까지 대기함으로써 명령어 위치에 따라 동기/비동기 모션을 수행합니다.

 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
# Async and sync example
indy.connect()

vel = 5
blend = 20

# Program loop 2 times
for i in range(0,2):
    # Syncronization with Second program after initail loop
    # Wait until Second program is finished
    indy.wait_for_program_finish()

    # First program
    prog = JsonProgramComponent(policy=0, resume_time=2)
    prog.add_joint_move_to(j_wp2, vel=vel, blend=blend)
    prog.add_move_home()

    indy.set_and_start_json_program(prog.program_done())    

    # Asyncronization with Second program
    # Wait until First program is finished, after then below program is executed
    indy.wait_for_program_finish()

    # Second program
    prog = JsonProgramComponent(policy=0, resume_time=2)                
    prog.add_task_move_to(t_wp3, vel=vel, blend=blend)
    prog.add_move_home()

    indy.set_and_start_json_program(prog.program_done())

indy.disconnect()

멀티 쓰레드

파이썬 프로그램은 기본적으로 하나의 쓰레드에서 실행됩니다. 그러므로 프로그램 메이커에서 병렬적으로 여러 프로그램을 실행하기 위해서는 파이썬 threading 모듈을 이용해야 합니다. 이 모듈을 통해 멀티 쓰레드를 구성하여 메인 쓰레드와 서브 쓰레드를 구분하고 각 프로그램을 동시에 실행할 수 있습니다. 쓰레드 구성 시에는 전역 변수를 활용하여 각 프로그램의 실행 여부를 결정하며, 프로그램 종료 시에는 stop_motion() 명령어를 통해 구동 중인 로봇을 정지시킨 다음 전역 변수를 통해 각 쓰레드를 종료합니다.

아래 예제에서는 모션 프로그램 구동 중 (메인 쓰레드) 현재 로봇의 위치 정보를 얻고 (서브 쓰레드 1), 다른 장치와의 인터페이스를 통해 디지털 입력 정보를 확인하는 작업 (서브 쓰레드 2) 작업을 수행합니다.

1
indy.connect()
 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
56
57
58
59
60
61
62
63
64
65
66
# Global variables
GLOBAL_INDICATOR = {'position': True, 'dio': True, 'program': True, 'terminated': False}


# Monitoring current robot position at every 1 sec 
def monitor_robot_position():
    global GLOBAL_INDICATOR
    while GLOBAL_INDICATOR['position']:
        if GLOBAL_INDICATOR['terminated']:
            break
        sleep(0.1)
        j_pos = indy.get_joint_pos()
        t_pos = indy.get_task_pos()
        print("Joint angles: ", j_pos)
        print("Task pose", t_pos)        

# Monitoring digital input at every 1 sec 
def monitor_dio():
    global GLOBAL_INDICATOR
    while GLOBAL_INDICATOR['dio']:
        if GLOBAL_INDICATOR['terminated']:
            break
        sleep(0.1)        
        dis = indy.get_di()

        btn1 = dis[1]
        btn2 = dis[3]
        btn3 = dis[5]
        print("Button 1/2/3 = [{}, {}, {}]".format(btn1, btn2, btn3))
        if btn1 == 1:
            # TODO: implement an action when button1 on
            pass
        if btn2 == 1:
            # TODO: implement an action when button2 on
            pass
        if btn3 == 1:
            # TODO: implement an action when button3 on
            pass

# Inifinity loop of robot program 
def run_program():
    global GLOBAL_INDICATOR
    while GLOBAL_INDICATOR['program']:        
        if GLOBAL_INDICATOR['terminated']:
            break

        prog = JsonProgramComponent(policy=0, resume_time=2)
        prog.add_move_home()
        prog.add_move_zero()

        indy.set_and_start_json_program(prog.program_done())
        indy.wait_for_program_finish() # Wait for finishing above json program

    GLOBAL_INDICATOR['position'] = False
    GLOBAL_INDICATOR['dio'] = False
    GLOBAL_INDICATOR['program'] = False


# Create each thread for 'run_program', 'monitor_robot_positio', and 'monitor_dio'
th1 = threading.Thread(target=run_program)
th2 = threading.Thread(target=monitor_robot_position)
th3 = threading.Thread(target=monitor_dio)

th3.start()
th2.start()
th1.start()
1
2
3
4
5
6
7
# Stop above program
indy.stop_motion()  # Stop current move

GLOBAL_INDICATOR['position'] = False
GLOBAL_INDICATOR['dio'] = False
GLOBAL_INDICATOR['program'] = False
GLOBAL_INDICATOR['terminated'] = True
1
indy.disconnect()