Skip to content

Commit df7d985

Browse files
authored
Merge pull request #118 from pockerman/feature_112_add_dynamics_library
Feature 112 add dynamics library
2 parents ec5c330 + d0c2b74 commit df7d985

39 files changed

+1774
-22
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22
MESSAGE(STATUS "Using CMake ${CMAKE_VERSION}")
33

44
SET(RLENVSCPP_VERSION_MAJOR 1)
@@ -103,6 +103,7 @@ FILE(GLOB SRCS src/rlenvs/*.cpp
103103
src/rlenvs/envs/connect2/*.cpp
104104
src/rlenvs/dynamics/*.cpp
105105
src/rlenvs/utils/*.cpp
106+
src/rlenvs/utils/io/*.cpp
106107
)
107108

108109
ADD_LIBRARY(rlenvscpplib SHARED ${SRCS})

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Currently, we provide a minimal number of wrappers for some common Gymnasium (fo
1919
In addition there are wrappers for
2020

2121
- ```GymWalk``` environment from <a href="https://github.com/mimoralea/gym-walk2">gym_walk</a>
22-
- ```gym-pybullet-drones``` from <a href="https://github.com/utiasDSL/gym-pybullet-drones/tree/main">gym-pybullet-drones</a>
22+
- ~```gym-pybullet-drones``` from <a href="https://github.com/utiasDSL/gym-pybullet-drones/tree/main">gym-pybullet-drones</a>~
2323
- ```GridWorld``` from <a href="https://github.com/DeepReinforcementLearning/DeepReinforcementLearningInAction">Deep Reinforcement Learning In Action</a>
2424
- ```Connect2``` from <a href="https://github.com/JoshVarty/AlphaZeroSimple">AlphaZeroSimple</a> see <a href="examples/example_7/example_7.cpp">example_7</a>
2525

@@ -33,7 +33,8 @@ There exist some wrappers for vector environments:
3333

3434
Apart from the exposed environments, ```rlenvscpp``` exposes classes that describe the dynamics of some popular rigid bodies:
3535

36-
- <a href="https://en.wikipedia.org/wiki/Differential_wheeled_robot">Differential drive</a> see <a href="examples/example_9/example_9.cpp">example_9</a>
36+
- <a href="https://en.wikipedia.org/wiki/Differential_wheeled_robot">Differential drive dynamics</a> see <a href="examples/example_9/example_9.cpp">example_9</a>
37+
- <a href="https://scholarsarchive.byu.edu/cgi/viewcontent.cgi?article=2324&context=facpub">Quadrotor dynamics</a> see <a href="examples/example_10/example_10.cpp">example_10</a>
3738

3839
In general, the environments exposed by the library should abide with <a href="https://github.com/deepmind/dm_env/blob/master/docs/index.md">dm_env</a> specification.
3940
The following snippet shows how to use the ```FrozenLake``` and ```Taxi``` environments from <a href="https://github.com/Farama-Foundation/Gymnasium/tree/main">Gymnasium</a>.
@@ -220,7 +221,6 @@ In addition, you need to install
220221
In addition, the library also incorporates, see ```(src/extern)```, the following libraries
221222

222223
- <a href="https://github.com/elnormous/HTTPRequest">HTTPRequest</a>
223-
- <a href="http://github.com/aantron/better-enums">better-enums</a>
224224
- <a href="https://github.com/nlohmann/json">nlohmann/json</a>
225225

226226
There are extra dependencies if you want to generate the documentation. Namely,

examples/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22

33
INCLUDE_DIRECTORIES(${PROJECT_INCL_DIR})
44
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
55

6-
SET(CMAKE_CXX_COMPILER /usr/bin/g++-11)
7-
SET(CMAKE_C_COMPILER /usr/bin/gcc-11)
6+
#SET(CMAKE_CXX_COMPILER /usr/bin/g++-11)
7+
#SET(CMAKE_C_COMPILER /usr/bin/gcc-11)
88
SET(CMAKE_CXX_STANDARD 20)
99
SET(CMAKE_CXX_STANDARD_REQUIRED True)
1010
SET(CMAKE_LINKER_FLAGS "-pthread")
@@ -29,3 +29,4 @@ ADD_SUBDIRECTORY(example_6)
2929
ADD_SUBDIRECTORY(example_7)
3030
ADD_SUBDIRECTORY(example_8)
3131
ADD_SUBDIRECTORY(example_9)
32+
ADD_SUBDIRECTORY(example_10)

examples/example_1/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22

33
SET(EXECUTABLE example_1)
44
SET(SOURCE ${EXECUTABLE}.cpp)

examples/example_10/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
2+
3+
SET(EXECUTABLE example_10)
4+
SET(SOURCE ${EXECUTABLE}.cpp)
5+
6+
ADD_EXECUTABLE(${EXECUTABLE} ${SOURCE})
7+
8+
TARGET_LINK_LIBRARIES(${EXECUTABLE} rlenvscpplib)
9+

examples/example_10/example_10.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* In this example we simulate a quadrotor.
3+
* The quadrotor data is taken from
4+
* https://sal.aalto.fi/publications/pdf-files/eluu11_public.pdf
5+
*
6+
*
7+
*
8+
*/
9+
10+
#include "rlenvs/rlenvs_types_v2.h"
11+
#include "rlenvs/dynamics/quadrotor_dynamics.h"
12+
#include "rlenvs/utils/io/csv_file_writer.h"
13+
#include "rlenvs/utils/unit_converter.h"
14+
15+
#include <iostream>
16+
#include <string>
17+
#include <map>
18+
#include <any>
19+
#include <array>
20+
#include <vector>
21+
22+
namespace example_10{
23+
24+
using namespace rlenvscpp::dynamics;
25+
using rlenvscpp::uint_t;
26+
using rlenvscpp::real_t;
27+
using rlenvscpp::RealVec;
28+
using rlenvscpp::utils::io::CSVWriter;
29+
30+
real_t compute_motor_speed(real_t t){
31+
32+
if(t <= 0.1){
33+
return 500 * t + 625.0;
34+
}
35+
else if( t > 0.1 && t <= 0.4){
36+
return -416.66 * t + 716.66;
37+
}
38+
else if( t > 0.4 && t <= 0.5){
39+
return 750.0 * t + 250.0;
40+
}
41+
else{
42+
return 625.0;
43+
}
44+
45+
}
46+
47+
}
48+
49+
50+
int main(){
51+
52+
using namespace example_10;
53+
54+
QuadrotorDynamicsConfig config;
55+
config.dt = 0.0001;
56+
config.mass = 0.468;
57+
config.l = 0.225;
58+
config.k_1 = 2.980e-6; // this is the k coeff
59+
config.k_2 = 1.140e-7; // this is the beta coeff
60+
config.Jx = 4.856e-3;
61+
config.Jy = 4.856e-3;
62+
config.Jz = 8.801e-3;
63+
64+
65+
// initialize the state variables
66+
std::array<std::pair<std::string, real_t>, 12> values;
67+
68+
// initial position in NED
69+
values[0] = std::make_pair("x", 0.0);
70+
values[1] = std::make_pair("y", 0.0);
71+
values[2] = std::make_pair("z", 0.0);
72+
73+
// initial translation velocities body coords
74+
values[3] = std::make_pair("u", 0.0);
75+
values[4] = std::make_pair("v", 0.0);
76+
values[5] = std::make_pair("w", 0.0);
77+
78+
// initial rotational velocities body coords
79+
values[6] = std::make_pair("p", 0.0);
80+
values[7] = std::make_pair("q", 0.0);
81+
values[8] = std::make_pair("r", 0.0);
82+
83+
// Euler angles
84+
values[9] = std::make_pair("phi", 0.0);
85+
values[10] = std::make_pair("theta", 0.0);
86+
values[11] = std::make_pair("psi", 0.0);
87+
88+
89+
SysState<12> state(std::move(values));
90+
QuadrotorDynamics dynamics(config, state);
91+
92+
// the motor velocities rad/sec
93+
RealVec omegas = RealVec::Zero(4);
94+
omegas[0] = omegas[1] = omegas[2] = omegas[3] = 625.0;
95+
96+
97+
CSVWriter csv_writer("state");
98+
csv_writer.open();
99+
100+
std::vector<std::string> names={"t",
101+
"x", "y", "z",
102+
"u", "v", "w",
103+
"p", "q", "r",
104+
"phi", "theta", "psi"};
105+
106+
csv_writer.write_column_names(names);
107+
108+
const real_t T = 2.0;
109+
real_t time = 0.0;
110+
111+
std::vector<real_t> row(13, 0.0);
112+
while(time < T){
113+
114+
std::cout<<"Time: "<<time<<std::endl;
115+
116+
auto omega_motor = compute_motor_speed(time);
117+
omegas[0] = omegas[1] = omegas[2] = omegas[3] = omega_motor;
118+
dynamics.integrate(omegas);
119+
120+
auto p = dynamics.get_position();
121+
auto v = dynamics.get_velocity();
122+
auto omega = dynamics.get_angular_velocity();
123+
auto euler = dynamics.get_euler_angles();
124+
125+
row[0] = time;
126+
row[1] = p[0];
127+
row[2] = p[1];
128+
row[3] = p[2];
129+
130+
row[4] = v[0];
131+
row[5] = v[1];
132+
row[6] = v[2];
133+
134+
row[7] = omega[0];
135+
row[8] = omega[1];
136+
row[9] = omega[2];
137+
138+
row[10] = rlenvscpp::utils::unit_converter::rad_to_degrees(euler[0]);
139+
row[11] = rlenvscpp::utils::unit_converter::rad_to_degrees(euler[1]);
140+
row[12] = rlenvscpp::utils::unit_converter::rad_to_degrees(euler[2]);
141+
142+
csv_writer.write_row(row);
143+
std::cout<<"Current position: ";
144+
std::cout<<p<<std::endl;
145+
std::cout<<euler<<std::endl;
146+
time += config.dt;
147+
}
148+
149+
csv_writer.close();
150+
151+
return 0;
152+
}

examples/example_10/plot.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
Utility script for plotting with matplotlib
3+
"""
4+
import matplotlib.pyplot as plt
5+
import csv
6+
import math
7+
import numpy as np
8+
9+
def main(filename):
10+
11+
with open(filename, 'r', newline='') as csvfile:
12+
csv_file_reader = csv.reader(csvfile, delimiter=",")
13+
14+
time = []
15+
x = []
16+
y = []
17+
z = []
18+
u = []
19+
v = []
20+
w = []
21+
p = []
22+
q = []
23+
r = []
24+
phi = []
25+
theta = []
26+
psi = []
27+
28+
for row in csv_file_reader:
29+
if not row[0].startswith('#'):
30+
try:
31+
32+
assert len(row) == 13
33+
34+
time.append(float(row[0]))
35+
x.append(float(row[1]))
36+
y.append(float(row[2]))
37+
z.append(float(row[3]))
38+
39+
u.append(float(row[4]))
40+
v.append(float(row[5]))
41+
w.append(float(row[6]))
42+
43+
p.append(float(row[7]))
44+
q.append(float(row[8]))
45+
r.append(float(row[9]))
46+
47+
phi.append(float(row[10]))
48+
theta.append(float(row[11]))
49+
psi.append(float(row[12]))
50+
except Exception as e:
51+
print(e)
52+
continue
53+
54+
assert len(time) == len(x), "Invalid length"
55+
plt.plot(time, x, label='X^G', linewidth=2)
56+
plt.plot(time, y, label='Y^G', linewidth=2)
57+
plt.plot(time, z, label='Z^G', linewidth=2)
58+
59+
plt.xlabel('time (secs)')
60+
plt.ylabel('position')
61+
plt.title('Quadrotor position in NED')
62+
plt.grid()
63+
plt.legend()
64+
plt.show()
65+
66+
67+
assert len(time) == len(phi), "Invalid length"
68+
69+
plt.plot(time, phi, label='$\phi$', linewidth=2)
70+
plt.plot(time, theta, label='$\theta$', linewidth=2)
71+
plt.plot(time, psi, label='$\psi$', linewidth=2)
72+
plt.xlabel('time (secs)')
73+
plt.ylabel('Angle')
74+
plt.title('Euler angles (deg)')
75+
plt.grid()
76+
plt.legend()
77+
plt.show()
78+
79+
80+
if __name__ == '__main__':
81+
main("/home/alex/qi3/rlenvs_from_cpp/build/examples/example_10/state.csv")
82+
83+
84+
85+

examples/example_2/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22

33
SET(SOURCE example_2.cpp)
44
SET(EXECUTABLE example_2)

examples/example_3/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22

33
SET(SOURCE example_3.cpp)
44
SET(EXECUTABLE example_3)

examples/example_4/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CMAKE_MINIMUM_REQUIRED(VERSION 3.6)
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
22

33
SET(SOURCE example_4.cpp)
44
SET(EXECUTABLE example_4)

0 commit comments

Comments
 (0)