teleop_key.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 #
00004 # Copyright (c) 2013 PAL Robotics SL.
00005 # Released under the BSD License.
00006 #
00007 # Authors:
00008 #   * Siegfried-A. Gevatter
00009 
00010 import curses
00011 import math
00012 
00013 import rospy
00014 from geometry_msgs.msg import Twist
00015 from geometry_msgs.msg import TwistStamped
00016 
00017 
00018 class Velocity(object):
00019 
00020     def __init__(self, min_velocity, max_velocity, num_steps):
00021         assert min_velocity > 0 and max_velocity > 0 and num_steps > 0
00022         self._min = min_velocity
00023         self._max = max_velocity
00024         self._num_steps = num_steps
00025         if self._num_steps > 1:
00026             self._step_incr = (max_velocity - min_velocity) / (self._num_steps - 1)
00027         else:
00028             # If num_steps is one, we always use the minimum velocity.
00029             self._step_incr = 0
00030 
00031     def __call__(self, value, step):
00032         """
00033         Takes a value in the range [0, 1] and the step and returns the
00034         velocity (usually m/s or rad/s).
00035         """
00036         if step == 0:
00037             return 0
00038 
00039         assert step > 0 and step <= self._num_steps
00040         max_value = self._min + self._step_incr * (step - 1)
00041         return value * max_value
00042 
00043 class TextWindow():
00044 
00045     _screen = None
00046     _window = None
00047     _num_lines = None
00048 
00049     def __init__(self, stdscr, lines=10):
00050         self._screen = stdscr
00051         self._screen.nodelay(True)
00052         curses.curs_set(0)
00053 
00054         self._num_lines = lines
00055 
00056     def read_key(self):
00057         keycode = self._screen.getch()
00058         return keycode if keycode != -1 else None
00059 
00060     def clear(self):
00061         self._screen.clear()
00062 
00063     def write_line(self, lineno, message):
00064         if lineno < 0 or lineno >= self._num_lines:
00065             raise ValueError, 'lineno out of bounds'
00066         height, width = self._screen.getmaxyx()
00067         y = (height / self._num_lines) * lineno
00068         x = 10
00069         for text in message.split('\n'):
00070             text = text.ljust(width)
00071             self._screen.addstr(y, x, text)
00072             y += 1
00073 
00074     def refresh(self):
00075         self._screen.refresh()
00076 
00077     def beep(self):
00078         curses.flash()
00079 
00080 class KeyTeleop():
00081 
00082     _interface = None
00083 
00084     _linear = None
00085     _angular = None
00086 
00087     def __init__(self, interface):
00088         self._interface = interface
00089         self._pub_cmd = rospy.Publisher('/mavros/setpoint_velocity/cmd_vel', TwistStamped)
00090 
00091         self._hz = rospy.get_param('~hz', 10)
00092 
00093         self._num_steps = rospy.get_param('~turbo/steps', 4)
00094 
00095         forward_min = rospy.get_param('~turbo/linear_forward_min', 0.5)
00096         forward_max = rospy.get_param('~turbo/linear_forward_max', 1.0)
00097         self._forward = Velocity(forward_min, forward_max, self._num_steps)
00098 
00099         backward_min = rospy.get_param('~turbo/linear_backward_min', 0.25)
00100         backward_max = rospy.get_param('~turbo/linear_backward_max', 0.5)
00101         self._backward = Velocity(backward_min, backward_max, self._num_steps)
00102 
00103         angular_min = rospy.get_param('~turbo/angular_min', 0.7)
00104         angular_max = rospy.get_param('~turbo/angular_max', 1.2)
00105         self._rotation = Velocity(angular_min, angular_max, self._num_steps)
00106 
00107     def run(self):
00108         self._linearX = 0
00109         self._linearY = 0
00110         #self._angular = 0
00111 
00112         rate = rospy.Rate(self._hz)
00113         while True:
00114             keycode = self._interface.read_key()
00115             if keycode:
00116                 if self._key_pressed(keycode):
00117                     self._publish()
00118             else:
00119                 self._publish()
00120                 rate.sleep()
00121 
00122     def _get_twist(self, linear, angular):
00123         twist = TwistStamped()
00124         if linearX >= 0:
00125             twist.twist.linear.x = self._forward(1.0, linearX)
00126         else:
00127             twist.twist.linear.x = self._backward(-1.0, -linearX)
00128         if linearY >= 0:
00129             twist.twist.linear.y = self._left(1.0, linearY)
00130         else:
00131             twist.twist.linear.yx = self._right(-1.0, -linearY)
00132                      
00133         #twist.angular.z = self._rotation(math.copysign(1, angular), abs(angular))
00134         return twist
00135 
00136     def _key_pressed(self, keycode):
00137         movement_bindings = {
00138             curses.KEY_UP:    ( 1,  0),
00139             curses.KEY_DOWN:  (-1,  0),
00140             curses.KEY_LEFT:  ( 0,  1),
00141             curses.KEY_RIGHT: ( 0, -1),
00142         }
00143         speed_bindings = {
00144             ord(' '): (0, 0),
00145         }
00146         if keycode in movement_bindings:
00147             acc = movement_bindings[keycode]
00148             ok = False
00149             if acc[0]:
00150                 linear = self._linear + acc[0]
00151                 if abs(linear) <= self._num_steps:
00152                     self._linear = linear
00153                     ok = True
00154             if acc[1]:
00155                 angular = self._angular + acc[1]
00156                 if abs(angular) <= self._num_steps:
00157                     self._angular = angular
00158                     ok = True
00159             if not ok:
00160                 self._interface.beep()
00161         elif keycode in speed_bindings:
00162             acc = speed_bindings[keycode]
00163             # Note: bounds aren't enforced here!
00164             if acc[0] is not None:
00165                 self._linear = acc[0]
00166             if acc[1] is not None:
00167                 self._angular = acc[1]
00168 
00169         elif keycode == ord('q'):
00170             rospy.signal_shutdown('Bye')
00171         else:
00172             return False
00173 
00174         return True
00175 
00176     def _publish(self):
00177         self._interface.clear()
00178         self._interface.write_line(2, 'Linear: %d, Angular: %d' % (self._linear, self._angular))
00179         self._interface.write_line(5, 'Use arrow keys to move, space to stop, q to exit.')
00180         self._interface.refresh()
00181 
00182         twist = self._get_twist(self._linear, self._angular)
00183         self._pub_cmd.publish(twist)
00184 
00185 
00186 class SimpleKeyTeleop():
00187     def __init__(self, interface):
00188         self._interface = interface
00189         self._pub_cmd = rospy.Publisher('/mavros/setpoint_velocity/cmd_vel', TwistStamped)
00190 
00191         self._hz = rospy.get_param('~hz', 10)
00192 
00193         self._forward_rate = rospy.get_param('~forward_rate', 0.8)
00194         self._backward_rate = rospy.get_param('~backward_rate', 0.5)
00195         self._rigth_rate = rospy.get_param('~rigth_rate', 0.5) 
00196         self._left_rate = rospy.get_param('~left_rate', 0.5)               
00197         #self._rotation_rate = rospy.get_param('~rotation_rate', 1.0)
00198         self._last_pressed = {}
00199         #self._angular = 0
00200         self._linearX = 0
00201         self._linearY = 0
00202 
00203     movement_bindings = {
00204         curses.KEY_LEFT: ( 1,  0),
00205         curses.KEY_RIGHT:(-1,  0),
00206         curses.KEY_DOWN: ( 0,  1),
00207         curses.KEY_UP:   ( 0, -1),
00208     }
00209 
00210     def run(self):
00211         rate = rospy.Rate(self._hz)
00212         self._running = True
00213         while self._running:
00214             while True:
00215                 keycode = self._interface.read_key()
00216                 if keycode is None:
00217                     break
00218                 self._key_pressed(keycode)
00219             self._set_velocity()
00220             self._publish()
00221             rate.sleep()
00222 
00223     def _get_twist(self, linearX, linearY):
00224         twist = TwistStamped()
00225         twist.twist.linear.x = linearX
00226         twist.twist.linear.y = linearY
00227         return twist
00228 
00229     def _set_velocity(self):
00230         now = rospy.get_time()
00231         keys = []
00232         for a in self._last_pressed:
00233             if now - self._last_pressed[a] < 0.4:
00234                 keys.append(a)
00235         #linear = 0.0
00236         #angular = 0.0
00237         linearX= 0.0
00238         linearY= 0.0
00239         for k in keys:
00240             lx, ly = self.movement_bindings[k]
00241             linearX += lx
00242             linearY += ly
00243         if linearX > 0:
00244             linearX = linearX * self._forward_rate
00245         else:
00246             linearX = linearX * self._backward_rate
00247         
00248         if linearY > 0:    
00249             linearY = linearY * self._left_rate
00250         else:
00251             linearY = linearY * self._rigth_rate   
00252         #self._angular = angular
00253         self._linearX = linearX
00254         self._linearY = linearY
00255 
00256     def _key_pressed(self, keycode):
00257         if keycode == ord('q'):
00258             self._running = False
00259             rospy.signal_shutdown('Bye')
00260         elif keycode in self.movement_bindings:
00261             self._last_pressed[keycode] = rospy.get_time()
00262 
00263     def _publish(self):
00264         self._interface.clear()
00265         self._interface.write_line(2, 'Linear x: %f, Linear y: %f' % (self._linearX, self._linearY))
00266         self._interface.write_line(5, 'Use arrow keys to move, q to exit.')
00267         self._interface.refresh()
00268 
00269         twist = self._get_twist(self._linearX, self._linearY)
00270         self._pub_cmd.publish(twist)
00271 
00272 
00273 def main(stdscr):
00274     rospy.init_node('tele')
00275     app = SimpleKeyTeleop(TextWindow(stdscr))
00276     app.run()
00277 
00278 if __name__ == '__main__':
00279     try:
00280         curses.wrapper(main)
00281     except rospy.ROSInterruptException:
00282         pass


gapter
Author(s):
autogenerated on Thu Jun 6 2019 22:05:13