Example 5
Example 5
In this example, we will review a Python script that prints out the positions of a selected group of Stretch's joints. This script is helpful if you need the joint positions after you teleoperated Stretch with the Xbox controller or physically moved the robot to the desired configuration after hitting the run stop button.
If you are looking for a continuous print of the joint states while Stretch is in action, then you can use the rostopic command-line tool shown in the Internal State of Stretch Tutorial.
Begin by starting up the stretch driver launch file.
# Terminal 1
roslaunch stretch_core stretch_driver.launch
cd catkin_ws/src/stretch_tutorials/src/
python3 joint_state_printer.py
position
information of the previously mentioned joints shown below.
name: ['joint_lift', 'wrist_extension', 'joint_wrist_yaw']
position: [0.6043133175850597, 0.19873586673129257, 0.017257283863713464]
The Code
#!/usr/bin/env python
import rospy
import sys
from sensor_msgs.msg import JointState
class JointStatePublisher():
"""
A class that prints the positions of desired joints in Stretch.
"""
def __init__(self):
"""
Function that initializes the subscriber.
:param self: The self reference.
"""
self.sub = rospy.Subscriber('joint_states', JointState, self.callback)
def callback(self, msg):
"""
Callback function to deal with the incoming JointState messages.
:param self: The self reference.
:param msg: The JointState message.
"""
self.joint_states = msg
def print_states(self, joints):
"""
print_states function to deal with the incoming JointState messages.
:param self: The self reference.
:param joints: A list of string values of joint names.
"""
joint_positions = []
for joint in joints:
if joint == "wrist_extension":
index = self.joint_states.name.index('joint_arm_l0')
joint_positions.append(4*self.joint_states.position[index])
continue
index = self.joint_states.name.index(joint)
joint_positions.append(self.joint_states.position[index])
print("name: " + str(joints))
print("position: " + str(joint_positions))
rospy.signal_shutdown("done")
sys.exit(0)
if __name__ == '__main__':
rospy.init_node('joint_state_printer', anonymous=True)
JSP = JointStatePublisher()
rospy.sleep(.1)
joints = ["joint_lift", "wrist_extension", "joint_wrist_yaw"]
#joints = ["joint_head_pan","joint_head_tilt", joint_gripper_finger_left", "joint_gripper_finger_right"]
JSP.print_states(joints)
rospy.spin()
The Code Explained
Now let's break the code down.
#!/usr/bin/env python
import rospy
import sys
from sensor_msgs.msg import JointState
rospy
if you are writing a ROS Node. Import sensor_msgs.msg
so that we can subscribe to JointState
messages.
self.sub = rospy.Subscriber('joint_states', JointState, self.callback)
JointState
messages. When a message comes in, ROS is going to pass it to the function "callback" automatically
def callback(self, msg):
self.joint_states = msg
JointState
messages are stored as self.joint_states. Further information about the this message type can be found here: JointState Message
def print_states(self, joints):
joint_positions = []
print_states()
function which takes in a list of joints of interest as its argument. the is also an empty list set as joint_positions and this is where the positions of the requested joints will be appended.
for joint in joints:
if joint == "wrist_extension":
index = self.joint_states.name.index('joint_arm_l0')
joint_positions.append(4*self.joint_states.position[index])
continue
index = self.joint_states.name.index(joint)
joint_positions.append(self.joint_states.position[index])
index()
function returns the index a of the name of the requested joint and appends the respective position to our joint_positions list.
rospy.signal_shutdown("done")
sys.exit(0)
rospy.init_node('joint_state_printer', anonymous=True)
JSP = JointStatePublisher()
rospy.sleep(.1)
rospy.init_node(NAME, ...)
, is very important as it tells rospy the name of your node -- until rospy has this information, it cannot start communicating with the ROS Master. NOTE: the name must be a base name, i.e. it cannot contain any slashes "/".
Declare object, JSP, from the JointStatePublisher
class.
The use of the rospy.sleep()
function is to allow the JSP class to initialize all of its features before requesting to publish joint positions of desired joints (running the print_states()
method).
joints = ["joint_lift", "wrist_extension", "joint_wrist_yaw"]
#joints = ["joint_head_pan","joint_head_tilt", joint_gripper_finger_left", "joint_gripper_finger_right"]
JSP.print_states(joints)
print_states()
method.
rospy.spin()
rospy.spin()
. This will allow the callback to be called whenever new messages come in. If we don't put this line in, then the node will not work, and ROS will not process any messages.