Staubli_VAL3_InlineMove.py
Go to the documentation of this file.
1 # Copyright 2017 - RoboDK Software S.L. - http://www.robodk.com/
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
6 # Unless required by applicable law or agreed to in writing, software
7 # distributed under the License is distributed on an "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 # See the License for the specific language governing permissions and
10 # limitations under the License.
11 
12 # ----------------------------------------------------
13 # This file is a POST PROCESSOR for Robot Offline Programming to generate programs
14 # for a Staubli (VAL3) robot with RoboDK
15 #
16 # To edit/test this POST PROCESSOR script file:
17 # Select "Program"->"Add/Edit Post Processor", then select your post or create a new one.
18 # You can edit this file using any text editor or Python editor. Using a Python editor allows to quickly evaluate a sample program at the end of this file.
19 # Python should be automatically installed with RoboDK
20 #
21 # You can also edit the POST PROCESSOR manually:
22 # 1- Open the *.py file with Python IDLE (right click -> Edit with IDLE)
23 # 2- Make the necessary changes
24 # 3- Run the file to open Python Shell: Run -> Run module (F5 by default)
25 # 4- The "test_post()" function is called automatically
26 # Alternatively, you can edit this file using a text editor and run it with Python
27 #
28 # To use a POST PROCESSOR file you must place the *.py file in "C:/RoboDK/Posts/"
29 # To select one POST PROCESSOR for your robot in RoboDK you must follow these steps:
30 # 1- Open the robot panel (double click a robot)
31 # 2- Select "Parameters"
32 # 3- Select "Unlock advanced options"
33 # 4- Select your post as the file name in the "Robot brand" box
34 #
35 # To delete an existing POST PROCESSOR script, simply delete this file (.py file)
36 #
37 # ----------------------------------------------------
38 # More information about RoboDK Post Processors and Offline Programming here:
39 # http://www.robodk.com/help#PostProcessor
40 # http://www.robodk.com/doc/en/PythonAPI/postprocessor.html
41 # ----------------------------------------------------
42 
43 
44 # ----------------------------------------------------
45 # Import RoboDK tools
46 from robodk import *
47 from robolink import *
48 
49 
50 # Program.pjx file (references data file as %s.dtx)
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.5.3" stackSize="5000" millimeterUnit="true" />
54 <Programs>
55 <Program file="MoveJoint.pgx" />
56 <Program file="MoveLine.pgx" />
57 <Program file="start.pgx" />
58 <Program file="stop.pgx" />
59 <Program file="main.pgx" />
60 </Programs>
61 <Database>
62 <Data file="%s.dtx" />
63 </Database>
64 <Libraries />
65 </Project>
66 '''
67 
68 PROGRAM_DTX = '''<?xml version="1.0" encoding="utf-8"?>
69 <Database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Data/2">
70  <Datas>
71  <Data name="mNomSpeed" access="private" xsi:type="array" type="mdesc" size="1" />
72  <Data name="fFrame1" access="private" xsi:type="array" type="frame" size="1">
73  <Value key="0" %s fatherId="world[0]" />
74  </Data>
75  <Data name="Input" access="private" xsi:type="array" type="dio" size="16">
76  <Value key="0" link="BasicIO-2\\%%I0" />
77  <Value key="1" link="BasicIO-2\\%%I1" />
78  <Value key="2" link="BasicIO-2\\%%I2" />
79  <Value key="3" link="BasicIO-2\\%%I3" />
80  <Value key="4" link="BasicIO-2\\%%I4" />
81  <Value key="5" link="BasicIO-2\\%%I5" />
82  <Value key="6" link="BasicIO-2\\%%I6" />
83  <Value key="7" link="BasicIO-2\\%%I7" />
84  <Value key="8" link="BasicIO-2\\%%I8" />
85  <Value key="9" link="BasicIO-2\\%%I9" />
86  <Value key="10" link="BasicIO-2\\%%I10" />
87  <Value key="11" link="BasicIO-2\\%%I11" />
88  <Value key="12" link="BasicIO-2\\%%I12" />
89  <Value key="13" link="BasicIO-2\\%%I13" />
90  <Value key="14" link="BasicIO-2\\%%I14" />
91  <Value key="15" link="BasicIO-2\\%%I15" />
92  </Data>
93  <Data name="Output" access="private" xsi:type="array" type="dio" size="16">
94  <Value key="0" link="BasicIO-2\\%%Q0" />
95  <Value key="1" link="BasicIO-2\\%%Q1" />
96  <Value key="2" link="BasicIO-2\\%%Q2" />
97  <Value key="3" link="BasicIO-2\\%%Q3" />
98  <Value key="4" link="BasicIO-2\\%%Q4" />
99  <Value key="5" link="BasicIO-2\\%%Q5" />
100  <Value key="6" link="BasicIO-2\\%%Q6" />
101  <Value key="7" link="BasicIO-2\\%%Q7" />
102  <Value key="8" link="BasicIO-2\\%%Q8" />
103  <Value key="9" link="BasicIO-2\\%%Q9" />
104  <Value key="10" link="BasicIO-2\\%%Q10" />
105  <Value key="11" link="BasicIO-2\\%%Q11" />
106  <Value key="12" link="BasicIO-2\\%%Q12" />
107  <Value key="13" link="BasicIO-2\\%%Q13" />
108  <Value key="14" link="BasicIO-2\\%%Q14" />
109  <Value key="15" link="BasicIO-2\\%%Q15" />
110  </Data>
111  <Data name="tCurrentTool" access="private" xsi:type="array" type="tool" size="1">
112  <Value key="0" %s fatherId="flange[0]" ioLink="valve1" />
113  </Data>
114  <Data name="mCurrentSpeed" access="private" xsi:type="array" type="mdesc" size="1" />
115  <Data name="pPointRx" access="private" xsi:type="array" type="pointRx" size="1">
116  <Value key="0" fatherId="fFrame1[0]" />
117  </Data>
118  </Datas>
119 </Database>
120 '''
121 
122 MOVELINE_PGX = '''<?xml version="1.0" encoding="utf-8"?>
123 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
124  <Program name="MoveLine">
125  <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
126  <Parameter name="x_nX" type="num" xsi:type="element" />
127  <Parameter name="x_nY" type="num" xsi:type="element" />
128  <Parameter name="x_nZ" type="num" xsi:type="element" />
129  <Parameter name="x_nRx" type="num" xsi:type="element" />
130  <Parameter name="x_nRy" type="num" xsi:type="element" />
131  <Parameter name="x_nRz" type="num" xsi:type="element" />
132  </Parameters>
133  <Code><![CDATA[begin
134  pPointRx.trsf.x = x_nX
135  pPointRx.trsf.y = x_nY
136  pPointRx.trsf.z = x_nZ
137  pPointRx.trsf.rx = x_nRx
138  pPointRx.trsf.ry = x_nRy
139  pPointRx.trsf.rz = x_nRz
140  movel(pPointRx,tCurrentTool,mCurrentSpeed)
141 end]]></Code>
142  </Program>
143 </Programs>
144 '''
145 
146 MOVEJOINT_PGX = '''<?xml version="1.0" encoding="utf-8"?>
147 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
148  <Program name="MoveJoint">
149  <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
150  <Parameter name="x_nJ1" type="num" xsi:type="element" />
151  <Parameter name="x_nJ2" type="num" xsi:type="element" />
152  <Parameter name="x_nJ3" type="num" xsi:type="element" />
153  <Parameter name="x_nJ4" type="num" xsi:type="element" />
154  <Parameter name="x_nJ5" type="num" xsi:type="element" />
155  <Parameter name="x_nJ6" type="num" xsi:type="element" />
156  </Parameters>
157  <Locals>
158  <Local name="l_jJoint" type="joint" xsi:type="array" size="1" />
159  </Locals>
160  <Code><![CDATA[begin
161  l_jJoint.j1 = x_nJ1
162  l_jJoint.j2 = x_nJ2
163  l_jJoint.j3 = x_nJ3
164  l_jJoint.j4 = x_nJ4
165  l_jJoint.j5 = x_nJ5
166  l_jJoint.j6 = x_nJ6
167  movej(l_jJoint,tCurrentTool ,mCurrentSpeed)
168 end]]></Code>
169  </Program>
170 </Programs>
171 '''
172 
173 MAIN_PGX = '''<?xml version="1.0" encoding="utf-8"?>
174 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
175  <Program name="main">
176  <Code><![CDATA[begin
177  close(tCurrentTool)
178  pPointRx.config.shoulder = lefty
179  pPointRx.config.elbow = epositive
180  pPointRx.config.wrist = wpositive
181  mCurrentSpeed.tvel = 100.00
182  mCurrentSpeed.blend = joint
183  mCurrentSpeed.reach = 0.010
184  mCurrentSpeed.leave = 0.010
185 %s
186 end]]></Code>
187  </Program>
188 </Programs>'''
189 
190 
191 # start.pjx file (references data file as %s.dtx)
192 START_PGX = '''<?xml version="1.0" encoding="utf-8"?>
193 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
194  <Program name="start">
195  <Code><![CDATA[begin
196  call main()
197 end]]></Code>
198  </Program>
199 </Programs>
200 '''
201 
202 STOP_PGX = '''<?xml version="1.0" encoding="utf-8"?>
203 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
204  <Program name="stop">
205  <Code><![CDATA[begin
206 end]]></Code>
207  </Program>
208 </Programs>
209 '''
210 
211 # Required if the program must be split:
212 
213 LOAD_NEXT_ONE = '''<?xml version="1.0" encoding="utf-8" ?>
214 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
215  <Program name="loadNextOne" access="private">
216  <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
217  <Parameter name="x_sName" type="string" xsi:type="element" />
218  </Parameters>
219  <Code><![CDATA[
220 begin
221  prog_swap:libLoad(x_sName)
222 end
223  ]]></Code>
224  </Program>
225 </Programs>'''
226 
227 START_PGX_MAIN = '''<?xml version="1.0" encoding="utf-8" ?>
228 <Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
229  <Program name="start" access="public">
230  <Code><![CDATA[
231 begin
232 %s
233 end
234  ]]></Code>
235  </Program>
236 </Programs>
237 '''
238 
239 PROGRAM_PJX_MAIN = '''<?xml version="1.0" encoding="utf-8" ?>
240 <Project xmlns="http://www.staubli.com/robotics/VAL3/Project/3">
241  <Parameters version="s7.3.1" stackSize="5000" millimeterUnit="true" />
242  <Programs>
243  <Program file="loadNextOne.pgx" />
244  <Program file="start.pgx" />
245  <Program file="stop.pgx" />
246  </Programs>
247  <Database>
248  <Data file="%s.dtx" />
249  </Database>
250  <Libraries>
251  <Library alias="prog" path="./%s.pjx" />
252  <Library alias="prog_swap" path="./%s.pjx" />
253  <Library alias="tooldata" path="saveChangeTool" />
254  </Libraries>
255 </Project>'''
256 
257 
259  """Converts a pose to a Staubli target target"""
260  x = H[0,3]
261  y = H[1,3]
262  z = H[2,3]
263  a = H[0,0]
264  b = H[0,1]
265  c = H[0,2]
266  d = H[1,2]
267  e = H[2,2]
268  if c > (1.0 - 1e-10):
269  ry1 = pi/2
270  rx1 = 0
271  rz1 = atan2(H[1,0],H[1,1])
272  elif c < (-1.0 + 1e-10):
273  ry1 = -pi/2
274  rx1 = 0
275  rz1 = atan2(H[1,0],H[1,1])
276  else:
277  sy = c
278  cy1 = +sqrt(1-sy*sy)
279  sx1 = -d/cy1
280  cx1 = e/cy1
281  sz1 = -b/cy1
282  cz1 = a/cy1
283  rx1 = atan2(sx1,cx1)
284  ry1 = atan2(sy,cy1)
285  rz1 = atan2(sz1,cz1)
286  return [x, y, z, rx1*180.0/pi, ry1*180.0/pi, rz1*180.0/pi]
287 
288 # ----------------------------------------------------
289 def pose_2_str(pose):
290  """Prints a pose target"""
291  [x,y,z,r,p,w] = Pose_2_Staubli_v2(pose)
292  return ('%.3f,%.3f,%.3f,%.3f,%.3f,%.3f' % (x,y,z,r,p,w))
293 
294 def angles_2_str(angles):
295  """Prints a joint target for Staubli VAL3 XML"""
296  str = ''
297  for i in range(len(angles)):
298  str = str + ('%.5f,' % (angles[i]))
299  str = str[:-1]
300  return str
301 
302 def pose_2_str_dtx(pose):
303  """Prints a pose target"""
304  [x,y,z,r,p,w] = Pose_2_Staubli_v2(pose)
305  return ('x="%.3f" y="%.3f" z="%.3f" rx="%.3f" ry="%.3f" rz="%.3f"' % (x,y,z,r,p,w))
306 
307 def getSaveFolder(strdir='C:\\', strtitle='Save program folder ...'):
308  import tkinter
309  from tkinter import filedialog
310  options = {}
311  options['initialdir'] = strdir
312  options['title'] = strtitle
313  root = tkinter.Tk()
314  root.withdraw()
315  file_path = tkinter.filedialog.askdirectory(**options)
316  return file_path
317 
318 # ----------------------------------------------------
319 # Object class that handles the robot instructions/syntax
320 class RobotPost(object):
321  """Robot post object"""
322  # other variables
323  ROBOT_POST = ''
324  ROBOT_NAME = ''
325  PROG_FILES = []
326  PROG_NAME = 'unknown'
327  MAIN_FOLDER = 'ProgRoboDK'
328  PROG_PGX = ''
329  PROG_MOVE_COUNT = 0
330  PROG_MOVE_COUNT_MAX = 200
331  LOG = ''
332  REF = eye(4)
333  TOOL = eye(4)
334  REF_COUNT = 0
335  TOOL_COUNT = 0
336  nAxes = 6
337  TAB_PGX = ' '
338  PROG_PGX_LIST = []
339  PROG_NAME_LIST = []
340  SPEED = -1
341  # Warning: if defaults are changed they must also be changed in main.pgx
342  CONF_shoulder = 0 # 0=lefty ; 1=righty
343  CONF_lowerarm = 0 # 0=epositive ; 1=enegative
344  CONF_flip = 0 # 0=wpositive ; 1=wnegative
345 
346  def __init__(self, robotpost=None, robotname=None, robot_axes = 6, **kwargs):
347  self.ROBOT_POST = robotpost
348  self.ROBOT_NAME = robotname
349  self.PROG = ''
350  self.LOG = ''
351  self.nAxes = robot_axes
352 
353  def ProgStart(self, progname):
354  self.PROG_NAME = progname
355  self.addline('// Program %s start' % progname)
356 
357  def ProgFinish(self, progname):
358  self.addline('')
359  self.addline('waitEndMove()')
360  self.addline('// Program %s end' % progname)
361 
362  def RemoveDirFTP(self, ftp, path):
363  import ftplib
364  """Recursively delete a directory tree on a remote server."""
365  wd = ftp.pwd()
366  try:
367  names = ftp.nlst(path)
368  except ftplib.all_errors as e:
369  # some FTP servers complain when you try and list non-existent paths
370  print('RemoveDirFTP: Could not remove {0}: {1}'.format(path, e))
371  return
372 
373  for name in names:
374  if os.path.split(name)[1] in ('.', '..'): continue
375  print('RemoveDirFTP: Checking {0}'.format(name))
376  try:
377  ftp.cwd(name) # if we can cwd to it, it's a folder
378  ftp.cwd(wd) # don't try a nuke a folder we're in
379  self.RemoveDirFTP(ftp, name)
380  except ftplib.all_errors:
381  ftp.delete(name)
382 
383  try:
384  ftp.rmd(path)
385  except ftplib.all_errors as e:
386  print('RemoveDirFTP: Could not remove {0}: {1}'.format(path, e))
387 
388  def UploadFTP(self, localpath):
389  import ftplib
390  import os
391  robot = None
392  try:
393  RDK = Robolink()
394  robot = RDK.Item(self.ROBOT_NAME, ITEM_TYPE_ROBOT)
395  [server_ip, port, remote_path, username, password] = robot.ConnectionParams()
396  except:
397  server_ip = 'localhost' # enter URL address of the robot it may look like: '192.168.1.123'
398  username = 'username' # enter FTP user name
399  password = 'password' # enter FTP password
400  remote_path = '/usr/usrapp/session/default/saveTraj/CAD' # enter the remote path
401  import sys
402  while True:
403  print("POPUP: Uploading program through FTP. Enter server parameters...")
404  sys.stdout.flush()
405 
406  # check if connection parameters are OK
407  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))
408  if values_ok:
409  print("Using default connection parameters")
410  else:
411  server_ip = mbox('Enter robot IP', entry=server_ip)
412  if not server_ip:
413  print('FTP upload cancelled by user')
414  return
415  remote_path = mbox('Enter the remote path (program folder) on the Staubli robot controller', entry=remote_path)
416  if not remote_path:
417  return
418  if remote_path.endswith('/'):
419  remote_path = remote_path[:-1]
420  rob_user_pass = mbox('Enter user name and password as\nuser-password', entry=('%s-%s' % (username, password)))
421  if not rob_user_pass:
422  return
423  name_value = rob_user_pass.split('-')
424  if len(name_value) < 2:
425  password = ''
426  else:
427  password = name_value[1]
428  username = name_value[0]
429  print("POPUP: <p>Connecting to <strong>%s</strong> using user name <strong>%s</strong> and password ****</p><p>Please wait...</p>" % (server_ip, username))
430  #print("POPUP: Trying to connect. Please wait...")
431  sys.stdout.flush()
432  if robot is not None:
433  robot.setConnectionParams(server_ip, port, remote_path, username, password)
434  pause(2)
435  try:
436  myFTP = ftplib.FTP(server_ip, username, password)
437  break;
438  except:
439  error_str = sys.exc_info()[1]
440  print("POPUP: Connection to %s failed: <p>%s</p>" % (server_ip,error_str))
441  sys.stdout.flush()
442  contin = mbox("Connection to %s failed. Reason:\n%s\n\nRetry?" % (server_ip,error_str))
443  if not contin:
444  return
445 
446  remote_path_prog = remote_path + '/' + self.MAIN_FOLDER
447  myPath = r'%s' % localpath
448  print("POPUP: Connected. Deleting existing files on %s..." % remote_path_prog)
449  sys.stdout.flush()
450  self.RemoveDirFTP(myFTP, remote_path_prog)
451  print("POPUP: Connected. Uploading program to %s..." % server_ip)
452  sys.stdout.flush()
453  try:
454  myFTP.cwd(remote_path)
455  myFTP.mkd(self.MAIN_FOLDER)
456  myFTP.cwd(remote_path_prog)
457  #print('asdf')
458  except:
459  error_str = sys.exc_info()[1]
460  print("POPUP: Remote path not found or can't be created: %s" % (remote_path))
461  sys.stdout.flush()
462  contin = mbox("Remote path\n%s\nnot found or can't create folder.\n\nChange path and permissions and retry." % remote_path)
463  return
464 
465  def uploadThis(path):
466  files = os.listdir(path)
467  os.chdir(path)
468  for f in files:
469  if os.path.isfile(path + r'\{}'.format(f)):
470  print(' Sending file: %s' % f)
471  print("POPUP: Sending file: %s" % f)
472  sys.stdout.flush()
473  fh = open(f, 'rb')
474  myFTP.storbinary('STOR %s' % f, fh)
475  fh.close()
476  elif os.path.isdir(path + r'\{}'.format(f)):
477  print(' Sending folder: %s' % f)
478  myFTP.mkd(f)
479  myFTP.cwd(f)
480  uploadThis(path + r'\{}'.format(f))
481  myFTP.cwd('..')
482  os.chdir('..')
483  uploadThis(myPath) # now call the recursive function
484 
485  def ProgSave(self, folder, progname, ask_user = False, show_result = False):
486  self.close_module()
487 
488  if ask_user or not DirExists(folder):
489  foldersave = getSaveFolder(folder, 'Save program as...')
490  if foldersave is not None and len(foldersave) > 0:
491  foldersave = foldersave
492  else:
493  return
494  else:
495  foldersave = folder
496 
497  nprogs = len(self.PROG_NAME_LIST)
498  print("Saving %i programs..." % nprogs)
499 
500  main_progname = 'Main' + progname
501  if nprogs > 1: # always create a main program
502  folderprog = foldersave + '/' + main_progname
503  self.MAIN_FOLDER = main_progname
504  else:
505  folderprog = foldersave + '/' + progname
506  self.MAIN_FOLDER = progname
507 
508  if not DirExists(folderprog):
509  import os
510  os.makedirs(folderprog)
511 
512  show_file_list = []
513  if nprogs > 1:
514  call_sequence = ''
515  for i in range(nprogs):
516  call_sequence+=(' if prog:libLoad("./%s")!=0\n' % self.PROG_NAME_LIST[i])
517  call_sequence+=(' logMsg("Error Loading RoboDK library")\n')
518  call_sequence+=(' popUpMsg("Error Loading RoboDK library")\n')
519  call_sequence+=(' endIf\n')
520  call_sequence+=(' wait(taskStatus("loading")==-1)\n')
521  if i < nprogs-1:
522  call_sequence+=(' taskCreate "loading",10,loadNextOne("./%s")\n' % self.PROG_NAME_LIST[i+1])
523  #call_sequence+=(' prog:fPartReal.trsf=fPartCad.trsf*fCadToReal.trsf\n')
524  #call_sequence+=(' prog:tCad.trsf=prog:tCad.trsf*{0,0,tooldata:nLength,0,0,0}\n')
525  call_sequence+=(' call prog:start()\n')
526  call_sequence+=(' \n')
527 
528  #-----------------------------------
529  # start.pgx
530  start_file = folderprog + '/start.pgx'
531  show_file_list.append(start_file)
532  fid = open(start_file, "w")
533  fid.write(START_PGX_MAIN % call_sequence)
534  fid.close()
535  #-----------------------------------
536  # mainprog.pjx
537  project_file = folderprog + '/%s.pjx' % main_progname
538  #show_file_list.append(project_file)
539  fid = open(project_file, "w")
540  dummy_folder = self.PROG_NAME_LIST[0] + '/' + self.PROG_NAME_LIST[0]
541  fid.write(PROGRAM_PJX_MAIN % (main_progname, dummy_folder, dummy_folder))
542  fid.close()
543  print('SAVED: %s\n' % project_file)
544  #-----------------------------------
545  # mainprog.dtx
546  program_data = folderprog + '/%s.dtx' % main_progname
547  show_file_list.append(project_file)
548  fid = open(program_data, "w")
549  fid.write(PROGRAM_DTX % (pose_2_str_dtx(self.REF), pose_2_str_dtx(self.TOOL)))
550  fid.close()
551  #-----------------------------------
552  # stop.pgx
553  stop_file = folderprog + '/stop.pgx'
554  fid = open(stop_file, "w")
555  fid.write(STOP_PGX)
556  fid.close()
557  #-----------------------------------
558  # loadNextOne.pgx
559  program_data = folderprog + '/loadNextOne.pgx'
560  fid = open(program_data, "w")
561  fid.write(LOAD_NEXT_ONE)
562  fid.close()
563  #-----------------------------------
564 
565  for i in range(nprogs):
566  if nprogs > 1: # Always create a main program loading sub programs
567  folderprog_final = folderprog + '/' + self.PROG_NAME_LIST[i]
568  else:
569  folderprog_final = folderprog
570 
571  if not DirExists(folderprog_final):
572  import os
573  os.makedirs(folderprog_final)
574 
575  #-----------------------------------
576  # start.pgx
577  start_file = folderprog_final + '/start.pgx'
578  #show_file_list.append(start_file)
579  fid = open(start_file, "w")
580  fid.write(START_PGX)
581  fid.close()
582  #-----------------------------------
583  # stop.pgx
584  stop_file = folderprog_final + '/stop.pgx'
585  fid = open(stop_file, "w")
586  fid.write(STOP_PGX)
587  fid.close()
588  #-----------------------------------
589  # MoveJoint.pgx
590  movej_file = folderprog_final + '/MoveJoint.pgx'
591  #show_file_list.append(start_file)
592  fid = open(movej_file, "w")
593  fid.write(MOVEJOINT_PGX)
594  fid.close()
595  #-----------------------------------
596  # MoveLine.pgx
597  movel_file = folderprog_final + '/MoveLine.pgx'
598  fid = open(movel_file, "w")
599  fid.write(MOVELINE_PGX)
600  fid.close()
601  #-----------------------------------
602  # program.PJX
603  project_file = folderprog_final + '/%s.pjx' % self.PROG_NAME
604  #show_file_list.append(project_file)
605  fid = open(project_file, "w")
606  fid.write(PROGRAM_PJX % self.PROG_NAME)
607  fid.close()
608  print('SAVED: %s\n' % project_file)
609  #-----------------------------------
610  # program.dtx
611  program_data = folderprog_final + '/%s.dtx' % self.PROG_NAME
612  show_file_list.append(program_data)
613  fid = open(program_data, "w")
614  fid.write(PROGRAM_DTX % (pose_2_str_dtx(self.REF), pose_2_str_dtx(self.TOOL)))
615  fid.close()
616  #-----------------------------------
617  # main.pgx
618  main_data = folderprog_final + '/main.pgx'
619  show_file_list.append(main_data)
620  fid = open(main_data, "w")
621  fid.write(MAIN_PGX % (self.PROG_PGX_LIST[i]))
622  fid.close()
623  #-----------------------------------
624 
625  #self.UploadFTP(folderprog)
626  self.PROG_FILES = folderprog
627 
628  if show_result:
629  if type(show_result) is str:
630  # Open file with provided application
631  import subprocess
632  for file_i in show_file_list:
633  p = subprocess.Popen([show_result, file_i])
634  #p = subprocess.Popen([show_result, start_file])
635  #p = subprocess.Popen([show_result, program_data])
636  elif type(show_result) is list:
637  import subprocess
638  p = subprocess.Popen(show_result + [filesave])
639  else:
640  # open file with default application
641  import os
642  os.startfile(start_file)
643  os.startfile(program_data)
644  if len(self.LOG) > 0:
645  mbox('Program generation LOG:\n\n' + self.LOG)
646  # attempt FTP upload
647 
648  def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass):
649  """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".
650  The connection parameters must be provided in the robot connection menu of RoboDK"""
651  UploadFTP(self.PROG_FILES, robot_ip, remote_path, ftp_user, ftp_pass)
652 
653  def MoveJ(self, pose, joints, conf_RLF=None):
654  """Add a joint movement"""
655  self.control_ProgSize()
656  self.addline('call MoveJoint(%s)' % angles_2_str(joints))
657 
658  def MoveL(self, pose, joints, conf_RLF=None):
659  """Add a linear movement"""
660  if pose is None:
661  raise Exception("Linear move must be a Cartesian target for VAL3")
662  self.control_ProgSize()
663 
664  if conf_RLF == None:
665  rear = self.CONF_shoulder
666  lowerarm = self.CONF_lowerarm
667  flip = self.CONF_flip
668  else:
669  [rear, lowerarm, flip] = conf_RLF
670 
671  if rear != self.CONF_shoulder:
672  self.addline('pPointRx.config.shoulder = %s' % ("righty" if rear>0 else "lefty"))
673  self.CONF_shoulder = rear
674  if lowerarm != self.CONF_lowerarm:
675  self.addline('pPointRx.config.elbow = %s' % ("enegative" if lowerarm>0 else "epositive"))
676  self.CONF_lowerarm = lowerarm
677  if flip != self.CONF_flip:
678  self.addline('pPointRx.config.wrist = %s' % ("wnegative" if flip>0 else "wpositive"))
679  self.CONF_flip = flip
680 
681  self.addline('call MoveLine(%s)' % pose_2_str(pose))
682 
683  def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None):
684  """Add a circular movement"""
685  self.control_ProgSize()
686  raise Exception("Circular moves not supported for this post processor")
687 
688  def setFrame(self, pose, frame_id=None, frame_name=None):
689  """Change the robot reference frame"""
690  if self.REF_COUNT > 1:
691  self.RunMessage('Warning: This post processor is meant to use one reference frame. Errors might follow.', True)
692  self.log('This post processor is meant to use one reference frame. Errors might follow.')
693 
694  self.control_ProgSize()
695  self.REF = pose
696  self.REF_COUNT = self.REF_COUNT + 1
697 
698  def setTool(self, pose, tool_id=None, tool_name=None):
699  """Change the robot TCP"""
700  if self.TOOL_COUNT > 1:
701  self.RunMessage('Warning: Only one tool allowed per program. Tool change skipped.', True)
702  self.log('Only one tool allowed per program')
703  return
704 
705  self.control_ProgSize()
706  self.TOOL = pose
707  self.TOOL_COUNT = self.TOOL_COUNT + 1
708 
709  def Pause(self, time_ms):
710  """Pause the robot program"""
711  self.control_ProgSize()
712  if time_ms < 0:
713  self.addline('popUpMsg("Paused. Press OK to continue")')
714  else:
715  self.addline('delay(%.3f)' % (time_ms*0.001))
716 
717  def setSpeed(self, speed_mms):
718  """Changes the robot speed (in mm/s)"""
719  if self.SPEED != speed_mms:
720  self.SPEED = speed_mms
721  self.addline('mCurrentSpeed.tvel = %.3f' % speed_mms)
722 
723  def setAcceleration(self, accel_mmss):
724  """Changes the robot acceleration (in mm/s2)"""
725  self.ACCEL_MMSS = accel_mmss
726 
727  def setSpeedJoints(self, speed_degs):
728  """Changes the robot joint speed (in deg/s)"""
729  self.SPEED_DEGS = speed_degs
730 
731  def setAccelerationJoints(self, accel_degss):
732  """Changes the robot joint acceleration (in deg/s2)"""
733  self.ACCEL_DEGSS = accel_degss
734 
735  def setZoneData(self, zone_mm):
736  """Changes the zone data approach (makes the movement more smooth)"""
737  self.addline('mCurrentSpeed.reach = %.3f' % zone_mm)
738  self.addline('mCurrentSpeed.leave = %.3f' % zone_mm)
739 
740  def setDO(self, io_var, io_value):
741  """Sets a variable (output) to a given value"""
742  if type(io_var) != str: # set default variable name if io_var is a number
743  io_var = 'OUT[%s]' % str(io_var)
744  if type(io_value) != str: # set default variable value if io_value is a number
745  if io_value > 0:
746  io_value = 'TRUE'
747  else:
748  io_value = 'FALSE'
749 
750  # at this point, io_var and io_value must be string values
751  self.addline('%s=%s' % (io_var, io_value))
752 
753  def waitDI(self, io_var, io_value, timeout_ms=-1):
754  """Waits for an input io_var to attain a given value io_value. Optionally, a timeout can be provided."""
755  if type(io_var) != str: # set default variable name if io_var is a number
756  io_var = 'IN[%s]' % str(io_var)
757  if type(io_value) != str: # set default variable value if io_value is a number
758  if io_value > 0:
759  io_value = 'TRUE'
760  else:
761  io_value = 'FALSE'
762 
763  # at this point, io_var and io_value must be string values
764  if timeout_ms < 0:
765  self.addline('WAIT FOR %s==%s' % (io_var, io_value))
766  else:
767  self.addline('WAIT FOR %s==%s TIMEOUT=%.1f' % (io_var, io_value, timeout_ms))
768 
769  def RunCode(self, code, is_function_call = False):
770  """Adds code or a function call"""
771  self.control_ProgSize()
772  if is_function_call:
773  code.replace(' ','_')
774  if not code.endswith(')'):
775  code = code + '()'
776  #call prog:start()
777  #self.addline('call prog:%s' % code)# add as a call
778  self.addline('//call prog:%s' % code)# add as a comment
779  else:
780  self.addline(code)
781 
782  def RunMessage(self, message, iscomment = False):
783  """Display a message in the robot controller screen (teach pendant)"""
784  self.control_ProgSize()
785  if iscomment:
786  self.addline('// ' + message)
787  else:
788  self.addline('popUpMsg("%s")' % message)
789 
790 # ------------------ private ----------------------
791  def addline(self, newline):
792  """Add a program line"""
793  self.PROG_PGX = self.PROG_PGX + self.TAB_PGX + newline + '\n'
794 
795  def addlog(self, newline):
796  """Add a log message"""
797  self.LOG = self.LOG + newline + '\n'
798 
799  def control_ProgSize(self):
801  if self.PROG_MOVE_COUNT > self.PROG_MOVE_COUNT_MAX:
802  self.close_module()
803 
804  def close_module(self):
805  if self.PROG_MOVE_COUNT == 0:
806  return
807 
808  progname = self.PROG_NAME
809  nprogs = len(self.PROG_NAME_LIST)
810  if nprogs > 0:
811  progname = progname + ('%i' % (nprogs+1))
812 
813  self.PROG_PGX_LIST.append(self.PROG_PGX)
814  self.PROG_NAME_LIST.append(progname)
815  self.PROG_PGX = ''
816  self.PROG_MOVE_COUNT = 0
817  # initialise next program
818  self.setSpeed(self.SPEED)
819  self.PROG_MOVE_COUNT = 0 # very important to avoid writting two programs
820 
821 
822 
823 # -------------------------------------------------
824 # ------------ For testing purposes ---------------
825 def Pose(xyzrpw):
826  [x,y,z,r,p,w] = xyzrpw
827  a = r*math.pi/180
828  b = p*math.pi/180
829  c = w*math.pi/180
830  ca = math.cos(a)
831  sa = math.sin(a)
832  cb = math.cos(b)
833  sb = math.sin(b)
834  cc = math.cos(c)
835  sc = math.sin(c)
836  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]])
837 
838 def test_post():
839  """Test the post with a basic program"""
840 
841  robot = RobotPost()
842 
843  robot.ProgStart("Program")
844  robot.RunMessage("Program generated by RoboDK using a custom post processor", True)
845  robot.setFrame(Pose([807.766544, -963.699898, 41.478944, 0, 0, 0]))
846  robot.setTool(Pose([62.5, -108.253175, 100, -60, 90, 0]))
847  robot.MoveJ(Pose([200, 200, 500, 180, 0, 180]), [-46.18419, -6.77518, -20.54925, 71.38674, 49.58727, -302.54752] )
848  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
849  robot.MoveL(Pose([200, 200, 262.132034, 180, 0, -150]), [-43.73892, -3.91728, -35.77935, 58.57566, 54.11615, -253.81122] )
850  robot.RunMessage("Setting air valve 1 on")
851  robot.RunCode("TCP_On", True)
852  robot.Pause(1000)
853  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
854  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
855  robot.MoveL(Pose([250, 250, 191.421356, 180, 0, -150]), [-39.75778, -1.04537, -40.37883, 52.09118, 54.15317, -246.94403] )
856  robot.RunMessage("Setting air valve off")
857  robot.RunCode("TCP_Off", True)
858  robot.Pause(1000)
859  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
860  robot.MoveL(Pose([250, 200, 278.023897, 180, 0, -150]), [-41.85389, -1.95619, -34.89154, 57.43912, 52.34162, -253.73403] )
861  robot.MoveL(Pose([250, 150, 191.421356, 180, 0, -150]), [-43.82111, 3.29703, -40.29493, 56.02402, 56.61169, -249.23532] )
862  robot.ProgFinish("Program")
863  # robot.ProgSave(".","Program",True)
864  print(robot.PROG_PGX)
865  if len(robot.LOG) > 0:
866  mbox('Program generation LOG:\n\n' + robot.LOG)
867 
868  input("Press Enter to close...")
869 
870 if __name__ == "__main__":
871  """Function to call when the module is executed by itself: test"""
872  test_post()
def __init__(self, robotpost=None, robotname=None, robot_axes=6, kwargs)
def setFrame(self, pose, frame_id=None, frame_name=None)
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=None)
Definition: robodk.py:1458
def getSaveFolder(strdir='C:\\', strtitle='Save program folder ...')
def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None)
def ProgSave(self, folder, progname, ask_user=False, show_result=False)
def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass)


ros_robodk_post_processors
Author(s): Victor Lamoine - Institut Maupertuis
autogenerated on Sun Jun 7 2020 03:50:22