Skip to content

Commit 6c79271

Browse files
[Refactor] DIff drive dynamics (#81)
* amend * amend * amend * amend * amend * amend * amend * amend * amend
1 parent 7c453bf commit 6c79271

File tree

4 files changed

+47
-25
lines changed

4 files changed

+47
-25
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ To create a fake screen you need to have `Xvfb` installed.
379379
| `line_trajectory.py` | One agent is rewarded to move in a line trajectory. | <img src="https://github.com/matteobettini/vmas-media/blob/main/media/scenarios/line_trajectory.gif?raw=true" alt="drawing" width="300"/> |
380380
| `circle_trajectory.py` | One agent is rewarded to move in a circle trajectory at the `desired_radius`. | <img src="https://github.com/matteobettini/vmas-media/blob/main/media/scenarios/circle_trajectory.gif?raw=true" alt="drawing" width="300"/> |
381381
| `diff_drive.py` | An example of the `diff_drive` dynamic model constraint. Both agents have rotational actions which can be controlled interactively. The first agent has differential drive dynamics. The second agent has standard vmas holonomic dynamics. | <img src="https://github.com/matteobettini/vmas-media/blob/main/media/scenarios/diff_drive.gif?raw=true" alt="drawing" width="300"/> |
382-
| `kinematic_bicycle.py` | An example of `kinematic_bicycle` dynamic model constraint. Both agents have rotational actions which can be controlled interactively. The first agent has kinematic bicycle model dynamics. The second agent has standard vmas holonomic dynamics. | <img src="https://github.com/matteobettini/vmas-media/blob/main/media/scenarios/kinematic_bicycle.gif?raw=true" alt="drawing" width="300"/> |
382+
| `kinematic_bicycle.py` | An example of `kinematic_bicycle` dynamic model constraint. Both agents have rotational actions which can be controlled interactively. The first agent has kinematic bicycle model dynamics. The second agent has standard vmas holonomic dynamics. | <img src="https://github.com/matteobettini/vmas-media/blob/main/media/scenarios/kinematic_bicycle.gif?raw=true" alt="drawing" width="300"/> |
383383

384384
### [MPE](https://github.com/openai/multiagent-particle-envs)
385385

vmas/scenarios/debug/diff_drive.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from typing import List
66

77
import torch
8-
98
from vmas import render_interactively
109
from vmas.simulator.core import Agent, World
1110
from vmas.simulator.dynamics.diff_drive import DiffDrive
@@ -25,11 +24,11 @@ def make_world(self, batch_dim: int, device: torch.device, **kwargs):
2524
2625
The first agent has differential drive dynamics.
2726
You can control its forward input with the LEFT and RIGHT arrows.
28-
You can control its rotation with N and M.
27+
You can control its rotation with UP and DOWN.
2928
3029
The second agent has standard vmas holonomic dynamics.
3130
You can control it with WASD
32-
You can control its rotation withQ and E.
31+
You can control its rotation with Q and E.
3332
3433
"""
3534
# T
@@ -46,7 +45,7 @@ def make_world(self, batch_dim: int, device: torch.device, **kwargs):
4645
collide=True,
4746
render_action=True,
4847
u_range=[1, 1],
49-
u_multiplier=[1, 0.001],
48+
u_multiplier=[1, 1],
5049
dynamics=DiffDrive(world, integration="rk4"),
5150
)
5251
else:

vmas/simulator/dynamics/diff_drive.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import math
55

66
import torch
7-
87
import vmas.simulator.core
98
import vmas.simulator.utils
109
from vmas.simulator.dynamics.common import Dynamics
@@ -23,35 +22,60 @@ def __init__(
2322
self.integration = integration
2423
self.world = world
2524

26-
def euler(self, f, rot):
27-
return f(rot)
25+
def euler(self, f, state):
26+
return state + self.dt * f(state)
2827

29-
def runge_kutta(self, f, rot):
30-
k1 = f(rot)
31-
k2 = f(rot + self.dt * k1[2] / 2)
32-
k3 = f(rot + self.dt * k2[2] / 2)
33-
k4 = f(rot + self.dt * k3[2])
28+
def runge_kutta(self, f, state):
29+
k1 = f(state)
30+
k2 = f(state + self.dt * k1 / 2)
31+
k3 = f(state + self.dt * k2 / 2)
32+
k4 = f(state + self.dt * k3)
3433

35-
return (1 / 6) * (k1 + 2 * k2 + 2 * k3 + k4)
34+
return state + (self.dt / 6) * (k1 + 2 * k2 + 2 * k3 + k4)
3635

3736
@property
3837
def needed_action_size(self) -> int:
3938
return 2
4039

4140
def process_action(self):
42-
u_forward = self.agent.action.u[:, 0]
43-
u_rot = self.agent.action.u[:, 1]
41+
velocity = self.agent.action.u[:, 0] # Forward velocity
42+
ang_velocity = self.agent.action.u[:, 1] # Angular velocity
43+
44+
# Current state of the agent
45+
state = torch.cat((self.agent.state.pos, self.agent.state.rot), dim=1)
4446

45-
def f(rot):
47+
def f(state):
48+
theta = state[:, 2]
4649
return torch.stack(
47-
[u_forward * torch.cos(rot), u_forward * torch.sin(rot), u_rot], dim=0
50+
[
51+
velocity * torch.cos(theta),
52+
velocity * torch.sin(theta),
53+
ang_velocity,
54+
],
55+
dim=-1,
4856
)
4957

5058
if self.integration == "euler":
51-
u = self.euler(f, self.agent.state.rot.squeeze(-1))
59+
new_state = self.euler(f, state)
5260
else:
53-
u = self.runge_kutta(f, self.agent.state.rot.squeeze(-1))
61+
new_state = self.runge_kutta(f, state)
62+
63+
# Calculate the change in state
64+
delta_state = new_state - state
65+
66+
# Calculate the accelerations required to achieve the change in state
67+
acceleration_x = delta_state[:, 0] / self.dt
68+
acceleration_y = delta_state[:, 1] / self.dt
69+
angular_acceleration = delta_state[:, 2] / self.dt
70+
71+
# Calculate the forces required for the linear accelerations
72+
force_x = self.agent.mass * acceleration_x
73+
force_y = self.agent.mass * acceleration_y
74+
75+
# Calculate the torque required for the angular acceleration
76+
torque = self.agent.moment_of_inertia * angular_acceleration
5477

55-
self.agent.state.force[:, vmas.simulator.utils.X] = u[vmas.simulator.utils.X]
56-
self.agent.state.force[:, vmas.simulator.utils.Y] = u[vmas.simulator.utils.Y]
57-
self.agent.state.torque = u_rot.unsqueeze(-1)
78+
# Update the physical force and torque required for the user inputs
79+
self.agent.state.force[:, vmas.simulator.utils.X] = force_x
80+
self.agent.state.force[:, vmas.simulator.utils.Y] = force_y
81+
self.agent.state.torque = torque.unsqueeze(-1)

vmas/simulator/dynamics/kinematic_bicycle.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from typing import Union
66

77
import torch
8-
98
import vmas.simulator.core
109
import vmas.simulator.utils
1110
from vmas.simulator.dynamics.common import Dynamics
@@ -75,7 +74,7 @@ def f(state):
7574
dy = velocity * torch.sin(theta + beta)
7675
dtheta = velocity / (self.l_f + self.l_r) * torch.sin(beta)
7776
return torch.stack(
78-
(dx, dy, dtheta), dim=1
77+
(dx, dy, dtheta), dim=-1
7978
) # Should return torch.Size([batch_size,3])
8079

8180
# Select the integration method

0 commit comments

Comments
 (0)