예제 #1
0
async def remove_from_scene_cb(req: srpc.s.RemoveFromScene.Request,
                               ui: WsClient) -> None:

    scene = glob.LOCK.scene_or_exception(ensure_project_closed=True)
    user_name = glob.USERS.user_name(ui)

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

        can_modify_scene()

        if not req.args.force and {
                proj.name
                async for proj in projects_using_object(scene.id, req.args.id)
        }:
            raise Arcor2Exception(
                "Can't remove object that is used in project(s).")

        if req.dry_run:
            return None

        if req.args.id not in scene.object_ids:
            raise Arcor2Exception("Unknown id.")

        await glob.LOCK.write_unlock(req.args.id, user_name)

        obj = scene.object(req.args.id)
        scene.delete_object(req.args.id)

        if req.args.id in glob.OBJECTS_WITH_UPDATED_POSE:
            glob.OBJECTS_WITH_UPDATED_POSE.remove(req.args.id)

        evt = sevts.s.SceneObjectChanged(obj)
        evt.change_type = Event.Type.REMOVE
        asyncio.ensure_future(notif.broadcast_event(evt))

        # TODO this should be done after scene is saved
        asyncio.ensure_future(
            remove_object_references_from_projects(req.args.id))
        return None
예제 #2
0
async def update_override_cb(req: srpc.o.UpdateOverride.Request,
                             ui: WsClient) -> None:

    scene = glob.LOCK.scene_or_exception()
    project = glob.LOCK.project_or_exception()

    obj = check_override(scene, project, req.args.id, req.args.override)

    await ensure_locked(req.args.id, ui)

    if req.dry_run:
        return

    for override in project.overrides[obj.id]:
        if override.name == override.name:
            override.value = req.args.override.value
    project.update_modified()

    evt = sevts.o.OverrideUpdated(req.args.override)
    evt.change_type = events.Event.Type.UPDATE
    evt.parent_id = req.args.id
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #3
0
파일: objects.py 프로젝트: Croolman/arcor2
async def delete_object_type_cb(req: srpc.o.DeleteObjectType.Request,
                                ui: WsClient) -> None:

    try:
        obj_type = glob.OBJECT_TYPES[req.args.id]
    except KeyError:
        raise Arcor2Exception("Unknown object type.")

    if obj_type.meta.built_in:
        raise Arcor2Exception("Can't delete built-in type.")

    for obj in glob.OBJECT_TYPES.values():
        if obj.meta.base == req.args.id:
            raise Arcor2Exception(f"Object type is base of '{obj.meta.type}'.")

    async for scene in scenes():
        check_scene_for_object_type(scene, req.args.id)

    if glob.SCENE:
        check_scene_for_object_type(glob.SCENE, req.args.id)

    if req.dry_run:
        return

    await storage.delete_object_type(req.args.id)

    # do not care so much if delete_model fails
    if obj_type.meta.object_model:
        try:
            await storage.delete_model(obj_type.meta.object_model.model().id)
        except storage.ProjectServiceException as e:
            glob.logger.error(str(e))

    del glob.OBJECT_TYPES[req.args.id]
    remove_object_type(req.args.id)

    evt = sevts.o.ChangedObjectTypes([obj_type.meta])
    evt.change_type = events.Event.Type.REMOVE
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #4
0
파일: robot.py 프로젝트: robofit/arcor2
async def hand_teaching_mode_cb(req: srpc.r.HandTeachingMode.Request, ui: WsClient) -> None:

    glob.LOCK.scene_or_exception()

    ensure_scene_started()
    robot_inst = await osa.get_robot_instance(req.args.robot_id)

    # in this case, method name does not correspond to feature name
    await check_feature(robot_inst, "hand_teaching")

    hand_teaching_mode = await run_in_executor(robot_inst.get_hand_teaching_mode)

    if req.args.enable == hand_teaching_mode:
        raise Arcor2Exception("That's the current state.")

    await ensure_locked(req.args.robot_id, ui)

    if req.dry_run:
        return

    await run_in_executor(robot_inst.set_hand_teaching_mode, req.args.enable)
    evt = HandTeachingMode(HandTeachingMode.Data(req.args.robot_id, req.args.enable))
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #5
0
async def update_action_point_joints_cb(
        req: srpc.p.UpdateActionPointJoints.Request, ui: WsClient) -> None:

    assert glob.SCENE
    assert glob.PROJECT

    robot_joints = glob.PROJECT.joints(req.args.joints_id)

    if {joint.name
            for joint in req.args.joints
        } != {joint.name
              for joint in robot_joints.joints}:
        raise Arcor2Exception("Joint names does not match the robot.")

    # TODO maybe joints values should be normalized? To <0, 2pi> or to <-pi, pi>?
    robot_joints.joints = req.args.joints
    robot_joints.is_valid = True
    glob.PROJECT.update_modified()

    evt = sevts.p.JointsChanged(robot_joints)
    evt.change_type = Event.Type.UPDATE
    asyncio.ensure_future(notif.broadcast_event(evt))
    return None
예제 #6
0
async def update_object_model_cb(req: srpc.o.UpdateObjectModel.Request,
                                 ui: WsClient) -> None:

    can_modify_scene()
    glob.LOCK.scene_or_exception(True)  # only allow while editing scene

    obj_data = glob.OBJECT_TYPES[req.args.object_type_id]

    if not obj_data.type_def:
        raise Arcor2Exception("ObjectType disabled.")

    if not issubclass(obj_data.type_def, CollisionObject):
        raise Arcor2Exception("Not a CollisionObject.")

    assert obj_data.meta.object_model
    assert obj_data.ast

    if req.args.object_model == obj_data.meta.object_model:
        raise Arcor2Exception("No change requested.")

    await ensure_write_locked(req.args.object_type_id,
                              glob.USERS.user_name(ui))

    if req.dry_run:
        return

    await update_object_model(obj_data.meta, req.args.object_model)
    obj_data.meta.object_model = req.args.object_model

    ot = obj_data.meta.to_object_type()
    ot.source = tree_to_str(obj_data.ast)

    obj_data.meta.modified = await storage.update_object_type(ot)

    evt = sevts.o.ChangedObjectTypes([obj_data.meta])
    evt.change_type = events.Event.Type.UPDATE
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #7
0
파일: objects.py 프로젝트: Croolman/arcor2
async def delete_override_cb(req: srpc.o.DeleteOverride.Request,
                             ui: WsClient) -> None:

    assert glob.PROJECT

    obj = check_override(req.args.id, req.args.override)

    if req.dry_run:
        return

    glob.PROJECT.overrides[obj.id] = [
        ov for ov in glob.PROJECT.overrides[obj.id]
        if ov.name != req.args.override.name
    ]

    if not glob.PROJECT.overrides[obj.id]:
        del glob.PROJECT.overrides[obj.id]

    glob.PROJECT.update_modified()

    evt = sevts.o.OverrideUpdated(req.args.override)
    evt.change_type = events.Event.Type.REMOVE
    evt.parent_id = req.args.id
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #8
0
async def add_action_point_orientation_using_robot_cb(
        req: srpc.p.AddActionPointOrientationUsingRobot.Request,
        ui: WsClient) -> None:
    """Adds orientation and joints to the action point.

    :param req:
    :return:
    """

    ensure_scene_started()

    assert glob.SCENE
    assert glob.PROJECT

    ap = glob.PROJECT.bare_action_point(req.args.action_point_id)
    hlp.is_valid_identifier(req.args.name)
    unique_name(req.args.name, glob.PROJECT.ap_orientation_names(ap.id))

    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(req.args.name, new_pose.orientation)
    glob.PROJECT.upsert_orientation(ap.id, orientation)

    evt = sevts.p.OrientationChanged(orientation)
    evt.change_type = Event.Type.ADD
    evt.parent_id = ap.id
    asyncio.ensure_future(notif.broadcast_event(evt))
    return None
예제 #9
0
async def remove_constant_cb(req: srpc.p.RemoveConstant.Request,
                             ui: WsClient) -> None:

    assert glob.PROJECT
    assert glob.SCENE

    const = glob.PROJECT.constant(req.args.constant_id)

    # check for usage
    for act in glob.PROJECT.actions:
        for param in act.parameters:
            if param.type == common.ActionParameter.TypeEnum.CONSTANT and param.str_from_value(
            ) == const.id:
                raise Arcor2Exception("Constant used as action parameter.")

    if req.dry_run:
        return

    glob.PROJECT.remove_constant(const.id)

    evt = sevts.p.ProjectConstantChanged(const)
    evt.change_type = Event.Type.REMOVE
    asyncio.ensure_future(notif.broadcast_event(evt))
    return None
예제 #10
0
async def hand_teaching_mode_cb(req: srpc.r.HandTeachingMode.Request,
                                ui: WsClient) -> None:

    ensure_scene_started()
    robot_inst = await osa.get_robot_instance(req.args.robot_id)

    otd = osa.get_obj_type_data(req.args.robot_id)
    assert otd.robot_meta is not None
    if not otd.robot_meta.features.hand_teaching:
        raise Arcor2Exception("Robot does not support hand teaching.")

    hand_teaching_mode = await run_in_executor(
        robot_inst.get_hand_teaching_mode)

    if req.args.enable == hand_teaching_mode:
        raise Arcor2Exception("That's the current state.")

    if req.dry_run:
        return

    await run_in_executor(robot_inst.set_hand_teaching_mode, req.args.enable)
    evt = HandTeachingMode(
        HandTeachingMode.Data(req.args.robot_id, req.args.enable))
    asyncio.ensure_future(notif.broadcast_event(evt))
예제 #11
0
파일: scene.py 프로젝트: ZdenekM/arcor2
async def set_scene_state(state: SceneState.Data.StateEnum,
                          message: Optional[str] = None) -> None:

    global _scene_state
    _scene_state = SceneState(SceneState.Data(state, message))
    asyncio.create_task(notif.broadcast_event(_scene_state))
예제 #12
0
async def new_object_type_cb(req: srpc.o.NewObjectType.Request,
                             ui: WsClient) -> None:

    async with ctx_write_lock(glob.LOCK.SpecialValues.ADDING_OBJECT, ui):
        meta = req.args

        if meta.type in glob.OBJECT_TYPES:
            raise Arcor2Exception("Object type already exists.")

        hlp.is_valid_type(meta.type)

        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())}.")

        base = glob.OBJECT_TYPES[meta.base]

        if base.meta.disabled:
            raise Arcor2Exception("Base object is disabled.")

        assert base.type_def is not None

        if issubclass(base.type_def, Robot):
            raise Arcor2Exception("Can't subclass Robot.")

        meta.has_pose = issubclass(base.type_def, GenericWithPose)

        if not meta.has_pose and meta.object_model:
            raise Arcor2Exception(
                "Object without pose can't have collision model.")

        if req.dry_run:
            return None

        obj = meta.to_object_type()
        ast = new_object_type(glob.OBJECT_TYPES[meta.base].meta, meta)
        obj.source = tree_to_str(ast)

        if meta.object_model:

            if meta.object_model.type == Model3dType.MESH:

                # TODO check whether mesh id exists - if so, then use existing mesh, if not, upload a new one
                # ...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.ProjectServiceException as e:
                    glob.logger.error(e)
                    raise Arcor2Exception(
                        f"Mesh ID {meta.object_model.mesh.id} does not exist.")

            else:

                meta.object_model.model().id = meta.type
                await storage.put_model(meta.object_model.model())

        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            base.type_def,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
        assert issubclass(type_def, base.type_def)
        actions = object_actions(type_def, ast)

        await storage.update_object_type(obj)

        glob.OBJECT_TYPES[meta.type] = ObjectTypeData(meta, type_def, actions,
                                                      ast)
        add_ancestor_actions(meta.type, glob.OBJECT_TYPES)

        evt = sevts.o.ChangedObjectTypes([meta])
        evt.change_type = events.Event.Type.ADD
        asyncio.ensure_future(notif.broadcast_event(evt))
        return None
예제 #13
0
async def get_object_types() -> UpdatedObjectTypes:
    """Serves to initialize or update knowledge about awailable ObjectTypes.

    :return:
    """

    initialization = False

    # initialize with built-in types, this has to be done just once
    if not glob.OBJECT_TYPES:
        logger.debug("Initialization of ObjectTypes.")
        initialization = True
        await hlp.run_in_executor(prepare_object_types_dir,
                                  settings.OBJECT_TYPE_PATH,
                                  settings.OBJECT_TYPE_MODULE)
        glob.OBJECT_TYPES.update(built_in_types_data())

    updated_object_types: ObjectTypeDict = {}

    object_type_ids: Union[set[str],
                           list[str]] = await storage.get_object_type_ids()

    if __debug__:  # this should uncover potential problems with order in which ObjectTypes are processed
        import random

        object_type_ids = list(object_type_ids)
        random.shuffle(object_type_ids)

    for obj_id in object_type_ids:
        await get_object_data(updated_object_types, obj_id)

    removed_object_ids = {
        obj
        for obj in glob.OBJECT_TYPES.keys() if obj not in object_type_ids
    } - built_in_types_names()
    updated_object_ids = {
        k
        for k in updated_object_types.keys() if k in glob.OBJECT_TYPES
    }
    new_object_ids = {
        k
        for k in updated_object_types.keys() if k not in glob.OBJECT_TYPES
    }

    logger.debug(f"Removed ids: {removed_object_ids}")
    logger.debug(f"Updated ids: {updated_object_ids}")
    logger.debug(f"New ids: {new_object_ids}")

    if not initialization and removed_object_ids:

        # TODO remove it from sys.modules

        remove_evt = ChangedObjectTypes([
            v.meta for k, v in glob.OBJECT_TYPES.items()
            if k in removed_object_ids
        ])
        remove_evt.change_type = Event.Type.REMOVE
        asyncio.ensure_future(notif.broadcast_event(remove_evt))

        for removed in removed_object_ids:
            assert removed not in built_in_types_names(
            ), "Attempt to remove built-in type."
            del glob.OBJECT_TYPES[removed]
            await hlp.run_in_executor(remove_object_type, removed)

    glob.OBJECT_TYPES.update(updated_object_types)

    logger.debug(f"All known ids: {glob.OBJECT_TYPES.keys()}")

    for obj_type in updated_object_types.values():

        # if description is missing, try to get it from ancestor(s)
        if not obj_type.meta.description:

            try:
                obj_type.meta.description = obj_description_from_base(
                    glob.OBJECT_TYPES, obj_type.meta)
            except otu.DataError as e:
                logger.error(
                    f"Failed to get info from base for {obj_type}, error: '{e}'."
                )

        if not obj_type.meta.disabled and not obj_type.meta.built_in:
            add_ancestor_actions(obj_type.meta.type, glob.OBJECT_TYPES)

    if not initialization:

        if updated_object_ids:
            update_evt = ChangedObjectTypes([
                v.meta for k, v in glob.OBJECT_TYPES.items()
                if k in updated_object_ids
            ])
            update_evt.change_type = Event.Type.UPDATE
            asyncio.ensure_future(notif.broadcast_event(update_evt))

        if new_object_ids:
            add_evt = ChangedObjectTypes([
                v.meta for k, v in glob.OBJECT_TYPES.items()
                if k in new_object_ids
            ])
            add_evt.change_type = Event.Type.ADD
            asyncio.ensure_future(notif.broadcast_event(add_evt))

    for obj_type in updated_object_types.values():

        if obj_type.type_def and issubclass(
                obj_type.type_def, Robot) and not obj_type.type_def.abstract():
            await get_robot_meta(obj_type)

    # if object does not change but its base has changed, it has to be reloaded
    for obj_id, obj in glob.OBJECT_TYPES.items():

        if obj_id in updated_object_ids:
            continue

        if obj.type_def and obj.meta.base in updated_object_ids:

            logger.debug(
                f"Re-importing {obj.meta.type} because its base {obj.meta.base} type has changed."
            )
            obj.type_def = await hlp.run_in_executor(
                hlp.import_type_def,
                obj.meta.type,
                Generic,
                settings.OBJECT_TYPE_PATH,
                settings.OBJECT_TYPE_MODULE,
            )

    return UpdatedObjectTypes(new_object_ids, updated_object_ids,
                              removed_object_ids)
예제 #14
0
async def remove_action_point_cb(req: srpc.p.RemoveActionPoint.Request,
                                 ui: WsClient) -> None:

    assert glob.PROJECT

    ap = glob.PROJECT.bare_action_point(req.args.id)

    for proj_ap in glob.PROJECT.action_points_with_parent:
        if proj_ap.parent == ap.id:
            raise Arcor2Exception(
                f"Can't remove parent of '{proj_ap.name}' AP.")

    ap_action_ids = glob.PROJECT.ap_action_ids(ap.id)

    # check if AP's actions aren't involved in logic
    # TODO 'force' param to remove logical connections?
    for logic in glob.PROJECT.logic:
        if (logic.start in ap_action_ids or logic.end in ap_action_ids or
            (logic.condition
             and logic.condition.parse_what().action_id in ap_action_ids)):
            raise Arcor2Exception("Remove logic connections first.")

    for act in glob.PROJECT.actions:

        if act.id in ap_action_ids:
            continue

        for param in act.parameters:
            if param.type == common.ActionParameter.TypeEnum.LINK:
                parsed_link = param.parse_link()
                linking_action = glob.PROJECT.action(parsed_link.action_id)
                if parsed_link.action_id in ap_action_ids:
                    raise Arcor2Exception(
                        f"Result of '{act.name}' is linked from '{linking_action.name}'."
                    )

            if not param.is_value():
                continue

            for joints in glob.PROJECT.ap_joints(ap.id):
                if plugin_from_type_name(param.type).uses_robot_joints(
                        glob.PROJECT, act.id, param.name, joints.id):
                    raise Arcor2Exception(
                        f"Joints {joints.name} used in action {act.name} (parameter {param.name})."
                    )

            for ori in glob.PROJECT.ap_orientations(ap.id):
                if plugin_from_type_name(param.type).uses_orientation(
                        glob.PROJECT, act.id, param.name, ori.id):
                    raise Arcor2Exception(
                        f"Orientation {ori.name} used in action {act.name} (parameter {param.name})."
                    )

            # TODO some hypothetical parameter type could use just bare ActionPoint (its position)

    if req.dry_run:
        return None

    glob.PROJECT.remove_action_point(req.args.id)

    evt = sevts.p.ActionPointChanged(ap)
    evt.change_type = Event.Type.REMOVE
    asyncio.ensure_future(notif.broadcast_event(evt))
    return None
예제 #15
0
async def new_object_type_cb(req: srpc.o.NewObjectType.Request,
                             ui: WsClient) -> None:

    async with ctx_write_lock(glob.LOCK.SpecialValues.ADDING_OBJECT,
                              glob.USERS.user_name(ui)):
        meta = req.args

        if meta.type in glob.OBJECT_TYPES:
            raise Arcor2Exception("Object type already exists.")

        hlp.is_valid_type(meta.type)

        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())}.")

        base = glob.OBJECT_TYPES[meta.base]

        if base.meta.disabled:
            raise Arcor2Exception("Base object is disabled.")

        assert base.type_def is not None

        if issubclass(base.type_def, Robot):
            raise Arcor2Exception("Can't subclass Robot.")

        meta.has_pose = issubclass(base.type_def, GenericWithPose)

        if issubclass(base.type_def, CollisionObject):
            if not meta.object_model:
                raise Arcor2Exception(
                    "Objects based on CollisionObject must have collision model."
                )
        else:
            if meta.object_model:
                raise Arcor2Exception(
                    "Only objects based on CollisionObject can have collision model."
                )

        if req.dry_run:
            return None

        obj = meta.to_object_type()
        ast = new_object_type(glob.OBJECT_TYPES[meta.base].meta, meta)
        obj.source = tree_to_str(ast)

        if meta.object_model:
            await update_object_model(meta, meta.object_model)

        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            base.type_def,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
        assert issubclass(type_def, base.type_def)
        actions = object_actions(type_def, ast)

        meta.modified = await storage.update_object_type(obj)

        glob.OBJECT_TYPES[meta.type] = ObjectTypeData(meta, type_def, actions,
                                                      ast)
        add_ancestor_actions(meta.type, glob.OBJECT_TYPES)

        evt = sevts.o.ChangedObjectTypes([meta])
        evt.change_type = events.Event.Type.ADD
        asyncio.ensure_future(notif.broadcast_event(evt))
        return None