00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 from __future__ import division
00035
00036 import math
00037 import rospy
00038 import time
00039
00040 from bwi_msgs.srv import QuestionDialog, QuestionDialogResponse, \
00041 QuestionDialogRequest
00042 from functools import partial
00043 from qt_gui.plugin import Plugin
00044 from python_qt_binding.QtGui import QFont, QGridLayout, QLabel, QLineEdit, \
00045 QPushButton, QTextBrowser, QVBoxLayout, QWidget
00046
00047 import os
00048 import rospkg
00049
00050 from geometry_msgs.msg import Twist
00051 from python_qt_binding import loadUi
00052 from python_qt_binding.QtCore import Qt, QTimer, SIGNAL, Slot
00053
00054 class QuestionDialogPlugin(Plugin):
00055
00056 def __init__(self, context):
00057 super(QuestionDialogPlugin, self).__init__(context)
00058
00059 self.setObjectName('QuestionDialogPlugin')
00060
00061 font_size = rospy.get_param("~font_size", 40)
00062
00063
00064 self._widget = QWidget()
00065 self._widget.setFont(QFont("Times", font_size, QFont.Bold))
00066 self._layout = QVBoxLayout(self._widget)
00067 self._text_browser = QTextBrowser(self._widget)
00068 self._layout.addWidget(self._text_browser)
00069 self._button_layout = QGridLayout()
00070 self._layout.addLayout(self._button_layout)
00071
00072
00073
00074 self._widget.setObjectName('QuestionDialogPluginUI')
00075 if context.serial_number() > 1:
00076 self._widget.setWindowTitle(self._widget.windowTitle() +
00077 (' (%d)' % context.serial_number()))
00078 context.add_widget(self._widget)
00079
00080
00081 self.service = rospy.Service('question_dialog', QuestionDialog,
00082 self.service_callback)
00083 self.response_ready = False
00084 self.response = None
00085 self.buttons = []
00086 self.text_label = None
00087 self.text_input = None
00088
00089 self.connect(self._widget, SIGNAL("update"), self.update)
00090 self.connect(self._widget, SIGNAL("timeout"), self.timeout)
00091
00092 def shutdown_plugin(self):
00093 self.service.shutdown()
00094
00095 def service_callback(self, req):
00096 self.response_ready = False
00097 self.request = req
00098 self._widget.emit(SIGNAL("update"))
00099
00100 start_time = time.time()
00101 while not self.response_ready:
00102 if self.request != req:
00103
00104 return QuestionDialogResponse(QuestionDialogRequest.PREEMPTED, "")
00105 if req.timeout != QuestionDialogRequest.NO_TIMEOUT:
00106 current_time = time.time()
00107 if current_time - start_time > req.timeout:
00108 self._widget.emit(SIGNAL("timeout"))
00109 return QuestionDialogResponse(
00110 QuestionDialogRequest.TIMED_OUT, "")
00111 time.sleep(0.2)
00112 return self.response
00113
00114 def update(self):
00115 self.clean()
00116 req = self.request
00117 self._text_browser.setText(req.message)
00118 if req.type == QuestionDialogRequest.DISPLAY:
00119
00120 self.response = QuestionDialogResponse(
00121 QuestionDialogRequest.NO_RESPONSE, "")
00122 self.response_ready = True
00123 elif req.type == QuestionDialogRequest.CHOICE_QUESTION:
00124 for index, options in enumerate(req.options):
00125 button = QPushButton(options, self._widget)
00126 button.clicked.connect(partial(self.handle_button, index))
00127 row = index / 3
00128 col = index % 3
00129 self._button_layout.addWidget(button, row, col)
00130 self.buttons.append(button)
00131 elif req.type == QuestionDialogRequest.TEXT_QUESTION:
00132 self.text_label = QLabel("Enter here: ", self._widget)
00133 self._button_layout.addWidget(self.text_label, 0, 0)
00134 self.text_input = QLineEdit(self._widget)
00135 self.text_input.editingFinished.connect(self.handle_text)
00136 self._button_layout.addWidget(self.text_input, 0, 1)
00137
00138 def timeout(self):
00139 self._text_browser.setText("Oh no! The request timed out.")
00140 self.clean()
00141
00142 def clean(self):
00143 while self._button_layout.count():
00144 item = self._button_layout.takeAt(0)
00145 item.widget().deleteLater()
00146 self.buttons = []
00147 self.text_input = None
00148 self.text_label = None
00149
00150 def handle_button(self, index):
00151 self.response = QuestionDialogResponse(index, "")
00152 self.clean()
00153 self.response_ready = True
00154
00155 def handle_text(self):
00156 self.response = QuestionDialogResponse(
00157 QuestionDialogRequest.TEXT_RESPONSE,
00158 self.text_input.text())
00159 self.clean()
00160 self.response_ready = True
00161
00162 def save_settings(self, plugin_settings, instance_settings):
00163
00164
00165 pass
00166
00167 def restore_settings(self, plugin_settings, instance_settings):
00168
00169
00170 pass
00171
00172
00173
00174
00175
00176
00177 class SimpleRobotSteeringPlugin(Plugin):
00178
00179 DEFAULT_LINEAR_VELOCITY = 1.0
00180 DEFAULT_ANGULAR_VELOCITY = math.pi / 2
00181
00182 def __init__(self, context):
00183 super(SimpleRobotSteeringPlugin, self).__init__(context)
00184 self.setObjectName('SimpleRobotSteeringPlugin')
00185
00186 self._publisher = None
00187
00188 self._widget = QWidget()
00189 rp = rospkg.RosPack()
00190 ui_file = os.path.join(rp.get_path('bwi_rqt_plugins'), 'resource', 'SimpleRobotSteering.ui')
00191 loadUi(ui_file, self._widget)
00192 self._widget.setObjectName('SimpleRobotSteeringUi')
00193 if context.serial_number() > 1:
00194 self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))
00195
00196 self._widget.keyPressEvent = self.keyPressEvent
00197 self._widget.keyReleaseEvent = self.keyReleaseEvent
00198 context.add_widget(self._widget)
00199
00200 self._widget.topic_line_edit.textChanged.connect(self._on_topic_changed)
00201
00202 self.linear_vel = 0
00203 self.angular_vel = 0
00204
00205
00206 self._widget.w_button.setFocus()
00207
00208
00209 self._update_parameter_timer = QTimer(self)
00210 self._update_parameter_timer.timeout.connect(self._on_parameter_changed)
00211 self._update_parameter_timer.start(100)
00212
00213 @Slot(str)
00214 def _on_topic_changed(self, topic):
00215 topic = str(topic)
00216 self._unregister_publisher()
00217 try:
00218 self._publisher = rospy.Publisher(topic, Twist, queue_size=10)
00219 except TypeError:
00220 self._publisher = rospy.Publisher(topic, Twist)
00221
00222 def keyPressEvent(self, event):
00223 if not event.isAutoRepeat():
00224 if event.key() == Qt.Key_W:
00225 self.linear_vel = SimpleRobotSteeringPlugin.DEFAULT_LINEAR_VELOCITY
00226 self._widget.w_button.setDown(True)
00227 self._widget.s_button.setDown(False)
00228 elif event.key() == Qt.Key_S:
00229 self.linear_vel = -SimpleRobotSteeringPlugin.DEFAULT_LINEAR_VELOCITY
00230 self._widget.s_button.setDown(True)
00231 self._widget.w_button.setDown(False)
00232 elif event.key() == Qt.Key_A:
00233 self.angular_vel = SimpleRobotSteeringPlugin.DEFAULT_ANGULAR_VELOCITY
00234 self._widget.a_button.setDown(True)
00235 self._widget.d_button.setDown(False)
00236 elif event.key() == Qt.Key_D:
00237 self.angular_vel = -SimpleRobotSteeringPlugin.DEFAULT_ANGULAR_VELOCITY
00238 self._widget.d_button.setDown(True)
00239 self._widget.a_button.setDown(False)
00240
00241 def keyReleaseEvent(self, event):
00242 if not event.isAutoRepeat():
00243 if self.linear_vel > 0 and event.key() == Qt.Key_W:
00244 self.linear_vel = 0
00245 self._widget.w_button.setDown(False)
00246 elif self.linear_vel < 0 and event.key() == Qt.Key_S:
00247 self.linear_vel = 0
00248 self._widget.s_button.setDown(False)
00249 elif self.angular_vel > 0 and event.key() == Qt.Key_A:
00250 self.angular_vel = 0
00251 self._widget.a_button.setDown(False)
00252 elif self.angular_vel < 0 and event.key() == Qt.Key_D:
00253 self.angular_vel = 0
00254 self._widget.d_button.setDown(False)
00255
00256
00257 def _on_parameter_changed(self):
00258 self._widget.linear_speed.setText("%.2f"%self.linear_vel)
00259 self._widget.angular_speed.setText("%.2f"%self.angular_vel)
00260 self._send_twist(self.linear_vel, self.angular_vel)
00261
00262 def _send_twist(self, x_linear, z_angular):
00263 if self._publisher is None:
00264 return
00265 twist = Twist()
00266 twist.linear.x = x_linear
00267 twist.linear.y = 0
00268 twist.linear.z = 0
00269 twist.angular.x = 0
00270 twist.angular.y = 0
00271 twist.angular.z = z_angular
00272
00273 self._publisher.publish(twist)
00274
00275 def _unregister_publisher(self):
00276 if self._publisher is not None:
00277 self._publisher.unregister()
00278 self._publisher = None
00279
00280 def shutdown_plugin(self):
00281 self._update_parameter_timer.stop()
00282 self._unregister_publisher()
00283
00284 def save_settings(self, plugin_settings, instance_settings):
00285 instance_settings.set_value('topic' , self._widget.topic_line_edit.text())
00286
00287 def restore_settings(self, plugin_settings, instance_settings):
00288
00289 value = instance_settings.value('topic', "/cmd_vel")
00290 value = rospy.get_param("~default_topic", value)
00291 self._widget.topic_line_edit.setText(value)