├── .gitignore
├── CMakeLists.txt
├── Makefile
├── launch
├── joystick_controller.launchtemplate
├── keyboard_controller.launch
├── keyboard_controller_outdoor.launch
└── keyboard_controller_with_tags.launch
├── mainpage.dox
├── manifest.xml
├── package.xml
└── src
├── drone_controller.py
├── drone_status.py
├── drone_video_display.py
├── joystick_controller.py
└── keyboard_controller.py
/.gitignore:
--------------------------------------------------------------------------------
1 | */bin/*
2 | */build/*
3 | *.pyc
4 | build
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 | project(ardrone_tutorials)
3 |
4 | find_package(catkin REQUIRED)
5 | catkin_package()
6 |
7 | #catkin_python_setup()
8 |
9 |
10 | install(PROGRAMS src/drone_controller.py
11 | src/drone_status.py
12 | src/drone_video_display.py
13 | src/joystick_controller.py
14 | src/keyboard_controller.py
15 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
16 | )
17 |
18 | install(DIRECTORY launch/
19 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
20 | )
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | include $(shell rospack find mk)/cmake.mk
--------------------------------------------------------------------------------
/launch/joystick_controller.launchtemplate:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/launch/keyboard_controller.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/launch/keyboard_controller_outdoor.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/launch/keyboard_controller_with_tags.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/mainpage.dox:
--------------------------------------------------------------------------------
1 | /**
2 | \mainpage
3 | \htmlinclude manifest.html
4 |
5 | \b ardrone_tutorials
6 |
7 |
10 |
11 | -->
12 |
13 |
14 | */
15 |
--------------------------------------------------------------------------------
/manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Controllers developed for the "Up and flying with the AR.Drone and ROS" tutorial series
4 |
5 | Mike Hamer
6 | BSD
7 |
8 | http://github.com/mikehamer/ardrone_tutorials
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 | ardrone_tutorials
3 | 1.0.0
4 |
5 | Controllers developed for the "Up and flying with the AR.Drone and ROS" tutorial series
6 |
7 | Mike Hamer
8 |
9 | catkin
10 |
11 | ardrone_autonomy
12 | joy
13 |
14 | BSD
15 | http://github.com/mikehamer/ardrone_tutorials
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/drone_controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # A basic drone controller class for the tutorial "Up and flying with the AR.Drone and ROS | Getting Started"
4 | # https://github.com/mikehamer/ardrone_tutorials_getting_started
5 |
6 | # This class implements basic control functionality which we will be using in future tutorials.
7 | # It can command takeoff/landing/emergency as well as drone movement
8 | # It also tracks the drone state based on navdata feedback
9 |
10 | # Import the ROS libraries, and load the manifest file which through will give us access to the project dependencies
11 | import roslib; roslib.load_manifest('ardrone_tutorials')
12 | import rospy
13 |
14 | # Import the messages we're interested in sending and receiving
15 | from geometry_msgs.msg import Twist # for sending commands to the drone
16 | from std_msgs.msg import Empty # for land/takeoff/emergency
17 | from ardrone_autonomy.msg import Navdata # for receiving navdata feedback
18 |
19 | # An enumeration of Drone Statuses
20 | from drone_status import DroneStatus
21 |
22 |
23 | # Some Constants
24 | COMMAND_PERIOD = 100 #ms
25 |
26 |
27 | class BasicDroneController(object):
28 | def __init__(self):
29 | # Holds the current drone status
30 | self.status = -1
31 |
32 | # Subscribe to the /ardrone/navdata topic, of message type navdata, and call self.ReceiveNavdata when a message is received
33 | self.subNavdata = rospy.Subscriber('/ardrone/navdata',Navdata,self.ReceiveNavdata)
34 |
35 | # Allow the controller to publish to the /ardrone/takeoff, land and reset topics
36 | self.pubLand = rospy.Publisher('/ardrone/land',Empty)
37 | self.pubTakeoff = rospy.Publisher('/ardrone/takeoff',Empty)
38 | self.pubReset = rospy.Publisher('/ardrone/reset',Empty)
39 |
40 | # Allow the controller to publish to the /cmd_vel topic and thus control the drone
41 | self.pubCommand = rospy.Publisher('/cmd_vel',Twist)
42 |
43 | # Setup regular publishing of control packets
44 | self.command = Twist()
45 | self.commandTimer = rospy.Timer(rospy.Duration(COMMAND_PERIOD/1000.0),self.SendCommand)
46 |
47 | # Land the drone if we are shutting down
48 | rospy.on_shutdown(self.SendLand)
49 |
50 | def ReceiveNavdata(self,navdata):
51 | # Although there is a lot of data in this packet, we're only interested in the state at the moment
52 | self.status = navdata.state
53 |
54 | def SendTakeoff(self):
55 | # Send a takeoff message to the ardrone driver
56 | # Note we only send a takeoff message if the drone is landed - an unexpected takeoff is not good!
57 | if(self.status == DroneStatus.Landed):
58 | self.pubTakeoff.publish(Empty())
59 |
60 | def SendLand(self):
61 | # Send a landing message to the ardrone driver
62 | # Note we send this in all states, landing can do no harm
63 | self.pubLand.publish(Empty())
64 |
65 | def SendEmergency(self):
66 | # Send an emergency (or reset) message to the ardrone driver
67 | self.pubReset.publish(Empty())
68 |
69 | def SetCommand(self,roll=0,pitch=0,yaw_velocity=0,z_velocity=0):
70 | # Called by the main program to set the current command
71 | self.command.linear.x = pitch
72 | self.command.linear.y = roll
73 | self.command.linear.z = z_velocity
74 | self.command.angular.z = yaw_velocity
75 |
76 | def SendCommand(self,event):
77 | # The previously set command is then sent out periodically if the drone is flying
78 | if self.status == DroneStatus.Flying or self.status == DroneStatus.GotoHover or self.status == DroneStatus.Hovering:
79 | self.pubCommand.publish(self.command)
80 |
81 |
--------------------------------------------------------------------------------
/src/drone_status.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # An enumeration of drone statuses for the tutorial "Up and flying with the AR.Drone and ROS | Getting Started"
4 | # https://github.com/mikehamer/ardrone_tutorials_getting_started
5 |
6 | class DroneStatus(object):
7 | Emergency = 0
8 | Inited = 1
9 | Landed = 2
10 | Flying = 3
11 | Hovering = 4
12 | Test = 5
13 | TakingOff = 6
14 | GotoHover = 7
15 | Landing = 8
16 | Looping = 9
--------------------------------------------------------------------------------
/src/drone_video_display.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # A basic video display window for the tutorial "Up and flying with the AR.Drone and ROS | Getting Started"
4 | # https://github.com/mikehamer/ardrone_tutorials_getting_started
5 |
6 | # This display window listens to the drone's video feeds and updates the display at regular intervals
7 | # It also tracks the drone's status and any connection problems, displaying them in the window's status bar
8 | # By default it includes no control functionality. The class can be extended to implement key or mouse listeners if required
9 |
10 | # Import the ROS libraries, and load the manifest file which through will give us access to the project dependencies
11 | import roslib; roslib.load_manifest('ardrone_tutorials')
12 | import rospy
13 |
14 | # Import the two types of messages we're interested in
15 | from sensor_msgs.msg import Image # for receiving the video feed
16 | from ardrone_autonomy.msg import Navdata # for receiving navdata feedback
17 |
18 | # We need to use resource locking to handle synchronization between GUI thread and ROS topic callbacks
19 | from threading import Lock
20 |
21 | # An enumeration of Drone Statuses
22 | from drone_status import DroneStatus
23 |
24 | # The GUI libraries
25 | from PySide import QtCore, QtGui
26 |
27 |
28 | # Some Constants
29 | CONNECTION_CHECK_PERIOD = 250 #ms
30 | GUI_UPDATE_PERIOD = 20 #ms
31 | DETECT_RADIUS = 4 # the radius of the circle drawn when a tag is detected
32 |
33 |
34 | class DroneVideoDisplay(QtGui.QMainWindow):
35 | StatusMessages = {
36 | DroneStatus.Emergency : 'Emergency',
37 | DroneStatus.Inited : 'Initialized',
38 | DroneStatus.Landed : 'Landed',
39 | DroneStatus.Flying : 'Flying',
40 | DroneStatus.Hovering : 'Hovering',
41 | DroneStatus.Test : 'Test (?)',
42 | DroneStatus.TakingOff : 'Taking Off',
43 | DroneStatus.GotoHover : 'Going to Hover Mode',
44 | DroneStatus.Landing : 'Landing',
45 | DroneStatus.Looping : 'Looping (?)'
46 | }
47 | DisconnectedMessage = 'Disconnected'
48 | UnknownMessage = 'Unknown Status'
49 |
50 | def __init__(self):
51 | # Construct the parent class
52 | super(DroneVideoDisplay, self).__init__()
53 |
54 | # Setup our very basic GUI - a label which fills the whole window and holds our image
55 | self.setWindowTitle('AR.Drone Video Feed')
56 | self.imageBox = QtGui.QLabel(self)
57 | self.setCentralWidget(self.imageBox)
58 |
59 | # Subscribe to the /ardrone/navdata topic, of message type navdata, and call self.ReceiveNavdata when a message is received
60 | self.subNavdata = rospy.Subscriber('/ardrone/navdata',Navdata,self.ReceiveNavdata)
61 |
62 | # Subscribe to the drone's video feed, calling self.ReceiveImage when a new frame is received
63 | self.subVideo = rospy.Subscriber('/ardrone/image_raw',Image,self.ReceiveImage)
64 |
65 | # Holds the image frame received from the drone and later processed by the GUI
66 | self.image = None
67 | self.imageLock = Lock()
68 |
69 | self.tags = []
70 | self.tagLock = Lock()
71 |
72 | # Holds the status message to be displayed on the next GUI update
73 | self.statusMessage = ''
74 |
75 | # Tracks whether we have received data since the last connection check
76 | # This works because data comes in at 50Hz but we're checking for a connection at 4Hz
77 | self.communicationSinceTimer = False
78 | self.connected = False
79 |
80 | # A timer to check whether we're still connected
81 | self.connectionTimer = QtCore.QTimer(self)
82 | self.connectionTimer.timeout.connect(self.ConnectionCallback)
83 | self.connectionTimer.start(CONNECTION_CHECK_PERIOD)
84 |
85 | # A timer to redraw the GUI
86 | self.redrawTimer = QtCore.QTimer(self)
87 | self.redrawTimer.timeout.connect(self.RedrawCallback)
88 | self.redrawTimer.start(GUI_UPDATE_PERIOD)
89 |
90 | # Called every CONNECTION_CHECK_PERIOD ms, if we haven't received anything since the last callback, will assume we are having network troubles and display a message in the status bar
91 | def ConnectionCallback(self):
92 | self.connected = self.communicationSinceTimer
93 | self.communicationSinceTimer = False
94 |
95 | def RedrawCallback(self):
96 | if self.image is not None:
97 | # We have some issues with locking between the display thread and the ros messaging thread due to the size of the image, so we need to lock the resources
98 | self.imageLock.acquire()
99 | try:
100 | # Convert the ROS image into a QImage which we can display
101 | image = QtGui.QPixmap.fromImage(QtGui.QImage(self.image.data, self.image.width, self.image.height, QtGui.QImage.Format_RGB888))
102 | if len(self.tags) > 0:
103 | self.tagLock.acquire()
104 | try:
105 | painter = QtGui.QPainter()
106 | painter.begin(image)
107 | painter.setPen(QtGui.QColor(0,255,0))
108 | painter.setBrush(QtGui.QColor(0,255,0))
109 | for (x,y,d) in self.tags:
110 | r = QtCore.QRectF((x*image.width())/1000-DETECT_RADIUS,(y*image.height())/1000-DETECT_RADIUS,DETECT_RADIUS*2,DETECT_RADIUS*2)
111 | painter.drawEllipse(r)
112 | painter.drawText((x*image.width())/1000+DETECT_RADIUS,(y*image.height())/1000-DETECT_RADIUS,str(d/100)[0:4]+'m')
113 | painter.end()
114 | finally:
115 | self.tagLock.release()
116 | finally:
117 | self.imageLock.release()
118 |
119 | # We could do more processing (eg OpenCV) here if we wanted to, but for now lets just display the window.
120 | self.resize(image.width(),image.height())
121 | self.imageBox.setPixmap(image)
122 |
123 | # Update the status bar to show the current drone status & battery level
124 | self.statusBar().showMessage(self.statusMessage if self.connected else self.DisconnectedMessage)
125 |
126 | def ReceiveImage(self,data):
127 | # Indicate that new data has been received (thus we are connected)
128 | self.communicationSinceTimer = True
129 |
130 | # We have some issues with locking between the GUI update thread and the ROS messaging thread due to the size of the image, so we need to lock the resources
131 | self.imageLock.acquire()
132 | try:
133 | self.image = data # Save the ros image for processing by the display thread
134 | finally:
135 | self.imageLock.release()
136 |
137 | def ReceiveNavdata(self,navdata):
138 | # Indicate that new data has been received (thus we are connected)
139 | self.communicationSinceTimer = True
140 |
141 | # Update the message to be displayed
142 | msg = self.StatusMessages[navdata.state] if navdata.state in self.StatusMessages else self.UnknownMessage
143 | self.statusMessage = '{} (Battery: {}%)'.format(msg,int(navdata.batteryPercent))
144 |
145 | self.tagLock.acquire()
146 | try:
147 | if navdata.tags_count > 0:
148 | self.tags = [(navdata.tags_xc[i],navdata.tags_yc[i],navdata.tags_distance[i]) for i in range(0,navdata.tags_count)]
149 | else:
150 | self.tags = []
151 | finally:
152 | self.tagLock.release()
153 |
154 | if __name__=='__main__':
155 | import sys
156 | rospy.init_node('ardrone_video_display')
157 | app = QtGui.QApplication(sys.argv)
158 | display = DroneVideoDisplay()
159 | display.show()
160 | status = app.exec_()
161 | rospy.signal_shutdown('Great Flying!')
162 | sys.exit(status)
163 |
--------------------------------------------------------------------------------
/src/joystick_controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # The Joystick Controller Node for the tutorial "Up and flying with the AR.Drone and ROS | Joystick Control"
4 | # https://github.com/mikehamer/ardrone_tutorials
5 |
6 | # This controller implements the base DroneVideoDisplay class, the DroneController class and subscribes to joystick messages
7 |
8 | # Import the ROS libraries, and load the manifest file which through will give us access to the project dependencies
9 | import roslib; roslib.load_manifest('ardrone_tutorials')
10 | import rospy
11 |
12 | # Load the DroneController class, which handles interactions with the drone, and the DroneVideoDisplay class, which handles video display
13 | from drone_controller import BasicDroneController
14 | from drone_video_display import DroneVideoDisplay
15 |
16 | # Import the joystick message
17 | from sensor_msgs.msg import Joy
18 |
19 | # Finally the GUI libraries
20 | from PySide import QtCore, QtGui
21 |
22 | # define the default mapping between joystick buttons and their corresponding actions
23 | ButtonEmergency = 0
24 | ButtonLand = 1
25 | ButtonTakeoff = 2
26 |
27 | # define the default mapping between joystick axes and their corresponding directions
28 | AxisRoll = 0
29 | AxisPitch = 1
30 | AxisYaw = 3
31 | AxisZ = 4
32 |
33 | # define the default scaling to apply to the axis inputs. useful where an axis is inverted
34 | ScaleRoll = 1.0
35 | ScalePitch = 1.0
36 | ScaleYaw = 1.0
37 | ScaleZ = 1.0
38 |
39 | # handles the reception of joystick packets
40 | def ReceiveJoystickMessage(data):
41 | if data.buttons[ButtonEmergency]==1:
42 | rospy.loginfo("Emergency Button Pressed")
43 | controller.SendEmergency()
44 | elif data.buttons[ButtonLand]==1:
45 | rospy.loginfo("Land Button Pressed")
46 | controller.SendLand()
47 | elif data.buttons[ButtonTakeoff]==1:
48 | rospy.loginfo("Takeoff Button Pressed")
49 | controller.SendTakeoff()
50 | else:
51 | controller.SetCommand(data.axes[AxisRoll]/ScaleRoll,data.axes[AxisPitch]/ScalePitch,data.axes[AxisYaw]/ScaleYaw,data.axes[AxisZ]/ScaleZ)
52 |
53 |
54 | # Setup the application
55 | if __name__=='__main__':
56 | import sys
57 | # Firstly we setup a ros node, so that we can communicate with the other packages
58 | rospy.init_node('ardrone_joystick_controller')
59 |
60 | # Next load in the parameters from the launch-file
61 | ButtonEmergency = int ( rospy.get_param("~ButtonEmergency",ButtonEmergency) )
62 | ButtonLand = int ( rospy.get_param("~ButtonLand",ButtonLand) )
63 | ButtonTakeoff = int ( rospy.get_param("~ButtonTakeoff",ButtonTakeoff) )
64 | AxisRoll = int ( rospy.get_param("~AxisRoll",AxisRoll) )
65 | AxisPitch = int ( rospy.get_param("~AxisPitch",AxisPitch) )
66 | AxisYaw = int ( rospy.get_param("~AxisYaw",AxisYaw) )
67 | AxisZ = int ( rospy.get_param("~AxisZ",AxisZ) )
68 | ScaleRoll = float ( rospy.get_param("~ScaleRoll",ScaleRoll) )
69 | ScalePitch = float ( rospy.get_param("~ScalePitch",ScalePitch) )
70 | ScaleYaw = float ( rospy.get_param("~ScaleYaw",ScaleYaw) )
71 | ScaleZ = float ( rospy.get_param("~ScaleZ",ScaleZ) )
72 |
73 | # Now we construct our Qt Application and associated controllers and windows
74 | app = QtGui.QApplication(sys.argv)
75 | display = DroneVideoDisplay()
76 | controller = BasicDroneController()
77 |
78 | # subscribe to the /joy topic and handle messages of type Joy with the function ReceiveJoystickMessage
79 | subJoystick = rospy.Subscriber('/joy', Joy, ReceiveJoystickMessage)
80 |
81 | # executes the QT application
82 | display.show()
83 | status = app.exec_()
84 |
85 | # and only progresses to here once the application has been shutdown
86 | rospy.signal_shutdown('Great Flying!')
87 | sys.exit(status)
--------------------------------------------------------------------------------
/src/keyboard_controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # The Keyboard Controller Node for the tutorial "Up and flying with the AR.Drone and ROS | Getting Started"
4 | # https://github.com/mikehamer/ardrone_tutorials
5 |
6 | # This controller extends the base DroneVideoDisplay class, adding a keypress handler to enable keyboard control of the drone
7 |
8 | # Import the ROS libraries, and load the manifest file which through will give us access to the project dependencies
9 | import roslib; roslib.load_manifest('ardrone_tutorials')
10 | import rospy
11 |
12 | # Load the DroneController class, which handles interactions with the drone, and the DroneVideoDisplay class, which handles video display
13 | from drone_controller import BasicDroneController
14 | from drone_video_display import DroneVideoDisplay
15 |
16 | # Finally the GUI libraries
17 | from PySide import QtCore, QtGui
18 |
19 |
20 | # Here we define the keyboard map for our controller (note that python has no enums, so we use a class)
21 | class KeyMapping(object):
22 | PitchForward = QtCore.Qt.Key.Key_E
23 | PitchBackward = QtCore.Qt.Key.Key_D
24 | RollLeft = QtCore.Qt.Key.Key_S
25 | RollRight = QtCore.Qt.Key.Key_F
26 | YawLeft = QtCore.Qt.Key.Key_W
27 | YawRight = QtCore.Qt.Key.Key_R
28 | IncreaseAltitude = QtCore.Qt.Key.Key_Q
29 | DecreaseAltitude = QtCore.Qt.Key.Key_A
30 | Takeoff = QtCore.Qt.Key.Key_Y
31 | Land = QtCore.Qt.Key.Key_H
32 | Emergency = QtCore.Qt.Key.Key_Space
33 |
34 |
35 | # Our controller definition, note that we extend the DroneVideoDisplay class
36 | class KeyboardController(DroneVideoDisplay):
37 | def __init__(self):
38 | super(KeyboardController,self).__init__()
39 |
40 | self.pitch = 0
41 | self.roll = 0
42 | self.yaw_velocity = 0
43 | self.z_velocity = 0
44 |
45 | # We add a keyboard handler to the DroneVideoDisplay to react to keypresses
46 | def keyPressEvent(self, event):
47 | key = event.key()
48 |
49 | # If we have constructed the drone controller and the key is not generated from an auto-repeating key
50 | if controller is not None and not event.isAutoRepeat():
51 | # Handle the important cases first!
52 | if key == KeyMapping.Emergency:
53 | controller.SendEmergency()
54 | elif key == KeyMapping.Takeoff:
55 | controller.SendTakeoff()
56 | elif key == KeyMapping.Land:
57 | controller.SendLand()
58 | else:
59 | # Now we handle moving, notice that this section is the opposite (+=) of the keyrelease section
60 | if key == KeyMapping.YawLeft:
61 | self.yaw_velocity += 1
62 | elif key == KeyMapping.YawRight:
63 | self.yaw_velocity += -1
64 |
65 | elif key == KeyMapping.PitchForward:
66 | self.pitch += 1
67 | elif key == KeyMapping.PitchBackward:
68 | self.pitch += -1
69 |
70 | elif key == KeyMapping.RollLeft:
71 | self.roll += 1
72 | elif key == KeyMapping.RollRight:
73 | self.roll += -1
74 |
75 | elif key == KeyMapping.IncreaseAltitude:
76 | self.z_velocity += 1
77 | elif key == KeyMapping.DecreaseAltitude:
78 | self.z_velocity += -1
79 |
80 | # finally we set the command to be sent. The controller handles sending this at regular intervals
81 | controller.SetCommand(self.roll, self.pitch, self.yaw_velocity, self.z_velocity)
82 |
83 |
84 | def keyReleaseEvent(self,event):
85 | key = event.key()
86 |
87 | # If we have constructed the drone controller and the key is not generated from an auto-repeating key
88 | if controller is not None and not event.isAutoRepeat():
89 | # Note that we don't handle the release of emergency/takeoff/landing keys here, there is no need.
90 | # Now we handle moving, notice that this section is the opposite (-=) of the keypress section
91 | if key == KeyMapping.YawLeft:
92 | self.yaw_velocity -= 1
93 | elif key == KeyMapping.YawRight:
94 | self.yaw_velocity -= -1
95 |
96 | elif key == KeyMapping.PitchForward:
97 | self.pitch -= 1
98 | elif key == KeyMapping.PitchBackward:
99 | self.pitch -= -1
100 |
101 | elif key == KeyMapping.RollLeft:
102 | self.roll -= 1
103 | elif key == KeyMapping.RollRight:
104 | self.roll -= -1
105 |
106 | elif key == KeyMapping.IncreaseAltitude:
107 | self.z_velocity -= 1
108 | elif key == KeyMapping.DecreaseAltitude:
109 | self.z_velocity -= -1
110 |
111 | # finally we set the command to be sent. The controller handles sending this at regular intervals
112 | controller.SetCommand(self.roll, self.pitch, self.yaw_velocity, self.z_velocity)
113 |
114 |
115 |
116 | # Setup the application
117 | if __name__=='__main__':
118 | import sys
119 | # Firstly we setup a ros node, so that we can communicate with the other packages
120 | rospy.init_node('ardrone_keyboard_controller')
121 |
122 | # Now we construct our Qt Application and associated controllers and windows
123 | app = QtGui.QApplication(sys.argv)
124 | controller = BasicDroneController()
125 | display = KeyboardController()
126 |
127 | display.show()
128 |
129 | # executes the QT application
130 | status = app.exec_()
131 |
132 | # and only progresses to here once the application has been shutdown
133 | rospy.signal_shutdown('Great Flying!')
134 | sys.exit(status)
--------------------------------------------------------------------------------