Skip to content

Commit 50dacec

Browse files
committed
Finally added takeoff/land keyboard commands
- Moved panda3d camera to its own folder - Made drone movement faster - Removed my experimental AI stuff, will be added back to a different repo
1 parent c1e9068 commit 50dacec

File tree

7 files changed

+49
-63
lines changed

7 files changed

+49
-63
lines changed

dronesim/__main__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
from dronesim import DroneSimulator
44
from dronesim.interface import DefaultDroneControl
55

6+
#Sensors
7+
from dronesim.sensor.panda3d.camera import Panda3DCameraSensor
8+
69
#App window
710
from dronesim.simapp import SimulatorApplication
811

@@ -16,8 +19,19 @@ def main():
1619
#Simulator environment
1720
drone = DroneSimulator()
1821
droneControl = DefaultDroneControl(drone, update_enable=True)
22+
#Application
1923
droneWindow = SimulatorApplication(droneControl)
24+
#== Add a camera sensor facing down ==
25+
downCam = Panda3DCameraSensor("downCameraRGB", size=(320,320))
26+
drone.addSensor(down_camera_rgb = downCam)
27+
#Insert camera into main app window and attach to the scene
28+
downCam.attachToEnv(droneWindow.render, droneWindow.graphicsEngine, droneWindow.win)
29+
#Move and rotate camera with the UAV object
30+
downCam.reparentTo(droneWindow.getUAVModelNode())
31+
#Face down
32+
downCam.setHpr(0, -90, 0)
33+
#Start the app
2034
droneWindow.run()
21-
35+
2236
if __name__ == "__main__":
2337
main()

dronesim/interface/control.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from abc import ABC
22

3-
from ..types import StepRC
3+
from ..types import StepRC, DroneAction
44

55
class IDroneControllable(ABC):
66
'''
@@ -31,3 +31,5 @@ def rotate_counterclockwise(self, x : float):
3131
pass
3232
def freeze(self):
3333
pass
34+
def directAction(self, action : DroneAction, args : dict = None):
35+
pass

dronesim/interface/default.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,10 @@ def freeze(self):
8989
self.__cmd_queue.put_nowait({
9090
'action': DroneAction.STOPINPLACE
9191
})
92+
93+
def directAction(self, action : DroneAction, args : dict = None):
94+
if args is None: args = {}
95+
self.__cmd_queue.put_nowait({
96+
'action': action,
97+
**args
98+
})

dronesim/physics/simple.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class SimpleDronePhysics(DronePhysicsEngine):
1515
GRAVITY = glm.vec3(0, 0, -1e-3)
1616
AIR_RESISTANCE = glm.vec3((0.95,)*3)
1717
#Angle is counter-clockwise from 3 o'clock position, so negate the magnitude to turn properly
18-
RC_SCALE = glm.vec4(0.09, 0.09, 0.05, -0.018)
18+
RC_SCALE = glm.vec4(0.09, 0.09, 0.09, -0.05)
1919

2020
#PID controller parameters
2121
STRAFE_CONTROL_PARAM = {'Kp': 0.45, 'Ki': 0.01, 'Kd': 0.0}

dronesim/sensor/camera.py renamed to dronesim/sensor/panda3d/camera.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
from .sensor import SensorBase
2+
from ..sensor import SensorBase
33
from panda3d.core import (
44
NodePath,
55
Camera,
@@ -16,7 +16,7 @@ class Panda3DCameraSensor(NodePath, SensorBase):
1616
CAMERA_TYPE_RGB = GraphicsOutput.RTPColor
1717
CAMERA_TYPE_DEPTH = GraphicsOutput.RTPDepth
1818

19-
def __init__(self, node_name : str, size = (512, 512), camera_type = CAMERA_TYPE_RGB):
19+
def __init__(self, node_name : str, size : tuple = (512, 512), camera_type = CAMERA_TYPE_RGB):
2020
super().__init__(Camera(node_name, PerspectiveLens()))
2121
self.tex = Texture()
2222
self.texfbuf = None
@@ -25,6 +25,8 @@ def __init__(self, node_name : str, size = (512, 512), camera_type = CAMERA_TYPE
2525
def update(self):
2626
'''Force render scene and return the image as a 'BGR' numpy array'''
2727
return
28+
def getViewportSize(self) -> tuple:
29+
return self.fbufsize
2830
def attachToEnv(self, scene : NodePath, gengine : GraphicsEngine, host_go : GraphicsOutput):
2931
#TODO: Check if this is even required
3032
self.node().setScene(scene)

dronesim/simapp.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from . import PACKAGE_BASE
2222
from .interface.control import IDroneControllable
2323
from .utils import IterEnumMixin, HUDMixin, rad2deg
24-
from .types import Vec4Tuple
24+
from .types import Vec4Tuple, DroneAction
2525

2626
import os
2727
import glm
@@ -358,6 +358,8 @@ def __init__(self,
358358
self.accept("f5", self.eToggleCameraMode)
359359
self.accept("f6", self.eToggleControlMode)
360360
self.accept("f11", self.eToggleFullscreen)
361+
self.accept("i", self.eHandleDroneCommandSend, [DroneAction.TAKEOFF])
362+
self.accept("k", self.eHandleDroneCommandSend, [DroneAction.LAND])
361363

362364
#Tasks
363365
self.updateEngineTask = self.taskMgr.add(self.updateEngine, "updateEngine")
@@ -464,6 +466,9 @@ def _updatePlayerMovementCommand(self):
464466
if self.camState.control == ControllingCharacter.player and self.movementState is not None:
465467
self.drone.rc_control(self.movementState)
466468

469+
def eHandleDroneCommandSend(self, cmd : DroneAction, params : dict = None):
470+
self.drone.directAction(cmd, params)
471+
467472
def _getMovementControlState(self) -> Vec4Tuple:
468473
#Returns whether a button/key is pressed
469474
isDown : typing.Callable[[ButtonHandle], bool] = self.mouseWatcherNode.isButtonDown
@@ -473,13 +478,21 @@ def _getMovementControlState(self) -> Vec4Tuple:
473478
btnL = KeyboardButton.ascii_key('a')
474479
btnR = KeyboardButton.ascii_key('d')
475480

481+
btnLArrow = KeyboardButton.left()
482+
btnRArrow = KeyboardButton.right()
483+
btnUArrow = KeyboardButton.up()
484+
btnDArrow = KeyboardButton.down()
485+
476486
state_lr = (isDown(btnR) - isDown(btnL))
477487
state_fwbw = (isDown(btnFw) - isDown(btnBw))
488+
state_yawlr = (isDown(btnRArrow) - isDown(btnLArrow))
489+
state_altud = (isDown(btnUArrow) - isDown(btnDArrow))
478490

479491
#Order is the same as the arguments of 'StepRC' type
480-
return (state_lr, state_fwbw, 0.0, 0.0)
492+
return (state_lr, state_fwbw, state_altud, state_yawlr)
481493

482494
def _updateHUD(self):
495+
#TODO: Any other way to hide OnscreenText?
483496
if not self.HUDState['visible']:
484497
self.camHUDText.setText('')
485498
self.debugHUDText.setText('')

examples/follow.py

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,19 @@
33
from dronesim.simapp import SimulatorApplication
44
from dronesim.interface import IDroneControllable
55
from dronesim.types import DroneAction, StepRC
6-
from dronesim.sensor.camera import Panda3DCameraSensor
6+
from dronesim.sensor.panda3d.camera import Panda3DCameraSensor
77

88
import threading
99
import time
1010
from collections import namedtuple
1111

12-
#AI stuff
13-
import torch
14-
import torch.nn as nn
15-
import torch.optim as optim
16-
import torch.nn.functional as F
17-
import torchvision.transforms as T
18-
19-
TENSOR_DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
20-
Transition = namedtuple('Transition', ('state', 'action', 'next_state', 'reward'))
21-
class ReplayMemory(object):
22-
def __init__(self, capacity):
23-
self.memory = deque([],maxlen=capacity)
24-
25-
def push(self, *args):
26-
"""Save a transition"""
27-
self.memory.append(Transition(*args))
28-
29-
def sample(self, batch_size):
30-
return random.sample(self.memory, batch_size)
31-
32-
def __len__(self):
33-
return len(self.memory)
34-
35-
36-
'''
37-
I/O Requirements:
38-
Inputs:
39-
- n-vector (n=number of distance rays). Value is intersection distance with path, or 0 if none
40-
- scalar, for use in decisions or additional input
41-
(junction decision for example, -1=left, 1=right, 0=stop or u-turn)
42-
Outputs:
43-
- vec3 - 2-degree of movements (l/r, fw/bw) and yaw control,
44-
representing the q-values of each action
45-
46-
'''
47-
48-
class DQN(nn.Module):
49-
def __init__(self, input_distances : int):
50-
super().__init__()
51-
self.dense1 = nn.Linear(input_distances, 16)
52-
self.dense2 = nn.Linear(16, 32)
53-
self.output = nn.Linear(32, 3)
54-
55-
def forward(self, x):
56-
x = x.to(TENSOR_DEVICE)
57-
x = self.dense1(x)
58-
x = self.dense2(x)
59-
return self.output(x)
60-
6112
class AIDroneControlAgent(threading.Thread, IDroneControllable):
6213
def __init__(self):
6314
super().__init__(daemon=True)
6415

6516
#Environment
6617
self.drone = DroneSimulator()
67-
self.model = DQN(10)
18+
self.model = None
6819

6920
#Add some sensors
7021
self.drone.addSensor(
@@ -73,7 +24,6 @@ def __init__(self):
7324
)
7425

7526
self.__state = dict()
76-
self.start()
7727

7828
def initEnv(self, app):
7929
self.drone.sensors['down_camera_rgb'].attachToEnv(app.render, app.graphicsEngine, app.win)
@@ -88,17 +38,14 @@ def initEnv(self, app):
8838
def run(self):
8939
self.drone.state = {"pos": 123}
9040
self.drone.step({'action': DroneAction.TAKEOFF})
41+
print(self.drone.sensors['down_camera_rgb'].getViewportSize())
9142
for _ in range(200):
9243
state = self.drone.step()
9344
for _ in range(2000):
9445
state = self.drone.step(StepRC(0,0.6,0,0))
9546
self.__update_debug_state(state)
9647
time.sleep(0.01)
9748

98-
#observation, reward, done, info = state
99-
#output = self.model.forward(torch.ones(1, 10))
100-
#print(output)
101-
10249
def __update_debug_state(self, state):
10350
observation, reward, done, info = state
10451
self.__state.update({
@@ -120,6 +67,7 @@ def main():
12067
droneControl = AIDroneControlAgent()
12168
droneWindow = SimulatorApplication(droneControl)
12269
droneControl.initEnv(droneWindow)
70+
droneControl.start()
12371
droneWindow.run()
12472

12573
if __name__ == "__main__":

0 commit comments

Comments
 (0)