def Load(self, rdk=None): #, stream_data=b''): """Save the class attributes as a RoboDK binary parameter""" # Use a dictionary and the str/eval buit-in conversion attribs_list = self._getAttribsSave() #if len(attribs_list) == 0: # print("Load settings: No attributes to load") # return False print("Loading data from RoboDK station...") if rdk is None: from robolink import Robolink rdk = Robolink() param_backup = self._SETTINGS_PARAM param_backup += "-Backup" bytes_data = rdk.getParam(param_backup, False) if len(bytes_data) > 0: import robodk result = robodk.ShowMessageYesNoCancel( "Something went wrong with the last test.\nRecover lost data?", "Auto recover") if result is None: return False elif not result: bytes_data = b'' # Clear backup data rdk.setParam(param_backup, b'', False) if len(bytes_data) <= 0: bytes_data = rdk.getParam(self._SETTINGS_PARAM, False) if len(bytes_data) <= 0: print("Load settings: No data for " + self._SETTINGS_PARAM) return False import pickle saved_dict = pickle.loads(bytes_data) for key in saved_dict.keys(): # if we have a list of attributes that we want, load it only if it is in the list if len(attribs_list) > 0 and not key in attribs_list: print("Obsolete variable saved (will be deleted): " + key) else: value = saved_dict[key] setattr(self, key, value) return True
def loadParameters(RDK=None): if RDK is None: RDK = Robolink() global RADIUS global PARENT radius = RDK.getParam(PARAM_RADIUS, True) if radius is not None and radius != '': RADIUS = float(radius) parent_name = RDK.getParam(PARAM_PARENT_NAME, True) if parent_name is not None and parent_name != '': item = RDK.Item(parent_name) if item.Valid() and item.Name() == parent_name: PARENT = item if PARENT is None: PARENT = RDK.ActiveStation()
class RunApplication: """Class to detect when the terminate signal is emited to stop an action. .. code-block:: python run = RunApplication() while run.Run(): # your main loop to run until the terminate signal is detected ... """ time_last = -1 param_name = None RDK = None def __init__(self, rdk=None): if rdk is None: from robolink import Robolink self.RDK = Robolink() else: self.RDK = rdk self.time_last = time.time() if len(sys.argv) > 0: path = sys.argv[0] folder = os.path.basename(os.path.dirname(path)) file = os.path.basename(path) if file.endswith(".py"): file = file[:-3] elif file.endswith(".exe"): file = file[:-4] self.param_name = file + "_" + folder self.RDK.setParam( self.param_name, "1") # makes sure we can run the file separately in debug mode def Run(self): time_now = time.time() if time_now - self.time_last < 0.25: return True self.time_last = time_now if self.param_name is None: # Unknown start return True keep_running = not (self.RDK.getParam(self.param_name) == 0) return keep_running
def loadParameters(RDK=None): if RDK is None: RDK = Robolink() global BOX_SIZE_XYZ global USE_METRIC global PARENT global CONV_PARENT size_x = RDK.getParam(PARAM_BOX_X, True) if size_x is not None and size_x != '': BOX_SIZE_XYZ[0] = float(size_x) size_y = RDK.getParam(PARAM_BOX_Y, True) if size_y is not None and size_y != '': BOX_SIZE_XYZ[1] = float(size_y) size_z = RDK.getParam(PARAM_BOX_Z, True) if size_z is not None and size_z != '': BOX_SIZE_XYZ[2] = float(size_z) metric = RDK.getParam(PARAM_UNITS, True) if metric is not None and metric != '': USE_METRIC = bool(metric == 'True') parent_name = RDK.getParam(PARAM_PARENT_NAME, True) if parent_name is not None and parent_name != '': item = RDK.Item(parent_name) if item.Valid() and item.Name() == parent_name: PARENT = item if PARENT is None: PARENT = RDK.ActiveStation() conv_parent_name = RDK.getParam(PARAM_CONV_PARENT_NAME, True) if conv_parent_name is not None and conv_parent_name != '': item = RDK.Item(conv_parent_name) if item.Valid() and item.Name() == conv_parent_name: CONV_PARENT = item
class robodk_api(driver): ''' This driver uses the RoboDK API to connect to a robot controller. It is based on the Robodk API (https://robodk.com/offline-programming). The driver will always provide access to the robot axis through the variable called "Axis" (float[6]). Optional variable definitions are used to access Station Parameters in RobotDK to be read or written by the driver. controller: str Robot name in RoboDK. Default = '', will take the first that founds. ''' def __init__(self, name: str, pipe: Optional[Pipe] = None): """ :param name: (optional) Name for the driver :param pipe: (optional) Pipe used to communicate with the driver thread. See gateway.py """ # Inherit driver.__init__(self, name, pipe) # Parameters self.controller = '' def connect(self) -> bool: """ Connect driver. : returns: True if connection stablished False if not """ try: #assert ROBODK_API_FOUND, "RoboDK API is not available." self._connection = Robolink() if self._connection: self.robot = self._connection.Item(self.controller) if self.robot: if self.robot.Valid() and self.robot.Type() == ITEM_TYPE_ROBOT: self.sendDebugInfo(f'Driver RoboDK Connected to {self.controller}...') return True else: self.sendDebugInfo(f'Item {self.controller} not found!') else: self.sendDebugInfo(f'Controler not found!') else: self.sendDebugInfo(f'Connection with Robolink not possible.') except Exception as e: self.sendDebugInfo('Exception '+str(e)) return False def disconnect(self): """ Disconnect driver. """ pass def addVariables(self, variables: dict): """ Add variables to the driver. Correctly added variables will be added to internal dictionary 'variables'. Any error adding a variable should be communicated to the server using sendDebugInfo() method. : param variables: Variables to add in a dict following the setup format. (See documentation) """ for var_id, var_data in variables.items(): try: if var_id == 'Axis': var_data['value'] = [None for i in range(var_data['size'])] self.variables[var_id] = var_data continue else: value = self._connection.getParam(var_id) if value is not None: var_data['value'] = None # Force first update self.variables[var_id] = var_data self.sendDebugVarInfo((f'SETUP: Variable found {var_id}', var_id)) continue except: pass self.sendDebugVarInfo((f'SETUP: Variable not found {var_id}', var_id)) def readVariables(self, variables: list) -> list: """ Read given variable values. In case that the read is not possible or generates an error BAD quality should be returned. : param variables: List of variable ids to be read. : returns: list of tupples including (var_id, var_value, VariableQuality) """ res = [] for var_id in variables: try: if var_id == 'Axis': new_value = self.robot.Joints().tr().rows[0] # robot joint rotations [Rax_1, Rax_2, Rax_3, Rax_4, Rax_5, Rax_6] new_value = [round(x,3) for x in new_value] res.append((var_id, new_value, VariableQuality.GOOD)) continue else: new_value = self._connection.getParam(var_id) if new_value is not None: new_value = self.getValueFromString(self.variables[var_id]['datatype'], new_value) res.append((var_id, new_value, VariableQuality.GOOD)) continue except: res.append((var_id, self.variables[var_id]['value'], VariableQuality.BAD)) return res def writeVariables(self, variables: list) -> list: """ Write given variable values. In case that the write is not possible or generates an error BAD quality should be returned. : param variables: List of tupples with variable ids and the values to be written (var_id, var_value). : returns: list of tupples including (var_id, var_value, VariableQuality) """ res = [] # TODO: Possible improvement can be to send multiple at once for (var_id, new_value) in variables: try: self._connection.setParam(var_id, new_value) res.append((var_id, new_value, VariableQuality.GOOD)) except: res.append((var_id, new_value, VariableQuality.BAD)) return res
def RecordProgram(): # Define the frames per second: FRAMES_PER_SECOND = 24 # Define the video extension (you may need to change the codec) #VIDEO_EXTENSION = ".avi" VIDEO_EXTENSION = ".mp4" # Choose the codec (mp4v, XVID or DIVX) #FOURCC = cv2.VideoWriter_fourcc(*'DIVX') # good quality (avi) #FOURCC = cv2.VideoWriter_fourcc(*'XVID') # low quality (avi) FOURCC = cv2.VideoWriter_fourcc(*'mp4v') # good quality (mp4) # Default screenshot style: SNAPSHOT_STYLE = "Snapshot" # Other snapshot styles are not recommended, otherwise it will create a delay and a lot of flickering # Instead, change the appearance of RoboDK in the menu Tools-Options-Display #SNAPSHOT_STYLE = "SnapshotWhite" #SNAPSHOT_STYLE = "SnapshotWhiteNoText" #SNAPSHOT_STYLE = "SnapshotNoTextNoFrames" PREFER_SOCKET = True # If available, prefer socket (usually faster) over temporary file to retrieve the image #------------------------------------------------------------------- # Use a temporary folder with tempfile.TemporaryDirectory(prefix='Record_') as td: RDK = Robolink() file_video_temp = os.path.join(td, 'RoboDK_Video' + VIDEO_EXTENSION) video = None frame = None use_socket = PREFER_SOCKET render_time_last = 0 time_per_frame = 1 / FRAMES_PER_SECOND app = RunApplication() while app.Run(): tic() # There's no need to get a new image if no render as occurred. render_time = int(RDK.Command("LastRender")) if (render_time_last != render_time): render_time_last = render_time def getSnapshot(use_socket, tempdir): fallback = False if use_socket: # Socket method. Added in version 5.3.2 try: bytes_img = RDK.Cam2D_Snapshot('', None) # None means station and will throw before version 5.3.2 if isinstance(bytes_img, bytes) and bytes_img != b'': return True, cv2.imdecode(np.frombuffer(bytes_img, np.uint8), cv2.IMREAD_UNCHANGED) except Exception: fallback = True pass # Fallback to tempfile method tf = tempdir + '/temp.png' if RDK.Command(SNAPSHOT_STYLE, tf) == 'OK': return not fallback, cv2.imread(tf) return False, None # Get the station snapshot success, frame = getSnapshot(use_socket, td) if not success: if use_socket: use_socket = False else: RDK.ShowMessage("Problems retrieving the RoboDK image buffer", False) break # Write the frame to the video file if video is None: # Requires at least one frame to extract the frame size. height, width = frame.shape[:2] video = cv2.VideoWriter(file_video_temp, FOURCC, FRAMES_PER_SECOND, (width, height)) video.write(frame) # Wait some time, if necessary, to have accurate frame rate elapsed = toc() if elapsed < time_per_frame: t_sleep = time_per_frame - elapsed print("Waiting for next frame: " + str(t_sleep)) pause(t_sleep) print("Done recording") # Check if nothing was saved if video is None: quit() video.release() # Save the file msg_str = "Saving video recording... " print(msg_str) RDK.ShowMessage(msg_str, False) # Create a suggested file name print("Saving video...") date_str = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") path_rdk = RDK.getParam('PATH_DESKTOP') # or path_rdk = RDK.getParam('PATH_OPENSTATION') file_name = "RoboDK-Video-" + date_str + VIDEO_EXTENSION # Ask the user to provide a file to save file_path = getSaveFileName(path_preference=path_rdk, strfile=file_name, defaultextension=VIDEO_EXTENSION, filetypes=[("Video file", "*" + VIDEO_EXTENSION)]) if not file_path: quit() # Save the file print("Saving video to: " + file_path) if os.path.exists(file_path): print("Deleting existing file: " + file_path) os.remove(file_path) # Move the file os.rename(file_video_temp, file_path) # Done msg_str = "Video recording saved: " + file_path print(msg_str) RDK.ShowMessage(msg_str, False)