@ -0,0 +1,53 @@ | |||||
<launch> | |||||
<arg name="debug_directory" value="$(env HELLO_FLEET_PATH)/debug/"/> | |||||
<!-- REALSENSE D435i --> | |||||
<include file="$(find stretch_core)/launch/d435i_low_resolution.launch"></include> | |||||
<node name="d435i_configure" pkg="stretch_core" type="d435i_configure" output="screen"> | |||||
<!--<param name="initial_mode" type="string" value="Default"/>--> | |||||
<param name="initial_mode" type="string" value="High Accuracy"/> | |||||
</node> | |||||
<!-- --> | |||||
<!-- STRETCH DRIVER --> | |||||
<param name="/stretch_driver/broadcast_odom_tf" type="bool" value="false"/> | |||||
<include file="$(find stretch_core)/launch/stretch_driver.launch" pass_all_args="true"/> | |||||
<!-- --> | |||||
<!-- example of args for funmap that loads a map on launch (should have double hyphen before load_map) --> | |||||
<!-- load_map FILENAME --> | |||||
<!-- MAPPING --> | |||||
<node name="funmap" pkg="stretch_funmap" type="funmap" output="screen" > | |||||
<param name="debug_directory" type="string" value="$(arg debug_directory)"/> | |||||
</node> | |||||
<!-- --> | |||||
<!-- IMU FILTER --> | |||||
<include file="$(find stretch_core)/launch/imu_filter.launch" /> | |||||
<!-- --> | |||||
<!-- ROBOT LOCALIZATION FILTER --> | |||||
<include file="$(find stretch_core)/launch/stretch_ekf.launch" /> | |||||
<!-- --> | |||||
<!-- LASER RANGE FINDER --> | |||||
<include file="$(find stretch_core)/launch/rplidar.launch" /> | |||||
<!-- --> | |||||
<!-- LASER SCAN MATCHER FOR ODOMETRY --> | |||||
<include file="$(find stretch_core)/launch/stretch_scan_matcher.launch" /> | |||||
<!-- --> | |||||
<!-- HELLO WORLD! --> | |||||
<node name="hello_world" pkg="stretch_demos" type="hello_world" output="screen"> | |||||
<param name="debug_directory" type="string" value="$(arg debug_directory)"/> | |||||
</node> | |||||
<!-- --> | |||||
<!-- KEYBOARD TELEOP --> | |||||
<node name="keyboard_teleop" pkg="stretch_core" type="keyboard_teleop" output="screen" args='--hello_world_on'/> | |||||
<!-- --> | |||||
</launch> |
@ -0,0 +1,51 @@ | |||||
<launch> | |||||
<arg name="debug_directory" value="$(env HELLO_FLEET_PATH)/debug/"/> | |||||
<!-- REALSENSE D435i --> | |||||
<include file="$(find stretch_core)/launch/d435i_high_resolution.launch"></include> | |||||
<node name="d435i_configure" pkg="stretch_core" type="d435i_configure" output="screen"> | |||||
<!--<param name="initial_mode" type="string" value="Default"/>--> | |||||
<param name="initial_mode" type="string" value="High Accuracy"/> | |||||
</node> | |||||
<!-- --> | |||||
<!-- STRETCH DRIVER --> | |||||
<param name="/stretch_driver/broadcast_odom_tf" type="bool" value="false"/> | |||||
<include file="$(find stretch_core)/launch/stretch_driver.launch" pass_all_args="true"/> | |||||
<!-- --> | |||||
<!-- example of args for funmap that loads a map on launch (should have double hyphen before load_map) --> | |||||
<!-- load_map FILENAME --> | |||||
<!-- MAPPING --> | |||||
<node name="funmap" pkg="stretch_funmap" type="funmap" output="screen" > | |||||
<param name="debug_directory" type="string" value="$(arg debug_directory)"/> | |||||
</node> | |||||
<!-- --> | |||||
<!-- IMU FILTER --> | |||||
<include file="$(find stretch_core)/launch/imu_filter.launch" /> | |||||
<!-- --> | |||||
<!-- ROBOT LOCALIZATION FILTER --> | |||||
<include file="$(find stretch_core)/launch/stretch_ekf.launch" /> | |||||
<!-- --> | |||||
<!-- LASER RANGE FINDER --> | |||||
<include file="$(find stretch_core)/launch/rplidar.launch" /> | |||||
<!-- --> | |||||
<!-- LASER SCAN MATCHER FOR ODOMETRY --> | |||||
<include file="$(find stretch_core)/launch/stretch_scan_matcher.launch" /> | |||||
<!-- --> | |||||
<!-- OPEN DRAWER --> | |||||
<node name="open_drawer" pkg="stretch_demos" type="open_drawer" output="screen"/> | |||||
<!-- --> | |||||
<!-- KEYBOARD TELEOP --> | |||||
<node name="keyboard_teleop" pkg="stretch_core" type="keyboard_teleop" output="screen" args='--open_drawer_on'/> | |||||
<!-- --> | |||||
</launch> |
@ -0,0 +1,266 @@ | |||||
#!/usr/bin/env python | |||||
from __future__ import print_function | |||||
from sensor_msgs.msg import JointState | |||||
from geometry_msgs.msg import Twist | |||||
from nav_msgs.msg import Odometry | |||||
import rospy | |||||
import actionlib | |||||
from control_msgs.msg import FollowJointTrajectoryAction | |||||
from control_msgs.msg import FollowJointTrajectoryGoal | |||||
from trajectory_msgs.msg import JointTrajectoryPoint | |||||
from sensor_msgs.msg import PointCloud2 | |||||
from control_msgs.msg import GripperCommandAction | |||||
from control_msgs.msg import GripperCommandGoal | |||||
from std_srvs.srv import Trigger, TriggerRequest, TriggerResponse | |||||
import math | |||||
import time | |||||
import threading | |||||
import sys | |||||
import tf2_ros | |||||
import argparse as ap | |||||
import hello_helpers.hello_misc as hm | |||||
import stretch_funmap.navigate as nv | |||||
class HelloWorldNode(hm.HelloNode): | |||||
def __init__(self): | |||||
hm.HelloNode.__init__(self) | |||||
self.rate = 10.0 | |||||
self.joint_states = None | |||||
self.joint_states_lock = threading.Lock() | |||||
self.move_base = nv.MoveBase(self) | |||||
self.letter_height_m = 0.2 | |||||
self.letter_top_lift_m = 1.05 | |||||
def joint_states_callback(self, joint_states): | |||||
with self.joint_states_lock: | |||||
self.joint_states = joint_states | |||||
def align_to_surface(self): | |||||
rospy.loginfo('align_to_surface') | |||||
trigger_request = TriggerRequest() | |||||
trigger_result = self.trigger_align_with_nearest_cliff_service(trigger_request) | |||||
rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
def pen_down(self): | |||||
rospy.loginfo('pen_down') | |||||
trigger_request = TriggerRequest() | |||||
trigger_result = self.trigger_reach_until_contact_service(trigger_request) | |||||
rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
# def turn_off_contact_regulation(self): | |||||
# rospy.loginfo('turn_off_contact_regulation') | |||||
# trigger_request = TriggerRequest() | |||||
# trigger_result = self.trigger_turn_off_contact_regulation_service(trigger_request) | |||||
# rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
def pen_up(self): | |||||
rospy.loginfo('pen_up') | |||||
#self.turn_off_contact_regulation() | |||||
with self.joint_states_lock: | |||||
wrist_position, wrist_velocity, wrist_effort = hm.get_wrist_state(self.joint_states) | |||||
#backoff_m = 0.03 # back away 3cm from the surface | |||||
backoff_m = 0.1 # back away 10cm from the surface | |||||
new_wrist_position = wrist_position - backoff_m | |||||
pose = {'wrist_extension': new_wrist_position} | |||||
self.move_to_pose(pose) | |||||
def vertical_line(self, move_down, half=False): | |||||
if move_down: | |||||
rospy.loginfo('vertical_line moving down') | |||||
else: | |||||
rospy.loginfo('vertical_line moving up') | |||||
with self.joint_states_lock: | |||||
i = self.joint_states.name.index('joint_lift') | |||||
lift_position = self.joint_states.position[i] | |||||
if not half: | |||||
length_m = self.letter_height_m | |||||
else: | |||||
length_m = self.letter_height_m / 2.0 | |||||
if move_down: | |||||
new_lift_position = lift_position - length_m | |||||
else: | |||||
new_lift_position = lift_position + length_m | |||||
pose = {'joint_lift': new_lift_position} | |||||
self.move_to_pose(pose) | |||||
def horizontal_line(self, move_right, half=False): | |||||
if move_right: | |||||
rospy.loginfo('horizontal_line moving right') | |||||
else: | |||||
rospy.loginfo('horizontal_line moving left') | |||||
length_m = self.letter_height_m / 2.0 | |||||
if half: | |||||
length_m = length_m / 2.0 | |||||
if move_right: | |||||
length_m = -length_m | |||||
use_simple_move = False | |||||
if use_simple_move: | |||||
pose = {'translate_mobile_base': length_m} | |||||
self.move_to_pose(pose) | |||||
else: | |||||
if length_m > 0: | |||||
at_goal = self.move_base.forward(length_m, detect_obstacles=False) | |||||
else: | |||||
at_goal = self.move_base.backward(length_m, detect_obstacles=False) | |||||
def space(self): | |||||
rospy.loginfo('space') | |||||
self.align_to_surface() | |||||
self.horizontal_line(move_right=True, half=True) | |||||
def move_arm_out_of_the_way(self): | |||||
initial_pose = {'wrist_extension': 0.01, | |||||
'joint_lift': 0.8, | |||||
'joint_wrist_yaw': 0.0} | |||||
rospy.loginfo('Move arm out of the way of the camera.') | |||||
self.move_to_pose(initial_pose) | |||||
def move_to_initial_configuration(self): | |||||
initial_pose = {'wrist_extension': 0.01, | |||||
'joint_lift': self.letter_top_lift_m, | |||||
'joint_wrist_yaw': 0.0} | |||||
rospy.loginfo('Move to initial arm pose for writing.') | |||||
self.move_to_pose(initial_pose) | |||||
def letter_h(self): | |||||
rospy.loginfo('Letter H') | |||||
#write an letter "H" down and to the right | |||||
self.align_to_surface() | |||||
self.pen_down() | |||||
self.vertical_line(move_down=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False, half=True) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False, half=True) | |||||
self.pen_down() | |||||
self.vertical_line(move_down=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False) | |||||
def letter_e(self): | |||||
rospy.loginfo('Letter E') | |||||
# write an letter "E" down and to the right | |||||
self.align_to_surface() | |||||
self.pen_down() | |||||
self.vertical_line(move_down=True) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=False) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=True, half=True) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False, half=True) | |||||
def letter_l(self): | |||||
rospy.loginfo('Letter L') | |||||
# write an letter "L" down and to the right | |||||
self.align_to_surface() | |||||
self.pen_down() | |||||
self.vertical_line(move_down=True) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=True) | |||||
self.pen_up() | |||||
self.vertical_line(move_down=False) | |||||
def letter_o(self): | |||||
rospy.loginfo('Letter O') | |||||
# write an letter "O" down and to the right | |||||
self.align_to_surface() | |||||
self.pen_down() | |||||
self.vertical_line(move_down=True) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=True) | |||||
self.pen_down() | |||||
self.vertical_line(move_down=False) | |||||
self.pen_down() | |||||
self.horizontal_line(move_right=False) | |||||
self.pen_up() | |||||
self.horizontal_line(move_right=True) | |||||
def trigger_write_hello_callback(self, request): | |||||
#self.move_arm_out_of_the_way() | |||||
self.move_to_initial_configuration() | |||||
self.align_to_surface() | |||||
self.letter_h() | |||||
self.space() | |||||
self.letter_e() | |||||
self.space() | |||||
self.letter_l() | |||||
self.space() | |||||
self.letter_l() | |||||
self.space() | |||||
self.letter_o() | |||||
self.space() | |||||
return TriggerResponse( | |||||
success=True, | |||||
message='Completed writing hello!' | |||||
) | |||||
def main(self): | |||||
hm.HelloNode.main(self, 'hello_world', 'hello_world', wait_for_first_pointcloud=False) | |||||
self.joint_states_subscriber = rospy.Subscriber('/stretch/joint_states', JointState, self.joint_states_callback) | |||||
self.trigger_write_hello_service = rospy.Service('/hello_world/trigger_write_hello', | |||||
Trigger, | |||||
self.trigger_write_hello_callback) | |||||
rospy.wait_for_service('/funmap/trigger_align_with_nearest_cliff') | |||||
rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_align_with_nearest_cliff.') | |||||
self.trigger_align_with_nearest_cliff_service = rospy.ServiceProxy('/funmap/trigger_align_with_nearest_cliff', Trigger) | |||||
rospy.wait_for_service('/funmap/trigger_reach_until_contact') | |||||
rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_reach_until_contact.') | |||||
self.trigger_reach_until_contact_service = rospy.ServiceProxy('/funmap/trigger_reach_until_contact', Trigger) | |||||
# rospy.wait_for_service('/funmap/trigger_turn_off_contact_regulation') | |||||
# rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_turn_off_contact_regulation.') | |||||
# self.trigger_turn_off_contact_regulation_service = rospy.ServiceProxy('/funmap/trigger_turn_off_contact_regulation', Trigger) | |||||
rate = rospy.Rate(self.rate) | |||||
while not rospy.is_shutdown(): | |||||
rate.sleep() | |||||
if __name__ == '__main__': | |||||
try: | |||||
parser = ap.ArgumentParser(description='Hello World demo for stretch.') | |||||
#parser.add_argument('--mapping_on', action='store_true', help='Turn on mapping control. For example, the space bar will trigger a head scan. This requires that the mapping node be run (funmap).') | |||||
args, unknown = parser.parse_known_args() | |||||
node = HelloWorldNode() | |||||
node.main() | |||||
except KeyboardInterrupt: | |||||
rospy.loginfo('interrupt received, so shutting down') | |||||
# except rospy.ROSInterruptException: | |||||
# pass | |||||
#rospy.loginfo('keyboard_teleop was interrupted', file=sys.stderr) | |||||
@ -0,0 +1,179 @@ | |||||
#!/usr/bin/env python | |||||
from __future__ import print_function | |||||
from sensor_msgs.msg import JointState | |||||
from geometry_msgs.msg import Twist | |||||
from nav_msgs.msg import Odometry | |||||
import rospy | |||||
import actionlib | |||||
from control_msgs.msg import FollowJointTrajectoryAction | |||||
from control_msgs.msg import FollowJointTrajectoryGoal | |||||
from trajectory_msgs.msg import JointTrajectoryPoint | |||||
from sensor_msgs.msg import PointCloud2 | |||||
from control_msgs.msg import GripperCommandAction | |||||
from control_msgs.msg import GripperCommandGoal | |||||
from std_srvs.srv import Trigger, TriggerRequest, TriggerResponse | |||||
import math | |||||
import time | |||||
import threading | |||||
import sys | |||||
import tf2_ros | |||||
import argparse as ap | |||||
import hello_helpers.hello_misc as hm | |||||
import stretch_funmap.navigate as nv | |||||
class OpenDrawerNode(hm.HelloNode): | |||||
def __init__(self): | |||||
hm.HelloNode.__init__(self) | |||||
self.rate = 10.0 | |||||
self.joint_states = None | |||||
self.joint_states_lock = threading.Lock() | |||||
self.move_base = nv.MoveBase(self) | |||||
self.letter_height_m = 0.2 | |||||
self.wrist_position = None | |||||
def joint_states_callback(self, joint_states): | |||||
with self.joint_states_lock: | |||||
self.joint_states = joint_states | |||||
wrist_position, wrist_velocity, wrist_effort = hm.get_wrist_state(joint_states) | |||||
self.wrist_position = wrist_position | |||||
def align_to_surface(self): | |||||
rospy.loginfo('align_to_surface') | |||||
trigger_request = TriggerRequest() | |||||
trigger_result = self.trigger_align_with_nearest_cliff_service(trigger_request) | |||||
rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
def extend_hook_until_contact(self): | |||||
rospy.loginfo('extend_hook_until_contact') | |||||
trigger_request = TriggerRequest() | |||||
trigger_result = self.trigger_reach_until_contact_service(trigger_request) | |||||
rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
def lower_hook_until_contact(self): | |||||
rospy.loginfo('lower_hook_until_contact') | |||||
trigger_request = TriggerRequest() | |||||
trigger_result = self.trigger_lower_until_contact_service(trigger_request) | |||||
rospy.loginfo('trigger_result = {0}'.format(trigger_result)) | |||||
def backoff_from_surface(self): | |||||
rospy.loginfo('backoff_from_surface') | |||||
if self.wrist_position is not None: | |||||
wrist_target_m = self.wrist_position - 0.012 #0.015 #0.018 #0.02 #0.022 #0.025 #0.008 #0.005 | |||||
pose = {'wrist_extension': wrist_target_m} | |||||
self.move_to_pose(pose) | |||||
return True | |||||
else: | |||||
rospy.logerr('backoff_from_surface: self.wrist_position is None!') | |||||
return False | |||||
def pull_open(self): | |||||
rospy.loginfo('pull_open') | |||||
if self.wrist_position is not None: | |||||
wrist_target_m = self.wrist_position - 0.2 | |||||
pose = {'wrist_extension': wrist_target_m} | |||||
self.move_to_pose(pose) | |||||
return True | |||||
else: | |||||
rospy.logerr('pull_open: self.wrist_position is None!') | |||||
return False | |||||
def push_closed(self): | |||||
rospy.loginfo('push_closed') | |||||
if self.wrist_position is not None: | |||||
wrist_target_m = self.wrist_position + 0.22 | |||||
pose = {'wrist_extension': wrist_target_m} | |||||
self.move_to_pose(pose) | |||||
return True | |||||
else: | |||||
rospy.logerr('pull_open: self.wrist_position is None!') | |||||
return False | |||||
def move_to_initial_configuration(self): | |||||
initial_pose = {'wrist_extension': 0.01, | |||||
'joint_gripper': 1.62, | |||||
'joint_gripper_finger_left': -0.25} | |||||
#'joint_lift': 0.71, | |||||
rospy.loginfo('Move to the initial configuration for drawer opening.') | |||||
self.move_to_pose(initial_pose) | |||||
def trigger_open_drawer_callback(self, request): | |||||
self.move_to_initial_configuration() | |||||
#self.align_to_surface() | |||||
self.extend_hook_until_contact() | |||||
success = self.backoff_from_surface() | |||||
if not success: | |||||
return TriggerResponse( | |||||
success=False, | |||||
message='Failed to backoff from the surface.' | |||||
) | |||||
self.lower_hook_until_contact() | |||||
success = self.pull_open() | |||||
if not success: | |||||
return TriggerResponse( | |||||
success=False, | |||||
message='Failed to pull open the drawer.' | |||||
) | |||||
push_drawer_closed = False | |||||
if push_drawer_closed: | |||||
rospy.sleep(3.0) | |||||
self.push_closed() | |||||
return TriggerResponse( | |||||
success=True, | |||||
message='Completed opening the drawer!' | |||||
) | |||||
def main(self): | |||||
hm.HelloNode.main(self, 'open_drawer', 'open_drawer', wait_for_first_pointcloud=False) | |||||
self.joint_states_subscriber = rospy.Subscriber('/stretch/joint_states', JointState, self.joint_states_callback) | |||||
self.trigger_open_drawer_service = rospy.Service('/open_drawer/trigger_open_drawer', | |||||
Trigger, | |||||
self.trigger_open_drawer_callback) | |||||
rospy.wait_for_service('/funmap/trigger_align_with_nearest_cliff') | |||||
rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_align_with_nearest_cliff.') | |||||
self.trigger_align_with_nearest_cliff_service = rospy.ServiceProxy('/funmap/trigger_align_with_nearest_cliff', Trigger) | |||||
rospy.wait_for_service('/funmap/trigger_reach_until_contact') | |||||
rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_reach_until_contact.') | |||||
self.trigger_reach_until_contact_service = rospy.ServiceProxy('/funmap/trigger_reach_until_contact', Trigger) | |||||
rospy.wait_for_service('/funmap/trigger_lower_until_contact') | |||||
rospy.loginfo('Node ' + self.node_name + ' connected to /funmap/trigger_lower_until_contact.') | |||||
self.trigger_lower_until_contact_service = rospy.ServiceProxy('/funmap/trigger_lower_until_contact', Trigger) | |||||
rate = rospy.Rate(self.rate) | |||||
while not rospy.is_shutdown(): | |||||
rate.sleep() | |||||
if __name__ == '__main__': | |||||
try: | |||||
parser = ap.ArgumentParser(description='Open Drawer behavior for stretch.') | |||||
#parser.add_argument('--mapping_on', action='store_true', help='Turn on mapping control. For example, the space bar will trigger a head scan. This requires that the mapping node be run (funmap).') | |||||
args, unknown = parser.parse_known_args() | |||||
node = OpenDrawerNode() | |||||
node.main() | |||||
except KeyboardInterrupt: | |||||
rospy.loginfo('interrupt received, so shutting down') | |||||
# except rospy.ROSInterruptException: | |||||
# pass | |||||
#rospy.loginfo('keyboard_teleop was interrupted', file=sys.stderr) | |||||