Lab 6: Controlling the head - cse481sp17/cse481c GitHub Wiki
In this lab, you will implement head movement on the Fetch.
Read the Head Interface docs
The head interface section of the Fetch docs explains that there are two ways to control the head. The first is to specify a point in space to look at. The second is to control the pan and tilt angles of the head directly.
Figure out the joint limits
Look at the "Robot Hardware Overview" section of the Fetch docs. As we did in the previous labs, we will look up the joint limits and maximum velocity of the pan and tilt angles.
- What are the joint limits of the pan/tilt joints?
- What is the maximum angular speed of the pan/tilt joints?
Based on the joint limits and the maximum angular speed, 2.5 seconds is a reasonable, conservative duration for a head trajectory.
Implement a demo
In this lab, we will go through the steps of implementing a demo for head movement.
Create a file called head_demo.py
in applications/scripts
.
Here is some starter code for the demo file:
#! /usr/bin/env python
import rospy
def print_usage():
print 'Usage:'
print ' rosrun applications head_demo.py look_at FRAME_ID X Y Z'
print ' rosrun applications head_demo.py pan_tilt PAN_ANG TILT_ANG'
print 'Examples:'
print ' rosrun applications head_demo.py look_at base_link 1 0 0.3'
print ' rosrun applications head_demo.py pan_tilt 0 0.707'
def wait_for_time():
"""Wait for simulated time to begin.
"""
while rospy.Time().now().to_sec() == 0:
pass
def main():
rospy.init_node('head_demo')
wait_for_time()
argv = rospy.myargv()
if len(argv) < 2:
print_usage()
return
command = argv[1]
if command == 'look_at':
if len(argv) < 6:
print_usage()
return
frame_id, x, y, z = argv[2], float(argv[3]), float(argv[4]), float(
argv[5])
rospy.logerr('Not implemented.')
elif command == 'pan_tilt':
if len(argv) < 4:
print_usage()
return
pan, tilt = float(argv[2]), float(argv[3])
rospy.logerr('Not implemented.')
else:
print_usage()
if __name__ == '__main__':
main()
As usual, you will need to complete the implementation.
applications
and fetch_api
?
What's the difference between Notice that our repo splits code into library code (fetch_api
) and application code (applications
).
A file like head_demo.py
is an application because it has a main
function.
In general, we would like our applications to be small, and for them to mostly call out to library code.
A common convention is to place Python application code in a folder named scripts
, while modules are placed in src
.
fetch_api
?
How do applications know about files in The demo file imports code from the fetch_api
module.
Normally, in Python, when you import a module, it is pre-installed on the system, or the file by the same name is adjacent to the current file.
So how do our demo files know where fetch_api
is, when there is no fetch_api.py
adjacent to our demo files?
This is something that catkin handles.
Our course repo already configures catkin properly, but in the future, we will show you how to configure catkin in this way.
fetch_api
?
How do I extend The fetch_api
module is defined in fetch_api/src/fetch_api
.
The actual content of the fetch_api
module is explicitly listed in fetch_api/src/fetch_api/__init__.py
.
For a class like Head
to be part of the fetch_api
module, we must import it in __init__.py
.
Implement head movement
Add the following starter code to fetch_api/src/fetch_api/head.py
:
#!/usr/bin/env python
# TODO: import ?????????
# TODO: import ???????_msgs.msg
# TODO: import ??????????_msgs.msg
import math
import rospy
LOOK_AT_ACTION_NAME = '' # TODO: Get the name of the look-at action
PAN_TILT_ACTION_NAME = '' # TODO: Get the name of the pan/tilt action
PAN_JOINT = '' # TODO: Get the name of the head pan joint
TILT_JOINT = '' # TODO: Get the name of the head tilt joint
PAN_TILT_TIME = 2.5 # How many seconds it should take to move the head.
class Head(object):
"""Head controls the Fetch's head.
It provides two interfaces:
head.look_at(frame_id, x, y, z)
head.pan_tilt(pan, tilt) # In radians
For example:
head = fetch_api.Head()
head.look_at('base_link', 1, 0, 0.3)
head.pan_tilt(0, math.pi/4)
"""
MIN_PAN = None # TODO: Minimum pan angle, in radians.
MAX_PAN = None # TODO: Maximum pan angle, in radians.
MIN_TILT = None # TODO: Minimum tilt angle, in radians.
MAX_TILT = None # TODO: Maximum tilt angle, in radians.
def __init__(self):
# TODO: Create actionlib clients
# TODO: Wait for both servers
pass
def look_at(self, frame_id, x, y, z):
"""Moves the head to look at a point in space.
Args:
frame_id: The name of the frame in which x, y, and z are specified.
x: The x value of the point to look at.
y: The y value of the point to look at.
z: The z value of the point to look at.
"""
# TODO: Create goal
# TODO: Fill out the goal (we recommend setting min_duration to 1 second)
# TODO: Send the goal
# TODO: Wait for result
rospy.logerr('Not implemented.')
def pan_tilt(self, pan, tilt):
"""Moves the head by setting pan/tilt angles.
Args:
pan: The pan angle, in radians. A positive value is clockwise.
tilt: The tilt angle, in radians. A positive value is downwards.
"""
# TODO: Check that the pan/tilt angles are within joint limits
# TODO: Create a trajectory point
# TODO: Set positions of the two joints in the trajectory point
# TODO: Set time of the trajectory point
# TODO: Create goal
# TODO: Add joint names to the list
# TODO: Add trajectory point created above to trajectory
# TODO: Send the goal
# TODO: Wait for result
rospy.logerr('Not implemented.')
Implementation hints:
- It is common to find "Stamped" messages in ROS. This means that the message includes a field of type
std_msgs/Header
. This is where you specify theframe_id
: in theheader
.
Now, add the Head
class to the fetch_api
module by editing fetch_api/src/fetch_api/__init__.py
and adding the following:
from .head import Head
Run the demo
rosrun applications head_demo.py look_at base_link 1 0 0.3
rosrun applications head_demo.py pan_tilt 0 0
Positive x
, y
, and z
are forward, left, and up, respectively.
The base_link
is in the center of the robot's base, on the ground.
So x=1, y=0, z=0.3 in base_link
means 1 meter straight ahead, 30 cm above the ground.