Skip to content

Commit

Permalink
Teaching (#51)
Browse files Browse the repository at this point in the history
Co-authored-by: Florian Messerer <[email protected]>
  • Loading branch information
FreyJo and fmesserer authored Sep 4, 2023
1 parent 555fc11 commit 516b82b
Show file tree
Hide file tree
Showing 16 changed files with 650 additions and 198 deletions.
2 changes: 1 addition & 1 deletion examples/auto_modeler/auto_model_friction.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def get_motor_with_friction_ocp_description_with_auto_model():

am = nosnoc.NosnocAutoModel(x=x, f_nonsmooth_ode=f_nonsmooth, x0=X0, u=u)
model = am.reformulate()

# constraints
lbu = -u_max * np.ones((1,))
ubu = u_max * np.ones((1,))
Expand Down
161 changes: 68 additions & 93 deletions examples/cart_pole_with_friction/cart_pole_with_friction.py
Original file line number Diff line number Diff line change
@@ -1,124 +1,99 @@
import numpy as np
from casadi import SX, horzcat, vertcat, cos, sin, inv
import matplotlib.pyplot as plt
import casadi as ca

import nosnoc


def solve_example():
# opts
opts = nosnoc.NosnocOpts()
opts.irk_scheme = nosnoc.IrkSchemes.RADAU_IIA
opts.n_s = 2
opts.homotopy_update_rule = nosnoc.HomotopyUpdateRule.SUPERLINEAR
opts.step_equilibration = nosnoc.StepEquilibrationMode.HEURISTIC_DELTA
def get_cart_pole_model_and_ocp(F_friction: float = 2.0, use_fillipov: bool = True):
# symbolics
px = ca.SX.sym('px')
theta = ca.SX.sym('theta')
q = ca.vertcat(px, theta)

# opts.N_stages = 50 # MATLAB setting
opts.N_stages = 15 # number of control intervals
opts.N_finite_elements = 2 # number of finite element on every control intevral
opts.terminal_time = 4.0 # Time horizon
opts.print_level = 1
v = ca.SX.sym('v')
theta_dot = ca.SX.sym('theta_dot')
q_dot = ca.vertcat(v, theta_dot)

## Model defintion
q = SX.sym('q', 2)
v = SX.sym('v', 2)
x = vertcat(q, v)
u = SX.sym('u') # control
x = ca.vertcat(q, q_dot)
u = ca.SX.sym('u') # control

m1 = 1 # cart
m2 = 0.1 # link
link_length = 1
g = 9.81
# Inertia matrix
M = vertcat(horzcat(m1 + m2, m2 * link_length * cos(q[1])),
horzcat(m2 * link_length * cos(q[1]), m2 * link_length**2))
M = ca.vertcat(ca.horzcat(m1 + m2, m2 * link_length * ca.cos(theta)),
ca.horzcat(m2 * link_length * ca.cos(theta), m2 * link_length**2))
# Coriolis force
C = SX.zeros(2, 2)
C[0, 1] = -m2 * link_length * v[1] * sin(q[1])

# all forces = Gravity+Control+Coriolis (+Friction)
f_all = vertcat(u, -m2 * g * link_length * sin(x[1])) - C @ v

# friction between cart and ground
F_friction = 2
# Dynamics with $ v > 0$
f_1 = vertcat(v, inv(M) @ (f_all - vertcat(F_friction, 0)))
# Dynamics with $ v < 0$
f_2 = vertcat(v, inv(M) @ (f_all + vertcat(F_friction, 0)))

F = [horzcat(f_1, f_2)]
# switching function (cart velocity)
c = [v[0]]
# Sign matrix # f_1 for c=v>0, f_2 for c=v<0
S = [np.array([[1], [-1]])]

# specify initial and end state, cost ref and weight matrix
x0 = np.array([1, 0 / 180 * np.pi, 0, 0]) # start downwards
x_ref = np.array([0, 180 / 180 * np.pi, 0, 0]) # end upwards
C = ca.SX.zeros(2, 2)
C[0, 1] = -m2 * link_length * theta_dot * ca.sin(theta)

Q = np.diag([1.0, 100.0, 1.0, 1.0])
Q_terminal = np.diag([100.0, 100.0, 10.0, 10.0])
R = 1.0
# all forces = Gravity + Control + Coriolis; Note: friction added later
f_all = ca.vertcat(u, -m2 * g * link_length * ca.sin(theta)) - C @ q_dot

# bounds
ubx = np.array([5.0, 240 / 180 * np.pi, 20.0, 20.0])
lbx = np.array([-0.0, -240 / 180 * np.pi, -20.0, -20.0])
u_max = 30.0
x0 = np.array([1, 0 / 180 * np.pi, 0, 0]) # start downwards

if use_fillipov:
# Dynamics with $ v > 0$
f_1 = ca.vertcat(q_dot, ca.inv(M) @ (f_all - ca.vertcat(F_friction, 0)))
# Dynamics with $ v < 0$
f_2 = ca.vertcat(q_dot, ca.inv(M) @ (f_all + ca.vertcat(F_friction, 0)))

F = [ca.horzcat(f_1, f_2)]
# switching function (cart velocity)
c = [v]
# Sign matrix # f_1 for c=v>0, f_2 for c=v<0
S = [np.array([[1], [-1]])]
model = nosnoc.NosnocModel(x=x, F=F, S=S, c=c, x0=x0, u=u)
else:
sigma = ca.SX.sym('sigma')

f_ode = ca.vertcat(q_dot,
ca.inv(M) @ (f_all - ca.vertcat(F_friction * ca.tanh(v / sigma), 0)))
model = nosnoc.NosnocAutoModel(x=x, f_nonsmooth_ode=f_ode, x0=x0, u=u, p=sigma)

## OCP description
# cost
x_ref = np.array([0, 180 / 180 * np.pi, 0, 0]) # end upwards
u_ref = 0.0
Q = np.diag([10, 100, 1, 1])
Q_terminal = np.diag([500, 100, 10, 10])
R = 1.0

# Stage cost
f_q = (x - x_ref).T @ Q @ (x - x_ref) + (u - u_ref).T @ R @ (u - u_ref)
f_q = (model.x - x_ref).T @ Q @ (model.x - x_ref) + (model.u - u_ref).T @ R @ (model.u - u_ref)
# terminal cost
f_terminal = (x - x_ref).T @ Q_terminal @ (x - x_ref)
g_terminal = []
f_terminal = (model.x - x_ref).T @ Q_terminal @ (model.x - x_ref)

model = nosnoc.NosnocModel(x=x, F=F, S=S, c=c, x0=x0, u=u)
# bounds
ubx = np.array([5.0, np.inf, np.inf, np.inf])
lbx = -np.array([5.0, np.inf, np.inf, np.inf])

u_max = 30.0
lbu = -np.array([u_max])
ubu = np.array([u_max])

ocp = nosnoc.NosnocOcp(lbu=lbu, ubu=ubu, f_q=f_q, f_terminal=f_terminal, g_terminal=g_terminal,
lbx=lbx, ubx=ubx)

## Solve OCP
solver = nosnoc.NosnocSolver(opts, model, ocp)

results = solver.solve()
return results

def main():
results = solve_example()
plot_results(results)
ocp = nosnoc.NosnocOcp(lbu=lbu, ubu=ubu, f_q=f_q, f_terminal=f_terminal, lbx=lbx, ubx=ubx)
return model, ocp


def plot_results(results):
nosnoc.latexify_plot()

x_traj = np.array(results["x_traj"])

plt.figure()
# states
plt.subplot(3, 1, 1)
plt.plot(results["t_grid"], x_traj[:, 0], label='$q_1$ - cart')
plt.plot(results["t_grid"], x_traj[:, 1], label='$q_2$ - pole')
plt.legend()
plt.grid()

plt.subplot(3, 1, 2)
plt.plot(results["t_grid"], x_traj[:, 2], label='$v_1$ - cart')
plt.plot(results["t_grid"], x_traj[:, 3], label='$v_2$ - pole')
plt.legend()
plt.grid()

# controls
plt.subplot(3, 1, 3)
plt.step(results["t_grid_u"], [results["u_traj"][0]] + results["u_traj"], label='u')
def solve_example():
# opts
opts = nosnoc.NosnocOpts()
opts.irk_scheme = nosnoc.IrkSchemes.RADAU_IIA
opts.n_s = 2
# opts.step_equilibration = nosnoc.StepEquilibrationMode.HEURISTIC_DELTA

plt.legend()
plt.grid()
opts.N_stages = 20 # number of control intervals
opts.N_finite_elements = 2 # number of finite element on every control intevral
opts.terminal_time = 5.0 # Time horizon
opts.print_level = 1

plt.show()
model, ocp = get_cart_pole_model_and_ocp()

## Solve OCP
solver = nosnoc.NosnocSolver(opts, model, ocp)
# solver.problem.print()

if __name__ == "__main__":
main()
results = solver.solve()
return results
12 changes: 12 additions & 0 deletions examples/cart_pole_with_friction/main_cartpole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from cart_pole_with_friction import solve_example
from parametric_cart_pole_with_friction import solve_paramteric_example
from pendulum_utils import plot_results

def main():
# results = solve_example()
results = solve_paramteric_example(with_global_var=True)
plot_results(results)


if __name__ == "__main__":
main()
100 changes: 33 additions & 67 deletions examples/cart_pole_with_friction/parametric_cart_pole_with_friction.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import numpy as np
from casadi import SX, horzcat, vertcat, cos, sin, inv
import matplotlib.pyplot as plt

import nosnoc


def solve_paramteric_example(with_global_var=False):
# opts
# options
opts = nosnoc.NosnocOpts()
opts.irk_scheme = nosnoc.IrkSchemes.RADAU_IIA
opts.n_s = 2
opts.homotopy_update_rule = nosnoc.HomotopyUpdateRule.SUPERLINEAR
opts.step_equilibration = nosnoc.StepEquilibrationMode.HEURISTIC_DELTA
opts.equidistant_control_grid = True
# opts.step_equilibration = nosnoc.StepEquilibrationMode.HEURISTIC_DELTA

opts.N_stages = 50 # number of control intervals
opts.N_stages = 20 # number of control intervals
opts.N_finite_elements = 2 # number of finite element on every control intevral
opts.terminal_time = 4.0 # Time horizon
opts.terminal_time = 5.0 # Time horizon
opts.print_level = 1
# faster options
opts.N_stages = 15 # number of control intervals

## Model defintion
q = SX.sym('q', 2)
Expand All @@ -46,7 +39,7 @@ def solve_paramteric_example(with_global_var=False):
v_global = m1
lbv_global = np.array([1.0])
ubv_global = np.array([100.0])
v_global_guess = np.array([1.5])
v_global_guess = np.array([1.2])
else:
p_global = vertcat(m1, m2)
p_global_val = np.array([1.0, 0.1])
Expand Down Expand Up @@ -86,32 +79,43 @@ def solve_paramteric_example(with_global_var=False):
# specify initial and end state, cost ref and weight matrix
x0 = np.array([1, 0 / 180 * np.pi, 0, 0]) # start downwards

Q = np.diag([1.0, 100.0, 1.0, 1.0])
Q_terminal = np.diag([100.0, 100.0, 10.0, 10.0])
R = 1.0
model = nosnoc.NosnocModel(x=x,
F=F,
S=S,
c=c,
x0=x0,
u=u,
p_global=p_global,
p_global_val=p_global_val,
p_time_var=p_time_var,
v_global=v_global)

# bounds
ubx = np.array([5.0, 240 / 180 * np.pi, 20.0, 20.0])
lbx = np.array([-0.0, -240 / 180 * np.pi, -20.0, -20.0])
u_max = 30.0
Q = np.diag([10, 100, 1, 1])
Q_terminal = np.diag([500, 100, 10, 10])
R = 1.0

# Stage cost
f_q = (x - x_ref).T @ Q @ (x - x_ref) + (u - u_ref).T @ R @ (u - u_ref)
f_q = (model.x - x_ref).T @ Q @ (model.x - x_ref) + (model.u - u_ref).T @ R @ (model.u - u_ref)
# terminal cost
f_terminal = (x - x_ref).T @ Q_terminal @ (x - x_ref)
g_terminal = []
f_terminal = (model.x - x_ref).T @ Q_terminal @ (model.x - x_ref)

model = nosnoc.NosnocModel(x=x, F=F, S=S, c=c, x0=x0, u=u,
p_global=p_global, p_global_val=p_global_val,
p_time_var=p_time_var,
v_global=v_global
)
# bounds
ubx = np.array([5.0, np.inf, np.inf, np.inf])
lbx = -np.array([5.0, np.inf, np.inf, np.inf])

u_max = 30.0
lbu = -np.array([u_max])
ubu = np.array([u_max])

ocp = nosnoc.NosnocOcp(lbu=lbu, ubu=ubu, f_q=f_q, f_terminal=f_terminal, g_terminal=g_terminal,
lbx=lbx, ubx=ubx, lbv_global=lbv_global, ubv_global=ubv_global, v_global_guess=v_global_guess)
ocp = nosnoc.NosnocOcp(lbu=lbu,
ubu=ubu,
f_q=f_q,
f_terminal=f_terminal,
lbx=lbx,
ubx=ubx,
lbv_global=lbv_global,
ubv_global=ubv_global,
v_global_guess=v_global_guess)

# create solver
solver = nosnoc.NosnocSolver(opts, model, ocp)
Expand All @@ -122,41 +126,3 @@ def solve_paramteric_example(with_global_var=False):
# solve OCP
results = solver.solve()
return results

def main():
results = solve_paramteric_example()
plot_results(results)



def plot_results(results):
nosnoc.latexify_plot()

x_traj = np.array(results["x_traj"])

plt.figure()
# states
plt.subplot(3, 1, 1)
plt.plot(results["t_grid"], x_traj[:, 0], label='$q_1$ - cart')
plt.plot(results["t_grid"], x_traj[:, 1], label='$q_2$ - pole')
plt.legend()
plt.grid()

plt.subplot(3, 1, 2)
plt.plot(results["t_grid"], x_traj[:, 2], label='$v_1$ - cart')
plt.plot(results["t_grid"], x_traj[:, 3], label='$v_2$ - pole')
plt.legend()
plt.grid()

# controls
plt.subplot(3, 1, 3)
plt.step(results["t_grid_u"], [results["u_traj"][0]] + results["u_traj"], label='u')

plt.legend()
plt.grid()

plt.show()


if __name__ == "__main__":
main()
Loading

0 comments on commit 516b82b

Please sign in to comment.