INTEGRATOR_TYPE_values = ['ERK', 'IRK', 'GNSF', 'DISCRETE']
    if integrator_type not in INTEGRATOR_TYPE_values:
        raise Exception('Invalid unit test value {} for parameter INTEGRATOR_TYPE. Possible values are' \
                ' {}. Exiting.'.format(integrator_type, INTEGRATOR_TYPE_values))

    # create ocp object to formulate the OCP
    ocp = AcadosOcp()

    Tf = 1.0
    N = 20

    # set model
    if integrator_type == 'DISCRETE':
        model = export_pendulum_ode_model_with_discrete_rk4(Tf / N)
    else:
        model = export_pendulum_ode_model()

    ocp.model = model

    nx = model.x.size()[0]
    nu = model.u.size()[0]
    ny = nx + nu
    ny_e = nx

    # set dimensions
    ocp.dims.ny = ny
    ocp.dims.ny_e = ny_e
    ocp.dims.nbu = nu
    ocp.dims.N = N

    # set cost
Beispiel #2
0
def run_closed_loop_experiment(FORMULATION):
    # create ocp object to formulate the OCP
    ocp = AcadosOcp()

    # set model
    model = export_pendulum_ode_model()
    ocp.model = model

    Tf = 1.0
    nx = model.x.size()[0]
    nu = model.u.size()[0]
    ny = nx + nu
    ny_e = nx
    N = 20

    # set dimensions
    # NOTE: all dimensions but N ar detected
    ocp.dims.N = N

    # set cost module
    ocp.cost.cost_type = 'LINEAR_LS'
    ocp.cost.cost_type_e = 'LINEAR_LS'

    Q = 2 * np.diag([1e3, 1e3, 1e-2, 1e-2])
    R = 2 * np.diag([1e-2])

    ocp.cost.W = scipy.linalg.block_diag(Q, R)

    ocp.cost.Vx = np.zeros((ny, nx))
    ocp.cost.Vx[:nx, :nx] = np.eye(nx)

    Vu = np.zeros((ny, nu))
    Vu[4, 0] = 1.0
    ocp.cost.Vu = Vu

    ocp.cost.Vx_e = np.eye(nx)
    ocp.cost.W_e = Q

    ocp.cost.yref = np.zeros((ny, ))
    ocp.cost.yref_e = np.zeros((ny_e, ))

    ocp.cost.zl = 2000 * np.ones((1, ))
    ocp.cost.Zl = 1 * np.ones((1, ))
    ocp.cost.zu = 2000 * np.ones((1, ))
    ocp.cost.Zu = 1 * np.ones((1, ))

    # set constraints
    Fmax = 80
    vmax = 5

    x0 = np.array([0.0, np.pi, 0.0, 0.0])
    ocp.constraints.x0 = x0

    # bound on u
    ocp.constraints.lbu = np.array([-Fmax])
    ocp.constraints.ubu = np.array([+Fmax])
    ocp.constraints.idxbu = np.array([0])
    if FORMULATION == 0:
        # soft bound on x
        ocp.constraints.lbx = np.array([-vmax])
        ocp.constraints.ubx = np.array([+vmax])
        ocp.constraints.idxbx = np.array([2])  # v is x[2]
        # indices of slacked constraints within bx
        ocp.constraints.idxsbx = np.array([0])

    elif FORMULATION == 1:
        # soft bound on x, using constraint h
        v1 = ocp.model.x[2]
        ocp.model.con_h_expr = v1

        ocp.constraints.lh = np.array([-vmax])
        ocp.constraints.uh = np.array([+vmax])
        # indices of slacked constraints within h
        ocp.constraints.idxsh = np.array([0])

    # set options
    ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'
    ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
    ocp.solver_options.integrator_type = 'ERK'
    ocp.solver_options.tf = Tf
    ocp.solver_options.nlp_solver_type = 'SQP'
    ocp.solver_options.tol = 1e-1 * tol

    json_filename = 'pendulum_soft_constraints.json'
    acados_ocp_solver = AcadosOcpSolver(ocp, json_file=json_filename)
    acados_integrator = AcadosSimSolver(ocp, json_file=json_filename)

    # closed loop
    Nsim = 20
    simX = np.ndarray((Nsim + 1, nx))
    simU = np.ndarray((Nsim, nu))
    xcurrent = x0

    for i in range(Nsim):
        simX[i, :] = xcurrent

        # solve ocp
        acados_ocp_solver.set(0, "lbx", xcurrent)
        acados_ocp_solver.set(0, "ubx", xcurrent)

        status = acados_ocp_solver.solve()
        if status != 0:
            raise Exception(
                'acados acados_ocp_solver returned status {}. Exiting.'.format(
                    status))

        simU[i, :] = acados_ocp_solver.get(0, "u")

        # simulate system
        acados_integrator.set("x", xcurrent)
        acados_integrator.set("u", simU[i, :])

        status = acados_integrator.solve()
        if status != 0:
            raise Exception(
                'acados integrator returned status {}. Exiting.'.format(
                    status))

        # update state
        xcurrent = acados_integrator.get("x")

    simX[Nsim, :] = xcurrent

    # get slack values at stage 1
    sl = acados_ocp_solver.get(1, "sl")
    su = acados_ocp_solver.get(1, "su")
    print("sl", sl, "su", su)

    # plot results
    # plot_pendulum(np.linspace(0, Tf, N+1), Fmax, simU, simX, latexify=False)

    # store results
    np.savetxt('test_results/simX_soft_formulation_' + str(FORMULATION), simX)
    np.savetxt('test_results/simU_soft_formulation_' + str(FORMULATION), simU)

    print("soft constraint example: ran formulation", FORMULATION,
          "successfully.")
Beispiel #3
0
def main(discretization='shooting_nodes'):
    # create ocp object to formulate the OCP
    ocp = AcadosOcp()

    # set model
    model = export_pendulum_ode_model()
    ocp.model = model

    integrator_type = 'LIFTED_IRK'  # ERK, IRK, GNSF, LIFTED_IRK

    if integrator_type == 'GNSF':
        acados_dae_model_json_dump(model)
        # structure detection in Matlab/Octave -> produces 'pendulum_ode_gnsf_functions.json'
        status = os.system('octave detect_gnsf_from_json.m')
        # load gnsf from json
        with open(model.name + '_gnsf_functions.json', 'r') as f:
            gnsf_dict = json.load(f)
        ocp.gnsf_model = gnsf_dict

    Tf = 1.0
    nx = model.x.size()[0]
    nu = model.u.size()[0]
    ny = nx + nu
    ny_e = nx
    N = 15

    # discretization
    ocp.dims.N = N
    # shooting_nodes = np.linspace(0, Tf, N+1)

    time_steps = np.linspace(0, 1, N)
    time_steps = Tf * time_steps / sum(time_steps)

    shooting_nodes = np.zeros((N + 1, ))
    for i in range(len(time_steps)):
        shooting_nodes[i + 1] = shooting_nodes[i] + time_steps[i]

    # nonuniform discretizations can be defined either by shooting_nodes or time_steps:
    if discretization == 'shooting_nodes':
        ocp.solver_options.shooting_nodes = shooting_nodes
    elif discretization == 'time_steps':
        ocp.solver_options.time_steps = time_steps
    else:
        raise NotImplementedError(
            f"discretization type {discretization} not supported.")

    # set num_steps
    ocp.solver_options.sim_method_num_steps = 2 * np.ones((N, ))
    ocp.solver_options.sim_method_num_steps[0] = 3

    # set num_stages
    ocp.solver_options.sim_method_num_stages = 2 * np.ones((N, ))
    ocp.solver_options.sim_method_num_stages[0] = 4

    # set cost
    Q = 2 * np.diag([1e3, 1e3, 1e-2, 1e-2])
    R = 2 * np.diag([1e-2])

    ocp.cost.W_e = Q
    ocp.cost.W = scipy.linalg.block_diag(Q, R)

    ocp.cost.cost_type = 'LINEAR_LS'
    ocp.cost.cost_type_e = 'LINEAR_LS'

    ocp.cost.Vx = np.zeros((ny, nx))
    ocp.cost.Vx[:nx, :nx] = np.eye(nx)

    Vu = np.zeros((ny, nu))
    Vu[4, 0] = 1.0
    ocp.cost.Vu = Vu

    ocp.cost.Vx_e = np.eye(nx)

    ocp.cost.yref = np.zeros((ny, ))
    ocp.cost.yref_e = np.zeros((ny_e, ))

    # set constraints
    Fmax = 80
    ocp.constraints.lbu = np.array([-Fmax])
    ocp.constraints.ubu = np.array([+Fmax])

    x0 = np.array([0.0, np.pi, 0.0, 0.0])
    ocp.constraints.x0 = x0
    ocp.constraints.idxbu = np.array([0])

    ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'  # FULL_CONDENSING_QPOASES
    ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
    ocp.solver_options.integrator_type = integrator_type
    ocp.solver_options.print_level = 0
    ocp.solver_options.nlp_solver_type = 'SQP'  # SQP_RTI, SQP

    # set prediction horizon
    ocp.solver_options.tf = Tf
    ocp.solver_options.initialize_t_slacks = 1

    # Set additional options for Simulink interface:
    acados_path = get_acados_path()
    json_path = os.path.join(acados_path,
                             'interfaces/acados_template/acados_template')
    with open(json_path + '/simulink_default_opts.json', 'r') as f:
        simulink_opts = json.load(f)
    ocp_solver = AcadosOcpSolver(ocp,
                                 json_file='acados_ocp.json',
                                 simulink_opts=simulink_opts)

    # ocp_solver = AcadosOcpSolver(ocp, json_file = 'acados_ocp.json')

    simX = np.ndarray((N + 1, nx))
    simU = np.ndarray((N, nu))

    # change options after creating ocp_solver
    ocp_solver.options_set("step_length", 0.99999)
    ocp_solver.options_set("globalization",
                           "fixed_step")  # fixed_step, merit_backtracking
    ocp_solver.options_set("tol_eq", TOL)
    ocp_solver.options_set("tol_stat", TOL)
    ocp_solver.options_set("tol_ineq", TOL)
    ocp_solver.options_set("tol_comp", TOL)

    # initialize solver
    for i in range(N):
        ocp_solver.set(i, "x", x0)
    status = ocp_solver.solve()

    if status not in [0, 2]:
        raise Exception('acados returned status {}. Exiting.'.format(status))

    # get primal solution
    for i in range(N):
        simX[i, :] = ocp_solver.get(i, "x")
        simU[i, :] = ocp_solver.get(i, "u")
    simX[N, :] = ocp_solver.get(N, "x")

    print("inequality multipliers at stage 1")
    print(ocp_solver.get(1, "lam"))  # inequality multipliers at stage 1
    print("slack values at stage 1")
    print(ocp_solver.get(1, "t"))  # slack values at stage 1
    print("multipliers of dynamic conditions between stage 1 and 2")
    print(ocp_solver.get(
        1, "pi"))  # multipliers of dynamic conditions between stage 1 and 2

    # initialize ineq multipliers and slacks at stage 1
    ocp_solver.set(1, "lam", np.zeros(2, ))
    ocp_solver.set(1, "t", np.zeros(2, ))

    ocp_solver.print_statistics(
    )  # encapsulates: stat = ocp_solver.get_stats("statistics")

    # timings
    time_tot = ocp_solver.get_stats("time_tot")
    time_lin = ocp_solver.get_stats("time_lin")
    time_sim = ocp_solver.get_stats("time_sim")
    time_qp = ocp_solver.get_stats("time_qp")

    print(
        f"timings OCP solver: total: {1e3*time_tot}ms, lin: {1e3*time_lin}ms, sim: {1e3*time_sim}ms, qp: {1e3*time_qp}ms"
    )
    # print("simU", simU)
    # print("simX", simX)
    iterate_filename = f'final_iterate_{discretization}.json'
    ocp_solver.store_iterate(filename=iterate_filename, overwrite=True)

    plot_pendulum(shooting_nodes, Fmax, simU, simX, latexify=False)
    del ocp_solver
Beispiel #4
0
def main(interface_type='ctypes'):

    # create ocp object to formulate the OCP
    ocp = AcadosOcp()

    # set model
    model = export_pendulum_ode_model()
    ocp.model = model

    nx = model.x.size()[0]
    nu = model.u.size()[0]
    ny = nx + nu
    ny_e = nx

    # define the different options for the use-case demonstration
    N0 = 20  # original number of shooting nodes
    N12 = 15  # change the number of shooting nodes for use-cases 1 and 2
    condN12 = max(1, round(N12/1)) # change the number of cond_N for use-cases 1 and 2 (for PARTIAL_* solvers only)
    Tf_01 = 1.0  # original final time and for use-case 1
    Tf_2 = Tf_01 * 0.7  # change final time for use-case 2 (but keep N identical)

    # set dimensions
    ocp.dims.N = N0

    # set cost
    Q = 2 * np.diag([1e3, 1e3, 1e-2, 1e-2])
    R = 2 * np.diag([1e-2])

    ocp.cost.W_e = Q
    ocp.cost.W = scipy.linalg.block_diag(Q, R)

    ocp.cost.cost_type = 'LINEAR_LS'
    ocp.cost.cost_type_e = 'LINEAR_LS'

    ocp.cost.Vx = np.zeros((ny, nx))
    ocp.cost.Vx[:nx, :nx] = np.eye(nx)

    Vu = np.zeros((ny, nu))
    Vu[4, 0] = 1.0
    ocp.cost.Vu = Vu

    ocp.cost.Vx_e = np.eye(nx)

    ocp.cost.yref = np.zeros((ny,))
    ocp.cost.yref_e = np.zeros((ny_e,))

    # set constraints
    Fmax = 80
    ocp.constraints.lbu = np.array([-Fmax])
    ocp.constraints.ubu = np.array([+Fmax])
    ocp.constraints.idxbu = np.array([0])

    ocp.constraints.x0 = np.array([0.0, np.pi, 0.0, 0.0])

    # set options
    ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'  # FULL_CONDENSING_QPOASES
    # PARTIAL_CONDENSING_HPIPM, FULL_CONDENSING_QPOASES, FULL_CONDENSING_HPIPM,
    # PARTIAL_CONDENSING_QPDUNES, PARTIAL_CONDENSING_OSQP
    ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
    ocp.solver_options.integrator_type = 'ERK'
    # ocp.solver_options.print_level = 1
    ocp.solver_options.nlp_solver_type = 'SQP'  # SQP_RTI, SQP

    # set prediction horizon
    ocp.solver_options.tf = Tf_01

    print(80*'-')
    print('generate code and compile...')

    if interface_type == 'cython':
        AcadosOcpSolver.generate(ocp, json_file='acados_ocp.json')
        AcadosOcpSolver.build(ocp.code_export_directory, with_cython=True)
        ocp_solver = AcadosOcpSolver.create_cython_solver('acados_ocp.json')
    elif interface_type == 'ctypes':
        ocp_solver = AcadosOcpSolver(ocp, json_file='acados_ocp.json')
    elif interface_type == 'cython_prebuilt':
        from c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
        ocp_solver = AcadosOcpSolverCython(ocp.model.name, ocp.solver_options.nlp_solver_type, ocp.dims.N)


    # test setting HPIPM options
    ocp_solver.options_set('qp_tol_ineq', 1e-8)
    ocp_solver.options_set('qp_tau_min', 1e-10)
    ocp_solver.options_set('qp_mu0', 1e0)

    # --------------------------------------------------------------------------------
    # 0) solve the problem defined here (original from code export), analog to 'minimal_example_ocp.py'
    nvariant = 0
    simX0 = np.ndarray((N0 + 1, nx))
    simU0 = np.ndarray((N0, nu))

    print(80*'-')
    print(f'solve original code with N = {N0} and Tf = {Tf_01} s:')
    status = ocp_solver.solve()

    if status != 0:
        ocp_solver.print_statistics()  # encapsulates: stat = ocp_solver.get_stats("statistics")
        raise Exception(f'acados returned status {status}.')

    # get solution
    for i in range(N0):
        simX0[i, :] = ocp_solver.get(i, "x")
        simU0[i, :] = ocp_solver.get(i, "u")
    simX0[N0, :] = ocp_solver.get(N0, "x")

    ocp_solver.print_statistics()  # encapsulates: stat = ocp_solver.get_stats("statistics")
    ocp_solver.store_iterate(filename=f'final_iterate_{interface_type}_variant{nvariant}.json', overwrite=True)

    if PLOT:# plot but don't halt
        plot_pendulum(np.linspace(0, Tf_01, N0 + 1), Fmax, simU0, simX0, latexify=False, plt_show=False, X_true_label=f'original: N={N0}, Tf={Tf_01}')
Beispiel #5
0
def main(cost_type='NONLINEAR_LS', hessian_approximation='EXACT', ext_cost_use_num_hess=0,
         integrator_type='ERK'):
    print(f"using: cost_type {cost_type}, integrator_type {integrator_type}")
    # create ocp object to formulate the OCP
    ocp = AcadosOcp()

    # set model
    model = export_pendulum_ode_model()
    ocp.model = model

    Tf = 1.0
    nx = model.x.size()[0]
    nu = model.u.size()[0]
    ny = nx + nu
    ny_e = nx
    N = 20

    ocp.dims.N = N

    # set cost
    Q = 2*np.diag([1e3, 1e3, 1e-2, 1e-2])
    R = 2*np.diag([1e-2])

    x = ocp.model.x
    u = ocp.model.u

    cost_W = scipy.linalg.block_diag(Q, R)

    if cost_type == 'LS':
        ocp.cost.cost_type = 'LINEAR_LS'
        ocp.cost.cost_type_e = 'LINEAR_LS'

        ocp.cost.Vx = np.zeros((ny, nx))
        ocp.cost.Vx[:nx,:nx] = np.eye(nx)

        Vu = np.zeros((ny, nu))
        Vu[4,0] = 1.0
        ocp.cost.Vu = Vu

        ocp.cost.Vx_e = np.eye(nx)

    elif cost_type == 'NONLINEAR_LS':
        ocp.cost.cost_type = 'NONLINEAR_LS'
        ocp.cost.cost_type_e = 'NONLINEAR_LS'

        ocp.model.cost_y_expr = vertcat(x, u)
        ocp.model.cost_y_expr_e = x

    elif cost_type == 'EXTERNAL':
        ocp.cost.cost_type = 'EXTERNAL'
        ocp.cost.cost_type_e = 'EXTERNAL'

        ocp.model.cost_expr_ext_cost = vertcat(x, u).T @ cost_W @ vertcat(x, u)
        ocp.model.cost_expr_ext_cost_e = x.T @ Q @ x

    else:
        raise Exception('Unknown cost_type. Possible values are \'LS\' and \'NONLINEAR_LS\'.')

    if cost_type in ['LS', 'NONLINEAR_LS']:
        ocp.cost.yref = np.zeros((ny, ))
        ocp.cost.yref_e = np.zeros((ny_e, ))
        ocp.cost.W_e = Q
        ocp.cost.W = cost_W

    # set constraints
    Fmax = 80
    ocp.constraints.constr_type = 'BGH'
    ocp.constraints.lbu = np.array([-Fmax])
    ocp.constraints.ubu = np.array([+Fmax])
    x0 = np.array([0.0, np.pi, 0.0, 0.0])
    ocp.constraints.x0 = x0
    ocp.constraints.idxbu = np.array([0])

    ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM' # FULL_CONDENSING_QPOASES
    ocp.solver_options.hessian_approx = hessian_approximation
    ocp.solver_options.regularize_method = 'CONVEXIFY'
    ocp.solver_options.integrator_type = integrator_type
    if ocp.solver_options.integrator_type == 'GNSF':
        import json
        with open('../getting_started/common/' + model.name + '_gnsf_functions.json', 'r') as f:
            gnsf_dict = json.load(f)
        ocp.gnsf_model = gnsf_dict

    ocp.solver_options.qp_solver_cond_N = 5

    # set prediction horizon
    ocp.solver_options.tf = Tf
    ocp.solver_options.nlp_solver_type = 'SQP' # SQP_RTI
    ocp.solver_options.ext_cost_num_hess = ext_cost_use_num_hess

    # create solver
    AcadosOcpSolver.generate(ocp, json_file='acados_ocp.json')
    AcadosOcpSolver.build(ocp.code_export_directory, with_cython=True)
    ocp_solver = AcadosOcpSolver.create_cython_solver('acados_ocp.json')

    # time create
    Ncreate = 1
    create_time = []
    for i in range(Ncreate):
        t0 = time.time()
        # ocp_solver = AcadosOcpSolver(ocp, json_file = 'acados_ocp.json', build=False, generate=False)
        from c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
        ocp_solver = AcadosOcpSolverCython(ocp.model.name, ocp.solver_options.nlp_solver_type, ocp.dims.N)
        create_time.append( time.time() - t0)
    print(f"create_time: min {np.min(create_time)*1e3:.4f} ms mean {np.mean(create_time)*1e3:.4f} ms max {np.max(create_time)*1e3:.4f} ms over {Ncreate} executions")
    # create_time: min 0.2189 ms mean 0.2586 ms max 0.6881 ms over 10000 executions

    # RESET
    Nreset = 3
    reset_time = []
    for i in range(Nreset):
        # set NaNs as input to test reset() -> NOT RECOMMENDED!!!
        # ocp_solver.options_set('print_level', 2)
        for i in range(N):
            ocp_solver.set(i, 'x', np.NaN * np.ones((nx,)))
            ocp_solver.set(i, 'u', np.NaN * np.ones((nu,)))
        status = ocp_solver.solve()
        ocp_solver.print_statistics() # encapsulates: stat = ocp_solver.get_stats("statistics")
        if status == 0:
            raise Exception(f'acados returned status {status}, although NaNs were given.')
        else:
            print(f'acados returned status {status}, which is expected, since NaNs were given.')

        t0 = time.time()
        ocp_solver.reset()
        reset_time.append( time.time() - t0)
    print(f"reset_time: min {np.min(reset_time)*1e3:.4f} ms mean {np.mean(reset_time)*1e3:.4f} ms max {np.max(reset_time)*1e3:.4f} ms over {Nreset} executions")

    # OLD: without HPIPM mem reset:
    # reset_time: min 0.0019 ms mean 0.0022 ms max 0.0250 ms over 10000 executions

    # NEW: with HPIPM mem reset:
    # reset_time: min 0.0036 ms mean 0.0047 ms max 0.0906 ms over 10000 executions

    for i in range(N):
        ocp_solver.set(i, 'x', x0)

    if cost_type == 'EXTERNAL':
        # NOTE: hessian is wrt [u,x]
        if ext_cost_use_num_hess:
            for i in range(N):
                ocp_solver.cost_set(i, "ext_cost_num_hess", np.diag([0.04, 4000, 4000, 0.04, 0.04, ]))
            ocp_solver.cost_set(N, "ext_cost_num_hess", np.diag([4000, 4000, 0.04, 0.04, ]))

    simX = np.ndarray((N+1, nx))
    simU = np.ndarray((N, nu))

    status = ocp_solver.solve()

    ocp_solver.print_statistics()
    if status != 0:
        raise Exception(f'acados returned status {status} for cost_type {cost_type}\n'
                        f'integrator_type = {integrator_type}.')

    # get solution
    for i in range(N):
        simX[i,:] = ocp_solver.get(i, "x")
        simU[i,:] = ocp_solver.get(i, "u")
    simX[N,:] = ocp_solver.get(N, "x")