qteleop.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 #
00003 # Qt python script to send tele-operation commands to vehicle
00004 #
00005 #   Copyright (C) 2009, 2011, 2012 Austin Robot Technology
00006 #   License: Modified BSD Software License Agreement
00007 #
00008 # $Id$
00009 
00010 PKG_NAME = 'ackermann_qt'
00011 
00012 import sys
00013 import os
00014 import math
00015 import threading
00016 
00017 from PyQt4 import QtGui
00018 from PyQt4 import QtCore
00019 
00020 import roslib;
00021 roslib.load_manifest(PKG_NAME)
00022 import rospy
00023 
00024 from ackermann_msgs.msg import AckermannDrive
00025 from ackermann_msgs.msg import AckermannDriveStamped
00026 
00027 # dynamic parameter reconfiguration
00028 from dynamic_reconfigure.server import Server as ReconfigureServer
00029 import ackermann_qt.cfg.QTeleopConfig as Config
00030 
00031 g_topic = rospy.Publisher('ackermann_cmd', AckermannDriveStamped)
00032 rospy.init_node('qteleop')
00033 
00034 # set path name for resolving icons
00035 icons_path = os.path.join(roslib.packages.get_pkg_dir(PKG_NAME),
00036                           os.path.join("icons", "teleop"))
00037 
00038 def find_icon(dir, basename, extlist=['.svg', '.png']):
00039     """Find icon file with basename in dir.
00040 
00041     extlist: a list of possible extensions
00042     returns: full path name if file found, None otherwise
00043 """
00044     for ext in extlist:
00045         pathname = os.path.join(dir, basename + ext)
00046         if os.path.exists(pathname):
00047             return pathname
00048     return None
00049 
00050 def pkg_icon(name):
00051     """Resolve package-relative icon name to path name.
00052     """
00053     pname = find_icon(icons_path, name)
00054     if pname == None:
00055         raise NameError, 'icon file not found'
00056     return pname
00057 
00058 
00059 class MainWindow(QtGui.QMainWindow):
00060     "Create vehicle tele-operation control window."
00061 
00062     def __init__(self, topic):
00063         QtGui.QMainWindow.__init__(self)
00064 
00065         self.topic = topic
00066         self.reconf_server = ReconfigureServer(Config, self.reconfigure)
00067 
00068         self.resize(350, 250)
00069         self.setIconSize(QtCore.QSize(32,32))
00070         self.setWindowTitle('Vehicle Tele-Operation')
00071 
00072         qexit = QtGui.QAction(QtGui.QIcon(pkg_icon('exit')), 'Exit', self)
00073         qexit.setShortcut('Ctrl+Q')
00074         self.connect(qexit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
00075 
00076         center_wheel = QtGui.QAction(QtGui.QIcon(pkg_icon('go-first')),
00077                             'center wheel', self)
00078         center_wheel.setShortcut(QtCore.Qt.Key_Home)
00079         self.connect(center_wheel, QtCore.SIGNAL('triggered()'),
00080                      self.center_wheel)
00081 
00082         go_left = QtGui.QAction(QtGui.QIcon(pkg_icon('go-previous')),
00083                             'steer left', self)
00084         go_left.setShortcut(QtCore.Qt.Key_Left)
00085         self.connect(go_left, QtCore.SIGNAL('triggered()'), self.go_left)
00086 
00087         go_left_more = QtGui.QAction('steer left more', self)
00088         go_left_more.setShortcut(QtGui.QKeySequence.SelectPreviousWord)
00089         self.connect(go_left_more, QtCore.SIGNAL('triggered()'),
00090                      self.go_left_more)
00091 
00092         go_left_less = QtGui.QAction('steer left less', self)
00093         go_left_less.setShortcut(QtGui.QKeySequence.MoveToPreviousWord)
00094         self.connect(go_left_less, QtCore.SIGNAL('triggered()'),
00095                      self.go_left_less)
00096 
00097         slow_down = QtGui.QAction(QtGui.QIcon(pkg_icon('go-down')),
00098                             'slow down', self)
00099         slow_down.setShortcut(QtCore.Qt.Key_Down)
00100         self.connect(slow_down, QtCore.SIGNAL('triggered()'), self.slow_down)
00101 
00102         speed_up = QtGui.QAction(QtGui.QIcon(pkg_icon('go-up')),
00103                               'speed up', self)
00104         speed_up.setShortcut(QtCore.Qt.Key_Up)
00105         self.connect(speed_up, QtCore.SIGNAL('triggered()'), self.speed_up)
00106 
00107         go_right = QtGui.QAction(QtGui.QIcon(pkg_icon('go-next')),
00108                               'steer right', self)
00109         go_right.setShortcut(QtCore.Qt.Key_Right)
00110         self.connect(go_right, QtCore.SIGNAL('triggered()'), self.go_right)
00111 
00112         go_right_less = QtGui.QAction('steer right less', self)
00113         go_right_less.setShortcut(QtGui.QKeySequence.MoveToNextWord)
00114         self.connect(go_right_less, QtCore.SIGNAL('triggered()'),
00115                      self.go_right_less)
00116 
00117         go_right_more = QtGui.QAction('steer right more', self)
00118         go_right_more.setShortcut(QtGui.QKeySequence.SelectNextWord)
00119         self.connect(go_right_more, QtCore.SIGNAL('triggered()'),
00120                      self.go_right_more)
00121 
00122         stop_car = QtGui.QAction(QtGui.QIcon(pkg_icon('go-bottom')),
00123                                  'stop car', self)
00124         stop_car.setShortcut(QtCore.Qt.Key_End)
00125         self.connect(stop_car, QtCore.SIGNAL('triggered()'), self.stop_car)
00126 
00127 
00128         menubar = self.menuBar()
00129         mfile = menubar.addMenu('&File')
00130         mfile.addAction(qexit)
00131 
00132         speed = menubar.addMenu('&Speed')
00133         speed.addAction(slow_down)
00134         speed.addAction(stop_car)
00135         speed.addAction(speed_up)
00136 
00137         wheel = menubar.addMenu('&Wheel')
00138         wheel.addAction(center_wheel)
00139         wheel.addAction(go_left)
00140         wheel.addAction(go_left_less)
00141         wheel.addAction(go_left_more)
00142         wheel.addAction(go_right)
00143         wheel.addAction(go_right_less)
00144         wheel.addAction(go_right_more)
00145 
00146         toolbar = self.addToolBar('Controls')
00147         toolbar.addAction(qexit)
00148         toolbar.addAction(center_wheel)
00149         toolbar.addAction(go_left)
00150         toolbar.addAction(slow_down)
00151         toolbar.addAction(stop_car)
00152         toolbar.addAction(speed_up)
00153         toolbar.addAction(go_right)
00154 
00155         self.ack_cmd = AckermannDriveStamped()
00156         self.ack_cmd.header.stamp = rospy.Time.now()
00157         self.drive = AckermannDrive()
00158         self.ack_cmd.drive = self.drive
00159         self.topic.publish(self.ack_cmd)
00160 
00161         self.updateStatusBar()
00162 
00163     def updateStatusBar(self):
00164         self.statusBar().showMessage('speed: '
00165                                      + str(self.drive.speed)
00166                                      + ' m/s,    angle: '
00167                                      + str(math.degrees(self.drive.steering_angle))
00168                                      + ' deg')
00169 
00170     def adjustCarCmd(self, v, a):
00171         """adjust AckermannDrive command
00172 
00173               @param v change in velocity (m/s)
00174               @param a change in steering angle (radians)
00175         """
00176 
00177         self.drive.speed += v
00178         self.drive.steering_angle += a
00179 
00180         # impose limits on commanded angle
00181         if self.drive.steering_angle > self.config.max_steering:
00182             self.drive.steering_angle = self.config.max_steering
00183         if self.drive.steering_angle < self.config.min_steering:
00184             self.drive.steering_angle = self.config.min_steering
00185 
00186         # clean up angle if it is very close to zero
00187         if math.fabs(self.drive.steering_angle) < self.config.epsilon_steering:
00188             self.drive.steering_angle = 0.0
00189 
00190         self.ack_cmd.header.stamp = rospy.Time.now()
00191         self.ack_cmd.drive = self.drive
00192         self.topic.publish(self.ack_cmd)
00193 
00194         self.updateStatusBar()
00195 
00196     def center_wheel(self):
00197         "center steering wheel"
00198         self.adjustCarCmd(0.0, -self.drive.steering_angle)
00199 
00200     def go_left(self):
00201         "steer left"
00202         self.adjustCarCmd(0.0, math.radians(1.0))
00203 
00204     def go_left_more(self):
00205         "steer more to left"
00206         self.adjustCarCmd(0.0, math.radians(4.0))
00207 
00208     def go_left_less(self):
00209         "steer a little to left"
00210         self.adjustCarCmd(0.0, math.radians(0.25))
00211 
00212     def go_right(self):
00213         "steer right"
00214         self.adjustCarCmd(0.0, math.radians(-1.0))
00215 
00216     def go_right_more(self):
00217         "steer more to right"
00218         self.adjustCarCmd(0.0, math.radians(-4.0))
00219 
00220     def go_right_less(self):
00221         "steer far to right"
00222         self.adjustCarCmd(0.0, math.radians(-0.25))
00223 
00224     def slow_down(self):
00225         "go one m/s slower"
00226         self.adjustCarCmd(-1.0, 0.0)    # one m/s slower
00227 
00228     def speed_up(self):
00229         "go one m/s faster"
00230         self.adjustCarCmd(1.0, 0.0)     # one m/s faster
00231 
00232     def stop_car(self):
00233         "stop car immediately"
00234         self.adjustCarCmd(-self.drive.speed, 0.0)
00235 
00236     def reconfigure(self, config, level):
00237         "Dynamic reconfigure server callback."
00238         rospy.logdebug('Reconfigure callback, level ' + str(level))
00239         rospy.logdebug('New config ' + str(config))
00240         self.config = config
00241         return config
00242 
00243 
00244 class QtThread(threading.Thread):
00245 
00246     def __init__(self, topic):
00247         self.topic = topic
00248         threading.Thread.__init__(self)
00249 
00250     def run(self):
00251         # run the program
00252         app = QtGui.QApplication(sys.argv)
00253         
00254         teleop = MainWindow(self.topic)
00255         teleop.show()
00256 
00257         # run Qt main loop until window terminates
00258         exit_status = app.exec_()
00259 
00260         rospy.signal_shutdown('Qt exit')
00261 
00262         sys.exit(exit_status)
00263 
00264 
00265 if __name__ == '__main__':
00266 
00267     #rospy.loginfo('starting tele-operation')
00268 
00269     try:
00270         QtThread(g_topic).start()
00271         rospy.spin()
00272     except rospy.ROSInterruptException: pass
00273 
00274     #rospy.loginfo('tele-operation completed')


ackermann_qt
Author(s): Jack O'Quin
autogenerated on Wed Aug 26 2015 10:39:38