ubuntu20.04安装osqp,osqpeigen
前言
osqp作为二次规划常见求解器,在各种开源项目中有广泛使用,但是其安装还是有一点麻烦,存在一些坑
一、OSQP编译报错
这里就简单讲一下osqp安装步骤,详细安装可以参考官网osqp官网
git clone https://github.com/osqp/osqp
cd osqp
mkdir build && cd build
cmake ..
make
sudo make install
提示:这里默认下载的时osqp的master版本,这也是网上很多代码编译不过的原因目前版本是1.0以上
安装完成之后在build\out 路径下
./osqp_demo
看能否正常运行,运行成功则安装正确。正确结果如下:
此时我们回去网上复制一些代码,自己尝试编译,看看是否安装正确,此时主要会发现两种代码:
第一种为基于0.6左右的老版本,第二种为1.0左右的新版本见第二部分
此处为老版本:
#include <stdlib.h>
#include "osqp/osqp.h"
int main(int argc, char **argv) {
// P矩阵是对称矩阵,只存储上三角部分,下三角部分视为零值
c_float P_x[3] = {4.0, 1.0, 2.0, };
// P矩阵非零元素个数为3
// nnz = number of non-zero elements.
c_int P_nnz = 3;
// P矩阵非零元素行索引,按照先第一列,再第二列。。。
// 的顺序排列。下例表示非零元素的行序号为0、0、1
c_int P_i[3] = {0, 0, 1, };
// 1-0=1表示第0列非零元素个数
// 3-1=2表示第1列非零元素个数
c_int P_p[3] = {0, 1, 3, };
c_float q[2] = {1.0, 1.0, };
// A矩阵非零元素
c_float A_x[4] = {1.0, 1.0, 1.0, 1.0, };
// A矩阵非零元素个数为4
c_int A_nnz = 4;
// A矩阵非零元素的行序号为0、1、0、2(按列排序)
c_int A_i[4] = {0, 1, 0, 2, };
// 2-0=2表示第0列2个元素非零
// 4-2=2表示第1列2个元素非零
c_int A_p[3] = {0, 2, 4, };
c_float l[3] = {1.0, 0.0, 0.0, };
c_float u[3] = {1.0, 0.7, 0.7, };
c_int n = 2;
c_int m = 3;
// Exitflag
c_int exitflag = 0;
// Workspace structures
OSQPWorkspace *work;
OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData));
// Populate data
if (data) {
data->n = n;
data->m = m;
data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
data->q = q;
data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
data->l = l;
data->u = u;
}
// Define solver settings as default
if (settings) {
osqp_set_default_settings(settings);
settings->alpha = 1.0; // Change alpha parameter
}
// Setup workspace
exitflag = osqp_setup(&work, data, settings);
// Solve Problem
osqp_solve(work);
// Cleanup
if (data) {
if (data->A) c_free(data->A);
if (data->P) c_free(data->P);
c_free(data);
}
if (settings) c_free(settings);
return exitflag;
对应的cmakelist为:
cmake_minimum_required(VERSION 2.8)
project(test)
# Find OSQP library and headers
find_package(osqp REQUIRED)
include_directories(
include
${EIGEN3_INCLUDE_DIRS}
${OSQP_INCLUDE_DIRS}
)
# Link the OSQP shared library
# add_executable(test_left_right_value src/test_left_right_value.cpp)
add_executable(state src/state.cpp)
add_executable(test_osqp src/test_osqp.cpp)
target_link_libraries(test_osqp osqp::osqp)
不出意外的话你的编译会报错:
vcar@vcar:~/note/c_plus_plus_test/build$ make
Scanning dependencies of target test_osqp
[ 25%] Building CXX object CMakeFiles/test_osqp.dir/src/test_osqp.cpp.o
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp: In function ‘int main(int, char**)’:
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:87:5: error: ‘c_float’ was not declared in this scope; did you mean ‘float’?
87 | c_float P_x[3] = {4.0, 1.0, 2.0, };
| ^~~~~~~
| float
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:90:5: error: ‘c_int’ was not declared in this scope; did you mean ‘u_int’?
90 | c_int P_nnz = 3;
| ^~~~~
| u_int
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:93:10: error: expected ‘;’ before ‘P_i’
93 | c_int P_i[3] = {0, 0, 1, };
| ^~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:96:10: error: expected ‘;’ before ‘P_p’
96 | c_int P_p[3] = {0, 1, 3, };
| ^~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:97:12: error: expected ‘;’ before ‘q’
97 | c_float q[2] = {1.0, 1.0, };
| ^~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:99:12: error: expected ‘;’ before ‘A_x’
99 | c_float A_x[4] = {1.0, 1.0, 1.0, 1.0, };
| ^~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:101:10: error: expected ‘;’ before ‘A_nnz’
101 | c_int A_nnz = 4;
| ^~~~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:103:10: error: expected ‘;’ before ‘A_i’
103 | c_int A_i[4] = {0, 1, 0, 2, };
| ^~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:106:10: error: expected ‘;’ before ‘A_p’
106 | c_int A_p[3] = {0, 2, 4, };
| ^~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:107:12: error: expected ‘;’ before ‘l’
107 | c_float l[3] = {1.0, 0.0, 0.0, };
| ^~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:108:12: error: expected ‘;’ before ‘u’
108 | c_float u[3] = {1.0, 0.7, 0.7, };
| ^~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:109:10: error: expected ‘;’ before ‘n’
109 | c_int n = 2;
| ^~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:110:10: error: expected ‘;’ before ‘m’
110 | c_int m = 3;
| ^~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:113:10: error: expected ‘;’ before ‘exitflag’
113 | c_int exitflag = 0;
| ^~~~~~~~~
| ;
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:116:47: error: ‘c_malloc’ was not declared in this scope; did you mean ‘malloc’?
116 | OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
| ^~~~~~~~
| malloc
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:117:5: error: ‘OSQPData’ was not declared in this scope
117 | OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData));
| ^~~~~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:117:20: error: ‘data’ was not declared in this scope
117 | OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData));
| ^~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:117:42: error: expected primary-expression before ‘)’ token
117 | OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData));
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:121:19: error: ‘n’ was not declared in this scope
121 | data->n = n;
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:122:19: error: ‘m’ was not declared in this scope
122 | data->m = m;
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:123:48: error: ‘P_nnz’ was not declared in this scope
123 | data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
| ^~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:123:55: error: ‘P_x’ was not declared in this scope
123 | data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:123:60: error: ‘P_i’ was not declared in this scope
123 | data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:123:65: error: ‘P_p’ was not declared in this scope
123 | data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:123:19: error: ‘csc_matrix’ was not declared in this scope
123 | data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
| ^~~~~~~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:124:19: error: ‘q’ was not declared in this scope
124 | data->q = q;
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:125:48: error: ‘A_nnz’ was not declared in this scope
125 | data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
| ^~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:125:55: error: ‘A_x’ was not declared in this scope
125 | data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:125:60: error: ‘A_i’ was not declared in this scope
125 | data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:125:65: error: ‘A_p’ was not declared in this scope
125 | data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
| ^~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:126:19: error: ‘l’ was not declared in this scope
126 | data->l = l;
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:127:19: error: ‘u’ was not declared in this scope
127 | data->u = u;
| ^
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:137:5: error: ‘exitflag’ was not declared in this scope
137 | exitflag = osqp_setup(&work, data, settings);
| ^~~~~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:140:16: error: cannot convert ‘OSQPWorkspace*’ {aka ‘OSQPWorkspace_*’} to ‘OSQPSolver*’
140 | osqp_solve(work);
| ^~~~
| |
| OSQPWorkspace* {aka OSQPWorkspace_*}
In file included from /usr/local/include/osqp/osqp.h:9,
from /home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:82:
/usr/local/include/osqp/osqp_api_functions.h:111:41: note: initializing argument 1 of ‘OSQPInt osqp_solve(OSQPSolver*)’
111 | OSQP_API OSQPInt osqp_solve(OSQPSolver* solver);
| ~~~~~~~~~~~~^~~~~~
In file included from /usr/local/include/osqp/osqp.h:8,
from /home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:82:
/usr/local/include/osqp/osqp_api_types.h:130:16: note: class type ‘OSQPWorkspace’ {aka ‘OSQPWorkspace_’} is incomplete
130 | typedef struct OSQPWorkspace_ OSQPWorkspace;
| ^~~~~~~~~~~~~~
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:144:22: error: ‘c_free’ was not declared in this scope; did you mean ‘free’?
144 | if (data->A) c_free(data->A);
| ^~~~~~
| free
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:145:22: error: ‘c_free’ was not declared in this scope; did you mean ‘free’?
145 | if (data->P) c_free(data->P);
| ^~~~~~
| free
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:146:9: error: ‘c_free’ was not declared in this scope; did you mean ‘free’?
146 | c_free(data);
| ^~~~~~
| free
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:148:19: error: ‘c_free’ was not declared in this scope; did you mean ‘free’?
148 | if (settings) c_free(settings);
| ^~~~~~
| free
make[2]: *** [CMakeFiles/test_osqp.dir/build.make:63: CMakeFiles/test_osqp.dir/src/test_osqp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/test_osqp.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
vcar@vcar:~/note/c_plus_plus_test/build$
报错原因就是直接从官网git clone下来的代码是master,其已经1.0.0版本了,而上面的代码是0.6.0 时期的代码,代码太老了,而库太新了。
因此希望编译通过则需要下载更老版本的osqp库本人下载了0.6.2版本代码,代码测试编译通过。
因为本人不想替换到已经安装的最新版osqp因此,采用了动态链接的方式来编译上述代码,注意修改osqp库位置,本人代码目录如下:
去官网下载osqp下载
然后编译:
cd osqp
mkdir build && cd build
cmake ..
make
然后将lib和include文件移动到工作目录下,我的路径如下
注意修改osqp头文件路径
#include <stdlib.h>
#include "osqp/include/osqp.h"
int main(int argc, char **argv) {
// P矩阵是对称矩阵,只存储上三角部分,下三角部分视为零值
c_float P_x[3] = {4.0, 1.0, 2.0, };
// P矩阵非零元素个数为3
// nnz = number of non-zero elements.
c_int P_nnz = 3;
// P矩阵非零元素行索引,按照先第一列,再第二列。。。
// 的顺序排列。下例表示非零元素的行序号为0、0、1
c_int P_i[3] = {0, 0, 1, };
// 1-0=1表示第0列非零元素个数
// 3-1=2表示第1列非零元素个数
c_int P_p[3] = {0, 1, 3, };
c_float q[2] = {1.0, 1.0, };
// A矩阵非零元素
c_float A_x[4] = {1.0, 1.0, 1.0, 1.0, };
// A矩阵非零元素个数为4
c_int A_nnz = 4;
// A矩阵非零元素的行序号为0、1、0、2(按列排序)
c_int A_i[4] = {0, 1, 0, 2, };
// 2-0=2表示第0列2个元素非零
// 4-2=2表示第1列2个元素非零
c_int A_p[3] = {0, 2, 4, };
c_float l[3] = {1.0, 0.0, 0.0, };
c_float u[3] = {1.0, 0.7, 0.7, };
c_int n = 2;
c_int m = 3;
// Exitflag
c_int exitflag = 0;
// Workspace structures
OSQPWorkspace *work;
OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
OSQPData *data = (OSQPData *)c_malloc(sizeof(OSQPData));
// Populate data
if (data) {
data->n = n;
data->m = m;
data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
data->q = q;
data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
data->l = l;
data->u = u;
}
// Define solver settings as default
if (settings) {
osqp_set_default_settings(settings);
settings->alpha = 1.0; // Change alpha parameter
}
// Setup workspace
exitflag = osqp_setup(&work, data, settings);
// Solve Problem
osqp_solve(work);
// Cleanup
if (data) {
if (data->A) c_free(data->A);
if (data->P) c_free(data->P);
c_free(data);
}
if (settings) c_free(settings);
return exitflag;
}
对应的cmakelist为:
cmake_minimum_required(VERSION 2.8)
project(test)
set(CMAKE_CXX_STANDARD 17)
# Set the path to OSQP library and include files
set(OSQP_ROOT "${CMAKE_SOURCE_DIR}/src/osqp")
set(OSQP_INCLUDE_DIR "${OSQP_ROOT}/include")
set(OSQP_LIB_DIR "${OSQP_ROOT}/lib")
# Add the OSQP include directory
include_directories(${OSQP_INCLUDE_DIR})
# Add the executable
add_executable(test_osqp src/test_osqp.cpp)
message(STATUS "OSQP_LIB_DIR path: ${OSQP_LIB_DIR}")
# Link the OSQP library
target_link_libraries(test_osqp
"${OSQP_LIB_DIR}/libosqp.so")
以上就是在安装了最新版的osqp之后,如何编译老版本的osqp代码
二、编译新版本的代码
如果希望基于最新的osqp库编译,则其测试
#include "osqp/osqp.h"
#include <stdlib.h>
#include <stdio.h>
int main(void) {
/* Load problem data */
OSQPFloat P_x[3] = { 4.0, 1.0, 2.0, };
OSQPInt P_nnz = 3;
OSQPInt P_i[3] = { 0, 0, 1, };
OSQPInt P_p[3] = { 0, 1, 3, };
OSQPFloat q[2] = { 1.0, 1.0, };
OSQPFloat A_x[4] = { 1.0, 1.0, 1.0, 1.0, };
OSQPInt A_nnz = 4;
OSQPInt A_i[4] = { 0, 1, 0, 2, };
OSQPInt A_p[3] = { 0, 2, 4, };
OSQPFloat l[3] = { 1.0, 0.0, 0.0, };
OSQPFloat u[3] = { 1.0, 0.7, 0.7, };
OSQPInt n = 2;
OSQPInt m = 3;
/* Exitflag */
OSQPInt exitflag;
/* Solver, settings, matrices */
OSQPSolver* solver = NULL;
OSQPSettings* settings = NULL;
OSQPCscMatrix* P = (malloc(sizeof(OSQPCscMatrix)));
OSQPCscMatrix* A = (malloc(sizeof(OSQPCscMatrix)));
// OSQPCscMatrix* P = static_cast<OSQPCscMatrix*>(malloc(sizeof(OSQPCscMatrix)));
// OSQPCscMatrix* A = static_cast<OSQPCscMatrix*>(malloc(sizeof(OSQPCscMatrix)));
/* Populate matrices */
csc_set_data(A, m, n, A_nnz, A_x, A_i, A_p);
csc_set_data(P, n, n, P_nnz, P_x, P_i, P_p);
/* Set default settings */
settings = (OSQPSettings *)malloc(sizeof(OSQPSettings));
if (settings) {
osqp_set_default_settings(settings);
settings->polishing = 1;
//settings->linsys_solver = OSQP_DIRECT_SOLVER;
//settings->linsys_solver = OSQP_INDIRECT_SOLVER;
}
OSQPInt cap = osqp_capabilities();
printf("This OSQP library supports:\n");
if(cap & OSQP_CAPABILITY_DIRECT_SOLVER) {
printf(" A direct linear algebra solver\n");
}
if(cap & OSQP_CAPABILITY_INDIRECT_SOLVER) {
printf(" An indirect linear algebra solver\n");
}
if(cap & OSQP_CAPABILITY_CODEGEN) {
printf(" Code generation\n");
}
if(cap & OSQP_CAPABILITY_DERIVATIVES) {
printf(" Derivatives calculation\n");
}
printf("\n");
/* Setup solver */
exitflag = osqp_setup(&solver, P, q, A, l, u, m, n, settings);
/* Solve problem */
if (!exitflag) exitflag = osqp_solve(solver);
/* Cleanup */
osqp_cleanup(solver);
if (A) free(A);
if (P) free(P);
if (settings) free(settings);
return (int)exitflag;
}
对应的cmakelist为:
cmake_minimum_required(VERSION 2.8)
project(test)
# Find OSQP library and headers
find_package(osqp REQUIRED)
include_directories(
include
${EIGEN3_INCLUDE_DIRS}
${OSQP_INCLUDE_DIRS}
)
# Link the OSQP shared library
# add_executable(test_left_right_value src/test_left_right_value.cpp)
add_executable(state src/state.cpp)
add_executable(test_osqp src/test_osqp.cpp)
target_link_libraries(test_osqp osqp::osqp)
此时不出意外的话又该出意外了,发现依然编译不过淦
vcar@vcar:~/note/c_plus_plus_test/build$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vcar/note/c_plus_plus_test/build
Scanning dependencies of target test_osqp
[ 25%] Building CXX object CMakeFiles/test_osqp.dir/src/test_osqp.cpp.o
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp: In function ‘int main()’:
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:28:29: error: invalid conversion from ‘void*’ to ‘OSQPCscMatrix*’ [-fpermissive]
28 | OSQPCscMatrix* P = (malloc(sizeof(OSQPCscMatrix)));
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
| |
| void*
/home/vcar/note/c_plus_plus_test/src/test_osqp.cpp:29:29: error: invalid conversion from ‘void*’ to ‘OSQPCscMatrix*’ [-fpermissive]
29 | OSQPCscMatrix* A = (malloc(sizeof(OSQPCscMatrix)));
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
| |
| void*
make[2]: *** [CMakeFiles/test_osqp.dir/build.make:63: CMakeFiles/test_osqp.dir/src/test_osqp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/test_osqp.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
vcar@vcar:~/note/c_plus_plus_test/build$ make
此时经过多方查找发现,只需要将
OSQPCscMatrix* P = (malloc(sizeof(OSQPCscMatrix)));
OSQPCscMatrix* A = (malloc(sizeof(OSQPCscMatrix)));
替换为
OSQPCscMatrix* P = static_cast<OSQPCscMatrix*>(malloc(sizeof(OSQPCscMatrix)));
OSQPCscMatrix* A = static_cast<OSQPCscMatrix*>(malloc(sizeof(OSQPCscMatrix)));
然后就能编译通过了