async def update_action_point_using_robot_cb( req: rpc.project.UpdateActionPointUsingRobotRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) new_pose = await get_end_effector_pose(req.args.robot.robot_id, req.args.robot.end_effector) if ap.parent: new_pose = tr.make_pose_rel_to_parent(glob.SCENE, glob.PROJECT, new_pose, ap.parent) ap.invalidate_joints() for joints in ap.robot_joints: asyncio.ensure_future( notif.broadcast_event( events.JointsChanged(events.EventType.UPDATE, ap.id, data=joints))) ap.position = new_pose.position glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionPointChanged(events.EventType.UPDATE_BASE, data=ap.bare()))) return None
async def remove_from_scene_cb(req: rpc.scene.RemoveFromSceneRequest, ui: WsClient) -> None: assert glob.SCENE if not req.args.force and { proj.name async for proj in projects_using_object(glob.SCENE.id, req.args.id) }: raise Arcor2Exception( "Can't remove object/service that is used in project(s).") if req.dry_run: return None if req.args.id in glob.SCENE_OBJECT_INSTANCES: obj = glob.SCENE.object(req.args.id) glob.SCENE.objects = [ obj for obj in glob.SCENE.objects if obj.id != req.args.id ] obj_inst = glob.SCENE_OBJECT_INSTANCES[req.args.id] await collision(obj_inst, remove=True) del glob.SCENE_OBJECT_INSTANCES[req.args.id] if req.args.id in OBJECTS_WITH_UPDATED_POSE: OBJECTS_WITH_UPDATED_POSE.remove(req.args.id) asyncio.ensure_future( notif.broadcast_event( events.SceneObjectChanged(events.EventType.REMOVE, data=obj))) elif req.args.id in glob.SERVICES_INSTANCES: # first check if some object is not using it for obj in glob.SCENE.objects: if req.args.id in glob.OBJECT_TYPES[obj.type].needs_services: raise Arcor2Exception( f"Object {obj.id} ({obj.type}) " f"relies on the service to be removed: {req.args.id}.") srv = glob.SCENE.service(req.args.id) glob.SCENE.services = [ srv for srv in glob.SCENE.services if srv.type != req.args.id ] del glob.SERVICES_INSTANCES[req.args.id] asyncio.ensure_future( notif.broadcast_event( events.SceneServiceChanged(events.EventType.REMOVE, data=srv))) else: raise Arcor2Exception("Unknown id.") glob.SCENE.update_modified() asyncio.ensure_future(remove_object_references_from_projects(req.args.id)) return None
async def remove_action_point_joints_cb( req: rpc.project.RemoveActionPointJointsRequest, ui: WsClient) -> None: """ Removes joints from action point. :param req: :return: """ assert glob.SCENE and glob.PROJECT ap, joints = glob.PROJECT.ap_and_joints(req.args.joints_id) for act in glob.PROJECT.actions(): for param in act.parameters: if PARAM_PLUGINS[param.type].uses_robot_joints( glob.PROJECT, act.id, param.id, req.args.joints_id): raise Arcor2Exception( f"Joints used in action {act.name} (parameter {param.id})." ) joints_to_be_removed = ap.joints(req.args.joints_id) ap.robot_joints = [ joints for joints in ap.robot_joints if joints.id != req.args.joints_id ] glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.JointsChanged(events.EventType.REMOVE, data=joints_to_be_removed))) return None
async def rename_object_cb(req: rpc.scene.RenameObjectRequest, ui: WsClient) -> None: assert glob.SCENE target_obj = glob.SCENE.object(req.args.id) for obj_name in glob.SCENE.object_names(): if obj_name == req.args.new_name: raise Arcor2Exception("Object name already exists.") if not hlp.is_valid_identifier(req.args.new_name): raise Arcor2Exception("Object name invalid (should be snake_case).") if req.dry_run: return None target_obj.name = req.args.new_name glob.SCENE.update_modified() asyncio.ensure_future( notif.broadcast_event( events.SceneObjectChanged(events.EventType.UPDATE, data=target_obj))) return None
async def update_service_configuration_cb( req: rpc.scene.UpdateServiceConfigurationRequest, ui: WsClient) -> None: assert glob.SCENE srv = glob.SCENE.service(req.args.type) # first check if some object is not using it for obj in glob.SCENE.objects: if req.args.type in glob.OBJECT_TYPES[obj.type].needs_services: raise Arcor2Exception( f"Object {obj.name} ({obj.type}) relies " f"on the service to be removed: {req.args.type}.") if req.dry_run: return None # TODO destroy current instance glob.SERVICES_INSTANCES[req.args.type] = await hlp.run_in_executor( glob.TYPE_DEF_DICT[req.args.type], req.args.new_configuration) srv.configuration_id = req.args.new_configuration glob.SCENE.update_modified() asyncio.ensure_future( notif.broadcast_event( events.SceneServiceChanged(events.EventType.UPDATE, data=srv))) return None
async def new_scene_cb(req: rpc.scene.NewSceneRequest, ui: WsClient) -> None: """ Creates and opens a new scene on the server. Fails if any scene is open or if scene id/name already exists. :param req: :return: """ if glob.PACKAGE_STATE.state in (common.PackageStateEnum.PAUSED, common.PackageStateEnum.RUNNING): raise Arcor2Exception("Can't create scene while package runs.") assert glob.SCENE is None for scene_id in (await storage.get_scenes()).items: if req.args.name == scene_id.name: raise Arcor2Exception("Name already used.") if req.dry_run: return None glob.SCENE = common.Scene(common.uid(), req.args.name, desc=req.args.desc) asyncio.ensure_future( notif.broadcast_event( events.OpenScene(data=events.OpenSceneData(glob.SCENE)))) return None
async def rename_action_point_cb(req: rpc.project.RenameActionPointRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) if req.args.new_name == ap.name: return None if not hlp.is_valid_identifier(req.args.new_name): raise Arcor2Exception("Name has to be valid Python identifier.") unique_name(req.args.new_name, glob.PROJECT.action_points_names) if req.dry_run: return None ap.name = req.args.new_name glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionPointChanged(events.EventType.UPDATE_BASE, data=ap.bare()))) return None
async def update_action_cb(req: rpc.project.UpdateActionRequest, ui: WsClient) -> None: assert glob.PROJECT assert glob.SCENE updated_project = copy.deepcopy(glob.PROJECT) updated_action = updated_project.action(req.args.action_id) updated_action.parameters = req.args.parameters check_action_params(updated_project, updated_action, find_object_action(updated_action)) if req.dry_run: return None orig_action = glob.PROJECT.action(req.args.action_id) orig_action.parameters = updated_action.parameters glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionChanged(events.EventType.UPDATE, data=updated_action))) return None
async def remove_action_point_orientation_cb(req: rpc.project.RemoveActionPointOrientationRequest, ui: WsClient) -> \ None: """ Removes orientation. :param req: :return: """ assert glob.SCENE and glob.PROJECT ap, orientation = glob.PROJECT.ap_and_orientation(req.args.action_point_id) for act in glob.PROJECT.actions(): for param in act.parameters: if PARAM_PLUGINS[param.type].uses_orientation( glob.PROJECT, act.id, param.id, req.args.orientation_id): raise Arcor2Exception( f"Orientation used in action {act.name} (parameter {param.id})." ) if req.dry_run: return None ap.orientations = [ ori for ori in ap.orientations if ori.id != req.args.orientation_id ] glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.OrientationChanged(events.EventType.REMOVE, data=orientation))) return None
async def add_action_cb(req: rpc.project.AddActionRequest, ui: WsClient) -> None: assert glob.PROJECT assert glob.SCENE ap = glob.PROJECT.action_point(req.args.action_point_id) unique_name(req.args.name, glob.PROJECT.action_user_names()) if not hlp.is_valid_identifier(req.args.name): raise Arcor2Exception("Action name has to be valid Python identifier.") new_action = common.Action(common.uid(), req.args.name, req.args.type, req.args.parameters) updated_project = copy.deepcopy(glob.PROJECT) updated_ap = updated_project.action_point(req.args.action_point_id) updated_ap.actions.append(new_action) check_action_params(updated_project, new_action, find_object_action(new_action)) if req.dry_run: return None ap.actions.append(new_action) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionChanged(events.EventType.ADD, ap.id, data=new_action))) return None
async def update_action_point_orientation_using_robot_cb( req: rpc.project.UpdateActionPointOrientationUsingRobotRequest, ui: WsClient) -> None: """ Updates orientation and joint of the action point. :param req: :return: """ assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) new_pose = await get_end_effector_pose(req.args.robot.robot_id, req.args.robot.end_effector) if ap.parent: new_pose = tr.make_pose_rel_to_parent(glob.SCENE, glob.PROJECT, new_pose, ap.parent) ori = glob.PROJECT.orientation(req.args.orientation_id) ori.orientation = new_pose.orientation glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.OrientationChanged(events.EventType.UPDATE, data=ori))) return None
async def add_action_point_orientation_using_robot_cb( req: rpc.project.AddActionPointOrientationUsingRobotRequest, ui: WsClient) -> None: """ Adds orientation and joints to the action point. :param req: :return: """ assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) unique_name(req.args.name, ap.orientation_names()) if req.dry_run: return None new_pose = await get_end_effector_pose(req.args.robot.robot_id, req.args.robot.end_effector) if ap.parent: new_pose = tr.make_pose_rel_to_parent(glob.SCENE, glob.PROJECT, new_pose, ap.parent) orientation = common.NamedOrientation(common.uid(), req.args.name, new_pose.orientation) ap.orientations.append(orientation) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.OrientationChanged(events.EventType.ADD, ap.id, data=orientation))) return None
async def add_action_point_orientation_cb( req: rpc.project.AddActionPointOrientationRequest, ui: WsClient) -> None: """ Adds orientation and joints to the action point. :param req: :return: """ assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) unique_name(req.args.name, ap.orientation_names()) if req.dry_run: return None orientation = common.NamedOrientation(common.uid(), req.args.name, req.args.orientation) ap.orientations.append(orientation) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.OrientationChanged(events.EventType.ADD, ap.id, data=orientation))) return None
async def update_action_logic_cb(req: rpc.project.UpdateActionLogicRequest, ui: WsClient) -> None: assert glob.PROJECT assert glob.SCENE action = glob.PROJECT.action(req.args.action_id) allowed_values = glob.PROJECT.action_ids() | common.ActionIOEnum.set() | { "" } for inp in req.args.inputs: if inp.default not in allowed_values: raise Arcor2Exception("Unknown input value.") for out in req.args.outputs: if out.default not in allowed_values: raise Arcor2Exception("Unknown output value.") action.inputs = req.args.inputs action.outputs = req.args.outputs glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionChanged(events.EventType.UPDATE, data=action))) return None
async def focus_object_done_cb(req: rpc.objects.FocusObjectDoneRequest, ui: WsClient) -> None: obj_id = req.args.id if obj_id not in FOCUS_OBJECT: raise Arcor2Exception( "focusObjectStart/focusObject has to be called first.") obj_type = glob.OBJECT_TYPES[osa.get_obj_type_name(obj_id)] assert obj_type.object_model and obj_type.object_model.mesh focus_points = obj_type.object_model.mesh.focus_points assert focus_points if len(FOCUS_OBJECT[obj_id]) < len(focus_points): raise Arcor2Exception("Not all points were done.") robot_id, end_effector = FOCUS_OBJECT_ROBOT[obj_id].as_tuple() robot_inst = await osa.get_robot_instance(robot_id) assert hasattr(robot_inst, "focus") # mypy does not deal with hasattr assert glob.SCENE obj = glob.SCENE.object(obj_id) fp: List[Position] = [] rp: List[Position] = [] for idx, pose in FOCUS_OBJECT[obj_id].items(): fp.append(focus_points[idx].position) rp.append(pose.position) mfa = MeshFocusAction(fp, rp) await glob.logger.debug( f'Attempt to focus for object {obj_id}, data: {mfa}') try: obj.pose = await hlp.run_in_executor(robot_inst.focus, mfa) # type: ignore except Arcor2Exception as e: await glob.logger.error(f"Focus failed with: {e}, mfa: {mfa}.") raise Arcor2Exception("Focusing failed.") from e await glob.logger.info(f"Done focusing for {obj_id}.") clean_up_after_focus(obj_id) asyncio.ensure_future( notif.broadcast_event( events.SceneObjectChanged(events.EventType.UPDATE, data=obj))) asyncio.ensure_future(scene_object_pose_updated(glob.SCENE.id, obj.id)) return None
async def save_project_cb(req: rpc.project.SaveProjectRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT await storage.update_project(glob.PROJECT) glob.PROJECT.modified = (await storage.get_project(glob.PROJECT.id)).modified asyncio.ensure_future(notif.broadcast_event(events.ProjectSaved())) return None
async def delete_project_cb(req: rpc.project.DeleteProjectRequest, ui: WsClient) -> None: project = await storage.get_project(req.args.id) await storage.delete_project(req.args.id) asyncio.ensure_future( notif.broadcast_event( events.ProjectChanged(events.EventType.REMOVE, data=project.bare()))) return None
async def save_scene_cb(req: rpc.scene.SaveSceneRequest, ui: WsClient) -> None: assert glob.SCENE await storage.update_scene(glob.SCENE) glob.SCENE.modified = (await storage.get_scene(glob.SCENE.id)).modified asyncio.ensure_future(notif.broadcast_event(events.SceneSaved())) for obj_id in OBJECTS_WITH_UPDATED_POSE: asyncio.ensure_future(scene_object_pose_updated(glob.SCENE.id, obj_id)) OBJECTS_WITH_UPDATED_POSE.clear() return None
async def copy_scene_cb(req: rpc.scene.CopySceneRequest, ui: WsClient) -> None: # TODO check if target_name is unique async with managed_scene(req.args.source_id, make_copy=True) as scene: scene.name = req.args.target_name asyncio.ensure_future( notif.broadcast_event( events.SceneChanged(events.EventType.UPDATE_BASE, data=scene.bare()))) return None
async def update_scene_description_cb( req: rpc.scene.UpdateSceneDescriptionRequest, ui: WsClient) -> None: async with managed_scene(req.args.scene_id) as scene: scene.desc = req.args.new_description scene.update_modified() asyncio.ensure_future( notif.broadcast_event( events.SceneChanged(events.EventType.UPDATE_BASE, data=scene.bare()))) return None
async def open_scene_cb(req: rpc.scene.OpenSceneRequest, ui: WsClient) -> None: if glob.PACKAGE_STATE.state in (common.PackageStateEnum.PAUSED, common.PackageStateEnum.RUNNING): raise Arcor2Exception("Can't open scene while package runs.") await open_scene(req.args.id) assert glob.SCENE asyncio.ensure_future( notif.broadcast_event( events.OpenScene(data=events.OpenSceneData(glob.SCENE)))) return None
async def update_project_description_cb( req: rpc.project.UpdateProjectDescriptionRequest, ui: WsClient) -> None: async with managed_project(req.args.project_id) as project: project.desc = req.args.new_description project.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ProjectChanged(events.EventType.UPDATE_BASE, data=project.bare()))) return None
async def update_action_point_position_cb( req: rpc.project.UpdateActionPointPositionRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) ap.position = req.args.new_position ap.invalidate_joints() for joints in ap.robot_joints: asyncio.ensure_future( notif.broadcast_event( events.JointsChanged(events.EventType.UPDATE, ap.id, data=joints))) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionPointChanged(events.EventType.UPDATE_BASE, data=ap.bare()))) return None
async def new_object_type_cb(req: rpc.objects.NewObjectTypeRequest, ui: WsClient) -> None: meta = req.args if meta.type in glob.OBJECT_TYPES: raise Arcor2Exception("Object type already exists.") if meta.base not in glob.OBJECT_TYPES: raise Arcor2Exception( f"Unknown base object type '{meta.base}', " f"known types are: {', '.join(glob.OBJECT_TYPES.keys())}.") if not hlp.is_valid_type(meta.type): raise Arcor2Exception("Object type invalid (should be CamelCase).") if req.dry_run: return None obj = meta.to_object_type() obj.source = new_object_type_source(glob.OBJECT_TYPES[meta.base], meta) if meta.object_model and meta.object_model.type != Model3dType.MESH: assert meta.type == meta.object_model.model().id await storage.put_model(meta.object_model.model()) # TODO check whether mesh id exists - if so, then use existing mesh, if not, upload a new one if meta.object_model and meta.object_model.type == Model3dType.MESH: # ...get whole mesh (focus_points) based on mesh id assert meta.object_model.mesh try: meta.object_model.mesh = await storage.get_mesh( meta.object_model.mesh.id) except storage.PersistentStorageException as e: await glob.logger.error(e) raise Arcor2Exception( f"Mesh ID {meta.object_model.mesh.id} does not exist.") await storage.update_object_type(obj) glob.OBJECT_TYPES[meta.type] = meta glob.ACTIONS[meta.type] = otu.object_actions( TYPE_TO_PLUGIN, hlp.type_def_from_source(obj.source, obj.id, Generic), obj.source) otu.add_ancestor_actions(meta.type, glob.ACTIONS, glob.OBJECT_TYPES) asyncio.ensure_future( notif.broadcast_event( events.ChangedObjectTypesEvent(events.EventType.ADD, data=[meta]))) return None
async def rename_scene_cb(req: rpc.scene.RenameSceneRequest, ui: WsClient) -> None: unique_name(req.args.new_name, (await scene_names())) if req.dry_run: return None async with managed_scene(req.args.id) as scene: scene.name = req.args.new_name asyncio.ensure_future( notif.broadcast_event( events.SceneChanged(events.EventType.UPDATE_BASE, data=scene.bare()))) return None
async def update_project_has_logic_cb( req: rpc.project.UpdateProjectHasLogicRequest, ui: WsClient) -> None: async with managed_project(req.args.project_id) as project: if project.has_logic and not req.args.new_has_logic: for act in project.actions(): act.inputs.clear() act.outputs.clear() if glob.PROJECT and glob.PROJECT.id == req.args.project_id: asyncio.ensure_future( notif.broadcast_event( events.ActionChanged(events.EventType.UPDATE, data=act))) project.has_logic = req.args.new_has_logic project.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ProjectChanged(events.EventType.UPDATE_BASE, data=project.bare()))) return None
async def update_action_point_joints_cb( req: rpc.project.UpdateActionPointJointsRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT robot_joints = glob.PROJECT.joints(req.args.joints_id) new_joints = await get_robot_joints(req.args.robot_id) robot_joints.joints = new_joints robot_joints.robot_id = req.args.robot_id robot_joints.is_valid = True glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.JointsChanged(events.EventType.UPDATE, data=robot_joints))) return None
async def copy_project_cb(req: rpc.project.CopyProjectRequest, ui: WsClient) -> None: unique_name(req.args.target_name, (await project_names())) if req.dry_run: return None async with managed_project(req.args.source_id, make_copy=True) as project: project.name = req.args.target_name asyncio.ensure_future( notif.broadcast_event( events.ProjectChanged(events.EventType.UPDATE_BASE, data=project.bare()))) return None
async def add_service_to_scene_cb(req: rpc.scene.AddServiceToSceneRequest, ui: WsClient) -> None: assert glob.SCENE srv = req.args await add_service_to_scene(srv, req.dry_run) if req.dry_run: return None glob.SCENE.services.append(srv) glob.SCENE.update_modified() asyncio.ensure_future( notif.broadcast_event( events.SceneServiceChanged(events.EventType.ADD, data=srv))) return None
async def cancel_action_cb(req: rpc.project.CancelActionRequest, ui: WsClient) -> None: assert glob.PROJECT if not glob.RUNNING_ACTION: raise Arcor2Exception("No action is running.") action = glob.PROJECT.action(glob.RUNNING_ACTION) obj_id, action_name = action.parse_type() obj = get_instance(obj_id) for act in glob.ACTIONS[obj.__class__.__name__]: if act.name != action_name: continue if not act.meta.cancellable: raise Arcor2Exception("Action is not cancellable.") try: action_method = getattr(obj, action_name) cancel_method = getattr(obj, obj.CANCEL_MAPPING[action_method.__name__]) except AttributeError as e: raise Arcor2Exception("Internal error.") from e cancel_params: Dict[str, Any] = {} cancel_sig = inspect.signature(cancel_method) assert glob.RUNNING_ACTION_PARAMS is not None for param_name, param in cancel_sig.parameters.items(): try: cancel_params[param_name] = glob.RUNNING_ACTION_PARAMS[param_name] except KeyError as e: raise Arcor2Exception( "Cancel method parameters should be subset of action parameters." ) from e await hlp.run_in_executor(cancel_method, *cancel_params.values()) asyncio.ensure_future(notif.broadcast_event(events.ActionCancelledEvent())) glob.RUNNING_ACTION = None glob.RUNNING_ACTION_PARAMS = None