コンテンツにスキップ

iLQR

iLQRを用いて線形/非線形モデルの最適制御を行います。

Warning

cpp_roboticsに実装しているiLQRでは制約が扱えません

double-integrator

#include <cpp_robotics/controller/ilqr.hpp>
#include <cpp_robotics/third_party/matplotlib-cpp/matplotlibcpp.h>
#include <chrono>

int main()
{
    using namespace cpp_robotics;
    namespace plt = matplotlibcpp;

    const double Ts = 0.05;

    Eigen::MatrixXd A(4, 4);
    A << 0, 0, 1, 0,
         0, 0, 0, 1,
         0, 0, -0.6, 0.0,
         0, 0, 0, -0.3;

    Eigen::MatrixXd B(4, 2);
    B << 0,0,
         0,0,
         0.7, 0,
         0, 1;

    auto model = std::make_shared<OCPContinuousLinearDynamics>(A, B, Ts);
    auto cost = std::make_shared<OCPCostQuadratic>(model, 30);
    cost->Q = (Eigen::VectorXd(4) << 5,5,0.5,0.5).finished().asDiagonal();
    cost->R = (Eigen::VectorXd(2) << 0.1,0.1).finished().asDiagonal();
    cost->Qf = cost->Q;

    iLQR ilqr(model, cost);

    Eigen::VectorXd x0(4);
    x0 << 5, 5, 3, -2;

    std::vector<double> u1, u2, x1, x2, t, solve_time;
    for(size_t i = 0; i < 100; i++)
    {
        auto start = std::chrono::system_clock::now();
        auto ret = ilqr.generate_trajectory(x0);
        auto end = std::chrono::system_clock::now();

        if(ret != iLQR::Result::SUCCESS)
        {
            std::cout << "Failed to solve at " << i << " code: " << static_cast<int>(ret) << std::endl;
        }

        double milliseconds = 1e-3 * std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

        x0 = model->eval(x0, ilqr.get_input()[0]);

        t.push_back(i * Ts);
        u1.push_back(ilqr.get_input()[0](0));
        u2.push_back(ilqr.get_input()[0](1));
        x1.push_back(ilqr.get_state()[0](0));
        x2.push_back(ilqr.get_state()[0](1));
        solve_time.push_back(milliseconds);
    }

    plt::named_plot("u1", t, u1);
    plt::named_plot("u2", t, u2);
    plt::named_plot("x1", t, x1);
    plt::named_plot("x2", t, x2);
    plt::legend();
    plt::show(false);

    plt::figure();
    plt::named_plot("solve_time[ms]", t, solve_time, ".");
    plt::legend();
    plt::show();

    return 0;
}

title

差動二輪

#include <cpp_robotics/controller/ilqr.hpp>
#include <cpp_robotics/third_party/matplotlib-cpp/matplotlibcpp.h>
#include <chrono>

class DiffBot : public cpp_robotics::OCPDiscreteNonlinearDynamics
{
public:
    DiffBot(double dt):
        OCPDiscreteNonlinearDynamics(3,2), dt_(dt) {}

    Eigen::VectorXd eval(const Eigen::VectorXd &x, const Eigen::VectorXd &u) override
    {
        Eigen::VectorXd x_next(3);
        x_next << x[0] + dt_ * (u[0] * std::cos(x[2]) - u[1] * std::sin(x[2])),
                  x[1] + dt_ * (u[0] * std::sin(x[2]) + u[1] * std::cos(x[2])),
                  x[2] + dt_ * (u[0] - u[1]);
        return x_next;
    }
private:
    double dt_;
};

int main()
{
    using namespace cpp_robotics;
    namespace plt = matplotlibcpp;

    const double Ts = 0.05;
    auto model = std::make_shared<DiffBot>(Ts);
    auto cost = std::make_shared<OCPCostServoQuadratic>(model, 30);
    cost->Q = (Eigen::VectorXd(3) << 5, 5, 3).finished().asDiagonal();
    cost->R = 1.0 * Eigen::MatrixXd::Identity(2, 2);
    cost->Qf = cost->Q;
    cost->set_x_ref_const((Eigen::VectorXd(3) << 3, 4, M_PI/2).finished());
    iLQR ilqr(model, cost);

    Eigen::VectorXd x0(3);
    x0 << 0, 0, 0;

    std::vector<double> u1, u2, x, y, theta, t, solve_time;
    for(size_t i = 0; i < 100; i++)
    {
        auto start = std::chrono::system_clock::now();
        auto ret = ilqr.generate_trajectory(x0);
        auto end = std::chrono::system_clock::now();

        if(ret != iLQR::Result::SUCCESS)
        {
            std::cout << "Failed to solve at " << i << " code: " << static_cast<int>(ret) << std::endl;
        }

        double milliseconds = 1e-3 * std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

        x0 = model->eval(x0, ilqr.get_input()[0]);

        t.push_back(i * Ts);
        u1.push_back(ilqr.get_input()[0](0));
        u2.push_back(ilqr.get_input()[0](1));
        x.push_back(ilqr.get_state()[0](0));
        y.push_back(ilqr.get_state()[0](1));
        theta.push_back(ilqr.get_state()[0](2));
        solve_time.push_back(milliseconds);
    }

    plt::named_plot("u1", t, u1);
    plt::named_plot("u2", t, u2);
    plt::named_plot("x", t, x);
    plt::named_plot("y", t, y);
    plt::named_plot("theta", t, theta);
    plt::legend();
    plt::show(false);

    plt::figure();
    plt::named_plot("solve_time[ms]", t, solve_time, ".");
    plt::legend();
    plt::show();

    return 0;
}

title