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)));

然后就能编译通过了

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值