IK Service - Code Walkthrough

From sdk-wiki
Jump to: navigation, search

Introduction

This example demonstrates the usage of the IK service that is available in Baxter. The main() function records the side of the joint on which the IK service is to be called and then invokes the ik_test() function. This is where the rospy node is initialized, default cartesian coordinates are initialized, and the IK service is called.
Service - "ExternalTools/<side>/PositionKinematicsNode/IKService"

Code Walkthrough

Now, let's break down the code

33 import argparse
34 import sys
35 
36 import rospy
37 
38 from geometry_msgs.msg import (
39     PoseStamped,
40     Pose,
41     Point,
42     Quaternion,
43 )
44 from std_msgs.msg import Header
45 
46 from baxter_core_msgs.srv import (
47     SolvePositionIK,
48     SolvePositionIKRequest,
49 )

The geometry message types are imported to build the request message for the IK service. The custom request and response message types (baxter_core_msgs-SolvePositionIK) are imported from the baxter_core_msgs package.

52 def ik_test(limb):
53     rospy.init_node("rsdk_ik_service_client")
54     ns = "ExternalTools/" + limb + "/PositionKinematicsNode/IKService"
55     iksvc = rospy.ServiceProxy(ns, SolvePositionIK)
56     ikreq = SolvePositionIKRequest()
57     hdr = Header(stamp=rospy.Time.now(), frame_id='base')

The ros node is initialized. An object for the service call is initialized by passing the service name ns and the Request-Response message type, SolvePositionIK. SolvePositionIKRequest is the IK Request message type that is generated at compile time.

58     poses = {
59         'left': PoseStamped(
60             header=hdr,
61             pose=Pose(
62                 position=Point(
63                     x=0.657579481614,
64                     y=0.851981417433,
65                     z=0.0388352386502,
66                 ),
67                 orientation=Quaternion(
68                     x=-0.366894936773,
69                     y=0.885980397775,
70                     z=0.108155782462,
71                     w=0.262162481772,
72                 ),
73             ),
74         ),
75         'right': PoseStamped(
76             header=hdr,
77             pose=Pose(
78                 position=Point(
79                     x=0.656982770038,
80                     y=-0.852598021641,
81                     z=0.0388609422173,
82                 ),
83                 orientation=Quaternion(
84                     x=0.367048116303,
85                     y=0.885911751787,
86                     z=-0.108908281936,
87                     w=0.261868353356,
88                 ),
89             ),
90         ),
91     }
92 
93     ikreq.pose_stamp.append(poses[limb])

The poses dictionary is populated with hard-coded cartesian coordinates for both the limbs. The last line indicates that the pose of the side of the limb under interest, is copied to the IK request message.

94     try:
95         rospy.wait_for_service(ns, 5.0)
96         resp = iksvc(ikreq)
97     except (rospy.ServiceException, rospy.ROSException), e:
98         rospy.logerr("Service call failed: %s" % (e,))
99         return 1

With a timeout of 5 seconds, the IK service is called along with the IK request message. The resp objects captures the response message which contains the joint positions. It throws an error on timeout.

 94     if (resp.isValid[0]):
 95         print("SUCCESS - Valid Joint Solution Found:")
 96         # Format solution into Limb API-compatible dictionary
 97         limb_joints = dict(zip(resp.joints[0].name, resp.joints[0].position))
 98         print limb_joints
 99     else:
100         print("INVALID POSE - No Valid Joint Solution Found.")
101 
102     return 0

The isValid[0] field is a boolean variable that indicates whether a successfull solution for the IK was found or not. The limb_joints is dictionary that holds the joint names and their corresponding position from the response message. This can be passed as a joint command to the position controller to move the arm to the corresponding position.

111 def main():
112     """RSDK Inverse Kinematics Example
113 
114     A simple example of using the Rethink Inverse Kinematics
115     Service which returns the joint angles and validity for
116     a requested Cartesian Pose.
117 
118     Run this example, passing the *limb* to test, and the
119     example will call the Service with a sample Cartesian
120     Pose, pre-defined in the example code, printing the
121     response of whether a valid joint solution was found,
122     and if so, the corresponding joint angles.
123     """
124     arg_fmt = argparse.RawDescriptionHelpFormatter
125     parser = argparse.ArgumentParser(formatter_class=arg_fmt,
126                                      description=main.__doc__)
127     parser.add_argument(
128         '-l', '--limb', choices=['left', 'right'], required=True,
129         help="the limb to test"
130     )
131     args = parser.parse_args(rospy.myargv()[1:])

The main function parses the arguments provided by the user to capture the side of the arm on which the example is to be run.

133     return ik_test(args.limb)
134 
135 if __name__ == '__main__':
136     sys.exit(main())

The ik_test() function is called with the side of the limb as an argument to calculate the IK service as explained above.