Skip to content

Commit 2f4f93c

Browse files
committed
Added FP and TP cameras
Beginning of physics engine state machine function name changes TODO: Update PID parameters for height
1 parent a69c45d commit 2f4f93c

File tree

8 files changed

+236
-60
lines changed

8 files changed

+236
-60
lines changed

TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Pretty long at the moment
55

66
- [x] Complete movement swap (camera to player)
77
- [x] Implement UAV movement by user
8+
- [ ] Show skybox texture
89
- [ ] Support for Ardupilot SITL interface
910
- [ ] Using Mavlink
1011
- [ ] Using integrated SITL as optional dependency

dronesim/interface/control.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ def rotate_counterclockwise(self, x : float):
3131
pass
3232
def freeze(self):
3333
pass
34-
def directAction(self, action : DroneAction, args : dict = None):
34+
def direct_action(self, action : DroneAction, args : dict = None):
3535
pass
36+
def get_debug_data(self) -> dict:
37+
return {}

dronesim/interface/default.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ def __init__(self,
2020
self._tick_rate = tick_rate
2121
self._update_enable = update_enable
2222
self._tps_update_period = tps_update_period
23-
self.__state = dict(tps=0)
23+
24+
self.__debug_data = dict(tps=0)
25+
self.__state = None
2426
self.__cmd_queue : Queue[StepActionType] = Queue()
2527

2628
self._th = threading.Thread(target=self.droneTick, daemon=True)
@@ -46,18 +48,18 @@ def droneTick(self):
4648

4749
#Perform step
4850
if self._update_enable:
49-
droneState = self.drone.step(cmd)
51+
self.__state = self.drone.step(cmd)
5052

5153
#Update TPS
5254
if time.time() - last_tick_check >= self._tps_update_period:
5355
tickDiff = (self.drone.metrics['ticks'] - last_ticks) / self._tps_update_period
5456
last_ticks = self.drone.metrics['ticks']
55-
self.__state['tps'] = int(tickDiff)
57+
self.__debug_data['tps'] = int(tickDiff)
5658
last_tick_check = time.time()
5759

58-
#Update state info from the simulation step
59-
observation, reward, done, info = droneState
60-
self.__state.update({
60+
#Update debug state info from the simulation step
61+
observation, reward, done, info = self.__state
62+
self.__debug_data.update({
6163
'state': info['state'],
6264
'observation': observation,
6365
'reward': reward,
@@ -72,6 +74,9 @@ def droneTick(self):
7274
def get_current_state(self):
7375
return self.__state
7476

77+
def get_debug_data(self) -> dict:
78+
return self.__debug_data
79+
7580
def rc_control(self, vector : StepRC):
7681
self.__cmd_queue.put_nowait(vector)
7782

@@ -90,7 +95,7 @@ def freeze(self):
9095
'action': DroneAction.STOPINPLACE
9196
})
9297

93-
def directAction(self, action : DroneAction, args : dict = None):
98+
def direct_action(self, action : DroneAction, args : dict = None):
9499
if args is None: args = {}
95100
self.__cmd_queue.put_nowait({
96101
'action': action,

dronesim/physics/simple.py

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,40 @@ class SimpleDronePhysics(DronePhysicsEngine):
1212
Assume units are in centimeters when translating to irl unit
1313
'''
1414

15-
GRAVITY = glm.vec3(0, 0, -1e-3)
16-
AIR_RESISTANCE = glm.vec3((0.95,)*3)
15+
GRAVITY = glm.vec3(0, 0, -2e-1)
16+
AIR_RESISTANCE = glm.vec3((0.98,)*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.09, -0.05)
18+
RC_SCALE = glm.vec4(0.2, 0.2, 0.1, -0.05)
19+
20+
TAKEOFF_COMPLETE_ERROR_MAX = 1e-1
21+
ARMED_MIN_THRUST = 1e-3
22+
TAKEOFF_COMPLETE_STABLE_TICKS = 30
1923

2024
#PID controller parameters
21-
STRAFE_CONTROL_PARAM = {'Kp': 0.45, 'Ki': 0.01, 'Kd': 0.0}
22-
LIFT_CONTROL_PARAM = {'Kp': 0.002, 'Ki': 0.002, 'Kd': 0.0}
23-
TURN_CONTROL_PARAM = {'Kp': 0.5, 'Ki': 0.0, 'Kd': 0.0}
25+
STRAFE_CONTROL_PARAM = {'Kp': 0.02, 'Ki': 0.0, 'Kd': 0.0}
26+
LIFT_CONTROL_PARAM = {'Kp': 0.019, 'Ki': 0.012, 'Kd': 0.0}
27+
TURN_CONTROL_PARAM = {'Kp': 0.2, 'Ki': 0.0, 'Kd': 0.0}
2428

2529
def reset(self, state : PhysicsStateType = None) -> PhysicsStateType:
30+
#TODO: put all of this in a dict-inheriting class and use that as state
31+
2632
#Position of the drone in space
2733
self.pos = glm.vec3((0,0,0))
2834
self.angle = glm.vec3((0,0,0))
2935
#Instantaneous velocity
3036
self.pvel = glm.vec4(0,0,0,1)
3137
self.fvel = glm.vec3()
3238
self.avel = glm.vec3()
39+
self.ticks = 0
40+
self._lastRC = None
41+
self._tickLogs : dict = {}
3342

3443
#Thrust to apply
3544
self.thrust_vec = glm.vec3()
3645

46+
#Landed, stationary
47+
self._operation = DroneState.LANDED
48+
3749
#Movement PID control. XY and W is for velocity, Z is for absolute position (altitude)
3850
self.control = Vec4PID(
3951
PID(**self.STRAFE_CONTROL_PARAM, sample_time=None),
@@ -45,9 +57,6 @@ def reset(self, state : PhysicsStateType = None) -> PhysicsStateType:
4557
self._state : PhysicsStateType = dict()
4658
self._updateState()
4759

48-
#Landed, stationary
49-
self._operation = DroneState.LANDED
50-
5160
return self.state
5261

5362
def _updateState(self):
@@ -76,33 +85,59 @@ def state(self, state):
7685
self.reset(state)
7786

7887
def step(self, action : StepActionType, dt : float = None) -> PhysicsStateType:
88+
self.ticks += 1
89+
7990
rcvec, op, params = self.decodeAction(action)
91+
92+
#State machine
8093
if op is not None:
8194
if op == DroneAction.TAKEOFF:
82-
self._operation = DroneState.TAKING_OFF
83-
self.control.z.setpoint = params.get("altitude", 10.0)
84-
85-
if rcvec is None:
86-
rcvec = StepRC(0,0,0,0)
95+
if self._operation == DroneState.LANDED:
96+
self._operation = DroneState.TAKING_OFF
97+
self.control.z.setpoint = params.get("altitude", 10.0)
98+
self._tickLogs[DroneState.TAKING_OFF] = 0
99+
100+
if self._operation == DroneState.TAKING_OFF:
101+
z_error = self.control.z.setpoint - self.pos.z
102+
abs_speed = glm.length(self.pvel.xyz)
103+
#print(abs_speed)
104+
if abs(z_error) < self.TAKEOFF_COMPLETE_ERROR_MAX:
105+
self._tickLogs[DroneState.TAKING_OFF] += 1
106+
if self._tickLogs[DroneState.TAKING_OFF] > self.TAKEOFF_COMPLETE_STABLE_TICKS:
107+
self._operation = DroneState.IN_AIR
108+
109+
#Save last RC for later
110+
if rcvec is not None:
111+
self._lastRC = (rcvec, self.ticks)
112+
#If no RC, reuse previous RC input for some steps
113+
else:
114+
if self._lastRC is not None and self._lastRC[0] is not None and self.ticks < self._lastRC[1] + 30:
115+
rcvec = self._lastRC[0]
116+
else:
117+
rcvec = StepRC(0,0,0,0)
87118

88119
#Which direction to move using RC
89120
rc_vec = glm.vec4(rcvec)
90121
rc_vec = glm.clamp(rc_vec, -1, 1)
91122
rc_vec *= self.RC_SCALE
92123

93124
is_on_surface = False
94-
is_accept_rc = False
125+
is_armed = self._operation != DroneState.LANDED
126+
is_accept_rc = self._operation == DroneState.IN_AIR
95127

96128
#RC thrust control
97-
self.control.x.setpoint = rc_vec.x # Target velocity
98-
self.control.y.setpoint = rc_vec.y # Target velocity
99-
self.control.w.setpoint = rc_vec.w # Target heading angle
100-
self.control.z.setpoint += rc_vec.z # Absolute height
129+
if is_accept_rc:
130+
self.control.x.setpoint = rc_vec.x # Target velocity
131+
self.control.y.setpoint = rc_vec.y # Target velocity
132+
self.control.w.setpoint = rc_vec.w # Target heading angle
133+
self.control.z.setpoint += rc_vec.z # Absolute height
134+
if self.control.z.setpoint < 0:
135+
self.control.z.setpoint = 0.0
101136

102137
#Apply thrust based on target position
103138
self.thrust_vec.x = self.control.x(self.pvel.x, dt)
104139
self.thrust_vec.y = self.control.y(self.pvel.y, dt)
105-
self.thrust_vec.z = self.control.z(self.pos.z, dt)
140+
self.thrust_vec.z = glm.max(self.control.z(self.pos.z, dt), self.ARMED_MIN_THRUST if is_armed else 0.0)
106141
self.avel.z = self.control.w(self.avel.z, dt)
107142

108143
#3D coordinate transformation matrix

0 commit comments

Comments
 (0)