47 from robolink
import *
51 PROGRAM_PJX =
'''<?xml version="1.0" encoding="utf-8" ?> 52 <Project xmlns="http://www.staubli.com/robotics/VAL3/Project/3"> 53 <Parameters version="s7.3.1" stackSize="5000" millimeterUnit="true" /> 55 <Program file="start.pgx" /> 56 <Program file="stop.pgx" /> 59 <Data file="%s.dtx" /> 66 PROGRAM_PJX_MAIN =
'''<?xml version="1.0" encoding="utf-8" ?> 67 <Project xmlns="http://www.staubli.com/robotics/VAL3/Project/3"> 68 <Parameters version="s7.3.1" stackSize="5000" millimeterUnit="true" /> 70 <Program file="loadNextOne.pgx" /> 71 <Program file="start.pgx" /> 72 <Program file="stop.pgx" /> 75 <Data file="%s.dtx" /> 78 <Library alias="prog" path="./%s.pjx" /> 79 <Library alias="prog_swap" path="./%s.pjx" /> 80 <Library alias="tooldata" path="saveChangeTool" /> 84 DATA_DTX =
'''<?xml version="1.0" encoding="utf-8" ?> 85 <Database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Data/2"> 87 <Data name="%s" access="public" xsi:type="array" type="frame" size="%i"> 89 <Data name="jPark" access="public" xsi:type="array" type="jointRx" size="1"> 90 <Value key="0" j1="0.000" j2="0.000" j3="90.000" j4="0.000" j5="90.000" j6="0.000" /> 92 <Data name="%s" access="public" xsi:type="array" type="jointRx" size="%i"> 94 <Data name="mNomSpeed" access="public" xsi:type="array" type="mdesc" size="1"> 95 <Value key="0" accel="100" vel="100" decel="100" tmax="99999" rmax="99999" blend="off" leave="50" reach="50" /> 97 <Data name="%s" access="public" xsi:type="array" type="mdesc" size="%i"> 99 <Data name="nTraj" access="public" xsi:type="array" type="num" size="1"/> 100 <Data name="nTimeStop" access="private" xsi:type="array" type="num" size="1"/> 101 <Data name="nTimeStart" access="private" xsi:type="array" type="num" size="1"/> 102 <Data name="nMode" access="private" xsi:type="array" type="num" size="1"/> 103 <Data name="nEtat" access="private" xsi:type="array" type="num" size="1"/> 104 <Data name="%s" access="public" xsi:type="array" type="pointRx" size="%i"> 106 <Data name="%s" access="public" xsi:type="array" type="tool" size="%i"> 112 DATA_DTX_MAIN =
'''<?xml version="1.0" encoding="utf-8" ?> 113 <Database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Data/2"> 115 <Data name="dioIN" access="public" xsi:type="array" type="dio" size="1"> 116 <Value key="0" link="fIn0" /> 118 <Data name="dioOUT" access="public" xsi:type="array" type="dio" size="1"> 119 <Value key="0" link="fOut0" /> 121 <Data name="dioRotationON" access="public" xsi:type="array" type="dio" size="1"> 122 <Value key="0" link="BasicIO-1\\%%Q0" /> 124 <Data name="dioRotationOFF" access="public" xsi:type="array" type="dio" size="1"> 125 <Value key="0" link="BasicIO-1\\%%Q1" /> 127 <Data name="dioBuse" access="public" xsi:type="array" type="dio" size="1"> 128 <Value key="0" link="BasicIO-1\\%%Q2" /> 130 <Data name="fPartCad" access="public" xsi:type="array" type="frame" size="1"> 132 <Data name="fCadToReal" access="public" xsi:type="array" type="frame" size="1"> 133 <Value key="0" x="0" y="0" z="0" rx="0" ry="0" rz="0" fatherId="fPartCad[0]" /> 135 <Data name="mNomSpeed" access="public" xsi:type="array" type="mdesc" size="1"> 136 <Value key="0" accel="100" vel="100" decel="100" tmax="99999" rmax="99999" blend="off" leave="50" reach="50" /> 138 <Data name="nTraj" access="public" xsi:type="array" type="num" size="1"/> 139 <Data name="nTimeStop" access="private" xsi:type="array" type="num" size="1"/> 140 <Data name="nTimeStart" access="private" xsi:type="array" type="num" size="1"/> 141 <Data name="nMode" access="private" xsi:type="array" type="num" size="1"/> 142 <Data name="nEtat" access="private" xsi:type="array" type="num" size="1"/> 143 <Data name="tCad" access="public" xsi:type="array" type="tool" size="1"> 150 START_PGX =
'''<?xml version="1.0" encoding="utf-8" ?> 151 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2"> 152 <Program name="start" access="public"> 163 STOP_PGX =
'''<?xml version="1.0" encoding="utf-8" ?> 164 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2"> 165 <Program name="stop" access="private"> 176 LOAD_NEXT_ONE =
'''<?xml version="1.0" encoding="utf-8" ?> 177 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2"> 178 <Program name="loadNextOne" access="private"> 179 <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1"> 180 <Parameter name="x_sName" type="string" xsi:type="element" /> 184 prog_swap:libLoad(x_sName) 192 """Converts a pose to a Staubli target target""" 201 if c > (1.0 - 1e-10):
204 rz1 =
atan2(H[1,0],H[1,1])
205 elif c < (-1.0 + 1e-10):
208 rz1 =
atan2(H[1,0],H[1,1])
219 return [x, y, z, rx1*180.0/pi, ry1*180.0/pi, rz1*180.0/pi]
223 """Prints a pose target""" 225 return (
'x="%.3f" y="%.3f" z="%.3f" rx="%.3f" ry="%.3f" rz="%.3f"' % (x,y,z,r,p,w))
228 """Prints a joint target for Staubli VAL3 XML""" 230 for i
in range(len(angles)):
231 str = str + (
'j%i="%.5f" ' % ((i+1), angles[i]))
237 from tkinter
import filedialog
239 options[
'initialdir'] = strdir
240 options[
'title'] = strtitle
243 file_path = tkinter.filedialog.askdirectory(**options)
249 """Robot post object""" 254 PROG_NAME =
'unknown' 255 MAIN_FOLDER =
'ProgRoboDK' 258 PROG_MOVE_COUNT_MAX = 200
268 SPEED = DEFAULT_SPEED
271 SMOOTH = DEFAULT_SMOOTH
272 REF_NAME =
'fPartReal' 273 REF_CURRENT =
'world[0]' 277 TOOL_CURRENT =
'flange[0]' 280 SPEED_NAME =
'mSpeed' 281 SPEED_CURRENT =
'mNomSpeed' 284 JOINT_NAME =
'jJoint' 287 POINT_NAME =
'pPoint' 291 def __init__(self, robotpost=None, robotname=None, robot_axes = 6, **kwargs):
300 self.
addline(
'// Program %s start' % progname)
305 self.
addline(
'// Program %s end' % progname)
310 """Recursively delete a directory tree on a remote server.""" 313 names = ftp.nlst(path)
314 except ftplib.all_errors
as e:
316 print(
'RemoveDirFTP: Could not remove {0}: {1}'.format(path, e))
320 if os.path.split(name)[1]
in (
'.',
'..'):
continue 321 print(
'RemoveDirFTP: Checking {0}'.format(name))
326 except ftplib.all_errors:
331 except ftplib.all_errors
as e:
332 print(
'RemoveDirFTP: Could not remove {0}: {1}'.format(path, e))
340 robot = RDK.Item(self.
ROBOT_NAME, ITEM_TYPE_ROBOT)
341 [server_ip, port, remote_path, username, password] = robot.ConnectionParams()
343 server_ip =
'localhost' 344 username =
'username' 345 password =
'password' 346 remote_path =
'/usr/usrapp/session/default/saveTraj/CAD' 349 print(
"POPUP: Uploading program through FTP. Enter server parameters...")
353 values_ok =
mbox(
'Using the following FTP connection parameters to transfer the program:\nRobot IP: %s\nRemote path: %s\nFTP username: %s\nFTP password: ****\n\nContinue?' % (server_ip, remote_path, username))
355 print(
"Using default connection parameters")
357 server_ip =
mbox(
'Enter robot IP', entry=server_ip)
359 print(
'FTP upload cancelled by user')
361 remote_path =
mbox(
'Enter the remote path (program folder) on the Staubli robot controller', entry=remote_path)
364 if remote_path.endswith(
'/'):
365 remote_path = remote_path[:-1]
366 rob_user_pass =
mbox(
'Enter user name and password as\nuser-password', entry=(
'%s-%s' % (username, password)))
367 if not rob_user_pass:
369 name_value = rob_user_pass.split(
'-')
370 if len(name_value) < 2:
373 password = name_value[1]
374 username = name_value[0]
375 print(
"POPUP: <p>Connecting to <strong>%s</strong> using user name <strong>%s</strong> and password ****</p><p>Please wait...</p>" % (server_ip, username))
378 if robot
is not None:
379 robot.setConnectionParams(server_ip, port, remote_path, username, password)
382 myFTP = ftplib.FTP(server_ip, username, password)
385 error_str = sys.exc_info()[1]
386 print(
"POPUP: Connection to %s failed: <p>%s</p>" % (server_ip,error_str))
388 contin =
mbox(
"Connection to %s failed. Reason:\n%s\n\nRetry?" % (server_ip,error_str))
392 remote_path_prog = remote_path +
'/' + self.
MAIN_FOLDER 393 myPath =
r'%s' % localpath
394 print(
"POPUP: Connected. Deleting existing files on %s..." % remote_path_prog)
397 print(
"POPUP: Connected. Uploading program to %s..." % server_ip)
400 myFTP.cwd(remote_path)
402 myFTP.cwd(remote_path_prog)
405 error_str = sys.exc_info()[1]
406 print(
"POPUP: Remote path not found or can't be created: %s" % (remote_path))
408 contin =
mbox(
"Remote path\n%s\nnot found or can't create folder.\n\nChange path and permissions and retry." % remote_path)
411 def uploadThis(path):
412 files = os.listdir(path)
415 if os.path.isfile(path +
r'\{}'.format(f)):
416 print(
' Sending file: %s' % f)
417 print(
"POPUP: Sending file: %s" % f)
420 myFTP.storbinary(
'STOR %s' % f, fh)
422 elif os.path.isdir(path +
r'\{}'.format(f)):
423 print(
' Sending folder: %s' % f)
426 uploadThis(path +
r'\{}'.format(f))
431 def ProgSave(self, folder, progname, ask_user = False, show_result = False):
436 if foldersave
is not None and len(foldersave) > 0:
437 foldersave = foldersave
444 print(
"Saving %i programs..." % nprogs)
446 main_progname =
'Main' + progname
448 folderprog = foldersave +
'/' + main_progname
451 folderprog = foldersave +
'/' + progname
456 os.makedirs(folderprog)
461 for i
in range(nprogs):
462 call_sequence+=(
' if prog:libLoad("./%s")!=0\n' % self.
PROG_NAME_LIST[i])
463 call_sequence+=(
' logMsg("Error Loading RoboDK library")\n')
464 call_sequence+=(
' popUpMsg("Error Loading RoboDK library")\n')
465 call_sequence+=(
' endIf\n')
466 call_sequence+=(
' wait(taskStatus("loading")==-1)\n')
468 call_sequence+=(
' taskCreate "loading",10,loadNextOne("./%s")\n' % self.
PROG_NAME_LIST[i+1])
469 call_sequence+=(
' prog:fPartReal.trsf=fPartCad.trsf*fCadToReal.trsf\n')
470 call_sequence+=(
' prog:tCad.trsf=prog:tCad.trsf*{0,0,tooldata:nLength,0,0,0}\n')
471 call_sequence+=(
' call prog:start()\n')
472 call_sequence+=(
' \n')
476 start_file = folderprog +
'/start.pgx' 477 show_file_list.append(start_file)
478 fid = open(start_file,
"w")
479 fid.write(START_PGX % call_sequence)
483 project_file = folderprog +
'/%s.pjx' % main_progname
485 fid = open(project_file,
"w")
487 fid.write(PROGRAM_PJX_MAIN % (main_progname, dummy_folder, dummy_folder))
489 print(
'SAVED: %s\n' % project_file)
492 program_data = folderprog +
'/%s.dtx' % main_progname
493 show_file_list.append(project_file)
494 fid = open(program_data,
"w")
499 stop_file = folderprog +
'/stop.pgx' 500 fid = open(stop_file,
"w")
505 program_data = folderprog +
'/loadNextOne.pgx' 506 fid = open(program_data,
"w")
507 fid.write(LOAD_NEXT_ONE)
511 for i
in range(nprogs):
515 folderprog_final = folderprog
519 os.makedirs(folderprog_final)
523 start_file = folderprog_final +
'/start.pgx' 525 fid = open(start_file,
"w")
530 stop_file = folderprog_final +
'/stop.pgx' 531 fid = open(stop_file,
"w")
536 project_file = folderprog_final +
'/%s.pjx' % self.
PROG_NAME_LIST[i]
538 fid = open(project_file,
"w")
541 print(
'SAVED: %s\n' % project_file)
544 program_data = folderprog_final +
'/%s.dtx' % self.
PROG_NAME_LIST[i]
546 fid = open(program_data,
"w")
555 if type(show_result)
is str:
558 for file_i
in show_file_list:
559 p = subprocess.Popen([show_result, file_i])
562 elif type(show_result)
is list:
564 p = subprocess.Popen(show_result + [filesave])
568 os.startfile(start_file)
569 os.startfile(program_data)
570 if len(self.
LOG) > 0:
571 mbox(
'Program generation LOG:\n\n' + self.
LOG)
575 """Send a program to the robot using the provided parameters. This method is executed right after ProgSave if we selected the option "Send Program to Robot". 576 The connection parameters must be provided in the robot connection menu of RoboDK""" 579 def MoveJ(self, pose, joints, conf_RLF=None):
580 """Add a joint movement""" 591 def MoveL(self, pose, joints, conf_RLF=None):
592 """Add a linear movement""" 599 str_config =
'shoulder="lefty" elbow="epositive" wrist="wpositive"' 601 [rear, lowerarm, flip] = conf_RLF
602 str_config =
'shoulder="%s" elbow="%s" wrist="%s"' % (
"righty" if rear>0
else "lefty",
"enegative" if lowerarm>0
else "epositive",
"wnegative" if flip>0
else "wpositive")
608 def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None):
609 """Add a circular movement""" 612 if conf_RLF_1 ==
None:
613 str_config =
'shoulder="lefty" elbow="epositive" wrist="wpositive"' 615 [rear, lowerarm, flip] = conf_RLF_1
616 str_config =
'shoulder="%s" elbow="%s" wrist="%s"' % (
"righty" if rear>0
else "lefty",
"enegative" if lowerarm>0
else "epositive",
"wnegative" if flip>0
else "wpositive")
624 def setFrame(self, pose, frame_id=None, frame_name=None):
625 """Change the robot reference frame""" 627 self.
RunMessage(
'Warning: This post processor is meant to use one reference frame. Errors might follow.',
True)
628 self.log(
'This post processor is meant to use one reference frame. Errors might follow.')
637 def setTool(self, pose, tool_id=None, tool_name=None):
638 """Change the robot TCP""" 640 self.
RunMessage(
'Warning: Only one tool allowed per program. Tool change skipped.',
True)
641 self.log(
'Only one tool allowed per program')
652 """Pause the robot program""" 655 self.
addline(
'popUpMsg("Paused. Press OK to continue")')
657 self.
addline(
'delay(%.3f)' % (time_ms*0.001))
660 """Changes the robot speed (in mm/s)""" 670 """Changes the robot acceleration (in mm/s2)""" 674 """Changes the robot joint speed (in deg/s)""" 678 """Changes the robot joint acceleration (in deg/s2)""" 682 """Changes the zone data approach (makes the movement more smooth)""" 687 """Sets a variable (output) to a given value""" 688 if type(io_var) != str:
689 io_var =
'OUT[%s]' % str(io_var)
690 if type(io_value) != str:
697 self.
addline(
'%s=%s' % (io_var, io_value))
699 def waitDI(self, io_var, io_value, timeout_ms=-1):
700 """Waits for an input io_var to attain a given value io_value. Optionally, a timeout can be provided.""" 701 if type(io_var) != str:
702 io_var =
'IN[%s]' % str(io_var)
703 if type(io_value) != str:
711 self.
addline(
'WAIT FOR %s==%s' % (io_var, io_value))
713 self.
addline(
'WAIT FOR %s==%s TIMEOUT=%.1f' % (io_var, io_value, timeout_ms))
715 def RunCode(self, code, is_function_call = False):
716 """Adds code or a function call""" 719 code.replace(
' ',
'_')
720 if not code.endswith(
')'):
724 self.
addline(
'//call prog:%s' % code)
729 """Display a message in the robot controller screen (teach pendant)""" 734 self.
addline(
'popUpMsg("%s")' % message)
738 """Add a program line""" 742 """Add a log message""" 743 self.
LOG = self.
LOG + newline +
'\n' 757 progname = progname + (
'%i' % (nprogs+1))
760 self.
PROG_DTX_LIST.append(DATA_DTX % (self.
REF_NAME, self.
REF_COUNT, self.
REF_DATA, self.
JOINT_NAME, self.
JOINT_COUNT, self.
JOINT_DATA, self.
SPEED_NAME, self.
SPEED_COUNT, self.
SPEED_DATA, self.
POINT_NAME, self.
POINT_COUNT, self.
POINT_DATA, self.
TOOL_NAME, self.
TOOL_COUNT, self.
TOOL_DATA))
789 [x,y,z,r,p,w] = xyzrpw
799 return Mat([[cb*ca, ca*sc*sb - cc*sa, sc*sa + cc*ca*sb, x],[cb*sa, cc*ca + sc*sb*sa, cc*sb*sa - ca*sc, y],[-sb, cb*sc, cc*cb, z],[0,0,0,1]])
802 """Test the post with a basic program""" 806 robot.ProgStart(
"Program")
807 robot.RunMessage(
"Program generated by RoboDK using a custom post processor",
True)
808 robot.setFrame(
Pose([807.766544, -963.699898, 41.478944, 0, 0, 0]))
809 robot.setTool(
Pose([62.5, -108.253175, 100, -60, 90, 0]))
810 robot.MoveJ(
Pose([200, 200, 500, 180, 0, 180]), [-46.18419, -6.77518, -20.54925, 71.38674, 49.58727, -302.54752] )
811 robot.MoveL(
Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
812 robot.MoveL(
Pose([200, 200, 262.132034, 180, 0, -150]), [-43.73892, -3.91728, -35.77935, 58.57566, 54.11615, -253.81122] )
813 robot.RunMessage(
"Setting air valve 1 on")
814 robot.RunCode(
"TCP_On",
True)
816 robot.MoveL(
Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
817 robot.MoveL(
Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
818 robot.MoveL(
Pose([250, 250, 191.421356, 180, 0, -150]), [-39.75778, -1.04537, -40.37883, 52.09118, 54.15317, -246.94403] )
819 robot.RunMessage(
"Setting air valve off")
820 robot.RunCode(
"TCP_Off",
True)
822 robot.MoveL(
Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
823 robot.MoveL(
Pose([250, 200, 278.023897, 180, 0, -150]), [-41.85389, -1.95619, -34.89154, 57.43912, 52.34162, -253.73403] )
824 robot.MoveL(
Pose([250, 150, 191.421356, 180, 0, -150]), [-43.82111, 3.29703, -40.29493, 56.02402, 56.61169, -249.23532] )
825 robot.ProgFinish(
"Program")
827 print(robot.PROG_PGX)
828 if len(robot.LOG) > 0:
829 mbox(
'Program generation LOG:\n\n' + robot.LOG)
831 input(
"Press Enter to close...")
833 if __name__ ==
"__main__":
834 """Function to call when the module is executed by itself: test"""
def setTool(self, pose, tool_id=None, tool_name=None)
def RunCode(self, code, is_function_call=False)
def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None)
def MoveJ(self, pose, joints, conf_RLF=None)
def setSpeed(self, speed_mms)
def ProgSave(self, folder, progname, ask_user=False, show_result=False)
def setZoneData(self, zone_mm)
def __init__(self, robotpost=None, robotname=None, robot_axes=6, kwargs)
def MoveL(self, pose, joints, conf_RLF=None)
def ProgStart(self, progname)
def control_ProgSize(self)
def setAccelerationJoints(self, accel_degss)
def RemoveDirFTP(self, ftp, path)
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=None)
def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass)
def UploadFTP(self, localpath)
def ProgFinish(self, progname)
def setSpeedJoints(self, speed_degs)
def addlog(self, newline)
def waitDI(self, io_var, io_value, timeout_ms=-1)
def getSaveFolder(strdir='C:\\', strtitle='Save program folder ...')
def setAcceleration(self, accel_mmss)
def setFrame(self, pose, frame_id=None, frame_name=None)
def RunMessage(self, message, iscomment=False)
def setDO(self, io_var, io_value)
def addline(self, newline)