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


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