00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 PKG_NAME = 'art_teleop'
00011
00012
00013 import sys
00014 import math
00015
00016 import pilot_cmd
00017 import nav_estop
00018
00019
00020 import roslib;
00021 roslib.load_manifest(PKG_NAME)
00022 import rospy
00023
00024
00025 from art_msgs.msg import ArtVehicle
00026 from art_msgs.msg import Gear
00027 from joy.msg import Joy
00028
00029
00030 from driver_base.msg import SensorLevels
00031 from dynamic_reconfigure.server import Server as ReconfigureServer
00032 import art_teleop.cfg.JoyConfig as JoyConfig
00033
00034 def clamp(minimum, value, maximum):
00035 "constrain value to the range [minimum .. maximum]"
00036 return max(minimum, min(value, maximum))
00037
00038 class JoyNode():
00039 "Vehicle joystick tele-operation node."
00040
00041 def __init__(self):
00042 "JoyNode constructor"
00043
00044
00045 self.run = 3
00046 self.suspend = 12
00047 self.estop = 13
00048
00049
00050 self.steer = 0
00051 self.drive = 4
00052 self.reverse = 6
00053 self.park = 7
00054 self.throttle = 18
00055 self.throttle_start = True
00056 self.brake = 19
00057 self.brake_start = True
00058 self.lowincrease_max = 11
00059 self.highincrease_max = 9
00060 self.lowdecrease_max = 10
00061 self.highdecrease_max = 8
00062
00063
00064
00065 rospy.init_node('josh_teleop')
00066 self.pilot = pilot_cmd.PilotCommand()
00067 self.reconf_server = ReconfigureServer(JoyConfig, self.reconfigure)
00068 self.joy = rospy.Subscriber('joy', Joy, self.joyCallback)
00069
00070
00071 def joyCallback(self, joy):
00072 "invoked every time a joystick message arrives"
00073 rospy.logdebug('joystick input:\n' + str(joy))
00074
00075
00076 if joy.buttons[self.estop]:
00077 rospy.logwarn('emergency stop')
00078 if self.use_navigator:
00079 self.nav.pause()
00080 else:
00081 self.pilot.halt()
00082 elif joy.buttons[self.suspend] and self.use_navigator:
00083 rospy.logwarn('suspend autonomous operation')
00084 self.nav.suspend()
00085 elif joy.buttons[self.run] and self.use_navigator:
00086 rospy.logwarn('start autonomous operation')
00087 self.nav.run()
00088
00089
00090 if joy.buttons[self.drive]:
00091 self.pilot.shift(Gear.Drive)
00092 rospy.loginfo('shifting to drive')
00093 elif joy.buttons[self.reverse]:
00094 self.pilot.shift(Gear.Reverse)
00095 rospy.loginfo('shifting to reverse')
00096 elif joy.buttons[self.park]:
00097 self.pilot.shift(Gear.Park)
00098 rospy.loginfo('shifting to park')
00099
00100
00101 if joy.buttons[self.lowincrease_max]:
00102 self.config['limit_forward'] += .5
00103 if joy.buttons[self.highincrease_max]:
00104 self.config['limit_forward'] += 2
00105 if joy.buttons[self.lowdecrease_max]:
00106 self.config['limit_forward'] -= .5
00107 if joy.buttons[self.highdecrease_max]:
00108 self.config['limit_forward'] -= 2
00109
00110
00111 self.setAngle(joy.axes[self.steer])
00112
00113
00114
00115
00116 br = (-joy.axes[self.brake] + 1) / 2
00117 th = (-joy.axes[self.throttle] + 1) / 2
00118 rospy.logdebug('joystick brake, throttle: '
00119 + str(br) + ', ' + str(th))
00120
00121
00122
00123 dv = 0
00124 if self.brake_start:
00125 if br == 0.5:
00126 br = 0
00127 else:
00128 self.brake_start = False
00129
00130 if self.throttle_start:
00131 if th == 0.5:
00132 th = 0
00133 else:
00134 self.throttle_start = False
00135
00136 if br > 0:
00137 dv = -br * 3
00138
00139 elif th == 0 and self.pilot.pstate.current.speed > 0:
00140 dv = -.1
00141
00142
00143
00144 elif th > 0:
00145 if self.pilot.pstate.current.speed < self.config['limit_forward']*th:
00146 dv = self.config['limit_forward']*th - self.pilot.pstate.current.speed
00147 if dv > 1:
00148 dv = 1 + math.pow(dv/self.config['limit_forward'], 2)
00149 else:
00150 dv = math.pow(dv, 2)
00151 elif self.pilot.pstate.current.speed > self.config['limit_forward']*th:
00152 dv = -.1
00153 else:
00154 dv = 0
00155 else:
00156 dv = 0
00157
00158
00159 self.pilot.car_ctl.acceleration = dv * 10
00160 if self.pilot.car_ctl.gear.value == Gear.Drive:
00161 self.pilot.car_ctl.speed = self.config['limit_forward']*th
00162 elif self.pilot.car_ctl.gear.value == Gear.Reverse:
00163 self.pilot.car_ctl.speed = -self.config['limit_reverse']*th
00164 else:
00165 self.pilot.car_ctl.speed = 0.0
00166 self.pilot.car_ctl.acceleration = 0.0
00167
00168
00169 if self.nav.is_suspended():
00170 self.pilot.publish()
00171 else:
00172 rospy.logdebug('car running autonomously (command ignored)')
00173
00174 def reconfigure(self, config, level):
00175 "Dynamic reconfigure server callback."
00176 rospy.loginfo('Reconfigure callback, level ' + str(level))
00177 rospy.loginfo('New config ' + str(config))
00178
00179 if level & SensorLevels.RECONFIGURE_CLOSE:
00180
00181 self.use_navigator = config['use_navigator']
00182 rospy.loginfo('use navigator = ' + str(self.use_navigator))
00183
00184 self.nav = nav_estop.EstopNavigator(self.use_navigator)
00185
00186 self.pilot.reconfigure(config['limit_forward'],
00187 config['limit_reverse'])
00188
00189 self.config = config
00190 return config
00191
00192 def setAngle(self, turn):
00193 "set wheel angle"
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 if self.pilot.pstate.current.speed == 0:
00204 percentage = 1
00205 else:
00206 percentage = -0.2738*(math.log(math.fabs(self.pilot.pstate.current.speed))) + 0.6937
00207 turn = turn * percentage * ArtVehicle.max_steer_radians
00208
00209
00210 self.pilot.steer(turn)
00211
00212 def maxFinder(self):
00213 if self.pilot.pstate.current.speed > self.config['limit_forward']:
00214 return self.pilot.state.current
00215 return self.config['limit_forward']
00216
00217 joynode = None
00218
00219
00220 def main():
00221 global joynode
00222 joynode = JoyNode()
00223 rospy.loginfo('joystick vehicle controller starting')
00224 try:
00225 rospy.spin()
00226 except rospy.ROSInterruptException: pass
00227 rospy.loginfo('joystick vehicle controller finished')
00228
00229 if __name__ == '__main__':
00230
00231 sys.exit(main())