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 import roslib
00026 roslib.load_manifest('falkor_ardrone')
00027
00028 import sys
00029 import rospy
00030 import math
00031 import pid
00032 import cv2
00033 import numpy as np
00034 from cv_bridge import CvBridge, CvBridgeError
00035
00036 from geometry_msgs.msg import Point
00037 from geometry_msgs.msg import Twist
00038 from std_msgs.msg import Empty
00039 from sensor_msgs.msg import Joy, Image
00040 from ardrone_autonomy.msg import Navdata
00041 from ardrone_autonomy.srv import LedAnim
00042 from ardrone_autonomy.srv import RecordEnable
00043 import std_srvs.srv
00044
00045 class ArdroneFollow:
00046 def __init__( self ):
00047 print "waiting for driver to startup"
00048 rospy.wait_for_service( "ardrone/setledanimation" )
00049 rospy.wait_for_service( "ardrone/setrecord" )
00050 print "driver started"
00051 self.led_service = rospy.ServiceProxy( "ardrone/setledanimation", LedAnim )
00052 self.record_service = rospy.ServiceProxy( "ardrone/setrecord", RecordEnable )
00053 self.recording = False
00054
00055 self.tracker_sub = rospy.Subscriber( "ardrone_tracker/found_point",
00056 Point, self.found_point_cb )
00057 self.goal_vel_pub = rospy.Publisher( "goal_vel", Twist )
00058 self.found_time = None
00059
00060 self.tracker_img_sub = rospy.Subscriber( "ardrone_tracker/image",
00061 Image, self.image_cb )
00062 self.tracker_image = None
00063
00064 self.timer = rospy.Timer( rospy.Duration( 0.10 ), self.timer_cb, False )
00065
00066 self.land_pub = rospy.Publisher( "ardrone/land", Empty )
00067 self.takeoff_pub = rospy.Publisher( "ardrone/takeoff", Empty )
00068 self.reset_pub = rospy.Publisher( "ardrone/reset", Empty )
00069
00070 self.angularZlimit = 3.141592 / 2
00071 self.linearXlimit = 1.0
00072 self.linearZlimit = 2.0
00073
00074
00075 self.xPid = pid.Pid( 0.080, 0.0, 0.0, self.angularZlimit )
00076 self.yPid = pid.Pid( 0.050, 0.0, 0.0, self.linearZlimit )
00077 self.zPid = pid.Pid( 0.050, 0.0, 0.0, self.linearXlimit )
00078
00079
00080 self.alpha = 0.5
00081
00082 self.xPid.setPointMin = 45
00083 self.xPid.setPointMax = 55
00084
00085 self.yPid.setPointMin = 40
00086 self.yPid.setPointMax = 60
00087
00088 self.zPid.setPointMin = 32
00089 self.zPid.setPointMax = 40
00090
00091 self.lastAnim = -1
00092
00093 self.found_point = Point( 0, 0, -1 )
00094 self.old_cmd = self.current_cmd = Twist()
00095
00096 self.joy_sub = rospy.Subscriber( "joy", Joy, self.callback_joy )
00097 self.manual_cmd = False
00098 self.auto_cmd = False
00099
00100 self.bridge = CvBridge()
00101
00102 self.navdata_sub = rospy.Subscriber( "/ardrone/navdata", Navdata, self.navdata_cb )
00103 self.navdata = None
00104 self.states = { 0: 'Unknown',
00105 1: 'Init',
00106 2: 'Landed',
00107 3: 'Flying',
00108 4: 'Hovering',
00109 5: 'Test',
00110 6: 'Taking Off',
00111 7: 'Goto Fix Point',
00112 8: 'Landing',
00113 9: 'Looping' }
00114
00115
00116
00117 cv2.namedWindow( 'AR.Drone Follow', cv2.cv.CV_WINDOW_NORMAL )
00118
00119 def toggle_record( self ):
00120 self.recording = not self.recording
00121
00122 self.record_service( enable = self.recording )
00123
00124 def navdata_cb( self, data ):
00125 self.navdata = data
00126
00127 def image_cb( self, data ):
00128 try:
00129 cv_image = self.bridge.imgmsg_to_cv( data, "passthrough" )
00130 except CvBridgeError, e:
00131 print e
00132
00133 self.tracker_image = np.asarray( cv_image )
00134
00135 def increase_z_setpt( self ):
00136 self.zPid.setPointMin *= 1.01
00137 self.zPid.setPointMax *= 1.01
00138
00139 def decrease_z_setpt( self ):
00140 self.zPid.setPointMin /= 1.01
00141 self.zPid.setPointMax /= 1.01
00142
00143 def callback_joy( self, data ):
00144 empty_msg = Empty()
00145
00146 if data.buttons[12] == 1 and self.last_buttons[12] == 0:
00147 self.takeoff()
00148
00149 if data.buttons[14] == 1 and self.last_buttons[14] == 0:
00150 self.land()
00151
00152 if data.buttons[16] == 1 and self.last_buttons[16] == 0:
00153 self.toggle_record()
00154
00155 if data.buttons[13] == 1 and self.last_buttons[13] == 0:
00156 self.reset()
00157
00158 if data.buttons[15] == 1 and self.last_buttons[15] == 0:
00159 self.auto_cmd = not self.auto_cmd
00160 self.hover()
00161
00162 if data.buttons[4] == 1:
00163 self.increase_z_setpt()
00164
00165 if data.buttons[6] == 1:
00166 self.decrease_z_setpt()
00167
00168 self.last_buttons = data.buttons
00169
00170
00171 self.current_cmd = Twist()
00172
00173 self.current_cmd.angular.x = self.current_cmd.angular.y = 0
00174 self.current_cmd.angular.z = data.axes[2] * self.angularZlimit
00175
00176 self.current_cmd.linear.z = data.axes[3] * self.linearZlimit
00177 self.current_cmd.linear.x = data.axes[1] * self.linearXlimit
00178 self.current_cmd.linear.y = data.axes[0] * self.linearXlimit
00179
00180 if ( self.current_cmd.linear.x == 0 and
00181 self.current_cmd.linear.y == 0 and
00182 self.current_cmd.linear.z == 0 and
00183 self.current_cmd.angular.z == 0 ):
00184 self.manual_cmd = False
00185 else:
00186 self.setLedAnim( 9 )
00187 self.manual_cmd = True
00188
00189 self.goal_vel_pub.publish( self.current_cmd )
00190
00191 def setLedAnim( self, animType, freq = 10 ):
00192 if self.lastAnim == type:
00193 return
00194
00195 msg = LedAnim();
00196 msg.type = animType;
00197 msg.freq = freq;
00198 msg.duration = 3600;
00199
00200 self.led_service( type = animType, freq = freq, duration = 255 )
00201 self.lastAnim = type
00202
00203 def takeoff( self ):
00204 self.takeoff_pub.publish( Empty() )
00205 self.setLedAnim( 9 )
00206
00207 def land( self ):
00208 self.land_pub.publish( Empty() )
00209
00210 def reset( self ):
00211 self.reset_pub.publish( Empty() )
00212
00213 def found_point_cb( self, data ):
00214 if data.z != -1.0:
00215 if self.found_point.z == -1.0:
00216 self.found_point = data
00217 else:
00218
00219 self.found_point.x = self.found_point.x * self.alpha + data.x * ( 1.0 - self.alpha )
00220 self.found_point.y = self.found_point.y * self.alpha + data.y * ( 1.0 - self.alpha )
00221 self.found_point.z = self.found_point.z * self.alpha + data.z * ( 1.0 - self.alpha )
00222 else:
00223 self.found_point = data
00224
00225 self.found_time = rospy.Time.now()
00226
00227 def hover( self ):
00228 hoverCmd = Twist()
00229 self.goal_vel_pub.publish( hoverCmd )
00230
00231 def hover_cmd_cb( self, data ):
00232 self.hover()
00233
00234 def put_text( self, vis, text, pos ):
00235 cv2.putText( vis, text,
00236 pos, cv2.FONT_HERSHEY_PLAIN, 1.0,
00237 (255, 255, 255) )
00238 cv2.putText( vis, text,
00239 pos, cv2.FONT_HERSHEY_PLAIN, 1.0,
00240 ( 0, 0, 0), thickness = 2 )
00241
00242 def draw_picture( self ):
00243 if self.tracker_image == None:
00244 return
00245
00246 vis = self.tracker_image.copy()
00247 (ySize, xSize, depth) = vis.shape
00248
00249 cx_min = int(self.xPid.setPointMin * xSize / 100)
00250 cx_max = int(self.xPid.setPointMax * xSize / 100)
00251 cx = int( ( cx_min + cx_max ) / 2 )
00252
00253 cy_min = int(self.yPid.setPointMin * ySize / 100)
00254 cy_max = int(self.yPid.setPointMax * ySize / 100)
00255 cy = int( ( cy_min + cy_max ) / 2 )
00256
00257 cv2.rectangle( vis, ( cx_min, cy_min ), ( cx_max, cy_max ),
00258 ( 0, 255, 255 ) )
00259
00260 areasqrt = np.sqrt( 640 * 480 )
00261 side_min_half = int( self.zPid.setPointMin * areasqrt / 100 / 2 )
00262 side_max_half = int( self.zPid.setPointMax * areasqrt / 100 / 2 )
00263
00264 cv2.rectangle( vis, ( cx - side_min_half, cy - side_min_half ),
00265 ( cx + side_min_half, cy + side_min_half ),
00266 ( 255, 255, 0 ) )
00267
00268 cv2.rectangle( vis, ( cx - side_max_half, cy - side_max_half ),
00269 ( cx + side_max_half, cy + side_max_half ),
00270 ( 255, 255, 0 ) )
00271
00272 if self.current_cmd.linear.x > 0:
00273 line_color = ( 0, 255, 0 )
00274 else:
00275 line_color = ( 0, 0, 255 )
00276
00277 cv2.line( vis, ( 320, 180 ), ( int( xSize/2 - self.current_cmd.angular.z * 320 ),
00278 int( ySize/2 - self.current_cmd.linear.z * 180 ) ),
00279 line_color,
00280 min( max( int( abs( self.current_cmd.linear.x ) * 255 ), 0 ), 255 ) )
00281
00282 if self.navdata != None:
00283 self.put_text( vis, 'State: %s' % self.states[ self.navdata.state ],
00284 ( 150, 240 ) )
00285 self.put_text( vis, 'Battery Percent: %4.1f' % self.navdata.batteryPercent,
00286 ( 150, 260 ) )
00287
00288 if self.manual_cmd:
00289 self.put_text( vis, 'MANUAL CONTROL', ( 150, 280 ) )
00290
00291 if self.auto_cmd:
00292 self.put_text( vis, 'TRACKING', ( 150, 300 ) )
00293
00294 if self.recording:
00295 self.put_text( vis, 'RECORDING', ( 150, 320 ) )
00296
00297 cv2.imshow( 'AR.Drone Follow', vis )
00298 cv2.waitKey( 1 )
00299
00300 def timer_cb( self, event ):
00301 self.draw_picture()
00302
00303
00304
00305 if ( self.found_time == None or
00306 ( rospy.Time.now() - self.found_time ).to_sec() > 1 ):
00307 self.found_point = Point( 0, 0, -1.0 )
00308 self.found_time = rospy.Time.now()
00309
00310 if event.last_real == None:
00311 dt = 0
00312 else:
00313 dt = ( event.current_real - event.last_real ).to_sec()
00314
00315 if self.found_point.z == -1.0:
00316 self.current_cmd = Twist()
00317 self.setLedAnim( 0, 2 )
00318 else:
00319 self.current_cmd.angular.z = self.xPid.get_output( self.found_point.x,
00320 dt )
00321 self.current_cmd.linear.z = self.yPid.get_output( self.found_point.y,
00322 dt )
00323 self.current_cmd.linear.x = self.zPid.get_output( self.found_point.z,
00324 dt )
00325
00326 self.setLedAnim( 8, 2 )
00327
00328 if self.auto_cmd == False or self.manual_cmd == True:
00329 self.setLedAnim( 9 )
00330 return
00331
00332 self.goal_vel_pub.publish( self.current_cmd )
00333
00334
00335 def main():
00336 rospy.init_node( 'ardrone_follow' )
00337 af = ArdroneFollow()
00338
00339 try:
00340 rospy.spin()
00341 except KeyboardInterrupt:
00342 print "Keyboard interrupted"
00343 af.usb_service()
00344
00345 if __name__ == '__main__':
00346 main()