Go to the documentation of this file.00001
00002
00003 import math
00004 import numpy
00005
00006 import rospy
00007 import os
00008 import sys
00009
00010 import imp
00011 try:
00012 imp.find_module("sensor_msgs")
00013 except:
00014 import roslib; roslib.load_manifest('jsk_teleop_joy')
00015
00016
00017 from sensor_msgs.msg import Joy
00018 from diagnostic_msgs.msg import DiagnosticStatus, DiagnosticArray
00019 import tf.transformations
00020 from joy_status import XBoxStatus, PS3Status, PS3WiredStatus
00021 from jsk_rviz_plugins.msg import OverlayMenu
00022 from plugin_manager import PluginManager
00023 from status_history import StatusHistory
00024 from diagnostic_updater import Updater as DiagnosticUpdater
00025
00026 AUTO_DETECTED_CLASS = None
00027
00028 def autoJoyDetect(msg):
00029 global AUTO_DETECTED_CLASS
00030 if AUTO_DETECTED_CLASS:
00031 return
00032 if len(msg.axes) == 27 and len(msg.buttons) == 19:
00033 rospy.loginfo("auto detected as ps3wired")
00034 AUTO_DETECTED_CLASS = PS3WiredStatus
00035 elif len(msg.axes) == 8 and len(msg.buttons) == 11:
00036 rospy.loginfo("auto detected as xbox")
00037 AUTO_DETECTED_CLASS = XBoxStatus
00038 elif len(msg.axes) == 20 and len(msg.buttons) == 17:
00039 rospy.loginfo("auto detected as ps3")
00040 AUTO_DETECTED_CLASS = PS3Status
00041 else:
00042 AUTO_DETECTED_CLASS = "UNKNOWN"
00043
00044 class JoyManager():
00045 STATE_INITIALIZATION = 1
00046 STATE_RUNNING = 2
00047 STATE_WAIT_FOR_JOY = 3
00048
00049 MODE_PLUGIN = 0
00050 MODE_MENU = 1
00051 mode = 0
00052
00053 plugin_instances = []
00054 def stateDiagnostic(self, stat):
00055 if self.state == self.STATE_INITIALIZATION:
00056 stat.summary(DiagnosticStatus.WARN,
00057 "initializing JoyManager")
00058 elif self.state == self.STATE_RUNNING:
00059 stat.summary(DiagnosticStatus.OK,
00060 "running")
00061 stat.add("Joy stick type", str(self.JoyStatus))
00062 elif self.state == self.STATE_WAIT_FOR_JOY:
00063 stat.summary(DiagnosticStatus.WARN,
00064 "waiting for joy message to detect joy stick type")
00065 return stat
00066 def pluginStatusDiagnostic(self, stat):
00067 if len(self.plugin_instances) == 0:
00068 stat.summary(DiagnosticStatus.ERROR, "no plugin is loaded")
00069 else:
00070 stat.summary(DiagnosticStatus.OK,
00071 "%d plugins are loaded" % (len(self.plugin_instances)))
00072 stat.add("instances", ", ".join([p.name for p in self.plugin_instances]))
00073 return stat
00074 def __init__(self):
00075 self.state = self.STATE_INITIALIZATION
00076 self.pre_status = None
00077 self.history = StatusHistory(max_length=10)
00078 self.menu_pub = rospy.Publisher("/overlay_menu", OverlayMenu)
00079 self.controller_type = rospy.get_param('~controller_type', 'auto')
00080 self.plugins = rospy.get_param('~plugins', {})
00081 self.current_plugin_index = 0
00082 self.selecting_plugin_index = 0
00083
00084 self.diagnostic_updater = DiagnosticUpdater()
00085 self.diagnostic_updater.setHardwareID("teleop_manager")
00086 self.diagnostic_updater.add("State", self.stateDiagnostic)
00087 self.diagnostic_updater.add("Plugin Status", self.pluginStatusDiagnostic)
00088
00089 self.diagnostic_updater.update()
00090 if self.controller_type == 'xbox':
00091 self.JoyStatus = XBoxStatus
00092 elif self.controller_type == 'ps3':
00093 self.JoyStatus = PS3Status
00094 elif self.controller_type == 'ps3wired':
00095 self.JoyStatus = PS3WiredStatus
00096 elif self.controller_type == 'auto':
00097 s = rospy.Subscriber('/joy', Joy, autoJoyDetect)
00098 self.state = self.STATE_WAIT_FOR_JOY
00099 error_message_published = False
00100 r = rospy.Rate(1)
00101 while not rospy.is_shutdown():
00102 self.diagnostic_updater.update()
00103 if AUTO_DETECTED_CLASS == "UNKNOWN":
00104 if not error_message_published:
00105 rospy.logfatal("unknown joy type")
00106 error_message_published = True
00107 r.sleep()
00108 elif AUTO_DETECTED_CLASS:
00109 self.JoyStatus = AUTO_DETECTED_CLASS
00110 s.unregister()
00111 break
00112 else:
00113 r.sleep()
00114 self.diagnostic_updater.update()
00115 self.plugin_manager = PluginManager('jsk_teleop_joy')
00116 self.loadPlugins()
00117 def loadPlugins(self):
00118 self.plugin_manager.loadPlugins()
00119 self.plugin_instances = self.plugin_manager.loadPluginInstances(self.plugins, self)
00120 def switchPlugin(self, index):
00121 self.current_plugin_index = index
00122 if len(self.plugin_instances) <= self.current_plugin_index:
00123 self.current_plugin_index = 0
00124 elif self.current_plugin_index < 0:
00125 self.current_plugin_index = len(self.plugin_instances)
00126 self.current_plugin.disable()
00127 self.current_plugin = self.plugin_instances[self.current_plugin_index]
00128 self.current_plugin.enable()
00129 def nextPlugin(self):
00130 rospy.loginfo('switching to next plugin')
00131 self.switchPlugin(self, self.current_plugin_index + 1)
00132 def start(self):
00133 self.publishMenu(0, close=True)
00134 self.diagnostic_updater.force_update()
00135 if len(self.plugin_instances) == 0:
00136 rospy.logfatal('no valid plugins are loaded')
00137 return False
00138 self.current_plugin = self.plugin_instances[0]
00139 self.current_plugin.enable()
00140 self.joy_subscriber = rospy.Subscriber('/joy', Joy, self.joyCB)
00141 self.state = self.STATE_RUNNING
00142 return True
00143 def publishMenu(self, index, close=False):
00144 menu = OverlayMenu()
00145 menu.menus = [p.name for p in self.plugin_instances]
00146 menu.current_index = index
00147 menu.title = "Joystick"
00148 if close:
00149 menu.action = OverlayMenu.ACTION_CLOSE
00150 self.menu_pub.publish(menu)
00151 def forceToPluginMenu(self, publish_menu=False):
00152 self.selecting_plugin_index = self.current_plugin_index
00153 if publish_menu:
00154 self.publishMenu(self.current_plugin_index)
00155 self.mode = self.MODE_MENU
00156 def processMenuMode(self, status, history):
00157 if history.new(status, "down") or history.new(status, "left_analog_down"):
00158 self.selecting_plugin_index = self.selecting_plugin_index + 1
00159 if self.selecting_plugin_index >= len(self.plugin_instances):
00160 self.selecting_plugin_index = 0
00161 self.publishMenu(self.selecting_plugin_index)
00162 elif history.new(status, "up") or history.new(status, "left_analog_up"):
00163 self.selecting_plugin_index = self.selecting_plugin_index - 1
00164 if self.selecting_plugin_index < 0:
00165 self.selecting_plugin_index = len(self.plugin_instances) - 1
00166 self.publishMenu(self.selecting_plugin_index)
00167 elif history.new(status, "cross") or history.new(status, "center"):
00168 self.publishMenu(self.selecting_plugin_index, close=True)
00169 self.mode = self.MODE_PLUGIN
00170 elif history.new(status, "circle"):
00171 self.publishMenu(self.selecting_plugin_index, close=True)
00172 self.mode = self.MODE_PLUGIN
00173 self.switchPlugin(self.selecting_plugin_index)
00174 else:
00175 self.publishMenu(self.selecting_plugin_index)
00176 def joyCB(self, msg):
00177 status = self.JoyStatus(msg)
00178 if self.mode == self.MODE_MENU:
00179 self.processMenuMode(status, self.history)
00180 else:
00181 if self.history.new(status, "center"):
00182 self.forceToPluginMenu()
00183 else:
00184 self.current_plugin.joyCB(status, self.history)
00185 self.pre_status = status
00186 self.history.add(status)
00187 self.diagnostic_updater.update()
00188
00189 def main():
00190 global g_manager
00191 rospy.sleep(1)
00192 rospy.init_node('jsk_teleop_joy')
00193 g_manager = JoyManager()
00194 result = g_manager.start()
00195 if not result:
00196 rospy.logfatal("Fatal Error")
00197 return False
00198 else:
00199 rospy.spin()
00200
00201 if __name__ == '__main__':
00202 main()
00203