mouse_teleop.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright (c) 2015 Enrique Fernandez
5 # Released under the BSD License.
6 #
7 # Authors:
8 # * Enrique Fernandez
9 
10 import Tkinter
11 
12 import rospy
13 from geometry_msgs.msg import Twist, Vector3
14 
15 import numpy
16 
17 
18 class MouseTeleop():
19  def __init__(self):
20  # Retrieve params:
21  self._frequency = rospy.get_param('~frequency', 0.0)
22  self._scale = rospy.get_param('~scale', 1.0)
23  self._holonomic = rospy.get_param('~holonomic', False)
24 
25  # Create twist publisher:
26  self._pub_cmd = rospy.Publisher('mouse_vel', Twist, queue_size=100)
27 
28  # Initialize twist components to zero:
29  self._v_x = 0.0
30  self._v_y = 0.0
31  self._w = 0.0
32 
33  # Initialize mouse position (x, y) to None (unknown); it's initialized
34  # when the mouse button is pressed on the _start callback that handles
35  # that event:
36  self._x = None
37  self._y = None
38 
39  # Create window:
40  self._root = Tkinter.Tk()
41  self._root.title('Mouse Teleop')
42 
43  # Make window non-resizable:
44  self._root.resizable(0, 0)
45 
46  # Create canvas:
47  self._canvas = Tkinter.Canvas(self._root, bg='white')
48 
49  # Create canvas objects:
50  self._canvas.create_arc(0, 0, 0, 0, fill='red', outline='red',
51  width=1, style=Tkinter.PIESLICE, start=90.0, tag='w')
52  self._canvas.create_line(0, 0, 0, 0, fill='blue', width=4, tag='v_x')
53 
54  if self._holonomic:
55  self._canvas.create_line(0, 0, 0, 0,
56  fill='blue', width=4, tag='v_y')
57 
58  # Create canvas text objects:
59  self._text_v_x = Tkinter.StringVar()
60  if self._holonomic:
61  self._text_v_y = Tkinter.StringVar()
62  self._text_w = Tkinter.StringVar()
63 
64  self._label_v_x = Tkinter.Label(self._root,
65  anchor=Tkinter.W, textvariable=self._text_v_x)
66  if self._holonomic:
67  self._label_v_y = Tkinter.Label(self._root,
68  anchor=Tkinter.W, textvariable=self._text_v_y)
69  self._label_w = Tkinter.Label(self._root,
70  anchor=Tkinter.W, textvariable=self._text_w)
71 
72  if self._holonomic:
73  self._text_v_x.set('v_x = %0.2f m/s' % self._v_x)
74  self._text_v_y.set('v_y = %0.2f m/s' % self._v_y)
75  self._text_w.set( 'w = %0.2f deg/s' % self._w)
76  else:
77  self._text_v_x.set('v = %0.2f m/s' % self._v_x)
78  self._text_w.set( 'w = %0.2f deg/s' % self._w)
79 
80  self._label_v_x.pack()
81  if self._holonomic:
82  self._label_v_y.pack()
83  self._label_w.pack()
84 
85  # Bind event handlers:
86  self._canvas.bind('<Button-1>', self._start)
87  self._canvas.bind('<ButtonRelease-1>', self._release)
88 
89  self._canvas.bind('<Configure>', self._configure)
90 
91  if self._holonomic:
92  self._canvas.bind('<B1-Motion>', self._mouse_motion_linear)
93  self._canvas.bind('<Shift-B1-Motion>', self._mouse_motion_angular)
94 
95  self._root.bind('<Shift_L>', self._change_to_motion_angular)
96  self._root.bind('<KeyRelease-Shift_L>',
98  else:
99  self._canvas.bind('<B1-Motion>', self._mouse_motion_angular)
100 
101  self._canvas.pack()
102 
103  # If frequency is positive, use synchronous publishing mode:
104  if self._frequency > 0.0:
105  # Create timer for the given frequency to publish the twist:
106  period = rospy.Duration(1.0 / self._frequency)
107 
108  self._timer = rospy.Timer(period, self._publish_twist)
109 
110  # Start window event manager main loop:
111  self._root.mainloop()
112 
113  def __del__(self):
114  if self._frequency > 0.0:
115  self._timer.shutdown()
116 
117  self._root.quit()
118 
119  def _start(self, event):
120  self._x, self._y = event.y, event.x
121 
122  self._y_linear = self._y_angular = 0
123 
124  self._v_x = self._v_y = self._w = 0.0
125 
126  def _release(self, event):
127  self._v_x = self._v_y = self._w = 0.0
128 
129  self._send_motion()
130 
131  def _configure(self, event):
132  self._width, self._height = event.height, event.width
133 
134  self._c_x = self._height / 2.0
135  self._c_y = self._width / 2.0
136 
137  self._r = min(self._height, self._width) * 0.25
138 
139  def _mouse_motion_linear(self, event):
140  self._v_x, self._v_y = self._relative_motion(event.y, event.x)
141 
142  self._send_motion()
143 
144  def _mouse_motion_angular(self, event):
145  self._v_x, self._w = self._relative_motion(event.y, event.x)
146 
147  self._send_motion()
148 
149  def _update_coords(self, tag, x0, y0, x1, y1):
150  x0 += self._c_x
151  y0 += self._c_y
152 
153  x1 += self._c_x
154  y1 += self._c_y
155 
156  self._canvas.coords(tag, (x0, y0, x1, y1))
157 
158  def _draw_v_x(self, v):
159  x = -v * float(self._width)
160 
161  self._update_coords('v_x', 0, 0, 0, x)
162 
163  def _draw_v_y(self, v):
164  y = -v * float(self._height)
165 
166  self._update_coords('v_y', 0, 0, y, 0)
167 
168  def _draw_w(self, w):
169  x0 = y0 = -self._r
170  x1 = y1 = self._r
171 
172  self._update_coords('w', x0, y0, x1, y1)
173 
174  yaw = w * numpy.rad2deg(self._scale)
175 
176  self._canvas.itemconfig('w', extent=yaw)
177 
178  def _send_motion(self):
179  v_x = self._v_x * self._scale
180  v_y = self._v_y * self._scale
181  w = self._w * self._scale
182 
183  linear = Vector3(v_x, v_y, 0.0)
184  angular = Vector3(0.0, 0.0, w)
185 
186  self._draw_v_x(self._v_x)
187  if self._holonomic:
188  self._draw_v_y(self._v_y)
189  self._draw_w(self._w)
190 
191  if self._holonomic:
192  self._text_v_x.set('v_x = %0.2f m/s' % self._v_x)
193  self._text_v_y.set('v_y = %0.2f m/s' % self._v_y)
194  self._text_w.set( 'w = %0.2f deg/s' % numpy.rad2deg(self._w))
195  else:
196  self._text_v_x.set('v = %0.2f m/s' % self._v_x)
197  self._text_w.set( 'w = %0.2f deg/s' % numpy.rad2deg(self._w))
198 
199  twist = Twist(linear, angular)
200  self._pub_cmd.publish(twist)
201 
202  def _publish_twist(self, event):
203  self._send_motion()
204 
205  def _relative_motion(self, x, y):
206  dx = self._x - x
207  dy = self._y - y
208 
209  dx /= float(self._width)
210  dy /= float(self._height)
211 
212  dx = max(-1.0, min(dx, 1.0))
213  dy = max(-1.0, min(dy, 1.0))
214 
215  return dx, dy
216 
217  def _change_to_motion_linear(self, event):
218  if self._y is not None:
219  y = event.x
220 
221  self._y_angular = self._y - y
222  self._y = self._y_linear + y
223 
224  def _change_to_motion_angular(self, event):
225  if self._y is not None:
226  y = event.x
227 
228  self._y_linear = self._y - y
229  self._y = self._y_angular + y
230 
231 
232 def main():
233  rospy.init_node('mouse_teleop')
234 
235  MouseTeleop()
236 
237 if __name__ == '__main__':
238  try:
239  main()
240  except rospy.ROSInterruptException:
241  pass
def _configure(self, event)
def _release(self, event)
def _mouse_motion_angular(self, event)
def _start(self, event)
def _relative_motion(self, x, y)
def _publish_twist(self, event)
def _change_to_motion_linear(self, event)
def _change_to_motion_angular(self, event)
def _mouse_motion_linear(self, event)
def _update_coords(self, tag, x0, y0, x1, y1)


mouse_teleop
Author(s): Enrique Fernandez
autogenerated on Mon Jun 10 2019 15:31:12