Adept_Vplus.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 an Adept Smart Controller CS robots using Adept's V+ 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 # ----------------------------------------------------
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,w,p,r] = Pose_2_Adept(pose)
54  return ('TRANS(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)' % (x,y,z,w,p,r))
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  PROG_EXT = 'vb1' # set the program extension
65 
66  # other variables
67  ROBOT_POST = ''
68  ROBOT_NAME = ''
69  PROG_FILES = []
70 
71  PROG = ''
72  LOG = ''
73  nAxes = 6
74  TAB = ''
75  REF_FRAME = None
76  SPEED_PERCENT = 25
77 
78  def __init__(self, robotpost=None, robotname=None, robot_axes = 6, **kwargs):
79  self.ROBOT_POST = robotpost
80  self.ROBOT_NAME = robotname
81  self.PROG = ''
82  self.LOG = ''
83  self.nAxes = robot_axes
84 
85  def ProgStart(self, progname):
86  self.addline('.PROGRAM %s()' % progname)
87  self.TAB = ' '
88  self.addline('BASE 0,0,0,0')
89 
90  def ProgFinish(self, progname):
91  self.TAB = ''
92  self.addline('.END')
93 
94  def ProgSave(self, folder, progname, ask_user = False, show_result = False):
95  progname = progname + '.' + self.PROG_EXT
96  if ask_user or not DirExists(folder):
97  filesave = getSaveFile(folder, progname, 'Save program as...')
98  if filesave is not None:
99  filesave = filesave.name
100  else:
101  return
102  else:
103  filesave = folder + '/' + progname
104  fid = open(filesave, "w")
105  fid.write(self.PROG)
106  fid.close()
107  print('SAVED: %s\n' % filesave) # tell RoboDK the path of the saved file
108  self.PROG_FILES = filesave
109 
110  # open file with default application
111  if show_result:
112  if type(show_result) is str:
113  # Open file with provided application
114  import subprocess
115  p = subprocess.Popen([show_result, filesave])
116  elif type(show_result) is list:
117  import subprocess
118  p = subprocess.Popen(show_result + [filesave])
119  else:
120  # open file with default application
121  import os
122  os.startfile(filesave)
123  if len(self.LOG) > 0:
124  mbox('Program generation LOG:\n\n' + self.LOG)
125 
126  def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass):
127  """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".
128  The connection parameters must be provided in the robot connection menu of RoboDK"""
129  UploadFTP(self.PROG_FILES, robot_ip, remote_path, ftp_user, ftp_pass)
130 
131  def MoveJ(self, pose, joints, conf_RLF=None):
132  """Add a joint movement"""
133  for i in range(len(joints)):
134  self.addline('DRIVE %i, %.3f, %.1f' % (i+1, joints[i], self.SPEED_PERCENT))
135  if pose is not None:
136  self.addline('MOVE frame1:' + pose_2_str(pose,joints))
137 
138  def MoveL(self, pose, joints, conf_RLF=None):
139  """Add a linear movement"""
140  if pose is None:
141  self.setFrame(eye(4))
142  self.addline('MOVES frame1:' + pose_2_str(pose,joints))
143 
144  def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None):
145  """Add a circular movement"""
146  self.addlog('Circular move is not supported!')
147 
148  def setFrame(self, pose, frame_id=None, frame_name=None):
149  """Change the robot reference frame"""
150  self.REF_FRAME = pose
151  self.addline('SET frame1 = ' + pose_2_str(pose))
152  # Adept's V+ for Staubli does not support changing the reference frame using complete orientation definition. We must then shift all targets and use the robot reference frame as the active reference frame
153 
154  def setTool(self, pose, tool_id=None, tool_name=None):
155  """Change the robot TCP"""
156  self.addline('TOOL ' + pose_2_str(pose))
157 
158  def Pause(self, time_ms):
159  """Pause the robot program"""
160  if time_ms <= 0:
161  self.addline('PAUSE')
162  else:
163  self.addline('DELAY %.3f' % (time_ms*0.001))
164 
165  def setSpeed(self, speed_mms):
166  """Changes the robot speed (in mm/s)"""
167  # assume 4000 mm/s to be 100% of the speed
168  self.SPEED_PERCENT = min(100*speed_mms/4000, 100)
169  self.addline('SPEED %.1f, 100 MMPS ALWAYS' % (speed_mms))
170  #self.addline('SPEED %.1f, %.1f MMPS ALWAYS' % (speed_mms, seld.SPEED_PERCENT))
171 
172  def setAcceleration(self, accel_mmss):
173  """Changes the robot acceleration (in mm/s2)"""
174  # Warning! Here, acceleration in mmss is considered as a percentage!
175  accel_percentage = min(100,max(0,accel_mmss))
176  self.addline('ACCEL %.1f, %.1f' % (accel_percentage, accel_percentage))
177 
178  def setSpeedJoints(self, speed_degs):
179  """Changes the robot joint speed (in deg/s)"""
180  self.addlog('setSpeedJoints not defined')
181 
182  def setAccelerationJoints(self, accel_degss):
183  """Changes the robot joint acceleration (in deg/s2)"""
184  self.addlog('setAccelerationJoints not defined')
185 
186  def setZoneData(self, zone_mm):
187  """Changes the zone data approach (makes the movement more smooth)"""
188  self.addlog('setZoneData not defined (%.1f mm)' % zone_mm)
189 
190  def setDO(self, io_var, io_value):
191  """Sets a variable (output) to a given value"""
192  if type(io_var) != str: # set default variable name if io_var is a number
193  io_var = 'OUT[%s]' % str(io_var)
194  if type(io_value) != str: # set default variable value if io_value is a number
195  if io_value > 0:
196  io_value = 'TRUE'
197  else:
198  io_value = 'FALSE'
199 
200  # at this point, io_var and io_value must be string values
201  self.addline('%s=%s' % (io_var, io_value))
202 
203  def waitDI(self, io_var, io_value, timeout_ms=-1):
204  """Waits for an input io_var to attain a given value io_value. Optionally, a timeout can be provided."""
205  if type(io_var) != str: # set default variable name if io_var is a number
206  io_var = 'IN[%s]' % str(io_var)
207  if type(io_value) != str: # set default variable value if io_value is a number
208  if io_value > 0:
209  io_value = 'TRUE'
210  else:
211  io_value = 'FALSE'
212 
213  # at this point, io_var and io_value must be string values
214  if timeout_ms < 0:
215  self.addline('WAIT FOR %s==%s' % (io_var, io_value))
216  else:
217  self.addline('WAIT FOR %s==%s TIMEOUT=%.1f' % (io_var, io_value, timeout_ms))
218 
219  def RunCode(self, code, is_function_call = False):
220  """Adds code or a function call"""
221  if is_function_call:
222  code.replace(' ','_')
223  if code.find('(') < 0:
224  code = code + '()'
225  self.addline(code)
226  else:
227  self.addline(code)
228 
229  def RunMessage(self, message, iscomment = False):
230  """Add a joint movement"""
231  if iscomment:
232  self.addline('; ' + message)
233  else:
234  self.addline('TYPE "' + message + '"')
235 
236 # ------------------ private ----------------------
237  def addline(self, newline):
238  """Add a program line"""
239  self.PROG = self.PROG + self.TAB + newline + '\n'
240 
241  def addlog(self, newline):
242  """Add a log message"""
243  self.LOG = self.LOG + newline + '\n'
244 
245 # -------------------------------------------------
246 # ------------ For testing purposes ---------------
247 def Pose(xyzrpw):
248  [x,y,z,r,p,w] = xyzrpw
249  a = r*math.pi/180
250  b = p*math.pi/180
251  c = w*math.pi/180
252  ca = math.cos(a)
253  sa = math.sin(a)
254  cb = math.cos(b)
255  sb = math.sin(b)
256  cc = math.cos(c)
257  sc = math.sin(c)
258  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]])
259 
260 def test_post():
261  """Test the post with a basic program"""
262 
263  robot = RobotPost('Vplus_custom', 'Generic Adept Robot')
264 
265  robot.ProgStart("Program")
266  robot.RunMessage("Program generated by RoboDK", True)
267  robot.setFrame(Pose([807.766544, -963.699898, 41.478944, 0, 0, 0]))
268  robot.setTool(Pose([62.5, -108.253175, 100, -60, 90, 0]))
269  robot.MoveJ(Pose([200, 200, 500, 180, 0, 180]), [-46.18419, -6.77518, -20.54925, 71.38674, 49.58727, -302.54752] )
270  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
271  robot.MoveL(Pose([200, 200, 262.132034, 180, 0, -150]), [-43.73892, -3.91728, -35.77935, 58.57566, 54.11615, -253.81122] )
272  robot.RunMessage("Setting air valve 1 on")
273  robot.RunCode("TCP_On", True)
274  robot.Pause(1000)
275  robot.MoveL(Pose([200, 250, 348.734575, 180, 0, -150]), [-41.62707, -8.89064, -30.01809, 60.62329, 49.66749, -258.98418] )
276  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
277  robot.MoveL(Pose([250, 250, 191.421356, 180, 0, -150]), [-39.75778, -1.04537, -40.37883, 52.09118, 54.15317, -246.94403] )
278  robot.RunMessage("Setting air valve off")
279  robot.RunCode("TCP_Off(55)", True)
280  robot.Pause(1000)
281  robot.MoveL(Pose([250, 300, 278.023897, 180, 0, -150]), [-37.52588, -6.32628, -34.59693, 53.52525, 49.24426, -251.44677] )
282  robot.MoveL(Pose([250, 200, 278.023897, 180, 0, -150]), [-41.85389, -1.95619, -34.89154, 57.43912, 52.34162, -253.73403] )
283  robot.MoveL(Pose([250, 150, 191.421356, 180, 0, -150]), [-43.82111, 3.29703, -40.29493, 56.02402, 56.61169, -249.23532] )
284  robot.ProgFinish("Program")
285  # robot.ProgSave(".","Program",True)
286  print(robot.PROG)
287  if len(robot.LOG) > 0:
288  mbox('Program generation LOG:\n\n' + robot.LOG)
289 
290  input("Press Enter to close...")
291 
292 if __name__ == "__main__":
293  """Function to call when the module is executed by itself: test"""
294  test_post()
def MoveJ(self, pose, joints, conf_RLF=None)
Definition: Adept_Vplus.py:131
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: Adept_Vplus.py:154
def RunCode(self, code, is_function_call=False)
Definition: Adept_Vplus.py:219
def ProgSave(self, folder, progname, ask_user=False, show_result=False)
Definition: Adept_Vplus.py:94
def MoveL(self, pose, joints, conf_RLF=None)
Definition: Adept_Vplus.py:138
def waitDI(self, io_var, io_value, timeout_ms=-1)
Definition: Adept_Vplus.py:203
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=None)
Definition: robodk.py:1458
def __init__(self, robotpost=None, robotname=None, robot_axes=6, kwargs)
Definition: Adept_Vplus.py:78
def RunMessage(self, message, iscomment=False)
Definition: Adept_Vplus.py:229
def setFrame(self, pose, frame_id=None, frame_name=None)
Definition: Adept_Vplus.py:148
def MoveC(self, pose1, joints1, pose2, joints2, conf_RLF_1=None, conf_RLF_2=None)
Definition: Adept_Vplus.py:144
def getSaveFile(strdir='C:\\', strfile='file.txt', strtitle='Save file as ...')
Definition: robodk.py:1354
def ProgSendRobot(self, robot_ip, remote_path, ftp_user, ftp_pass)
Definition: Adept_Vplus.py:126
def pose_2_str(pose, joints=None, reference=None)
Definition: Adept_Vplus.py:49


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