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.
| 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
|
| 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.
| print(indy.get_joint_pos()) # Joint angle (degree)
print(indy.get_task_pos()) # Task-space pose (meter and degree)
|
| 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())
|
| 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())
|
| 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())
|
| 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())
|
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.
| file_name = 'test.json'
teach_config = indy.load_teaching_data(file_name)
|
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()
|
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()
|
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
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()
|
| # 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
|