Skip to content

Commit ac7ab11

Browse files
author
Shunichi09
committed
Add: two wheeled model and environment
1 parent cca3578 commit ac7ab11

File tree

14 files changed

+274
-106
lines changed

14 files changed

+274
-106
lines changed

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: python
2+
3+
python:
4+
- 3.7
5+
6+
install:
7+
- pip install --upgrade pip setuptools wheel
8+
- pip install coveralls
9+
10+
script:
11+
- coverage run --source=PythonLinearNonlinearControl setup.py test
12+
13+
after_success:
14+
- coveralls

PythonLinearNonlinearControl/configs/first_order_lag.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ class FirstOrderLagConfigModule():
2323

2424
def __init__(self):
2525
"""
26-
Args:
27-
save_dit (str): save directory
2826
"""
2927
# opt configs
3028
self.opt_config = {
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from .first_order_lag import FirstOrderLagConfigModule
2+
from .two_wheeled import TwoWheeledConfigModule
23

34
def make_config(args):
45
"""
56
Returns:
67
config (ConfigModule class): configuration for the each env
78
"""
89
if args.env == "FirstOrderLag":
9-
return FirstOrderLagConfigModule()
10+
return FirstOrderLagConfigModule()
11+
elif args.env == "TwoWheeledConst" or args.env == "TwoWheeled":
12+
return TwoWheeledConfigModule()
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import numpy as np
2+
3+
class TwoWheeledConfigModule():
4+
# parameters
5+
ENV_NAME = "TwoWheeled-v0"
6+
TYPE = "Nonlinear"
7+
TASK_HORIZON = 1000
8+
PRED_LEN = 10
9+
STATE_SIZE = 3
10+
INPUT_SIZE = 2
11+
DT = 0.01
12+
# cost parameters
13+
R = np.eye(INPUT_SIZE)
14+
Q = np.eye(STATE_SIZE)
15+
Sf = np.eye(STATE_SIZE)
16+
# bounds
17+
INPUT_LOWER_BOUND = np.array([-1.5, 3.14])
18+
INPUT_UPPER_BOUND = np.array([1.5, 3.14])
19+
20+
def __init__(self):
21+
"""
22+
"""
23+
# opt configs
24+
self.opt_config = {
25+
"Random": {
26+
"popsize": 5000
27+
},
28+
"CEM": {
29+
"popsize": 500,
30+
"num_elites": 50,
31+
"max_iters": 15,
32+
"alpha": 0.3,
33+
"init_var":1.,
34+
"threshold":0.001
35+
},
36+
"MPPI":{
37+
"beta" : 0.6,
38+
"popsize": 5000,
39+
"kappa": 0.9,
40+
"noise_sigma": 0.5,
41+
},
42+
"iLQR":{
43+
},
44+
"NMPC-CGMRES":{
45+
},
46+
"NMPC-Newton":{
47+
},
48+
}
49+
50+
@staticmethod
51+
def input_cost_fn(u):
52+
""" input cost functions
53+
Args:
54+
u (numpy.ndarray): input, shape(input_size, )
55+
or shape(pop_size, input_size)
56+
Returns:
57+
cost (numpy.ndarray): cost of input, none or shape(pop_size, )
58+
"""
59+
return (u**2) * np.diag(TwoWheeledConfigModule.R) * 0.1
60+
61+
@staticmethod
62+
def state_cost_fn(x, g_x):
63+
""" state cost function
64+
Args:
65+
x (numpy.ndarray): state, shape(pred_len, state_size)
66+
or shape(pop_size, pred_len, state_size)
67+
g_x (numpy.ndarray): goal state, shape(state_size, )
68+
or shape(pop_size, state_size)
69+
Returns:
70+
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
71+
"""
72+
return ((x - g_x)**2) * np.diag(TwoWheeledConfigModule.Q)
73+
74+
@staticmethod
75+
def terminal_state_cost_fn(terminal_x, terminal_g_x):
76+
"""
77+
Args:
78+
terminal_x (numpy.ndarray): terminal state,
79+
shape(state_size, ) or shape(pop_size, state_size)
80+
terminal_g_x (numpy.ndarray): terminal goal state,
81+
shape(state_size, ) or shape(pop_size, state_size)
82+
Returns:
83+
cost (numpy.ndarray): cost of state, none or shape(pop_size, )
84+
"""
85+
return ((terminal_x - terminal_g_x)**2) \
86+
* np.diag(TwoWheeledConfigModule.Sf)

PythonLinearNonlinearControl/envs/first_order_lag.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ def reset(self, init_x=None):
7070
self.curr_x = init_x
7171

7272
# goal
73-
self.goal_state = np.array([0., 0, -2., 3.])
73+
self.g_x = np.array([0., 0, -2., 3.])
7474

7575
# clear memory
7676
self.history_x = []
7777
self.history_g_x = []
7878

79-
return self.curr_x, {"goal_state": self.goal_state}
79+
return self.curr_x, {"goal_state": self.g_x}
8080

8181
def step(self, u):
8282
"""
@@ -99,15 +99,17 @@ def step(self, u):
9999
# cost
100100
cost = 0
101101
cost = np.sum(u**2)
102-
cost += np.sum((self.curr_x-g_x)**2)
102+
cost += np.sum((self.curr_x - self.g_x)**2)
103103

104104
# save history
105105
self.history_x.append(next_x.flatten())
106-
self.history_g_x.append(self.goal_state.flatten())
106+
self.history_g_x.append(self.g_x.flatten())
107107

108108
# update
109109
self.curr_x = next_x.flatten()
110110
# update costs
111111
self.step_count += 1
112112

113-
return next_x.flatten(), cost, self.step_count > self.config["max_step"], {"goal_state" : self.goal_state}
113+
return next_x.flatten(), cost, \
114+
self.step_count > self.config["max_step"], \
115+
{"goal_state" : self.g_x}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from .first_order_lag import FirstOrderLagEnv
2+
from .two_wheeled import TwoWheeledConstEnv
23

34
def make_env(args):
45

56
if args.env == "FirstOrderLag":
67
return FirstOrderLagEnv()
8+
elif args.env == "TwoWheeledConst":
9+
return TwoWheeledConstEnv()
710

8-
raise NotImplementedError("There is not {} Env".format(name))
11+
raise NotImplementedError("There is not {} Env".format(args.env))
Lines changed: 38 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,49 @@
11
import numpy as np
2-
import scipy
3-
from scipy import integrate
2+
43
from .env import Env
54

6-
class TwoWheeledConstEnv(Env):
7-
""" Two wheeled robot with constant goal Env
5+
def step_two_wheeled_env(curr_x, u, dt, method="Oylar"):
6+
""" step two wheeled enviroment
7+
8+
Args:
9+
curr_x (numpy.ndarray): current state, shape(state_size, )
10+
u (numpy.ndarray): input, shape(input_size, )
11+
dt (float): sampling time
12+
Returns:
13+
next_x (numpy.ndarray): next state, shape(state_size. )
14+
15+
Notes:
16+
TODO: deal with another method, like Runge Kutta
817
"""
9-
def __init__(self):
10-
"""
11-
"""
12-
self.config = {"state_size" : 3,\
13-
"input_size" : 2,\
14-
"dt" : 0.01,\
15-
"max_step" : 500,\
16-
"input_lower_bound": [-1.5, -3.14],\
17-
"input_upper_bound": [1.5, 3.14],
18-
}
19-
20-
super(TwoWheeledEnv, self).__init__(self.config)
18+
B = np.array([[np.cos(curr_x[-1]), 0.],
19+
[np.sin(curr_x[-1]), 0.],
20+
[0., 1.]])
2121

22-
def reset(self, init_x=None):
23-
""" reset state
24-
Returns:
25-
init_x (numpy.ndarray): initial state, shape(state_size, )
26-
info (dict): information
27-
"""
28-
self.step_count = 0
29-
30-
self.curr_x = np.zeros(self.config["state_size"])
31-
32-
if init_x is not None:
33-
self.curr_x = init_x
34-
35-
# goal
36-
self.goal_state = np.array([0., 0, -2., 3.])
37-
38-
# clear memory
39-
self.history_x = []
40-
self.history_g_x = []
41-
42-
return self.curr_x, {"goal_state": self.goal_state}
43-
44-
def step(self, u):
45-
"""
46-
Args:
47-
u (numpy.ndarray) : input, shape(input_size, )
48-
Returns:
49-
next_x (numpy.ndarray): next state, shape(state_size, )
50-
cost (float): costs
51-
done (bool): end the simulation or not
52-
info (dict): information
53-
"""
54-
# clip action
55-
u = np.clip(u,
56-
self.config["input_lower_bound"],
57-
self.config["input_lower_bound"])
22+
x_dot = np.matmul(B, u[:, np.newaxis])
5823

59-
# step
60-
next_x = np.matmul(self.A, self.curr_x[:, np.newaxis]) \
61-
+ np.matmul(self.B, u[:, np.newaxis])
62-
63-
# TODO: implement costs
24+
next_x = x_dot.flatten() * dt + curr_x
6425

65-
# save history
66-
self.history_x.append(next_x.flatten())
67-
self.history_g_x.append(self.goal_state.flatten())
68-
69-
# update
70-
self.curr_x = next_x.flatten()
71-
# update costs
72-
self.step_count += 1
26+
return next_x
7327

74-
return next_x.flatten(), 0., self.step_count > self.config["max_step"], {"goal_state" : self.goal_state}
75-
76-
class TwoWheeledEnv(Env):
77-
""" Two wheeled robot Env
28+
class TwoWheeledConstEnv(Env):
29+
""" Two wheeled robot with constant goal Env
7830
"""
7931
def __init__(self):
8032
"""
8133
"""
8234
self.config = {"state_size" : 3,\
8335
"input_size" : 2,\
8436
"dt" : 0.01,\
85-
"max_step" : 500,\
37+
"max_step" : 1000,\
8638
"input_lower_bound": [-1.5, -3.14],\
8739
"input_upper_bound": [1.5, 3.14],
8840
}
8941

90-
super(TwoWheeledEnv, self).__init__(self.config)
42+
super(TwoWheeledConstEnv, self).__init__(self.config)
9143

9244
def reset(self, init_x=None):
9345
""" reset state
46+
9447
Returns:
9548
init_x (numpy.ndarray): initial state, shape(state_size, )
9649
info (dict): information
@@ -103,16 +56,17 @@ def reset(self, init_x=None):
10356
self.curr_x = init_x
10457

10558
# goal
106-
self.goal_state = np.array([0., 0, -2., 3.])
59+
self.g_x = np.array([5., 5., 0.])
10760

10861
# clear memory
10962
self.history_x = []
11063
self.history_g_x = []
11164

112-
return self.curr_x, {"goal_state": self.goal_state}
65+
return self.curr_x, {"goal_state": self.g_x}
11366

11467
def step(self, u):
115-
"""
68+
""" step environments
69+
11670
Args:
11771
u (numpy.ndarray) : input, shape(input_size, )
11872
Returns:
@@ -124,22 +78,25 @@ def step(self, u):
12478
# clip action
12579
u = np.clip(u,
12680
self.config["input_lower_bound"],
127-
self.config["input_lower_bound"])
81+
self.config["input_upper_bound"])
12882

12983
# step
130-
next_x = np.matmul(self.A, self.curr_x[:, np.newaxis]) \
131-
+ np.matmul(self.B, u[:, np.newaxis])
84+
next_x = step_two_wheeled_env(self.curr_x, u, self.config["dt"])
13285

133-
# TODO: implement costs
86+
# TODO: costs
87+
costs = 0.
88+
costs += 0.1 * np.sum(u**2)
89+
costs += np.sum((self.curr_x - self.g_x)**2)
13490

13591
# save history
13692
self.history_x.append(next_x.flatten())
137-
self.history_g_x.append(self.goal_state.flatten())
93+
self.history_g_x.append(self.g_x.flatten())
13894

13995
# update
14096
self.curr_x = next_x.flatten()
14197
# update costs
14298
self.step_count += 1
14399

144-
return next_x.flatten(), 0., self.step_count > self.config["max_step"], {"goal_state" : self.goal_state}
145-
100+
return next_x.flatten(), costs, \
101+
self.step_count > self.config["max_step"], \
102+
{"goal_state" : self.g_x}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from .first_order_lag import FirstOrderLagModel
2+
from .two_wheeled import TwoWheeledModel
23

34
def make_model(args, config):
45

56
if args.env == "FirstOrderLag":
67
return FirstOrderLagModel(config)
8+
elif args.env == "TwoWheeledConst" or args.env == "TwoWheeled":
9+
return TwoWheeledModel(config)
710

811
raise NotImplementedError("There is not {} Model".format(args.env))

0 commit comments

Comments
 (0)