Skip to content

Program Maker

Program maker enables Conty program tree based on Python programming. Users implement more flexible and advanced robotic works using various logics, multi-threads, and async feature of this maker. In addition, it integrates with other commercial vision system as well as supported visions (IndyEye, Pickit).

To use program maker, users first create indy object same as previous section, and then imports JsonProgramComponent module because this maker send commands through IndyDCP. It is also recommended that the connect() and disconnect() functions should be executed as IndyDCP programs.

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"    # example STEP IP address
robot_name = "NRMK-Indy7"   # "NRMK-IndyRP2" for IndyRP2
indy = client.IndyDCPClient(robot_ip, robot_name)  # create indy object
1
2
indy.connect() # connect to robot
indy.disconnect() # disconnect with robot

Basic Tutorial

Program maker makes JSON string, describing a program, when users initialize the program (creating prog object), configure the program tree, and complete the program writing. Then, a robot runs the program after receiving the JSON string through extended IndyDCP command.

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

indy.set_joint_speed_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()

Save Teaching Points

To add teaching poitns in program tree, users should get current joint anlges or task space positions first. Thus, users acquire the robot postions with extended IndyDCP command, and save them as a json file.

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()

Robot Motion Command

Using the defined teaching points, users can make a motion program by configuring velocity level and blending radius of robot, and select joint or task move based on the type of each point.

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()

Digital Output and Tool Command

The example below is about controlling digital output signal of IndyCB and tool command. But, users should preset tool property with Conty for using tool command.

 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()

Sync/Async Motion

The wait_for_program_finish() command in the example below allows users to configure sync or async motion program. It waits until the program delivered as JSON string is completed, so users can regulate synchronization by adding the command between JSON programs.

 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()

Multi Thread

Python programs are executed on single thread by default. Therefore, users should use python threading module to run multiple programs concurrently. This module allows users to configure main thread with sub threads and communicate with each threads simultaneously. Also, users can determine whether to run each thread with global variables easily. To stop the program, users execute stop_motion() command, and then terminate each thread through global variables.

In the example below, while the motion program is running on main thread, other sub threads obtain the current robot position and check the digital input information through the interface with other devices.

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
# 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)        
        btn1 = indy.get_smart_di(1)
        btn2 = indy.get_smart_di(3)
        btn3 = indy.get_smart_di(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()