这里的最优控制问题参考的是伪谱法处理优化问题,参考下面这个链接:
在matlab中有NLP问题的求解器fmincon,可以用来求解伪谱法离散之后的非线性规划问题,但是伪谱法离散的程序需要自己编写。另外有求解器GPOPS2也能利用伪谱法处理最优控制问题,但是速度比较慢,而且gpops的求解器核心也是ipopt,为了加快求解速度,抛弃matlab来使用求解器。我选择基于bocop的核心源码来完成自定义求解器。
GPOPS2使用参考:
用GPOPS2解最优控制问题-优快云博客
c++求解器Bocop链接:
control-toolbox/bocop: Bocop 3 (github.com)
求解器Bocop的学习笔记如下:
最优控制工具箱Bocop学习笔记(一)——下载与安装 - 知乎 (zhihu.com)
求解器依赖的两个库,一个自动微分工具CppAD,一个是内点法求解器ipopt,这两个库的链接和安装参考如下:
CppAD/cppad_ipopt at master · coin-or/CppAD (github.com)
coin-or/Ipopt: COIN-OR Interior Point Optimizer IPOPT (github.com)
Linux | Ubuntu 20.04安装ipopt和cppAD | 安装全流程+报错解决_csdn ipopt anzhaung-优快云博客
注:cppad库的安装比较简单,而ipopt安装相对复杂,需要安装其他的依赖,例如线性求解器MUMPS,要多尝试几种方法,但是我推荐安装方法使用coinbrew安装。下列指令仅供参考:
安装依赖:
sudo apt-get install gcc g++ gfortran cmake git patch wget pkg-config liblapack-dev libblas-dev
下载coinbrew
脚本和修改权限:
wget https://raw.githubusercontent.com/coin-or/coinbrew/master/coinbrew
chmod u+x coinbrew
克隆ipopt库:
./coinbrew fetch Ipopt
配置ipopt,我这里选择的线性求解器是mumps,也可以选择HSL,将Ipopt安装到/usr/local
目录,安装目录很重要,一般都是这个:
./coinbrew build Ipopt --prefix=/usr/local --test --enable-linear-solver=mumps
接下来新建项目bocopcore,拖入bocop的核心源码src,添加一个例子goddard,抛弃了bocop的gui界面。
重写main.cpp:
/** ********************************************************************
* \mainpage Bocop3 main workflow
*
* create OCP and initialize from .def file
*
* create dOCP from OCP
*
* create NLPSolver (Ipopt)
*
* call solve() from NLPSolver
*
* **********************************************************************/
#include <iostream>
#include "OCP.h"
#include "dOCPCppAD.h"
#include "NLPSolverIpopt.h"
int main(int argc, char **argv) {
OCP *myocp = new OCP();
myocp->initialize();
// Assume the problem definition file is named 'problem.def'
std::string definition_file = (argc > 1) ? argv[1] : "problem.def";
myocp->load(definition_file);
// Initialize the derived OCP class which is designed to handle the specific Goddard problem
dOCPCppAD *mydocp = new dOCPCppAD();
mydocp->setOCP(myocp);
mydocp->initialize();
// Initialize the solver
NLPSolver *mysolver = new NLPSolverIpopt();
mysolver->setNLP(mydocp);
mysolver->setOptions(myocp->getDefinitionMap());
// Solve the problem
mysolver->solve();
// Cleanup
delete myocp;
delete mydocp;
delete mysolver;
return 0;
}
重写cmake文件:
cmake_minimum_required(VERSION 3.16)
project(bocopcorelib)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 包含目录
include_directories(${CMAKE_SOURCE_DIR})
include_directories(AD DOCP NLP OCP tools goddard)
# 手动包含 CppAD 和 IPOPT 目录
include_directories(/usr/local/include/cppad) # CppAD 的头文件路径
include_directories(/usr/local/include/coin-or) # IPOPT 的头文件路径
# 寻找 CppAD 库
find_library(CPPAD_LIBRARY NAMES cppad_lib HINTS /usr/local/lib)
# 寻找 IPOPT 库
find_library(IPOPT_LIBRARY NAMES ipopt HINTS /usr/local/lib)
# 检查库是否找到
if(NOT CPPAD_LIBRARY)
message(FATAL_ERROR "Cannot find cppad library")
endif()
if(NOT IPOPT_LIBRARY)
message(FATAL_ERROR "Cannot find ipopt library")
endif()
# 源文件列表
set(SOURCES
AD/dOCPCppAD.cpp
DOCP/dOCP.cpp
DOCP/dODE.cpp
DOCP/dControl.cpp
DOCP/dState.cpp
DOCP/solution.cpp
NLP/NLPSolverIpopt.cpp
OCP/OCP.cpp
tools/tools.cpp
tools/tools_interpolation.cpp
goddard/problem.cpp
)
# 添加动态库目标
add_library(bocopcore SHARED ${SOURCES})
target_link_libraries(bocopcore ${IPOPT_LIBRARY} ${CPPAD_LIBRARY})
# 添加主程序可执行文件
add_executable(bocop_solver main.cpp)
target_link_libraries(bocop_solver bocopcore ${IPOPT_LIBRARY} ${CPPAD_LIBRARY})
在文件目录下新建build,编译链接项目,即可得到可执行程序:bocop_solver
求解结果:
本文最重要的是在c++下求解复杂的最优控制问题。后续可以修改代码中的problem文件和代码,更改为自己的最优控制或者轨迹优化问题,进行求解。但是bocop采用的配点方法是梯形法、龙格库达、三阶高斯方法;如果想要更改为LGL、CGL等配点方法,需要在dOCP代码中进行代码修改,这也是后续的工作量。