Пример #1
0
                        type=str,
                        required=True,
                        help="ModuleFamily/ModuleName")
    return parser.parse_args(args)


if __name__ == '__main__':

    parser = parse_args(rospy.myargv(sys.argv[1:]))

    rospy.init_node(name="effort_ctrl", anonymous=True)

    # Set up HEBI ROS interface
    hebi_families = parser.module.split('/')[0]
    hebi_names = parser.module.split('/')[1]
    hebi_wrap = HebirosWrapper(parser.hebi_group, [hebi_families],
                               [hebi_names])
    hebi_mapping = [parser.module]

    cmd_msg = CommandMsg()
    cmd_msg.name = hebi_mapping
    cmd_msg.settings.name = hebi_mapping
    cmd_msg.settings.effort_gains.name = hebi_mapping
    cmd_msg.settings.effort_gains.kp = [1]
    cmd_msg.settings.effort_gains.ki = [0]
    cmd_msg.settings.effort_gains.kd = [0]
    cmd_msg.settings.effort_gains.i_clamp = [0]
    hebi_wrap.send_command_with_acknowledgement(cmd_msg)

    _hold_position = False
    _hold_joint_effort = None
    def __init__(self, hebi_group_name, hebi_mapping, hebi_gains, urdf_str, base_link, end_link):
        rospy.loginfo("Creating {} instance".format(self.__class__.__name__))

        self.openmeta_testbench_manifest_path = rospy.get_param('~openmeta/testbench_manifest_path', None)
        if self.openmeta_testbench_manifest_path is not None:
            self._testbench_manifest = load_json_file(self.openmeta_testbench_manifest_path)

            # TestBench Parameters
            self._params = {}
            for tb_param in self._testbench_manifest['Parameters']:
                self._params[tb_param['Name']] = tb_param['Value']  # WARNING: If you use these values - make sure to check the type

            # TestBench Metrics
            self._metrics = {}
            for tb_metric in self._testbench_manifest['Metrics']:  # FIXME: Hmm, this is starting to look a lot like OpenMDAO...
                self._metrics[tb_metric['Name']] = tb_metric['Value']

        if hebi_gains is None:
            hebi_gains = {
                'p': [float(self._params['p_gain'])]*3,
                'i': [float(self._params['i_gain'])]*3,
                'd': [float(self._params['d_gain'])]*3
            }

        hebi_families = []
        hebi_names = []
        for actuator in hebi_mapping:
            family, name = actuator.split('/')
            hebi_families.append(family)
            hebi_names.append(name)
        rospy.loginfo("  hebi_group_name: %s", hebi_group_name)
        rospy.loginfo("  hebi_families: %s", hebi_families)
        rospy.loginfo("  hebi_names: %s", hebi_names)
        self.hebi_wrap = HebirosWrapper(hebi_group_name, hebi_families, hebi_names)
        # Set PID Gains
        cmd_msg = CommandMsg()
        cmd_msg.name = hebi_mapping
        cmd_msg.settings.name = hebi_mapping
        cmd_msg.settings.control_strategy = [4, 4, 4]
        cmd_msg.settings.position_gains.name = hebi_mapping
        cmd_msg.settings.position_gains.kp = hebi_gains['p']
        cmd_msg.settings.position_gains.ki = hebi_gains['i']
        cmd_msg.settings.position_gains.kd = hebi_gains['d']
        cmd_msg.settings.position_gains.i_clamp = [0.25, 0.25, 0.25]  # TODO: Tune me.
        self.hebi_wrap.send_command_with_acknowledgement(cmd_msg)

        if base_link is None or end_link is None:
            robot = Robot.from_xml_string(urdf_str)
            if not base_link:
                base_link = robot.get_root()
                # WARNING: There may be multiple leaf nodes
            if not end_link:
                end_link = [x for x in robot.link_map.keys() if x not in robot.child_map.keys()][0]
        # pykdl
        self.kdl_fk = KDLKinematics(URDF.from_xml_string(urdf_str), base_link, end_link)
        self._active_joints = self.kdl_fk.get_joint_names()

        # joint data
        self.position_fbk = [0.0]*self.hebi_wrap.hebi_count
        self.velocity_fbk = [0.0]*self.hebi_wrap.hebi_count
        self.effort_fbk = [0.0]*self.hebi_wrap.hebi_count

        # joint state publisher
        while not rospy.is_shutdown() and len(self.hebi_wrap.get_joint_positions()) < len(self.hebi_wrap.hebi_mapping):
            rospy.sleep(0.1)
        self._joint_state_pub = rospy.Publisher('joint_states', JointState, queue_size=1)
        self.hebi_wrap.add_feedback_callback(self._joint_state_cb)

        # Set up Waypoint/Trajectory objects
        self.start_wp = WaypointMsg()
        self.start_wp.names = self.hebi_wrap.hebi_mapping
        self.end_wp = copy.deepcopy(self.start_wp)
        self.goal = TrajectoryGoal()
        self.goal.waypoints = [self.start_wp, self.end_wp]

        self._hold_positions = [0.0]*3
        self._hold = True
        self.jointstate = JointState()
        self.jointstate.name = self.hebi_wrap.hebi_mapping
        rospy.sleep(1.0)
class HebiArmController(object):
    def __init__(self, hebi_group_name, hebi_mapping, hebi_gains, urdf_str, base_link, end_link):
        rospy.loginfo("Creating {} instance".format(self.__class__.__name__))

        self.openmeta_testbench_manifest_path = rospy.get_param('~openmeta/testbench_manifest_path', None)
        if self.openmeta_testbench_manifest_path is not None:
            self._testbench_manifest = load_json_file(self.openmeta_testbench_manifest_path)

            # TestBench Parameters
            self._params = {}
            for tb_param in self._testbench_manifest['Parameters']:
                self._params[tb_param['Name']] = tb_param['Value']  # WARNING: If you use these values - make sure to check the type

            # TestBench Metrics
            self._metrics = {}
            for tb_metric in self._testbench_manifest['Metrics']:  # FIXME: Hmm, this is starting to look a lot like OpenMDAO...
                self._metrics[tb_metric['Name']] = tb_metric['Value']

        if hebi_gains is None:
            hebi_gains = {
                'p': [float(self._params['p_gain'])]*3,
                'i': [float(self._params['i_gain'])]*3,
                'd': [float(self._params['d_gain'])]*3
            }

        hebi_families = []
        hebi_names = []
        for actuator in hebi_mapping:
            family, name = actuator.split('/')
            hebi_families.append(family)
            hebi_names.append(name)
        rospy.loginfo("  hebi_group_name: %s", hebi_group_name)
        rospy.loginfo("  hebi_families: %s", hebi_families)
        rospy.loginfo("  hebi_names: %s", hebi_names)
        self.hebi_wrap = HebirosWrapper(hebi_group_name, hebi_families, hebi_names)
        # Set PID Gains
        cmd_msg = CommandMsg()
        cmd_msg.name = hebi_mapping
        cmd_msg.settings.name = hebi_mapping
        cmd_msg.settings.control_strategy = [4, 4, 4]
        cmd_msg.settings.position_gains.name = hebi_mapping
        cmd_msg.settings.position_gains.kp = hebi_gains['p']
        cmd_msg.settings.position_gains.ki = hebi_gains['i']
        cmd_msg.settings.position_gains.kd = hebi_gains['d']
        cmd_msg.settings.position_gains.i_clamp = [0.25, 0.25, 0.25]  # TODO: Tune me.
        self.hebi_wrap.send_command_with_acknowledgement(cmd_msg)

        if base_link is None or end_link is None:
            robot = Robot.from_xml_string(urdf_str)
            if not base_link:
                base_link = robot.get_root()
                # WARNING: There may be multiple leaf nodes
            if not end_link:
                end_link = [x for x in robot.link_map.keys() if x not in robot.child_map.keys()][0]
        # pykdl
        self.kdl_fk = KDLKinematics(URDF.from_xml_string(urdf_str), base_link, end_link)
        self._active_joints = self.kdl_fk.get_joint_names()

        # joint data
        self.position_fbk = [0.0]*self.hebi_wrap.hebi_count
        self.velocity_fbk = [0.0]*self.hebi_wrap.hebi_count
        self.effort_fbk = [0.0]*self.hebi_wrap.hebi_count

        # joint state publisher
        while not rospy.is_shutdown() and len(self.hebi_wrap.get_joint_positions()) < len(self.hebi_wrap.hebi_mapping):
            rospy.sleep(0.1)
        self._joint_state_pub = rospy.Publisher('joint_states', JointState, queue_size=1)
        self.hebi_wrap.add_feedback_callback(self._joint_state_cb)

        # Set up Waypoint/Trajectory objects
        self.start_wp = WaypointMsg()
        self.start_wp.names = self.hebi_wrap.hebi_mapping
        self.end_wp = copy.deepcopy(self.start_wp)
        self.goal = TrajectoryGoal()
        self.goal.waypoints = [self.start_wp, self.end_wp]

        self._hold_positions = [0.0]*3
        self._hold = True
        self.jointstate = JointState()
        self.jointstate.name = self.hebi_wrap.hebi_mapping
        rospy.sleep(1.0)

    def execute(self, rate, joint_states, durations):
        max_height = 0.0

        while not rospy.is_shutdown():
            if len(joint_states) > 0:
                # start waypoint
                self.start_wp.positions = self.position_fbk
                self.start_wp.velocities = [0.0]*self.hebi_wrap.hebi_count
                self.start_wp.accelerations = [0.0]*self.hebi_wrap.hebi_count

                # end waypoint
                self.end_wp.positions = joint_states.pop(0)
                self.end_wp.velocities = [0.0]*self.hebi_wrap.hebi_count
                self.end_wp.accelerations = [0.0]*self.hebi_wrap.hebi_count
                self._hold_positions = self.end_wp.positions

                # action goal
                self.goal.times = [0.0, durations.pop()]

                self._hold = False
                self.hebi_wrap.trajectory_action_client.send_goal(self.goal)
                self.hebi_wrap.trajectory_action_client.wait_for_result()
                self._hold = True

                # check status
                if abs(self.position_fbk[0] - self.end_wp.positions[0]) > 0.0872665:
                    print("Failed to achieve objective position.")
                    break

            else:
                rospy.sleep(2.0)
                fk = self.kdl_fk.forward(self.position_fbk)
                max_height = fk.tolist()[2][3]
                print("Max Height: {}".format(max_height))
                break

            rate.sleep()

        if self.openmeta_testbench_manifest_path is not None:
            steps_completed = 0
            if 7 <= len(joint_states):
                steps_completed = 0
            elif 5 <= len(joint_states) < 7:
                steps_completed = 1
            elif 3 <= len(joint_states) < 5:
                steps_completed = 2
            elif len(joint_states) < 3:
                steps_completed = 3
            self._metrics['steps_completed'] = steps_completed
            self._metrics['max_height'] = max_height
            self._write_metrics_to_tb_manifest()

    def _joint_state_cb(self, msg):
        if not rospy.is_shutdown():
            if self._hold:
                self.jointstate.position = self._hold_positions
                self.jointstate.velocity = []
                self.hebi_wrap.joint_state_publisher.publish(self.jointstate)

            self.position_fbk = self.hebi_wrap.get_joint_positions()
            self.velocity_fbk = self.hebi_wrap.get_joint_velocities()
            self.effort_fbk = self.hebi_wrap.get_joint_efforts()

            jointstate = JointState()
            jointstate.header.stamp = rospy.Time.now()
            jointstate.name = self._active_joints
            jointstate.position = self.position_fbk
            jointstate.velocity = self.velocity_fbk
            jointstate.effort = self.effort_fbk
            self._joint_state_pub.publish(jointstate)

    def _write_metrics_to_tb_manifest(self):
        # Write to testbench_manifest metric
        for tb_metric in self._testbench_manifest['Metrics']:
            if tb_metric['Name'] in self._metrics:
                tb_metric['Value'] = self._metrics[tb_metric['Name']]

        # Save updated testbench_manifest.json
        with open(self.openmeta_testbench_manifest_path, 'w') as savefile:
            json_str = json.dumps(self._testbench_manifest, sort_keys=True, indent=2, separators=(',', ': '))
            savefile.write(json_str)
def main():
    # ROS stuff
    rospy.init_node('hexapod_leg_fsm_node', anonymous=True)

    # Parse node args
    parser = parse_args(sys.argv[1:])
    hebi_group_name = parser.hebi_group_name
    hebi_mapping_hip = parser.hebi_mapping_hip
    hebi_mapping_knee = parser.hebi_mapping_knee
    hebi_mapping_ankle = parser.hebi_mapping_ankle
    base_link_name = parser.base_link_name
    end_link_name = parser.end_link_name
    from_master_topic = parser.from_master_topic
    to_master_topic = parser.to_master_topic
    step_height = parser.step_height

    # Hardware interface
    hebi_mapping = [hebi_mapping_hip, hebi_mapping_knee, hebi_mapping_ankle]
    hebi_families = []
    hebi_names = []
    for actuator in hebi_mapping:
        family, name = actuator.split('/')
        hebi_families.append(family)
        hebi_names.append(name)
    hebi_wrap = HebirosWrapper(hebi_group_name, hebi_families, hebi_names)
    #   Set PID Gains
    cmd_msg = CommandMsg()
    cmd_msg.name = hebi_mapping
    cmd_msg.settings.name = hebi_mapping
    cmd_msg.settings.position_gains.name = hebi_mapping
    cmd_msg.settings.position_gains.kp = [5, 8, 2]
    cmd_msg.settings.position_gains.ki = [0.001, 0.001, 0.001]
    cmd_msg.settings.position_gains.kd = [0, 0, 0]
    cmd_msg.settings.position_gains.i_clamp = [0.25, 0.25, 0.25]  # TODO: Tune me.
    hebi_wrap.send_command_with_acknowledgement(cmd_msg)

    # Get URDF
    urdf_str = ""
    urdf_loaded = False
    while not rospy.is_shutdown() and not urdf_loaded:
        if rospy.has_param('robot_description'):
            urdf_str = rospy.get_param('robot_description')
            urdf_loaded = True
            rospy.loginfo("Pulled {} from parameter server.".format(rospy.resolve_name('robot_description')))
        else:
            rospy.sleep(0.01)  # sleep for 10 ms of ROS time

    ### CREATE LEG STATE INSTANCES ###
    wait_for_master = WaitForMaster(hebiros_wrapper=hebi_wrap, from_master_topic=from_master_topic, to_master_topic=to_master_topic)
    step = Step(hebiros_wrapper=hebi_wrap, urdf_str=urdf_str, base_link=base_link_name, end_link=end_link_name, step_height=step_height)
    push = Push(hebiros_wrapper=hebi_wrap, urdf_str=urdf_str, base_link=base_link_name, end_link=end_link_name)

    ### CREATE TOP SM ###
    top = StateMachine(outcomes=['exit','success'])

    ### INITIALIZE USERDATA ###
    top.userdata.prev_joint_pos = [0,0,0]
    top.userdata.target_end_link_point = None
    top.userdata.execution_time = None
    top.userdata.active_joints = None

    remapping_list = ['prev_joint_pos', 'prev_joint_pos', 'target_end_link_point', 'execution_time', 'active_joints']
    remapping_dict = {userdata: userdata for userdata in remapping_list}

    with top:
        StateMachine.add('WAIT_FOR_MASTER', wait_for_master,
                         transitions={'exit':'exit', 'step':'STEP', 'push':'PUSH'},
                         remapping=remapping_dict)

        StateMachine.add('STEP', step,
                         transitions={'ik_failed':'WAIT_FOR_MASTER', 'success':'WAIT_FOR_MASTER'},
                         remapping=remapping_dict)

        StateMachine.add('PUSH', push,
                         transitions={'ik_failed':'WAIT_FOR_MASTER', 'success':'WAIT_FOR_MASTER'},
                         remapping=remapping_dict)

    sis = smach_ros.IntrospectionServer(str(rospy.get_name()), top, '/SM_ROOT' + str(rospy.get_name()))
    sis.start()

    #user_input = raw_input("Please press the 'Return/Enter' key to start executing \
    #     - pkg: hexapod_leg_fsm_node.py | node: " + str(rospy.get_name()) + "\n")
    print("Input received. Executing...")
    top.execute()

    rospy.spin()
    sis.stop()
    print("\nExiting " + str(rospy.get_name()))
Пример #5
0
    def __init__(self, hebi_group_name, modules, base_link_name,
                 end_link_name):

        self._hold_position = False
        self._hold_joint_angles = []

        # Set up HEBI ROS interface
        self.hebi_families = [module.split('/')[0] for module in modules]
        self.hebi_names = [module.split('/')[1] for module in modules]
        self.hebi_wrap = HebirosWrapper(hebi_group_name, self.hebi_families,
                                        self.hebi_names)
        self.hebi_mapping = modules

        #   Set HEBI Gains  # FIXME: Hardcoded for now  # FIXME: Uncomment if simulating
        """
        cmd_msg = CommandMsg()
        cmd_msg.name = self.hebi_mapping
        cmd_msg.settings.name = self.hebi_mapping
        cmd_msg.settings.position_gains.name = self.hebi_mapping
        cmd_msg.settings.position_gains.kp = [1.3, 2.6, 2.5, 1, 0.8]
        cmd_msg.settings.position_gains.ki = [0] * 5
        cmd_msg.settings.position_gains.kd = [0] * 5
        cmd_msg.settings.position_gains.i_clamp = [0] * 5
        self.hebi_wrap.send_command_with_acknowledgement(cmd_msg)
        """

        # Check ROS Parameter server for robot_description URDF
        urdf_str = ""
        urdf_loaded = False
        while not rospy.is_shutdown() and not urdf_loaded:
            if rospy.has_param('/robot_description'):
                urdf_str = rospy.get_param('/robot_description')
                urdf_loaded = True
                rospy.loginfo(
                    "Pulled /robot_description from parameter server.")
            else:
                rospy.sleep(0.01)  # sleep for 10 ms of ROS time

        # pykdl_utils setup
        robot_urdf = URDF.from_xml_string(urdf_str)
        self.kdl_fk = KDLKinematics(robot_urdf, base_link_name, end_link_name)

        # trac-ik setup
        self.trac_ik = IK(
            base_link_name,
            end_link_name,
            urdf_string=urdf_str,
            timeout=0.1,
            epsilon=1e-4,
            solve_type="Distance")  # FIXME: Decrease timeout as able

        # joint state publisher
        # Wait for connections to be setup
        while not rospy.is_shutdown() and len(
                self.hebi_wrap.get_joint_positions()) < len(self.hebi_mapping):
            rospy.sleep(0.1)
        self._joint_state_pub = rospy.Publisher('/joint_states',
                                                JointState,
                                                queue_size=1)
        self._active_joints = self.kdl_fk.get_joint_names()
        self.hebi_wrap.add_feedback_callback(self._joint_state_cb)
        self.hebi_wrap.add_feedback_callback(self._hold_position_cb)
Пример #6
0
class ArmController(object):
    def __init__(self, hebi_group_name, modules, base_link_name,
                 end_link_name):

        self._hold_position = False
        self._hold_joint_angles = []

        # Set up HEBI ROS interface
        self.hebi_families = [module.split('/')[0] for module in modules]
        self.hebi_names = [module.split('/')[1] for module in modules]
        self.hebi_wrap = HebirosWrapper(hebi_group_name, self.hebi_families,
                                        self.hebi_names)
        self.hebi_mapping = modules

        #   Set HEBI Gains  # FIXME: Hardcoded for now  # FIXME: Uncomment if simulating
        """
        cmd_msg = CommandMsg()
        cmd_msg.name = self.hebi_mapping
        cmd_msg.settings.name = self.hebi_mapping
        cmd_msg.settings.position_gains.name = self.hebi_mapping
        cmd_msg.settings.position_gains.kp = [1.3, 2.6, 2.5, 1, 0.8]
        cmd_msg.settings.position_gains.ki = [0] * 5
        cmd_msg.settings.position_gains.kd = [0] * 5
        cmd_msg.settings.position_gains.i_clamp = [0] * 5
        self.hebi_wrap.send_command_with_acknowledgement(cmd_msg)
        """

        # Check ROS Parameter server for robot_description URDF
        urdf_str = ""
        urdf_loaded = False
        while not rospy.is_shutdown() and not urdf_loaded:
            if rospy.has_param('/robot_description'):
                urdf_str = rospy.get_param('/robot_description')
                urdf_loaded = True
                rospy.loginfo(
                    "Pulled /robot_description from parameter server.")
            else:
                rospy.sleep(0.01)  # sleep for 10 ms of ROS time

        # pykdl_utils setup
        robot_urdf = URDF.from_xml_string(urdf_str)
        self.kdl_fk = KDLKinematics(robot_urdf, base_link_name, end_link_name)

        # trac-ik setup
        self.trac_ik = IK(
            base_link_name,
            end_link_name,
            urdf_string=urdf_str,
            timeout=0.1,
            epsilon=1e-4,
            solve_type="Distance")  # FIXME: Decrease timeout as able

        # joint state publisher
        # Wait for connections to be setup
        while not rospy.is_shutdown() and len(
                self.hebi_wrap.get_joint_positions()) < len(self.hebi_mapping):
            rospy.sleep(0.1)
        self._joint_state_pub = rospy.Publisher('/joint_states',
                                                JointState,
                                                queue_size=1)
        self._active_joints = self.kdl_fk.get_joint_names()
        self.hebi_wrap.add_feedback_callback(self._joint_state_cb)
        self.hebi_wrap.add_feedback_callback(self._hold_position_cb)

    def _joint_state_cb(self, msg):
        if not rospy.is_shutdown() and self._active_joints is not None:
            jointstate = JointState()
            jointstate.header.stamp = rospy.Time.now()
            jointstate.name = self._active_joints
            jointstate.position = self.hebi_wrap.get_joint_positions()
            jointstate.velocity = []
            jointstate.effort = []
            self._joint_state_pub.publish(jointstate)

    def _hold_position_cb(self, msg):
        if not rospy.is_shutdown() and self._hold_position:
            jointstate = JointState()
            jointstate.name = self.hebi_wrap.hebi_mapping
            jointstate.position = self._hold_joint_angles
            jointstate.velocity = []
            jointstate.effort = []
            self.hebi_wrap.joint_state_publisher.publish(jointstate)

    def move_to_pose(self, target_pose, mode, move_duration=0):
        """
        :param target_pose: [x,y,z,R,P,Y] or Pose msg
        :type target_pose: list or Pose

        :param mode: "trajectory" or "command"
        :type mode: str

        :param move_duration: time in seconds to complete move
        :type move_duration: float

        :return:
        """
        xyz_bounds = [0.01, 0.01, 0.01]
        wxyz_bounds = [0.05, 0.05, 0.05]

        if not isinstance(target_pose, Pose):
            # xyz
            target_xyz = [0, 0, 0]
            for i in range(3):
                if target_pose[i] in ("", " "):
                    xyz_bounds[i] = 1e5
                else:
                    target_xyz[i] = float(target_pose[i])

            # RPY
            target_rpy = [0, 0, 0]  # Tait-Byran Extrinsic xyz Euler angles
            for i in range(3):
                if target_pose[3 + i] in ("", " "):
                    wxyz_bounds[i] = 1e5
                else:
                    target_rpy[i] = float(target_pose[3 + i])
            # wxyz
            target_wxyz = transforms.quaternion_from_euler(
                target_rpy[0], target_rpy[1], target_rpy[2],
                axes='sxyz').tolist()
        else:
            target_xyz = [
                target_pose.position.x, target_pose.position.y,
                target_pose.position.z
            ]
            target_wxyz = [
                target_pose.orientation.w, target_pose.orientation.x,
                target_pose.orientation.y, target_pose.orientation.z
            ]

        print("Seed angles: {}".format(
            [round(ang, 4) for ang in self.hebi_wrap.get_joint_positions()]))
        print("Target End-Effector Pose...")
        print("  xyz: {}".format(target_xyz))
        print("  wxyz: {}".format(target_wxyz))
        print("Bounds...")
        print("  xyz: {}".format(xyz_bounds))
        print("  wxyz: {}".format(wxyz_bounds))

        # Get target joint angles
        target_jt_angles = self.trac_ik.get_ik(
            self.hebi_wrap.get_joint_positions(), target_xyz[0], target_xyz[1],
            target_xyz[2], target_wxyz[0], target_wxyz[1], target_wxyz[2],
            target_wxyz[3], xyz_bounds[0], xyz_bounds[1], xyz_bounds[2],
            wxyz_bounds[0], wxyz_bounds[1], wxyz_bounds[2])

        if target_jt_angles is None:
            print("NO JOINT SOLUTION FOUND FOR END-EFFECTOR POSE "
                  "\n(x: {}, y: {}, z: {}, W: {}, X: {}, Y: {}, Z: {})"
                  "\nPLEASE TRY AGAIN.".format(*target_xyz + target_wxyz))
            return False

        else:
            if mode == "trajectory":
                goal = TrajectoryGoal()
                start_wp = WaypointMsg()
                start_wp.names = self.hebi_mapping
                start_wp.positions = self.hebi_wrap.get_joint_positions()
                start_wp.velocities = [0] * len(self.hebi_mapping)
                start_wp.accelerations = [0] * len(self.hebi_mapping)
                goal.waypoints.append(start_wp)

                end_wp = WaypointMsg()
                end_wp.names = self.hebi_mapping
                end_wp.positions = target_jt_angles
                end_wp.velocities = [0] * len(self.hebi_mapping)
                end_wp.accelerations = [0] * len(self.hebi_mapping)
                goal.waypoints.append(end_wp)
                goal.times.extend([0, move_duration])

                self._hold_position = False
                self.hebi_wrap.trajectory_action_client.send_goal_and_wait(
                    goal)
                self._hold_joint_angles = self.hebi_wrap.get_joint_positions()
                self._hold_position = True

            else:  # mode == "command"
                cmd = JointState()
                cmd.name = self.hebi_mapping
                cmd.position = target_jt_angles
                cmd.velocity = [0] * len(self.hebi_mapping)
                cmd.effort = [0] * len(self.hebi_mapping)

                self._hold_position = False
                self.hebi_wrap.joint_state_publisher.publish(cmd)
                self._hold_joint_angles = target_jt_angles
                self._hold_position = True
            return True

    def get_end_effector_pose(self):
        h_transform_mat = self.kdl_fk.forward(
            self.hebi_wrap.get_joint_positions())
        return _get_pose_from_homogeneous_matrix(h_transform_mat)