Skip to content

Commit

Permalink
Update Lunar lander step to match performance with Gymnasium (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudo-rnd-thoughts authored Mar 14, 2024
1 parent e3e05f3 commit 85a2215
Showing 1 changed file with 49 additions and 21 deletions.
70 changes: 49 additions & 21 deletions mo_gymnasium/envs/lunar_lander/lunar_lander.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
FPS,
LEG_DOWN,
MAIN_ENGINE_POWER,
MAIN_ENGINE_Y_LOCATION,
SCALE,
SIDE_ENGINE_AWAY,
SIDE_ENGINE_HEIGHT,
Expand Down Expand Up @@ -46,7 +47,7 @@ def __init__(self, *args, **kwargs):
def step(self, action):
assert self.lander is not None

# Update wind
# Update wind and apply to the lander
assert self.lander is not None, "You forgot to call reset()"
if self.enable_wind and not (self.legs[0].ground_contact or self.legs[1].ground_contact):
# the function used for wind is tanh(sin(2 k x) + sin(pi k x)),
Expand All @@ -60,12 +61,13 @@ def step(self, action):

# the function used for torque is tanh(sin(2 k x) + sin(pi k x)),
# which is proven to never be periodic, k = 0.01
torque_mag = math.tanh(math.sin(0.02 * self.torque_idx) + (math.sin(math.pi * 0.01 * self.torque_idx))) * (
self.turbulence_power
torque_mag = (
math.tanh(math.sin(0.02 * self.torque_idx) + (math.sin(math.pi * 0.01 * self.torque_idx)))
* self.turbulence_power
)
self.torque_idx += 1
self.lander.ApplyTorque(
(torque_mag),
torque_mag,
True,
)

Expand All @@ -74,9 +76,15 @@ def step(self, action):
else:
assert self.action_space.contains(action), f"{action!r} ({type(action)}) invalid "

# Engines
# Apply Engine Impulses

# Tip is the (X and Y) components of the rotation of the lander.
tip = (math.sin(self.lander.angle), math.cos(self.lander.angle))

# Side is the (-Y and X) components of the rotation of the lander.
side = (-tip[1], tip[0])

# Generate two random numbers between -1/SCALE and 1/SCALE.
dispersion = [self.np_random.uniform(-1.0, +1.0) / SCALE for _ in range(2)]

m_power = 0.0
Expand All @@ -87,21 +95,29 @@ def step(self, action):
assert m_power >= 0.5 and m_power <= 1.0
else:
m_power = 1.0

# 4 is move a bit downwards, +-2 for randomness
ox = tip[0] * (4 / SCALE + 2 * dispersion[0]) + side[0] * dispersion[1]
oy = -tip[1] * (4 / SCALE + 2 * dispersion[0]) - side[1] * dispersion[1]
# The components of the impulse to be applied by the main engine.
ox = tip[0] * (MAIN_ENGINE_Y_LOCATION / SCALE + 2 * dispersion[0]) + side[0] * dispersion[1]
oy = -tip[1] * (MAIN_ENGINE_Y_LOCATION / SCALE + 2 * dispersion[0]) - side[1] * dispersion[1]

impulse_pos = (self.lander.position[0] + ox, self.lander.position[1] + oy)
p = self._create_particle(
3.5, # 3.5 is here to make particle speed adequate
impulse_pos[0],
impulse_pos[1],
m_power,
) # particles are just a decoration
p.ApplyLinearImpulse(
(ox * MAIN_ENGINE_POWER * m_power, oy * MAIN_ENGINE_POWER * m_power),
impulse_pos,
True,
)
if self.render_mode is not None:
# particles are just a decoration, with no impact on the physics, so don't add them when not rendering
p = self._create_particle(
3.5, # 3.5 is here to make particle speed adequate
impulse_pos[0],
impulse_pos[1],
m_power,
)
p.ApplyLinearImpulse(
(
ox * MAIN_ENGINE_POWER * m_power,
oy * MAIN_ENGINE_POWER * m_power,
),
impulse_pos,
True,
)
self.lander.ApplyLinearImpulse(
(-ox * MAIN_ENGINE_POWER * m_power, -oy * MAIN_ENGINE_POWER * m_power),
impulse_pos,
Expand All @@ -110,25 +126,36 @@ def step(self, action):

s_power = 0.0
if (self.continuous and np.abs(action[1]) > 0.5) or (not self.continuous and action in [1, 3]):
# Orientation engines
# Orientation/Side engines
if self.continuous:
direction = np.sign(action[1])
s_power = np.clip(np.abs(action[1]), 0.5, 1.0)
assert s_power >= 0.5 and s_power <= 1.0
else:
# action = 1 is left, action = 3 is right
direction = action - 2
s_power = 1.0

# The components of the impulse to be applied by the side engines.
ox = tip[0] * dispersion[0] + side[0] * (3 * dispersion[1] + direction * SIDE_ENGINE_AWAY / SCALE)
oy = -tip[1] * dispersion[0] - side[1] * (3 * dispersion[1] + direction * SIDE_ENGINE_AWAY / SCALE)

# The constant 17 is a constant, that is presumably meant to be SIDE_ENGINE_HEIGHT.
# However, SIDE_ENGINE_HEIGHT is defined as 14
# This causes the position of the thrust on the body of the lander to change, depending on the orientation of the lander.
# This in turn results in an orientation dependent torque being applied to the lander.
impulse_pos = (
self.lander.position[0] + ox - tip[0] * 17 / SCALE,
self.lander.position[1] + oy + tip[1] * SIDE_ENGINE_HEIGHT / SCALE,
)
if self.render_mode is not None:
# particles are just a decoration, so don't add them when not rendering
# particles are just a decoration, with no impact on the physics, so don't add them when not rendering
p = self._create_particle(0.7, impulse_pos[0], impulse_pos[1], s_power)
p.ApplyLinearImpulse(
(ox * SIDE_ENGINE_POWER * s_power, oy * SIDE_ENGINE_POWER * s_power),
(
ox * SIDE_ENGINE_POWER * s_power,
oy * SIDE_ENGINE_POWER * s_power,
),
impulse_pos,
True,
)
Expand All @@ -142,6 +169,7 @@ def step(self, action):

pos = self.lander.position
vel = self.lander.linearVelocity

state = [
(pos.x - VIEWPORT_W / SCALE / 2) / (VIEWPORT_W / SCALE / 2),
(pos.y - (self.helipad_y + LEG_DOWN / SCALE)) / (VIEWPORT_H / SCALE / 2),
Expand Down

0 comments on commit 85a2215

Please sign in to comment.