00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 import Tkinter
00011
00012 import rospy
00013 from geometry_msgs.msg import Twist, Vector3
00014
00015 import numpy
00016
00017
00018 class MouseTeleop():
00019 def __init__(self):
00020
00021 self._frequency = rospy.get_param('~frequency', 0.0)
00022 self._scale = rospy.get_param('~scale', 1.0)
00023 self._holonomic = rospy.get_param('~holonomic', False)
00024
00025
00026 self._pub_cmd = rospy.Publisher('mouse_vel', Twist, queue_size=100)
00027
00028
00029 self._v_x = 0.0
00030 self._v_y = 0.0
00031 self._w = 0.0
00032
00033
00034
00035
00036 self._x = None
00037 self._y = None
00038
00039
00040 self._root = Tkinter.Tk()
00041 self._root.title('Mouse Teleop')
00042
00043
00044 self._root.resizable(0, 0)
00045
00046
00047 self._canvas = Tkinter.Canvas(self._root, bg='white')
00048
00049
00050 self._canvas.create_arc(0, 0, 0, 0, fill='red', outline='red',
00051 width=1, style=Tkinter.PIESLICE, start=90.0, tag='w')
00052 self._canvas.create_line(0, 0, 0, 0, fill='blue', width=4, tag='v_x')
00053
00054 if self._holonomic:
00055 self._canvas.create_line(0, 0, 0, 0,
00056 fill='blue', width=4, tag='v_y')
00057
00058
00059 self._text_v_x = Tkinter.StringVar()
00060 if self._holonomic:
00061 self._text_v_y = Tkinter.StringVar()
00062 self._text_w = Tkinter.StringVar()
00063
00064 self._label_v_x = Tkinter.Label(self._root,
00065 anchor=Tkinter.W, textvariable=self._text_v_x)
00066 if self._holonomic:
00067 self._label_v_y = Tkinter.Label(self._root,
00068 anchor=Tkinter.W, textvariable=self._text_v_y)
00069 self._label_w = Tkinter.Label(self._root,
00070 anchor=Tkinter.W, textvariable=self._text_w)
00071
00072 if self._holonomic:
00073 self._text_v_x.set('v_x = %0.2f m/s' % self._v_x)
00074 self._text_v_y.set('v_y = %0.2f m/s' % self._v_y)
00075 self._text_w.set( 'w = %0.2f deg/s' % self._w)
00076 else:
00077 self._text_v_x.set('v = %0.2f m/s' % self._v_x)
00078 self._text_w.set( 'w = %0.2f deg/s' % self._w)
00079
00080 self._label_v_x.pack()
00081 if self._holonomic:
00082 self._label_v_y.pack()
00083 self._label_w.pack()
00084
00085
00086 self._canvas.bind('<Button-1>', self._start)
00087 self._canvas.bind('<ButtonRelease-1>', self._release)
00088
00089 self._canvas.bind('<Configure>', self._configure)
00090
00091 if self._holonomic:
00092 self._canvas.bind('<B1-Motion>', self._mouse_motion_linear)
00093 self._canvas.bind('<Shift-B1-Motion>', self._mouse_motion_angular)
00094
00095 self._root.bind('<Shift_L>', self._change_to_motion_angular)
00096 self._root.bind('<KeyRelease-Shift_L>',
00097 self._change_to_motion_linear)
00098 else:
00099 self._canvas.bind('<B1-Motion>', self._mouse_motion_angular)
00100
00101 self._canvas.pack()
00102
00103
00104 if self._frequency > 0.0:
00105
00106 period = rospy.Duration(1.0 / self._frequency)
00107
00108 self._timer = rospy.Timer(period, self._publish_twist)
00109
00110
00111 self._root.mainloop()
00112
00113 def __del__(self):
00114 if self._frequency > 0.0:
00115 self._timer.shutdown()
00116
00117 self._root.quit()
00118
00119 def _start(self, event):
00120 self._x, self._y = event.y, event.x
00121
00122 self._y_linear = self._y_angular = 0
00123
00124 self._v_x = self._v_y = self._w = 0.0
00125
00126 def _release(self, event):
00127 self._v_x = self._v_y = self._w = 0.0
00128
00129 self._send_motion()
00130
00131 def _configure(self, event):
00132 self._width, self._height = event.height, event.width
00133
00134 self._c_x = self._height / 2.0
00135 self._c_y = self._width / 2.0
00136
00137 self._r = min(self._height, self._width) * 0.25
00138
00139 def _mouse_motion_linear(self, event):
00140 self._v_x, self._v_y = self._relative_motion(event.y, event.x)
00141
00142 self._send_motion()
00143
00144 def _mouse_motion_angular(self, event):
00145 self._v_x, self._w = self._relative_motion(event.y, event.x)
00146
00147 self._send_motion()
00148
00149 def _update_coords(self, tag, x0, y0, x1, y1):
00150 x0 += self._c_x
00151 y0 += self._c_y
00152
00153 x1 += self._c_x
00154 y1 += self._c_y
00155
00156 self._canvas.coords(tag, (x0, y0, x1, y1))
00157
00158 def _draw_v_x(self, v):
00159 x = -v * float(self._width)
00160
00161 self._update_coords('v_x', 0, 0, 0, x)
00162
00163 def _draw_v_y(self, v):
00164 y = -v * float(self._height)
00165
00166 self._update_coords('v_y', 0, 0, y, 0)
00167
00168 def _draw_w(self, w):
00169 x0 = y0 = -self._r
00170 x1 = y1 = self._r
00171
00172 self._update_coords('w', x0, y0, x1, y1)
00173
00174 yaw = w * numpy.rad2deg(self._scale)
00175
00176 self._canvas.itemconfig('w', extent=yaw)
00177
00178 def _send_motion(self):
00179 v_x = self._v_x * self._scale
00180 v_y = self._v_y * self._scale
00181 w = self._w * self._scale
00182
00183 linear = Vector3(v_x, v_y, 0.0)
00184 angular = Vector3(0.0, 0.0, w)
00185
00186 self._draw_v_x(self._v_x)
00187 if self._holonomic:
00188 self._draw_v_y(self._v_y)
00189 self._draw_w(self._w)
00190
00191 if self._holonomic:
00192 self._text_v_x.set('v_x = %0.2f m/s' % self._v_x)
00193 self._text_v_y.set('v_y = %0.2f m/s' % self._v_y)
00194 self._text_w.set( 'w = %0.2f deg/s' % numpy.rad2deg(self._w))
00195 else:
00196 self._text_v_x.set('v = %0.2f m/s' % self._v_x)
00197 self._text_w.set( 'w = %0.2f deg/s' % numpy.rad2deg(self._w))
00198
00199 twist = Twist(linear, angular)
00200 self._pub_cmd.publish(twist)
00201
00202 def _publish_twist(self, event):
00203 self._send_motion()
00204
00205 def _relative_motion(self, x, y):
00206 dx = self._x - x
00207 dy = self._y - y
00208
00209 dx /= float(self._width)
00210 dy /= float(self._height)
00211
00212 dx = max(-1.0, min(dx, 1.0))
00213 dy = max(-1.0, min(dy, 1.0))
00214
00215 return dx, dy
00216
00217 def _change_to_motion_linear(self, event):
00218 if self._y is not None:
00219 y = event.x
00220
00221 self._y_angular = self._y - y
00222 self._y = self._y_linear + y
00223
00224 def _change_to_motion_angular(self, event):
00225 if self._y is not None:
00226 y = event.x
00227
00228 self._y_linear = self._y - y
00229 self._y = self._y_angular + y
00230
00231
00232 def main():
00233 rospy.init_node('mouse_teleop')
00234
00235 MouseTeleop()
00236
00237 if __name__ == '__main__':
00238 try:
00239 main()
00240 except rospy.ROSInterruptException:
00241 pass