跳转至

机械臂遥操

目前本项目给出的遥操示例都是面向于机械臂的, 经过测试直接复制模块接入人性机器人进行遥操是没问题的, 但是由于人性机器人代码大部份都较为闭源难以兼容, 因此没有集成进项目.

为什么机械臂遥操要单独列出?

对于机械臂运动, 由于遥操给出的目标坐标总是坐标较为连续, 并且控制频率较高, 因此部分机械臂会提供专门的遥操接口来保证遥操的同步性, 并且由于IK求解有强约束与弱约束两种方式(目标位置的准确度、当前机械臂各关节运动速度、幅度等约束条件), 对于基础的IK接口, 很可能出现位置不可达或者关节卡死的情况, 这就需要使用专门的弱约束IK来提升操控的体感.

快速实现一个遥操

需要注意, 遥操需要你自带一个遥操设备, 可以是QuestVR, agilex Pika, Apple Vision Pro等, 只要能获取相对运动信息的设备都可以, 甚至你可以基于IMU传感器DIY一个设备用来遥操.

首先你要在注册机器人的时候在传感器中绑定你的遥操设备, 以Pika为例:

def __init__(self, ...):
    self.sensors = {
            "image": {
                "cam_head": RealsenseSensor("cam_head"),
                "cam_left_wrist": RealsenseSensor("cam_left_wrist"),
                "cam_right_wrist": RealsenseSensor("cam_right_wrist"),
            }, 
            "teleop":{
                "pika_left": PikaRosSensor("left_pika"),
                "pika_right": PikaRosSensor("right_pika"),
            }
        }

然后需要在set_up()中初始化你的设备:

def set_up(self):
    ...
    self.sensors["teleop"]["pika_left"].set_up("/pika_pose_l","/gripper_l/joint_states")
    self.sensors["teleop"]["pika_right"].set_up("/pika_pose_r","/gripper_r/joint_states")

    self.set_collect_type({...,
                            "teleop": ["end_pose", "gripper"],
                            })

最后写一个main函数用于执行遥操, 或者直接在主函数中编写:

if __name__ == "__main__":
    import time

    # 只有使用了ros来控制才需要初始化一个ros节点
    import rospy
    rospy.init_node("rm_controller_node", anonymous=True)

    robot = MyRobot()
    robot.set_up()

    robot.reset()
    time.sleep(3)

    # 等待数据稳定
    while True:
        data = robot.get()
        if data[1]["pika_left"]["end_pose"] is not None and data[1]["pika_right"]["end_pose"] is not None and\
            data[0]["left_arm"]["qpos"] is not None and data[0]["left_arm"]["qpos"] is not None:
            break
        else:
            time.sleep(0.1)

    print("start teleop")

    time.sleep(3)

    # 将第一帧的坐标作为基坐标
    left_base_pose = data[0]["left_arm"]["qpos"]
    right_base_pose = data[0]["right_arm"]["qpos"]

    # 开始遥操
    while True:
        try:
            data = robot.get()

            # 这里获取到的坐标是四元数, 转为欧拉角
            left_delta_pose = matrix_to_xyz_rpy(data[1]["pika_left"]["end_pose"])
            right_delta_pose = matrix_to_xyz_rpy(data[1]["pika_right"]["end_pose"])

            # 计算基于基坐标的位置变化
            left_wrist_mat = apply_local_delta_pose(left_base_pose, left_delta_pose)
            right_wrist_mat = apply_local_delta_pose(right_base_pose, right_delta_pose)

            # 由于计算变化返回的是四元数, 这里再转回欧拉角
            l_data = matrix_to_xyz_rpy(left_wrist_mat)
            r_data = matrix_to_xyz_rpy(right_wrist_mat)

            print("left:", l_data.tolist())
            print("right:", r_data.tolist())

            # 设置移动的信息 (如果设备有提供专门遥操接口,则推荐实现此接口, 否则直接用qos接口)
            move_data = {
                "arm":{
                    "left_arm": {
                        "teleop_qpos":l_data},
                    "right_arm": {
                        "teleop_qpos":r_data},
                }
            }

            robot.move(move_data)
            time.sleep(0.02)
        except:
            print("data is none")
            time.sleep(0.1)