Ejemplo n.º 1
0
async def managed_scene(
        scene_id: str,
        make_copy: bool = False
) -> AsyncGenerator[UpdateableCachedScene, None]:

    save_back = False

    if glob.SCENE and glob.SCENE.id == scene_id:
        if make_copy:
            scene = copy.deepcopy(glob.SCENE)
            save_back = True
        else:
            scene = glob.SCENE
    else:
        save_back = True
        scene = UpdateableCachedScene(await storage.get_scene(scene_id))

    if make_copy:
        scene.id = common.Scene.uid()

    try:
        yield scene
    finally:
        if save_back:
            asyncio.ensure_future(storage.update_scene(scene.scene))
Ejemplo n.º 2
0
async def add_object_to_scene(scene: UpdateableCachedScene, obj: SceneObject, dry_run: bool = False) -> None:
    """

    :param obj:
    :param add_to_scene: Set to false to only create object instance and add its collision model (if any).
    :return:
    """

    check_object(scene, obj, new_one=True)

    if dry_run:
        return None

    scene.upsert_object(obj)
    glob.logger.debug(f"Object {obj.id} ({obj.type}) added to scene.")
Ejemplo n.º 3
0
def lock() -> Lock:
    """Creates lock with initialized scene and project."""
    test = "test"
    lock = Lock({})

    scene = UpdateableCachedScene(cmn.Scene(test, description=test))
    lock.scene = scene
    project = UpdateableCachedProject(cmn.Project(test, lock.scene.id, description=test, has_logic=True))
    lock.project = project

    assert lock.scene == scene
    assert lock.scene_or_exception() == scene

    assert lock.project == project
    assert lock.project_or_exception() == project

    # add some scene and project objects
    test_object = cmn.SceneObject(test, "TestType")
    lock.scene.upsert_object(test_object)
    ap = lock.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap", cmn.Position(0, 0, 0))
    ap_ap = lock.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap_ap", cmn.Position(0, 0, 1), ap.id)
    ap_ap_ap = lock.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap_ap_ap", cmn.Position(0, 0, 2), ap_ap.id)
    lock.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap2", cmn.Position(0, 1, 0))
    ori = cmn.NamedOrientation("ori", cmn.Orientation())
    lock.project.upsert_orientation(ap_ap_ap.id, ori)
    action = cmn.Action("action", "test/type", parameters=[], flows=[])
    lock.project.upsert_action(ap_ap_ap.id, action)
    return lock
Ejemplo n.º 4
0
async def new_scene_cb(req: srpc.s.NewScene.Request, 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 PackageState.RUN_STATES:
        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

    await get_object_types()  # TODO not ideal, may take quite long time
    glob.SCENE = UpdateableCachedScene(
        common.Scene(req.args.name, desc=req.args.desc))
    asyncio.ensure_future(
        notif.broadcast_event(
            sevts.s.OpenScene(sevts.s.OpenScene.Data(glob.SCENE.scene))))
    asyncio.ensure_future(scene_srv.delete_all_collisions())  # just for sure
    return None
Ejemplo n.º 5
0
async def calibrate_camera(scene: UpdateableCachedScene,
                           camera: Camera) -> None:

    assert camera.color_camera_params

    await notif.broadcast_event(
        ProcessState(
            ProcessState.Data(CAMERA_CALIB,
                              ProcessState.Data.StateEnum.Started)))
    try:
        img = await run_in_executor(camera.color_image)
        estimated_pose = await run_in_executor(
            calib_client.estimate_camera_pose, camera.color_camera_params, img)
    except Arcor2Exception as e:
        await notif.broadcast_event(
            ProcessState(
                ProcessState.Data(CAMERA_CALIB,
                                  ProcessState.Data.StateEnum.Failed, str(e))))
        glob.logger.exception("Failed to calibrate the camera.")
        return

    await update_scene_object_pose(scene, scene.object(camera.id),
                                   estimated_pose.pose, camera)
    await notif.broadcast_event(
        ProcessState(
            ProcessState.Data(CAMERA_CALIB,
                              ProcessState.Data.StateEnum.Finished)))
Ejemplo n.º 6
0
async def delete_scene_cb(
        req: srpc.s.DeleteScene.Request,
        ui: WsClient) -> Optional[srpc.s.DeleteScene.Response]:

    if glob.LOCK.scene:
        raise Arcor2Exception("Scene has to be closed first.")

    user_name = glob.USERS.user_name(ui)

    async with ctx_write_lock(req.args.id, user_name, auto_unlock=req.dry_run):
        assoc_projects = await associated_projects(req.args.id)

        if assoc_projects:
            resp = srpc.s.DeleteScene.Response(result=False)
            resp.messages = ["Scene has associated projects."]
            resp.data = assoc_projects
            asyncio.create_task(glob.LOCK.write_unlock(req.args.id, user_name))
            return resp

        if req.dry_run:
            return None

        scene = UpdateableCachedScene(await storage.get_scene(req.args.id))
        asyncio.create_task(glob.LOCK.write_unlock(req.args.id, user_name))
        await storage.delete_scene(req.args.id)
        evt = sevts.s.SceneChanged(scene.bare)
        evt.change_type = Event.Type.REMOVE
        asyncio.ensure_future(notif.broadcast_event(evt))
        return None
Ejemplo n.º 7
0
async def new_scene_cb(req: srpc.s.NewScene.Request, 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:
    """

    async with glob.LOCK.get_lock(dry_run=req.dry_run):
        if glob.PACKAGE_STATE.state in PackageState.RUN_STATES:
            raise Arcor2Exception("Can't create scene while package runs.")

        if glob.LOCK.scene:
            raise Arcor2Exception("Scene has to be closed first.")

        for scene_id in await storage.get_scenes():
            if req.args.name == scene_id.name:
                raise Arcor2Exception("Name already used.")

        if req.dry_run:
            return None

        await get_object_types()  # TODO not ideal, may take quite long time
        glob.LOCK.scene = UpdateableCachedScene(
            common.Scene(req.args.name, description=req.args.description))
        asyncio.ensure_future(
            notify_scene_opened(
                sevts.s.OpenScene(sevts.s.OpenScene.Data(
                    glob.LOCK.scene.scene))))
        asyncio.ensure_future(
            scene_srv.delete_all_collisions())  # just for sure
        return None
Ejemplo n.º 8
0
async def update_scene_object_pose(
    scene: UpdateableCachedScene,
    obj: SceneObject,
    pose: Optional[Pose] = None,
    obj_inst: Optional[GenericWithPose] = None,
    lock_owner: Optional[str] = None,
) -> None:
    """Performs all necessary actions when pose of an object is updated.

    :param obj:
    :param pose:
    :param obj_inst:
    :param lock_owner: if present, object is unlocked at the end of function
    :return:
    """

    if pose:
        # SceneObject pose was not updated before
        obj.pose = pose
    else:
        # SceneObject pose was already updated
        pose = obj.pose

    scene.update_modified()

    evt = SceneObjectChanged(obj)
    evt.change_type = Event.Type.UPDATE
    await notif.broadcast_event(evt)

    glob.OBJECTS_WITH_UPDATED_POSE.add(obj.id)

    if scene_started():

        if obj_inst is None:
            inst = get_instance(obj.id)
            assert isinstance(inst, GenericWithPose)
            obj_inst = inst

        assert pose is not None

        # Object pose is property that might call scene service - that's why it has to be called using executor.
        await hlp.run_in_executor(setattr, obj_inst, "pose", pose)

    if lock_owner:
        await glob.LOCK.read_unlock(obj.id, lock_owner)
Ejemplo n.º 9
0
def test_slots() -> None:
    """Tests whether classes from cached module uses __slots__."""

    s = Scene("")
    p = Project("", s.id)

    assert not hasattr(CachedScene(s), "__dict__")
    assert not hasattr(CachedProject(p), "__dict__")
    assert not hasattr(UpdateableCachedScene(s), "__dict__")
    assert not hasattr(UpdateableCachedProject(p), "__dict__")
Ejemplo n.º 10
0
async def open_scene(scene_id: str) -> None:

    await asyncio.gather(scene_srv.delete_all_collisions(), get_object_types())
    glob.LOCK.scene = UpdateableCachedScene(await storage.get_scene(scene_id))

    try:
        for obj in glob.LOCK.scene.objects:
            check_object(glob.LOCK.scene, obj)
    except Arcor2Exception as e:
        glob.LOCK.scene = None
        raise Arcor2Exception(f"Failed to open scene. {str(e)}") from e
Ejemplo n.º 11
0
async def open_scene(scene_id: str) -> None:

    await get_object_types()
    asyncio.ensure_future(scene_srv.delete_all_collisions())
    glob.SCENE = UpdateableCachedScene(await storage.get_scene(scene_id))

    try:
        for obj in glob.SCENE.objects:
            check_object(obj)
    except Arcor2Exception as e:
        glob.SCENE = None
        raise Arcor2Exception(f"Failed to open scene. {str(e)}") from e
Ejemplo n.º 12
0
async def delete_scene_cb(
        req: srpc.s.DeleteScene.Request,
        ui: WsClient) -> Optional[srpc.s.DeleteScene.Response]:

    assoc_projects = await associated_projects(req.args.id)

    if assoc_projects:
        resp = srpc.s.DeleteScene.Response(result=False)
        resp.messages = ["Scene has associated projects."]
        resp.data = assoc_projects
        return resp

    if req.dry_run:
        return None

    scene = UpdateableCachedScene(await storage.get_scene(req.args.id))
    await storage.delete_scene(req.args.id)
    evt = sevts.s.SceneChanged(scene.bare)
    evt.change_type = Event.Type.REMOVE
    asyncio.ensure_future(notif.broadcast_event(evt))
    return None
Ejemplo n.º 13
0
async def test_ctx_read_lock() -> None:

    test = "test"
    user = "******"

    glob.LOCK = Lock({})
    assert await glob.LOCK.get_locked_roots_count() == 0

    glob.LOCK.scene = UpdateableCachedScene(cmn.Scene(test, description=test))
    glob.LOCK.project = UpdateableCachedProject(cmn.Project(test, glob.LOCK.scene.id, description=test, has_logic=True))

    async def patch() -> set[str]:
        return {glob.LOCK.project_or_exception().id, glob.LOCK.scene_or_exception().id}

    storage.get_project_ids = storage.get_scene_ids = patch

    # add some scene and project objects
    test_object = cmn.SceneObject(test, "TestType")
    glob.LOCK.scene.upsert_object(test_object)
    ap = glob.LOCK.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap", cmn.Position(0, 0, 0), test_object.id)
    ap_ap = glob.LOCK.project.upsert_action_point(cmn.BareActionPoint.uid(), "ap_ap", cmn.Position(0, 0, 1), ap.id)

    assert await glob.LOCK.get_locked_roots_count() == 0

    await glob.LOCK.write_lock(ap_ap.id, user, True)

    assert await glob.LOCK.is_write_locked(test_object.id, user)
    assert await glob.LOCK.is_write_locked(ap.id, user)
    assert await glob.LOCK.is_write_locked(ap_ap.id, user)

    async with ctx_read_lock(test_object.id, user):
        pass

    assert await glob.LOCK.is_write_locked(test_object.id, user)
    assert await glob.LOCK.is_write_locked(ap.id, user)
    assert await glob.LOCK.is_write_locked(ap_ap.id, user)
Ejemplo n.º 14
0
async def open_scene(scene_id: str) -> None:

    scene = await storage.get_scene(scene_id)

    if sp := await get_scene_problems(
            scene
    ):  # this also refreshes ObjectTypes / calls get_object_types()
        logger.warning(
            f"Scene {scene.name} can't be opened due to the following problem(s)..."
        )
        for spp in sp:
            logger.warning(spp)
        raise Arcor2Exception("Scene has some problems.")

    glob.LOCK.scene = UpdateableCachedScene(scene)


def get_robot_instance(
    obj_id: str
) -> Robot:  # TODO remove once https://github.com/python/mypy/issues/5374 is solved

    robot_inst = get_instance(obj_id, Robot)  # type: ignore
    assert isinstance(robot_inst, Robot)
    return robot_inst


T = TypeVar("T", bound=Generic)


# TODO "thanks" to https://github.com/python/mypy/issues/3737, `expected_type: type[T] = Generic` can't be used