Nachi_AX_FD.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 Nachi robots (FD controllers and AX) as well as OTC robots with FD controllers
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 
48 # ----------------------------------------------------
49 def pose_2_str(pose,joints=None,reference=None):
50  """Converts a pose target to a string"""
51  if reference is not None:
52  pose = reference*pose
53  [x,y,z,r,p,w] = Pose_2_Nachi(pose)
54  return ('(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)' % (x,y,z,r,p,w))
55 
56 def angles_2_str(angles):
57  """Contverts a joint target to a string"""
58  return '(%s)' % (','.join(format(ji, ".5f") for ji in angles))
59 
60 # ----------------------------------------------------
61 # Object class that handles the robot instructions/syntax
62 class RobotPost(object):
63  """Robot post object"""
64  BASE_PROGNAME = None #'MZ07L-01-A'
65  MAX_LINES_X_PROG = 95000 # maximum number of lines per program
66  PROG_ID = 5 # Program ID to store the program
67  nPROGS = 0
68  SKIP_OUTPUT = False
69 
70  # other variables
71  ROBOT_POST = ''
72  ROBOT_NAME = ''
73  PROG_FILES = []
74  PROGRAM_NAME = 'unknown'
75  PROG = ''
76  PROGS = []
77  LOG = ''
78  nAxes = 6
79  TAB = ''
80  REF_FRAME = None
81  TOOL_ID = 1 # default id for the tool (H=TOOL_ID)
82  SPEED_MMS = 500 # default 500mm/s speed
83  CURRENT_LINES = 0
84 
85 
86  def __init__(self, robotpost=None, robotname=None, robot_axes = 6, **kwargs):
87  self.ROBOT_POST = robotpost
88  self.ROBOT_NAME = robotname
89  self.PROG = ''
90  self.LOG = ''
91  self.nAxes = robot_axes
92  if self.BASE_PROGNAME is None and type(robotname) == str:
93  robotnamelist = robotname.split(' ')
94  if len(robotnamelist) > 1:
95  self.BASE_PROGNAME = robotnamelist[1] + '-01-A'
96  else:
97  self.BASE_PROGNAME = 'MZ07L-01-A'
98 
99  for k,v in kwargs.items():
100  if k == 'lines_x_prog':
102 
103  def ProgStart(self, progname, generate_sub_program=False):
104  if self.nPROGS > 0 and not generate_sub_program:
105  self.SKIP_OUTPUT = True
106  return
107 
108  import re
109  m = re.search(r'\d+$', progname)
110  # if the string ends in digits m will be a Match object, or None otherwise.
111  if m is not None:
112  self.PROG_ID = int(m.group())
113 
114  self.nPROGS = self.nPROGS + 1
115  self.CURRENT_LINES = 0
116  self.PROGRAM_NAME = progname
117  self.RunMessage('Program %s' % progname, True) # comment
118  self.TAB = ''
119  self.PROG = ''
120 
121  def ProgFinish(self, progname):
122  self.TAB = ''
123  self.addline('END')
124 
125  def ProgSave(self, folder, progname, ask_user = False, show_result = False):
126  # File extensions are the program number and the file name is the robot type and –A. So the file name for the SRA120EL program 200 would be SRA120EL-01-A.200.
127  progname = self.BASE_PROGNAME
128  progname_base = progname
129  if ask_user or not DirExists(folder):
130  filesave = getSaveFile(folder, progname, 'Save program as...')
131  if filesave is not None:
132  filesave = filesave.name
133  folder = getFileDir(filesave)
134  else:
135  return
136  else:
137  filesave = '%s/%s.%03i' % (folder, progname, self.PROG_ID)
138  #----------------------------
139  # Save file(s)
140  self.PROG_FILES = []
141  if self.nPROGS > 1: # save multiple programs
142  self.PROGS.append(self.PROG)
143  #self.nPROGS = self.nPROGS + 1 # Not required: We already added the counter
144  self.nPROGS = len(self.PROGS)
145  mainprog = '\' Main program %s calls %i subprograms\n' % (self.PROGRAM_NAME, self.nPROGS)
146  for i in range(self.nPROGS):
147  fsavei = ('%s/%s.%03i' % (folder, progname_base, self.PROG_ID+i+1))
148  #mainprog = mainprog + ('%s.%03i\n' % (progname_base, self.PROG_ID+i+1))
149  mainprog += 'CALLP [%03i]\n' % (self.PROG_ID+i+1)
150  fid = open(fsavei, "w")
151  fid.write(self.PROGS[i])
152  fid.close()
153  self.PROG_FILES.append(fsavei)
154  mainprog = mainprog + 'END\n'
155  fid = open(filesave, "w")
156  fid.write(mainprog)
157  fid.close()
158  self.PROG_FILES.append(filesave)
159  print('SAVED: %s\n' % filesave) # tell RoboDK the path of the saved file
160 
161  else: # save one single program
162  #filesave = '%s.%03i' % (filesave, self.PROG_ID)
163  fid = open(filesave, "w")
164  fid.write(self.PROG)
165  fid.close()
166  print('SAVED: %s\n' % filesave) # tell RoboDK the path of the saved file
167  self.PROG_FILES.append(filesave)
168 
169  # open file with default application
170  if show_result:
171  if type(show_result) is str:
172  # Open file with provided application
173  import subprocess
174  for file in self.PROG_FILES:
175  p = subprocess.Popen([show_result, file])
176  elif type(show_result) is list:
177  import subprocess
178  p = subprocess.Popen(show_result + [filesave])
179  else:
180  # open file with default application
181  import os
182  os.startfile(filesave)
183  if len(self.LOG) > 0:
184  mbox('Program generation LOG:\n\n' + self.LOG)
185 
186 
187  def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass):
188  """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".
189  The connection parameters must be provided in the robot connection menu of RoboDK"""
190  UploadFTP(self.PROG_FILES, robot_ip, remote_path, ftp_user, ftp_pass)
191 
192  def MoveJ(self, pose, joints, conf_RLF=None):
193  """Add a joint movement"""
194  #MOVEX A=1,M1X,P,(1960,0,1725,0,0,-180),R=5.0,H=1,MS,CONF=0000
195  self.addline('MOVEX M1J,P,%s,S=%.2f,H=%i,MS' % (angles_2_str(joints) , self.SPEED_MMS , self.TOOL_ID))
196 
197  def MoveL(self, pose, joints, conf_RLF=None):
198  """Add a linear movement"""
199  #MOVEX A=1,M1J,L,(0,90,-90,0),R= 5.0,H=1,MS
200  if pose is None:
201  self.addline('MOVEX M1J,L,%s,S=%.2f,H=%i,MS' % (angles_2_str(joints) , self.SPEED_MMS , self.TOOL_ID))
202  else:
203  self.addline('MOVEX M1X,L,%s,S=%.2f,H=%i,MS' % (pose_2_str(pose,joints,self.REF_FRAME) , self.SPEED_MMS , self.TOOL_ID))
204 
205  def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None):
206  """Add a circular movement"""
207  self.addline('MOVEX M1X,C1,%s,S=%.2f,H=%i,MS' % (pose_2_str(pose1,joints1,self.REF_FRAME) , self.SPEED_MMS , self.TOOL_ID))
208  self.addline('MOVEX M1X,C2,%s,S=%.2f,H=%i,MS' % (pose_2_str(pose2,joints2,self.REF_FRAME) , self.SPEED_MMS , self.TOOL_ID))
209 
210  def setFrame(self, pose, frame_id=None, frame_name=None):
211  """Change the robot reference frame"""
212  self.RunMessage('Using the reference frame:', True)
213  self.RunMessage('USERFRAME=%s' % (pose_2_str(pose)), True)
214  self.RunMessage('(using all targets with respect to the robot reference)', True)
215  self.REF_FRAME = pose
216  # all targets are given with respect to the robot base
217  # alternatively, we can use:
218  #P1 = (500,0,0,0,0,0)
219  #P2 = (500,500,0,0,0,0)
220  #P3 = (1000,0,0,0,0,0)
221  #MODUSRCOORD 1,1,2,3
222  #CHGCOORD 1
223 
224  def setTool(self, pose, tool_id=None, tool_name=None):
225  """Change the robot TCP"""
226  #self.addline('TOOL[%i]=%s' % (self.TOOL_ID , pose_2_str(pose)))
227  if tool_id is None or tool_id < 0:
228  tool_id = 1
229  self.TOOL_ID = tool_id
230  self.RunMessage('Using the tool:', True)
231  self.RunMessage('TOOL%i=%s' % (self.TOOL_ID , pose_2_str(pose)), True)
232  [x,y,z,w,p,r] = Pose_2_Nachi(pose)
233  #LETVF V11!,62.5
234  #LETVF V12!,-108.253
235  #LETVF V13!,100
236  #LETVF V14!,0
237  #LETVF V15!,90
238  #LETVF V16!,-60
239  #SETTOOL 1,1,V11!
240  self.addline('MOVEX M1J,P,P*,S=%.1f,H=%i,MS' % (self.SPEED_MMS, self.TOOL_ID))
241  #self.addline('LETVF V11!,%.3f' % x)
242  #self.addline('LETVF V12!,%.3f' % y)
243  #self.addline('LETVF V13!,%.3f' % z)
244  #self.addline('LETVF V14!,%.3f' % w)
245  #self.addline('LETVF V15!,%.3f' % p)
246  #self.addline('LETVF V16!,%.3f' % r)
247  #self.addline('SETTOOL %i,1,V11!' % self.TOOL_ID)
248 
249  def Pause(self, time_ms):
250  """Pause the robot program"""
251  if time_ms <= 0:
252  self.addline('PAUSE 99999')
253  else:
254  self.addline('PAUSE %.3f' % (time_ms*0.001))
255 
256  def setSpeed(self, speed_mms):
257  """Changes the robot speed (in mm/s)"""
258  self.SPEED_MMS = speed_mms
259 
260  def setAcceleration(self, accel_mmss):
261  """Changes the robot speed (in mm/s)"""
262  self.addlog('setAcceleration not defined')
263 
264  def setSpeedJoints(self, speed_degs):
265  """Changes the robot joint speed (in deg/s)"""
266  self.addlog('setSpeedJoints not defined')
267 
268  def setAccelerationJoints(self, accel_degss):
269  """Changes the robot joint acceleration (in deg/s2)"""
270  self.addlog('setAccelerationJoints not defined')
271 
272  def setZoneData(self, zone_mm):
273  """Changes the zone data approach (makes the movement more smooth)"""
274  self.RADIUS = zone_mm
275 
276  def setDO(self, io_var, io_value):
277  """Sets a variable (output) to a given value"""
278  setreset = "SET"
279  if type(io_var) != str: # set default variable name if io_var is a number
280  io_var = '[%02i]' % int(io_var)
281  if type(io_value) != str: # set default variable value if io_value is a number
282  if io_value > 0:
283  setreset = "SET"
284  else:
285  setreset = "RESET"
286 
287  # at this point, io_var and io_value must be string values
288  #self.addline('SETM %s,%s' % (io_var, io_value))
289  self.addline('%s %s' % (setreset, io_var))
290 
291  def waitDI(self, io_var, io_value, timeout_ms=-1):
292  """Waits for an input io_var to attain a given value io_value. Optionally, a timeout can be provided."""
293  waitij = ""
294  if type(io_var) != str: # set default variable name if io_var is a number
295  io_var = '[%02i]' % (int(io_var))
296  if type(io_value) != str: # set default variable value if io_value is a number
297  if io_value > 0:
298  waitij = 'WAITI'
299  else:
300  waitij = 'WAITJ'
301 
302  # at this point, io_var and io_value must be string values
303  self.addline('%s %s' % (waitij, io_var))
304  #if timeout_ms < 0:
305  # self.addline('WAITI %s' % (io_var))
306  #else:
307  # self.addline('WAITI %s' % (io_var))
308 
309  def RunCode(self, code, is_function_call = False):
310  """Adds code or a function call"""
311  if is_function_call:
312  self.RunMessage('Call program %s:' % code, True) # comment
313  #self.addline('%s.%i' % (self.BASE_PROGNAME , name_2_id(code)))
314  self.addline('CALLP %03i' % (name_2_id(code)))
315  #code.replace(' ','_')
316  #if code.find('(') < 0:
317  # code = code + '()'
318  else:
319  self.addline(code)
320 
321  def RunMessage(self, message, iscomment = False):
322  """Add a joint movement"""
323  if iscomment:
324  self.addline('\' ' + message)
325  else:
326  self.addline('REM "' + message + '"')
327 
328 # ------------------ private ----------------------
329  def addline(self, newline):
330  """Add a program line"""
331  if self.SKIP_OUTPUT:
332  return
333 
334  if self.CURRENT_LINES > self.MAX_LINES_X_PROG:
335  self.CURRENT_LINES = 0
336  self.ProgFinish(self.PROGRAM_NAME)
337  self.PROGS.append(self.PROG)
338  self.ProgStart(self.PROGRAM_NAME, True)
339  #-----------------------
340  self.PROG += self.TAB + newline + '\n'
341  self.CURRENT_LINES = self.CURRENT_LINES + 1
342 
343  def addlog(self, newline):
344  """Add a log message"""
345  self.LOG = self.LOG + newline + '\n'
346 
347 # -------------------------------------------------
348 # ------------ For testing purposes ---------------
349 def Pose(xyzrpw):
350  [x,y,z,r,p,w] = xyzrpw
351  a = r*math.pi/180
352  b = p*math.pi/180
353  c = w*math.pi/180
354  ca = math.cos(a)
355  sa = math.sin(a)
356  cb = math.cos(b)
357  sb = math.sin(b)
358  cc = math.cos(c)
359  sc = math.sin(c)
360  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]])
361 
362 def test_post():
363  """Test the post with a basic program"""
364 
365  robot = RobotPost('Nachi program', 'Generic Nachi Robot')
366 
367  robot.ProgStart("Program")
368  robot.RunMessage("Program generated by RoboDK", True)
369  robot.setFrame(Pose([807.766544, -963.699898, 41.478944, 0, 0, 0]))
370  robot.setTool(Pose([62.5, -108.253175, 100, -60, 90, 0]))
371  robot.MoveJ(Pose([200, 200, 500, 180, 0, 180]), [-46.18419, -6.77518, -20.54925, 71.38674, 49.58727, -302.54752] )
372  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
373  robot.MoveL(Pose([200, 200, 262.132034, 180, 0, -150]), [-43.73892, -3.91728, -35.77935, 58.57566, 54.11615, -253.81122] )
374  robot.RunMessage("Setting air valve 1 on")
375  robot.RunCode("TCP_On", True)
376  robot.Pause(1000)
377  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
378  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
379  robot.MoveL(Pose([250, 250, 191.421356, 180, 0, -150]), [-39.75778, -1.04537, -40.37883, 52.09118, 54.15317, -246.94403] )
380  robot.RunMessage("Setting air valve off")
381  robot.RunCode("TCP_Off(55)", True)
382  robot.Pause(1000)
383  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
384  robot.MoveL(Pose([250, 200, 278.023897, 180, 0, -150]), [-41.85389, -1.95619, -34.89154, 57.43912, 52.34162, -253.73403] )
385  robot.MoveL(Pose([250, 150, 191.421356, 180, 0, -150]), [-43.82111, 3.29703, -40.29493, 56.02402, 56.61169, -249.23532] )
386  robot.ProgFinish("Program")
387  # robot.ProgSave(".","Program",True)
388  if robot.nPROGS > 0:
389  for i in range(len(robot.PROGS)):
390  print(robot.PROGS[i])
391  else:
392  print(robot.PROG)
393  if len(robot.LOG) > 0:
394  mbox('Program generation LOG:\n\n' + robot.LOG)
395 
396  input("Press Enter to close...")
397 
398 if __name__ == "__main__":
399  """Function to call when the module is executed by itself: test"""
400  test_post()
def RunMessage(self, message, iscomment=False)
Definition: Nachi_AX_FD.py:321
def ProgStart(self, progname, generate_sub_program=False)
Definition: Nachi_AX_FD.py:103
def waitDI(self, io_var, io_value, timeout_ms=-1)
Definition: Nachi_AX_FD.py:291
def setFrame(self, pose, frame_id=None, frame_name=None)
Definition: Nachi_AX_FD.py:210
def MoveJ(self, pose, joints, conf_RLF=None)
Definition: Nachi_AX_FD.py:192
def RunCode(self, code, is_function_call=False)
Definition: Nachi_AX_FD.py:309
def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None)
Definition: Nachi_AX_FD.py:205
def MoveL(self, pose, joints, conf_RLF=None)
Definition: Nachi_AX_FD.py:197
def UploadFTP(program, robot_ip, remote_path, ftp_user, ftp_pass)
Definition: robodk.py:1312
def setTool(self, pose, tool_id=None, tool_name=None)
Definition: Nachi_AX_FD.py:224
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=None)
Definition: robodk.py:1458
def pose_2_str(pose, joints=None, reference=None)
Definition: Nachi_AX_FD.py:49
def ProgSave(self, folder, progname, ask_user=False, show_result=False)
Definition: Nachi_AX_FD.py:125
def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass)
Definition: Nachi_AX_FD.py:187
def __init__(self, robotpost=None, robotname=None, robot_axes=6, kwargs)
Definition: Nachi_AX_FD.py:86
def getSaveFile(strdir='C:\\', strfile='file.txt', strtitle='Save file as ...')
Definition: robodk.py:1354


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