This example demonstrates basic joint position control. A joint position waypoint is a configuration of the arm in joint space i.e. simultaneous joint angles for the arm´s seven degrees of freedom). In this example, we enable the robot moving the limb in zero-g mode. Interacting with the arm´s navigator buttons, we can record a sequence of joint position waypoints. Upon completion of recording, we will continuously command the limb loop through the recorded joint sequence.


Contents


Introduction


This example demonstrates the usage of the position controller for simple joint position moves. The main() function calls the record() method which records the waypoints as desired by the user. Then, the playback() method is invoked which demonstrates a smooth motion playback through the recorded joint positions.
Interfaces -

  • Limb.move_to_joint_positions()
  • Limb.set_joint_position_speed()
  • Limb.joint_angles()
  • Navigator.wheel()
  • Navigator.button_state()

If you would like to follow along with the actual source code for the example on GitHub, it can be found through this link for joint position waypoints example.


Usage


Verify that the robot is enabled from an SDK terminal session, ex:

 

$ rosrun intera_interface robot_enable.py

 
Start the joint position waypoints example program, you can specify the joint position motion speed ratio -s or joint position accuracy(rad) -a on which we will run the example.

For example, run the example with 0.1 speed ratio and 0.1 accuracy:

 

$ rosrun intera_examples joint_position_waypoints.py -s 0.1 -a 0.1

 
Moving the arm in zero-g mode, when we reach a joint position configuration we would like to record, press that navigator wheel.


 You will then be prompted with instructions for recording joint position waypoints.

 

Press Navigator 'OK/Wheel' button to record a new joint joint position waypoint.
Press Navigator 'Rethink' button when finished recording waypoints to begin playback.

 
Moving the arm in zero-g mode, when we reach a joint position configuration we would like to record, press that navigator wheel.


 You will get the feedback that the joint position waypoint has been recorded:

 

Waypoint Recorded


When done recording waypoints, pressing the navigator's 'Rethink' button will begin playback.

 

[INFO] [WallTime: 1399571721.540300] Waypoint Playback Started
  Press Ctrl-C to stop...

 
 The program will begin looping through the recorded joint positions. When the previous joint position command is fully achieved (within the accuracy threshold), the next recorded joint position will be commanded.

 

Waypoint playback loop #1
Waypoint playback loop #2
...

 

Pressing Control-C at any time will stop playback and exit the example.


Arguments


Important Arguments:

-s or --speed : The joint position motion speed ratio [0.0-1.0] (default:= 0.3)

-a or --accuracy : The threshold in Radians at which the current joint position command is considered successful before sending the next following joint position command. (default:= 0.008726646)

See the joint position waypoint's available arguments on the command line by passing joint_position_waypoints.py the -h, help argument:

 

$ rosrun intera_examples joint_position_waypoints.py -h
usage: joint_position_waypoints.py [-h] [-s SPEED] [-a ACCURACY]
 
RSDK Joint Position Waypoints Example
 
    Records joint positions each time the navigator 'OK/wheel'
    button is pressed.
    Upon pressing the navigator 'Rethink' button, the recorded joint positions
    will begin playing back in a loop.
    
 
optional arguments:
  -h, --help            show this help message and exit
  -s SPEED, --speed SPEED
                        joint position motion speed ratio [0.0-1.0] (default:=
                        0.3)
  -a ACCURACY, --accuracy ACCURACY
                        joint position accuracy (rad) at which waypoints must
                        achieve


Code Walkthrough


Now, let's break down the code.

 

import argparse
import sys

import rospy

import intera_interface

 

This imports the intera interface for accessing the limb and the gripper class.

  

class Waypoints(object):
    def __init__(self, speed, accuracy, limb="right"):
        # Create intera_interface limb instance
        self._arm = limb
        self._limb = intera_interface.Limb(self._arm)

        # Parameters which will describe joint position moves
        self._speed = speed
        self._accuracy = accuracy

        # Recorded waypoints
        self._waypoints = list()

        # Recording state
        self._is_recording = False

        # Verify robot is enabled
        print("Getting robot state... ")
        self._rs = intera_interface.RobotEnable()
        self._init_state = self._rs.state().enabled
        print("Enabling robot... ")
        self._rs.enable()

        # Create Navigator I/O
        self._navigator_io = intera_interface.Navigator(self._arm)

 

An instance of the limb interface for the side under interest is created. An instance of the interface for the corresponding navigator, _navigator_io, is also created. The robot is then enabled. It is important to note that the robot should be enabled in order to control the limb's movement.

  

    def _record_waypoint(self, value):
        """
        Stores joint position waypoints

        Navigator 'OK/Wheel' button callback
        """
        if value != 'OFF':
            print("Waypoint Recorded")
            self._waypoints.append(self._limb.joint_angles())

 

The joint_angles() method retrieves the current joint angles and they are then appended to the _waypoints list.

   

    def _stop_recording(self, value):
        """
        Sets is_recording to false

        Navigator 'Rethink' button callback
        """
        # On navigator Rethink button press, stop recording
        if value != 'OFF':
            print("Recording Stopped")
            self._is_recording = False

 

This Rethink button's press event is captured.

  

    def record(self):
        """
        Records joint position waypoints upon each Navigator 'OK/Wheel' button
        press.
        """
        rospy.loginfo("Waypoint Recording Started")
        print("Press Navigator 'OK/Wheel' button to record a new joint "
        "joint position waypoint.")
        print("Press Navigator 'Rethink' button when finished recording "
              "waypoints to begin playback")
        # Connect Navigator callbacks
        # Navigator scroll wheel button press
        ok_id = self._navigator.register_callback(self._record_waypoint, 'right_button_ok')
        # Navigator Rethink button press
        show_id = self._navigator.register_callback(self._stop_recording, 'right_button_show')

        # Set recording flag
        self._is_recording = True

        # Loop until waypoints are done being recorded ('Rethink' Button Press)
        while not rospy.is_shutdown() and self._is_recording:
            rospy.sleep(1.0)

        # We are now done with the navigator callbacks, disconnecting them
        self._navigator.deregister_callback(ok_id)
        self._navigator.deregister_callback(show_id)

 

The navigator 'OK/Wheel' button invokes the _record_waypoint() method on a press event, which records the current joint positions as explained above. Similarly, the navigator 'Rethink' button invokes the _stop_recording method on a press event, which sets the is_recording variable to false.

  

    def playback(self):
        """
        Loops playback of recorded joint position waypoints until program is
        exited
        """
        rospy.sleep(1.0)

        rospy.loginfo("Waypoint Playback Started")
        print("  Press Ctrl-C to stop...")

        # Set joint position speed ratio for execution
        self._limb.set_joint_position_speed(self._speed)

        # Loop until program is exited
        loop = 0
        while not rospy.is_shutdown():
            loop += 1
            print("Waypoint playback loop #%d " % (loop,))
            for waypoint in self._waypoints:
                if rospy.is_shutdown():
                    break
                self._limb.move_to_joint_positions(waypoint, timeout=20.0,
                                                   threshold=self._accuracy)
            # Sleep for a few seconds between playback loops
            rospy.sleep(3.0)

        # Set joint position speed back to default
        self._limb.set_joint_position_speed(0.3)

 

The set_joint_position_speed() method sets the ratio of max joint speed to use during joint position moves. The method move_to_joint_positions(), moves the joints to the commanded position. It is important to note that there is not trajectory planning involved here. Instead, this is passed onto a low pass filter and the intermediate positions between the start and goal positions are obtained. They are then published as a joint command message using the set_joint_positions() method. Thus, all the waypoints that were stored are visited along a smooth trajectory.

  

    def clean_shutdown(self):
        print("\nExiting example...")
        if not self._init_state:
            print("Disabling robot...")
            self._rs.disable()
        return True

 

On shutdown, the robot is sent to its initial state that was captured.

  

def main():
    """RSDK Joint Position Waypoints Example

    Records joint positions each time the navigator 'OK/wheel'
    button is pressed.
    Upon pressing the navigator 'Rethink' button, the recorded joint positions
    will begin playing back in a loop.
    """
    arg_fmt = argparse.RawDescriptionHelpFormatter
    parser = argparse.ArgumentParser(formatter_class=arg_fmt,
                                     description=main.__doc__)
    parser.add_argument(
        '-s', '--speed', default=0.3, type=float,
        help='joint position motion speed ratio [0.0-1.0] (default:= 0.3)'
    )
    parser.add_argument(
        '-a', '--accuracy',
        default=intera_interface.settings.JOINT_ANGLE_TOLERANCE, type=float,
        help='joint position accuracy (rad) at which waypoints must achieve'
    )
    args = parser.parse_args(rospy.myargv()[1:])

 

The speed and accuracy on which the example is to be demonstrated is captured from the command line arguments.

  

    print("Initializing node... ")
    rospy.init_node("rsdk_joint_position_waypoints")

    waypoints = Waypoints(args.speed, args.accuracy)

    # Register clean shutdown
    rospy.on_shutdown(waypoints.clean_shutdown)

    # Begin example program
    waypoints.record()
    waypoints.playback()

if __name__ == '__main__':
    main()

 

The node is initialized and an instance of the Waypoints class is created. The user defined waypoints are recorded using the record() method and are played back using the playback() method as explained above.