Motoman.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 Motoman robot (Inform III programming language)
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 def get_safe_name(progname, max_chars = 32):
45  """Get a safe program name"""
46  # Remove special characters
47  for c in r'-[]/\;,><&*:%=+@!#^()|?^':
48  progname = progname.replace(c,'')
49  # Set a program name by default:
50  if len(progname) <= 0:
51  progname = 'Program'
52  # Force the program to start with a letter (not a number)
53  if progname[0].isdigit():
54  progname = 'P' + progname
55  # Set the maximum size of a program (number of characters)
56  if len(progname) > max_chars:
57  progname = progname[:max_chars]
58  return progname
59 
60 
61 # ----------------------------------------------------
62 # Import RoboDK tools
63 from robodk import *
64 import sys
65 
66 # ----------------------------------------------------
67 # Object class that handles the robot instructions/syntax
68 class RobotPost(object):
69  """Robot post object defined for Motoman robots"""
70  PROG_EXT = 'JBI' # set the program extension
71  MAX_LINES_X_PROG = 2000 # maximum number of lines per program. It will then generate multiple "pages (files)". This can be overriden by RoboDK settings.
72  DONT_USE_MFRAME = True # Set to false to use MFRAME for setting reference frames automatically within the program
73  DONT_USE_SETTOOL = True # Set to false to use SETTOOL for setting the tool within the program
74  USE_RELATIVE_JOB = True # Set to False to always use pulses (Otherwise, it might require a special/paid option
75 
76  INCLUDE_SUB_PROGRAMS = True # Generate sub programs
77  STR_V = 'V=100.0' # set default cartesian speed
78  STR_VJ = 'VJ=50.00' # set default joints speed
79  STR_PL = '' # Rounding value (from 0 to 4) (in RoboDK, set to 100 mm rounding for PL=4
80  ACTIVE_FRAME = 9 # Active UFrame Id (register)
81  ACTIVE_TOOL = 9 # Active UTool Id (register)
82  SPARE_PR = 95 # Spare Position register for calculations
83 
84  REGISTER_DIGITS = 5
85 
86  # Pulses per degree (provide these in the robot parameters menu: Double click the motoman robot in RoboDK, select "Parameters"
87  PULSES_X_DEG = [1,1,1,1,1,1]
88 
89  # PROG specific variables:
90  LINE_COUNT = 0 # Count the number of instructions (limited by MAX_LINES_X_PROG)
91  P_COUNT = 0 # Count the number of P targets in one file
92  C_COUNT = 0 # Count the number of P targets in one file
93  nProgs = 0 # Count the number of programs and sub programs
94  LBL_ID_COUNT = 0 # Number of labels used
95 
96  # other variables
97  ROBOT_POST = ''
98  ROBOT_NAME = ''
99  PROG_FILES = [] # List of Program files to be uploaded through FTP
100 
101  PROG_NAMES = [] # List of PROG NAMES
102  PROG_LIST = [] # List of PROG
103  FOLDERNAME = '' # Folder inside the robot
104 
105  PROG_NAME = 'unknown' # Original name of the current program (example: ProgA)
106  PROG_NAME_CURRENT = 'unknown' # Auto generated name (different from PROG_NAME if we have more than 1 page per program. Example: ProgA2)
107 
108  PROG_COMMENT = 'Generated using RoboDK'
109 
110  nPages = 0 # Count the number of pages
111  PROG_NAMES_MAIN = [] # List of programs called by a main program due to splitting
112 
113  PROG = [] # Save the program lines
114  PROG_TARGETS = [] # Save the program lines (targets section)
115  LOG = '' # Save a log
116 
117  nAxes = 6 # Important: This is usually provided by RoboDK automatically. Otherwise, override the __init__ procedure.
118  AXES_TYPE = ['R','R','R','R','R','R'] # Important: This is usually set up by RoboDK automatically. Otherwise, override the __init__ procedure.
119  # 'R' for rotative axis, 'L' for linear axis, 'T' for external linear axis (linear track), 'J' for external rotative axis (turntable)
120  #AXES_TYPE = ['R','R','R','R','R','R','T','J','J'] #example of a robot with one external linear track axis and a turntable with 2 rotary axes
121  AXES_TRACK = []
122  AXES_TURNTABLE = []
123  HAS_TRACK = False
124  HAS_TURNTABLE = False
125 
126  # Specific to ARC welding applications
127  SPEED_BACKUP = None
128  LAST_POSE = None
129  POSE_FRAME = eye(4)
130  POSE_FRAME = eye(4)
131  LAST_CONFDATA = [None, None, None, None] # [pulses(None, Pulses(0), Cartesian) , base(or None), tool, config]
132 
133  def __init__(self, robotpost=None, robotname=None, robot_axes = 6, **kwargs):
134  if self.DONT_USE_MFRAME:
135  self.ACTIVE_FRAME = None
136  self.ROBOT_POST = robotpost
137  self.ROBOT_NAME = robotname
138  self.nAxes = robot_axes
139  self.PROG = []
140  self.LOG = ''
141  #for k,v in kwargs.iteritems(): # python2
142  for k,v in kwargs.items():
143  if k == 'lines_x_prog':
145  if k == 'axes_type':
146  self.AXES_TYPE = v
147  if k == 'pulses_x_deg':
148  self.PULSES_X_DEG = v
149 
150  for i in range(len(self.AXES_TYPE)):
151  if self.AXES_TYPE[i] == 'T':
152  self.AXES_TRACK.append(i)
153  self.HAS_TRACK = True
154  elif self.AXES_TYPE[i] == 'J':
155  self.AXES_TURNTABLE.append(i)
156  self.HAS_TURNTABLE = True
157 
158 
159  def ProgStart(self, progname, new_page = False):
160  progname = get_safe_name(progname)
161  progname_i = progname
162  if new_page:
163  #nPages = len(self.PROG_LIST)
164  if self.nPages == 0:
165  if len(self.PROG_NAMES_MAIN) > 0:
166  print("Can't split %s: Two or more programs are split into smaller programs" % progname)
167  print(self.PROG_NAMES_MAIN)
168  raise Exception("Only one program at a time can be split into smaller programs")
169  self.PROG_NAMES_MAIN.append(self.PROG_NAME) # add the first program in the list to be genrated as a subprogram call
170  self.nPages = self.nPages + 1
171 
172  self.nPages = self.nPages + 1
173  progname_i = "%s%i" % (self.PROG_NAME, self.nPages)
174  self.PROG_NAMES_MAIN.append(progname_i)
175 
176  else:
177  if self.nProgs > 1 and not self.INCLUDE_SUB_PROGRAMS:
178  return
179  self.PROG_NAME = progname
180  self.nProgs = self.nProgs + 1
181  #self.PROG_NAMES = []
182 
183  self.PROG_NAME_CURRENT = progname_i
184  self.PROG_NAMES.append(progname_i)
185 
186  def SetFolder(self, foldername):
187  if len(foldername) is not 0:
188  self.FOLDERNAME = get_safe_name(foldername)
189  else:
190  self.FOLDERNAME = ''
191 
192  def ProgFinish(self, progname, new_page = False):
193  progname = get_safe_name(progname)
194  if not new_page:
195  # Reset page count
196  self.nPages = 0
197 
198  #if self.nPROGS > 1:
199  # # Motoman does not support defining multiple programs in the same file, so one program per file
200  # return
201  header = ''
202  header += '/JOB' + '\n'
203  header += '//NAME %s' % progname + '\n'
204  if len(self.FOLDERNAME) is not 0:
205  header += '///FOLDERNAME %s' % self.FOLDERNAME + '\n'
206  header += '//POS' + '\n'
207  header += '///NPOS %i,0,0,%i,0,0' % (self.C_COUNT, self.P_COUNT)
208 
209  # Targets are added at this point
210 
211  import time
212  datestr = time.strftime("%Y/%m/%d %H:%M")
213 
214  header_ins = ''
215  header_ins += '//INST' + '\n'
216  header_ins += '///DATE %s' % datestr + '\n'
217  #///DATE 2012/04/25 14:11
218  header_ins += '///COMM %s\n' % self.PROG_COMMENT[:32] # comment: max 32 chars
219  if self.USE_RELATIVE_JOB:
220  header_ins += '///ATTR SC,RW,RJ' + '\n'
221  if self.ACTIVE_FRAME is not None:
222  header_ins += '////FRAME USER %i' % self.ACTIVE_FRAME + '\n'
223  else:
224  header_ins += '///ATTR SC,RW' + '\n'
225 
226  header_ins += '///GROUP1 RB1' + '\n'
227  header_ins += 'NOP'
228  #if self.HAS_TURNTABLE:
229  # header = header + '/APPL' + '\n'
230 
231  self.PROG.insert(0, header_ins)
232  self.PROG.append('END')
233 
234  self.PROG_TARGETS.insert(0, header)
235 
236  self.PROG = self.PROG_TARGETS + self.PROG
237 
238 
239 
240  # Save PROG in PROG_LIST
241  self.PROG_LIST.append(self.PROG)
242  self.PROG = []
243  self.PROG_TARGETS = []
244  self.LINE_COUNT = 0
245  self.P_COUNT = 0
246  self.C_COUNT = 0
247  self.LAST_CONFDATA = [None, None, None, None]
248  self.LBL_ID_COUNT = 0
249 
250  def progsave(self, folder, progname, ask_user = False, show_result = False):
251  print(folder)
252  if not folder.endswith('/'):
253  folder = folder + '/'
254  progname = progname + '.' + self.PROG_EXT
255  if ask_user or not DirExists(folder):
256  filesave = getSaveFile(folder, progname, 'Save program as...')
257  if filesave is not None:
258  filesave = filesave.name
259  else:
260  return
261  else:
262  filesave = folder + progname
263  import io
264  fid = io.open(filesave, "w", newline='\r\n')
265  #fid.write(self.PROG)
266  for line in self.PROG:
267  fid.write(line.decode('unicode-escape'))
268  fid.write(u'\n')
269  fid.close()
270  print('SAVED: %s\n' % filesave) # tell RoboDK the path of the saved file
271  self.PROG_FILES.append(filesave)
272 
273  # open file with default application
274  if show_result:
275  if type(show_result) is str:
276  # Open file with provided application
277  import subprocess
278  p = subprocess.Popen([show_result, filesave])
279  elif type(show_result) is list:
280  import subprocess
281  p = subprocess.Popen(show_result + [filesave])
282  else:
283  # open file with default application
284  import os
285  os.startfile(filesave)
286  #if len(self.LOG) > 0:
287  # mbox('Program generation LOG:\n\n' + self.LOG)
288 
289 
290 
291  def ProgSave(self, folder, progname, ask_user = False, show_result = False):
292  progname = get_safe_name(progname)
293  nfiles = len(self.PROG_LIST)
294  if nfiles >= 1:
295  if self.LINE_COUNT > 0:
296  # Progfinish was not called!
297  print("Warning: ProgFinish was not called properly")
298  self.PROG_LIST.append(self.PROG)
299  self.PROG_NAMES.append("Unknown")
300  self.PROG = []
301  self.LINE_COUNT = 0
302 
303  if len(self.PROG_NAMES_MAIN) > 1:
304  # Warning: the program might be cut to a maximum number of chars
305  progname_main = "M_" + self.PROG_NAMES_MAIN[0]
306  self.INCLUDE_SUB_PROGRAMS = True # Force generation of main program
307  self.ProgStart(progname_main)
308  for prog_call in self.PROG_NAMES_MAIN:
309  self.RunCode(prog_call, True)
310 
311  self.ProgFinish(progname_main)
312 
313  # Save the last program added to the PROG_LIST
314  self.PROG = self.PROG_LIST.pop()
315  progname_last = self.PROG_NAMES.pop()
316  self.progsave(folder, progname_last, ask_user, show_result)
317  #-------------------------
318  #self.LOG = ''
319  if len(self.PROG_FILES) == 0:
320  # cancelled by user
321  return
322 
323  first_file = self.PROG_FILES[0]
324  folder_user = getFileDir(first_file)
325  # progname_user = getFileName(self.FILE_SAVED)
326 
327  # Generate each program
328  for i in range(len(self.PROG_LIST)):
329  self.PROG = self.PROG_LIST[i]
330  self.progsave(folder_user, self.PROG_NAMES[i], False, show_result)
331 
332  elif nfiles == 1:
333  self.PROG = self.PROG_NAMES[0]
334  self.progsave(folder, progname, ask_user, show_result)
335 
336  else:
337  print("Warning! Program has not been properly finished")
338  self.progsave(folder, progname, ask_user, show_result)
339 
340  if show_result and len(self.LOG) > 0:
341  mbox('Program generation LOG:\n\n' + self.LOG)
342 
343  def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass):
344  """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".
345  The connection parameters must be provided in the robot connection menu of RoboDK"""
346  UploadFTP(self.PROG_FILES, robot_ip, remote_path, ftp_user, ftp_pass)
347 
348  def MoveJ(self, pose, joints, conf_RLF=None):
349  """Add a joint movement"""
350  self.page_size_control() # Important to control the maximum lines per program and not save last target on new program
351  target_id = self.add_target_joints(joints)
352  self.addline("MOVJ C%05d %s%s" % (target_id, self.STR_VJ, self.STR_PL))
353  self.LAST_POSE = pose
354 
355  def MoveL(self, pose, joints, conf_RLF=None):
356  """Add a linear movement"""
357  #if self.LAST_POSE is not None and pose is not None:
358  # # Skip adding a new movement if the new position is the same as the last one
359  # if distance(pose.Pos(), self.LAST_POSE.Pos()) < 0.1 and pose_angle_between(pose, self.LAST_POSE) < 0.1:
360  # return
361 
362  self.page_size_control() # Important to control the maximum lines per program and not save last target on new program
363 
364  if pose is None:
365  target_id = self.add_target_joints(joints)
366  else:
367  target_id = self.add_target_cartesian(self.POSE_FRAME*pose, joints, conf_RLF)
368 
369  self.addline("MOVL C%05d %s%s" % (target_id, self.STR_V, self.STR_PL))
370  self.LAST_POSE = pose
371 
372  def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None):
373  """Add a circular movement"""
374  self.page_size_control() # Important to control the maximum lines per program and not save last target on new program
375 
376  if self.LAST_POSE is not None:
377  target_id0 = self.add_target_cartesian(self.POSE_FRAME*self.LAST_POSE, joints1, conf_RLF_1)
378  self.addline("MOVC C%05d %s%s" % (target_id0, self.STR_V, self.STR_PL))
379 
380  target_id1 = self.add_target_cartesian(self.POSE_FRAME*pose1, joints1, conf_RLF_1)
381  target_id2 = self.add_target_cartesian(self.POSE_FRAME*pose2, joints2, conf_RLF_2)
382 
383  self.addline("MOVC C%05d %s%s" % (target_id1, self.STR_V, self.STR_PL))
384  self.addline("MOVC C%05d %s%s" % (target_id2, self.STR_V, self.STR_PL))
385 
386  self.LAST_POSE = None
387 
388  def setFrame(self, pose, frame_id, frame_name):
389  """Change the robot reference frame"""
390  xyzwpr = Pose_2_Motoman(pose)
391  if self.DONT_USE_MFRAME:
392  self.ACTIVE_FRAME = None
393  self.POSE_FRAME = pose
394  self.RunMessage('Using %s (targets wrt base):' % (str(frame_name)), True)
395  self.RunMessage('%.1f,%.1f,%.1f,%.1f,%.1f,%.1f' % (xyzwpr[0], xyzwpr[1], xyzwpr[2], xyzwpr[3], xyzwpr[4], xyzwpr[5]), True)
396  else:
397  self.POSE_FRAME = eye(4)
398  if frame_id is None or frame_id < 0:
399  self.RunMessage('Setting Frame %i (%s):' % (self.ACTIVE_FRAME, str(frame_name)), True)
400  decimals = [1000,1000,1000,100,100,100]
401  frame_calc = [eye(4), transl(200,0,0), transl(0,200,0)]
402  for m in range(3):
403  xyzwpr_pm = Pose_2_Motoman(pose*frame_calc[m])
404  for i in range(6):
405  self.addline("SETE P%05d (%i) %i" % (self.SPARE_PR+m, i+1, round(xyzwpr_pm[i]*decimals[i])))
406  for i in range(6,self.nAxes):
407  self.addline("SETE P%05d (%i) %i" % (self.SPARE_PR+m, i+1, 0))
408 
409  self.addline("MFRAME UF#(%i) P%05d P%05d P%05d" % (self.ACTIVE_FRAME, self.SPARE_PR, self.SPARE_PR+1, self.SPARE_PR+2))
410 
411  else:
412  self.ACTIVE_FRAME = frame_id
413  self.RunMessage('Frame %i (%s) should be close to:' % (self.ACTIVE_FRAME, str(frame_name)), True)
414  self.RunMessage('%.1f,%.1f,%.1f,%.1f,%.1f,%.1f' % (xyzwpr[0], xyzwpr[1], xyzwpr[2], xyzwpr[3], xyzwpr[4], xyzwpr[5]), True)
415 
416  def setTool(self, pose, tool_id, tool_name):
417  """Change the robot TCP"""
418  xyzwpr = Pose_2_Motoman(pose)
419  if tool_id is None or tool_id < 0:
420  if self.DONT_USE_SETTOOL:
421  self.RunMessage('Tool %s should be close to:' % (str(tool_name)), True)
422  self.RunMessage('%.1f,%.1f,%.1f,%.1f,%.1f,%.1f' % (xyzwpr[0], xyzwpr[1], xyzwpr[2], xyzwpr[3], xyzwpr[4], xyzwpr[5]), True)
423  else:
424  self.RunMessage('Setting Tool %i (%s):' % (self.ACTIVE_TOOL, str(tool_name)), True)
425  decimals = [1000,1000,1000,100,100,100]
426  for i in range(6):
427  self.addline("SETE P%05d (%i) %i" % (self.SPARE_PR, i+1, round(xyzwpr[i]*decimals[i])))
428  for i in range(6,self.nAxes):
429  self.addline("SETE P%05d (%i) %i" % (self.SPARE_PR, i+1, 0))
430 
431  self.addline("SETTOOL TL#(%i) P%05d" % (self.ACTIVE_TOOL, self.SPARE_PR))
432 
433  else:
434  self.ACTIVE_TOOL = tool_id
435  self.RunMessage('Tool %i (%s) should be close to:' % (self.ACTIVE_TOOL, str(tool_name)), True)
436  self.RunMessage('%.1f,%.1f,%.1f,%.1f,%.1f,%.1f' % (xyzwpr[0], xyzwpr[1], xyzwpr[2], xyzwpr[3], xyzwpr[4], xyzwpr[5]), True)
437 
438  def Pause(self, time_ms):
439  """Pause the robot program"""
440  if time_ms <= 0:
441  self.addline('PAUSE')
442  else:
443  self.addline('TIMER T=%.2f' % (time_ms*0.001))
444 
445  def setSpeed(self, speed_mms):
446  speedl = max(1, speed_mms)
447  self.STR_V = "V=%.1f" % speedl
448 
449  def setAcceleration(self, accel_mmss):
450  """Changes the robot acceleration (in mm/s2)"""
451  self.addlog('Set acceleration not defined')
452 
453  def setSpeedJoints(self, speed_degs):
454  """Changes the robot joint speed (in deg/s)"""
455  speedj = max(0.01, min(speed_degs, 100.0)) # Joint speed must be in %
456  if speedj < 100:
457  self.STR_VJ = "VJ=%.2f" % speedj
458  else:
459  self.STR_VJ = "VJ=%.1f" % speedj
460 
461  def setAccelerationJoints(self, accel_degss):
462  """Changes the robot joint acceleration (in deg/s2)"""
463  self.addlog('Set acceleration not defined')
464 
465  def setZoneData(self, zone_mm):
466  """Changes the zone data approach (makes the movement more smooth)"""
467  if zone_mm < 0:
468  self.STR_PL = ''
469  else:
470  self.STR_PL = ' PL=%i' % round(min(zone_mm, 8))
471 
472  def setDO(self, io_var, io_value):
473  """Sets a variable (output) to a given value"""
474  if type(io_var) != str: # set default variable name if io_var is a number
475  io_var = 'OT#(%s)' % str(io_var)
476  if type(io_value) != str: # set default variable value if io_value is a number
477  if io_value > 0:
478  io_value = 'ON'
479  else:
480  io_value = 'OFF'
481 
482  # at this point, io_var and io_value must be string values
483  #DOUT OT#(2) ON
484  self.addline('DOUT %s %s' % (io_var, io_value))
485 
486  def waitDI(self, io_var, io_value, timeout_ms=-1):
487  """Waits for an input io_var to attain a given value io_value. Optionally, a timeout can be provided."""
488  if type(io_var) != str: # set default variable name if io_var is a number
489  io_var = 'IN#(%s)' % str(io_var)
490  if type(io_value) != str: # set default variable value if io_value is a number
491  if io_value > 0:
492  io_value = 'ON'
493  else:
494  io_value = 'OFF'
495 
496  # at this point, io_var and io_value must be string values
497  if timeout_ms <= 0:
498  #WAIT IN#(12)=ON
499  self.addline('WAIT %s=%s' % (io_var, io_value))
500  else:
501  #self.LBL_ID_COUNT = self.LBL_ID_COUNT + 1
502  self.addline('WAIT %s=%s T=%.2f' % (io_var, io_value, timeout_ms*0.001))
503 
504 
505  def RunCode(self, code, is_function_call = False):
506  """Adds code or a function call"""
507  if is_function_call:
508  code = get_safe_name(code,8)
509  #if code.startswith("ArcStart"):
510  #return
511 
512  # default program call
513  code.replace(' ','_')
514  self.addline('CALL JOB:%s' % (code))
515  else:
516  #if code.endswith(';'):
517  #code = code[:-1]
518  self.addline(code)
519 
520  def RunMessage(self, message, iscomment = False):
521  """Add a message/comment"""
522  if iscomment:
523  for i in range(0,len(message), 29):
524  i2 = min(i + 29, len(message))
525  self.addline("'%s" % message[i:i2])
526 
527  else:
528  for i in range(0,len(message), 25):
529  i2 = min(i + 25, len(message))
530  self.addline('MSG "%s"' % message[i:i2])
531 
532 # ------------------ Motoman specifics ------------------
533  def Macro(self, number, mf, args):
534  macro_line = 'MACRO%s MJ#(%s)' % (number, mf)
535 
536  if len(args) > 16:
537  self.addlog('Macro supports only 16 arguments')
538  return
539 
540  for arg in args:
541  # Only ARGF are supported
542  macro_line += (' ARGF%s' % (arg))
543 
544  self.addline(macro_line)
545 
546  def Arcon(self, asf_number = 0):
547  if asf_number is 0:
548  self.addline('ARCON')
549  else:
550  self.addline('ARCON ASF#(%s)' % asf_number)
551 
552  def Arcof(self, aef_number = 0):
553  if aef_number is 0:
554  self.addline('ARCOF')
555  else:
556  self.addline('ARCOF AEF#(%s)' % aef_number)
557 
558 # ------------------ private ----------------------
559  def page_size_control(self):
560  if self.LINE_COUNT >= self.MAX_LINES_X_PROG:
561  self.ProgFinish(self.PROG_NAME, True)
562  self.ProgStart(self.PROG_NAME, True)
563 
564 
565  def addline(self, newline, movetype = ' '):
566  """Add a program line"""
567  if self.nProgs > 1 and not self.INCLUDE_SUB_PROGRAMS:
568  return
569 
570  self.page_size_control()
571  self.LINE_COUNT = self.LINE_COUNT + 1
572  self.PROG.append(newline)
573 
574  def addline_targets(self, newline):
575  """Add a line at the end of the program (used for targets)"""
576  self.PROG_TARGETS.append(newline)
577 
578  def addlog(self, newline):
579  """Add a log message"""
580  if self.nProgs > 1 and not self.INCLUDE_SUB_PROGRAMS:
581  return
582  self.LOG = self.LOG + newline + '\n'
583 
584 # ------------------ targets ----------------------
585 
586  def setCartesian(self, confdata):
587  #self.LAST_CONFDATA = [none/pulses(0)/postype(1), base, tool, config]
588  if self.ACTIVE_FRAME is not None and self.ACTIVE_FRAME != self.LAST_CONFDATA[1]:
589  self.addline_targets("///USER %i" % self.ACTIVE_FRAME)
590  self.LAST_CONFDATA[1] = self.ACTIVE_FRAME
591 
592  if self.ACTIVE_TOOL != self.LAST_CONFDATA[2]:
593  self.addline_targets("///TOOL %i" % self.ACTIVE_TOOL)
594  self.LAST_CONFDATA[2] = self.ACTIVE_TOOL
595 
596  if self.LAST_CONFDATA[0] != 2:
597  if self.ACTIVE_FRAME is not None:
598  self.addline_targets("///POSTYPE USER")
599  else:
600  self.addline_targets("///POSTYPE BASE")
601 
602  self.addline_targets("///RECTAN")
603  self.addline_targets("///RCONF %s" % confdata)
604  self.LAST_CONFDATA[3] = confdata
605 
606 
607  elif self.LAST_CONFDATA[3] != confdata:
608  self.addline_targets("///RCONF %s" % confdata)
609  self.LAST_CONFDATA[3] = confdata
610 
611  self.LAST_CONFDATA[0] = 2
612 
613  def setPulses(self):
614  #self.LAST_CONFDATA = [none/pulses(0)/postype(1), base, tool, config]
615  if self.LAST_CONFDATA[0] is None:
616  self.addline_targets("///TOOL %i" % self.ACTIVE_TOOL)
617  self.LAST_CONFDATA[2] = self.ACTIVE_TOOL
618 
619  if self.LAST_CONFDATA[0] != 1:
620  self.addline_targets("///POSTYPE PULSE")
621  self.addline_targets("///PULSE")
622  self.LAST_CONFDATA[0] = 1
623 
624  self.LAST_CONFDATA[0] = 1
625  self.LAST_CONFDATA[1] = None
626  self.LAST_CONFDATA[2] = None
627  self.LAST_CONFDATA[3] = None
628 
629  def add_target_joints(self, joints):
630  if self.nProgs > 1 and not self.INCLUDE_SUB_PROGRAMS:
631  return
632 
633  self.setPulses()
634  cid = self.C_COUNT
635  self.C_COUNT = self.C_COUNT + 1
636 
637  str_pulses=[]
638  for i in range(len(joints)):
639  str_pulses.append('%i' % round(joints[i] * self.PULSES_X_DEG[i]))
640 
641  self.addline_targets('C%05i=' % cid + ','.join(str_pulses))
642  return cid
643 
644  def add_target_cartesian(self, pose, joints, conf_RLF):
645  if self.nProgs > 1 and not self.INCLUDE_SUB_PROGRAMS:
646  return
647 
648  if not self.USE_RELATIVE_JOB:
649  return self.add_target_joints(joints)
650 
651  xyzwpr = Pose_2_Motoman(pose)
652 
653  if conf_RLF is None:
654  conf_RLF = [0,0,0]
655 
656  turns = [0,0,0]
657  if len(joints) >= 6:
658  turnJ4 = (joints[3]+180)//360
659  turnJ6 = (joints[5]+180)//360
660  turnJ1 = (joints[0]+180)//360
661  turns = [turnJ4, turnJ6, turnJ1]
662 
663  confdata = '%i,%i,%i,%i,%i,%i,0,0' % tuple(conf_RLF[:3] + turns[:3])
664  self.setCartesian(confdata)
665  cid = self.C_COUNT
666  self.C_COUNT = self.C_COUNT + 1
667  self.addline_targets('C%05i=' % cid + '%.3f,%.3f,%.3f,%.2f,%.2f,%.2f' % tuple(xyzwpr))
668  return cid
669 
670 #/JOB
671 #//NAME TESTTCPX
672 #//POS
673 #///NPOS 3,0,0,19,0,0
674 #///TOOL 23
675 #///POSTYPE PULSE
676 #///PULSE
677 #C00000=2730,-84461,-101368,0,-77310,67137
678 #///TOOL 13
679 #C00001=76697,-73189,-80544,374,-78336,86207
680 #C00002=81732,-66267,-100360,-2451,-62876,82497
681 #///USER 8
682 #///TOOL 23
683 #///POSTYPE USER
684 #///RECTAN
685 #///RCONF 0,0,0,0,1,0,0,0
686 #P0010=0.000,0.000,10.205,0.00,0.00,0.00
687 #P0011=0.001,0.006,-9.794,-170.32,90.00,-170.32
688 #///RCONF 0,0,0,0,0,0,0,0
689 #P0012=13.500,0.000,0.000,0.00,0.00,0.00
690 #///RCONF 0,0,0,0,1,0,0,0
691 #P0015=0.000,0.000,0.000,180.00,90.00,180.00
692 #///RCONF 0,0,0,0,0,0,0,0
693 #P0020=0.000,0.000,0.000,-90.00,0.00,0.00
694 #P0021=0.000,0.000,-5.000,0.00,0.00,0.00
695 #///RCONF 1,0,0,0,0,0,0,0
696 #P0022=0.004,0.003,8.297,-90.00,0.00,-90.00
697 #P0023=-0.003,-0.003,-9.351,-90.00,0.00,-90.00
698 #///POSTYPE BASE
699 #///RCONF 0,0,0,0,0,0,0,0
700 #P0024=0.000,0.000,8.824,0.00,0.00,0.00
701 #///TOOL 0
702 #P0026=-276.205,101.089,162.089,0.08,-83.39,-19.88
703 #P0027=-276.205,101.634,162.089,179.99,-6.61,160.20
704 #///USER 8
705 #///TOOL 23
706 #///POSTYPE USER
707 #///RCONF 0,0,0,0,1,0,0,0
708 #P0028=0.410,-0.016,0.147,0.00,-90.00,0.00
709 #///RCONF 1,0,0,0,0,0,0,0
710 #P0030=-0.004,0.001,-0.527,-90.00,0.00,-90.00
711 #P0100=0.000,0.000,50.000,0.00,90.00,0.00
712 #P0101=0.000,0.000,-25.000,0.00,90.00,0.00
713 #P0103=0.000,0.000,25.000,-90.00,0.00,-90.00
714 #P0104=0.000,0.000,-25.000,-90.00,0.00,-90.00
715 #P0110=-100.000,0.000,0.000,0.00,0.00,0.00
716 #P0111=0.000,0.000,200.000,0.00,0.00,0.00
717 #//INST
718 #///DATE 2012/04/25 14:11
719 #///COMM 1ER PROGRAM POUR VERIFIER LE TCP
720 #///ATTR SC,RW
721 #///GROUP1 RB1
722 #NOP
723 #DOUT OT#(5) ON
724 #DOUT OT#(2) ON
725 
726 
727 
728 
729 # -------------------------------------------------
730 # ------------ For testing purposes ---------------
731 def Pose(xyzrpw):
732  [x,y,z,r,p,w] = xyzrpw
733  a = r*math.pi/180
734  b = p*math.pi/180
735  c = w*math.pi/180
736  ca = math.cos(a)
737  sa = math.sin(a)
738  cb = math.cos(b)
739  sb = math.sin(b)
740  cc = math.cos(c)
741  sc = math.sin(c)
742  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]])
743 
744 def test_post():
745  """Test the post with a basic program"""
746 
747  robot = RobotPost('Motomantest', 'Motoman robot', 6)
748 
749  robot.ProgStart("Program")
750  robot.RunMessage("Program generated by RoboDK", True)
751  robot.setFrame(Pose([807.766544, -963.699898, 41.478944, 0, 0, 0]), None, 0)
752  robot.setTool(Pose([62.5, -108.253175, 100, -60, 90, 0]), None, 0)
753  robot.MoveJ(Pose([200, 200, 500, 180, 0, 180]), [-46.18419, -6.77518, -20.54925, 71.38674, 49.58727, -302.54752] )
754  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
755  robot.MoveL(Pose([200, 200, 262.132034, 180, 0, -150]), [-43.73892, -3.91728, -35.77935, 58.57566, 54.11615, -253.81122] )
756  robot.RunMessage("Setting air valve 1 on")
757  robot.RunCode("TCP_On", True)
758  robot.Pause(1000)
759  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
760  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
761  robot.MoveL(Pose([250, 250, 191.421356, 180, 0, -150]), [-39.75778, -1.04537, -40.37883, 52.09118, 54.15317, -246.94403] )
762  robot.RunMessage("Setting air valve off")
763  robot.RunCode("TCP_Off", True)
764  robot.Pause(1000)
765  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
766  robot.MoveL(Pose([250, 200, 278.023897, 180, 0, -150]), [-41.85389, -1.95619, -34.89154, 57.43912, 52.34162, -253.73403] )
767  robot.MoveL(Pose([250, 150, 191.421356, 180, 0, -150]), [-43.82111, 3.29703, -40.29493, 56.02402, 56.61169, -249.23532] )
768  robot.ProgFinish("Program")
769  # robot.ProgSave(".","Program",True)
770 
771  robot.PROG = robot.PROG_LIST.pop()
772  for line in robot.PROG:
773  print(line)
774 
775  if len(robot.LOG) > 0:
776  mbox('Program generation LOG:\n\n' + robot.LOG)
777 
778  input("Press Enter to close...")
779 
780 if __name__ == "__main__":
781  """Function to call when the module is executed by itself: test"""
782  test_post()
def ProgFinish(self, progname, new_page=False)
Definition: Motoman.py:192
def setDO(self, io_var, io_value)
Definition: Motoman.py:472
def setTool(self, pose, tool_id, tool_name)
Definition: Motoman.py:416
def RunMessage(self, message, iscomment=False)
Definition: Motoman.py:520
def transl(tx, ty=None, tz=None)
Definition: robodk.py:187
def __init__(self, robotpost=None, robotname=None, robot_axes=6, kwargs)
Definition: Motoman.py:133
def MoveL(self, pose, joints, conf_RLF=None)
Definition: Motoman.py:355
def waitDI(self, io_var, io_value, timeout_ms=-1)
Definition: Motoman.py:486
def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass)
Definition: Motoman.py:343
def MoveJ(self, pose, joints, conf_RLF=None)
Definition: Motoman.py:348
def add_target_cartesian(self, pose, joints, conf_RLF)
Definition: Motoman.py:644
def UploadFTP(program, robot_ip, remote_path, ftp_user, ftp_pass)
Definition: robodk.py:1312
def RunCode(self, code, is_function_call=False)
Definition: Motoman.py:505
def ProgStart(self, progname, new_page=False)
Definition: Motoman.py:159
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=None)
Definition: robodk.py:1458
def Macro(self, number, mf, args)
Definition: Motoman.py:533
def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None)
Definition: Motoman.py:372
def setFrame(self, pose, frame_id, frame_name)
Definition: Motoman.py:388
def getSaveFile(strdir='C:\\', strfile='file.txt', strtitle='Save file as ...')
Definition: robodk.py:1354
def get_safe_name(progname, max_chars=32)
Definition: Motoman.py:44
def ProgSave(self, folder, progname, ask_user=False, show_result=False)
Definition: Motoman.py:291
def setAccelerationJoints(self, accel_degss)
Definition: Motoman.py:461
def addline(self, newline, movetype=' ')
Definition: Motoman.py:565
def progsave(self, folder, progname, ask_user=False, show_result=False)
Definition: Motoman.py:250


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