Kairbon'Blog.

robocup3D 如何将参数文件打包为动态库

字数统计: 1.7k阅读时长: 9 min
2019/07/13

(本文适合hfut robocup3d足球队员阅读)

我校Robocup3d队伍使用的是来自于UT的底层代码,我们在这基础上进行优化,修改。

在现在的比赛中,通常要提交二进制代码,在底层文件中,我们通过cma算法优化出来的参数会以文本的形式存在,这样会导致别人直接可以看到我们的参数文件。

下面我们先进行分析

在sh脚本启动的时候,会根据机器人的type来进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

for ((i=1;i<=$NUM_PLAYERS;i++)); do
case $i in
1|2)
echo "Running agent No. $i -- Type 1"
"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 1 --paramsfile paramfiles/defaultParams_t1.txt &#> /dev/null &
#"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 2 --paramsfile paramfiles/defaultParams_t2.txt > stdout$i 2> stderr$i &
;;
3|4)
echo "Running agent No. $i -- Type 1"
"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 1 --paramsfile paramfiles/defaultParams_t1.txt &#> /dev/null &
#"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 1 --paramsfile paramfiles/defaultParams_t1.txt > stdout$i 2> stderr$i &
;;
5|6)
echo "Running agent No. $i -- Type 0"
"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 0 --paramsfile paramfiles/defaultParams_t0.txt &#> /dev/null &
#"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 0 --paramsfile paramfiles/defaultParams_t0.txt > stdout$i 2> stderr$i &
;;
7|8)
echo "Running agent No. $i -- Type 3"
"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 1 --paramsfile paramfiles/defaultParams_t1.txt &#> /dev/null &
#"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 1 --paramsfile paramfiles/defaultParams_t1.txt > stdout$i 2> stderr$i &
;;
*)
echo "Running agent No. $i -- Type 4"
"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 4 --paramsfile paramfiles/defaultParams_t4.txt &#> /dev/null &
#"$BINARY_DIR/$AGENT_BINARY" $opt --unum $i --type 4 --paramsfile paramfiles/defaultParams_t4.txt > stdout$i 2> stderr$i &
;;

esac
sleep 1
done

注入之后,在底层文件的main函数中

调用 ReadOptions(argc,argv)
下面是ReadOptions函数的一部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
else if(strcmp(argv[i], "--unum") == 0) {
if(i == argc - 1) {
PrintHelp();
exit(0);
}
uNum = atoi(argv[i + 1]);
}
else if(strcmp(argv[i], "--paramsfile") == 0) {
if(i == argc - 1) {
PrintHelp();
exit(0);
}
string inputsFile = argv[i+1];
LoadParams(inputsFile);
}

在这个函数中,又调用
LoadParams(inputsFile);
对注入的参数文件进行划分和注入

所以我们的参数注入就是在这里进行

我们不将参数文件通过sh文件引入,而是将其写成c++文件(通过一个将文本转换成为c++文件的脚本),然后将其编译,再将它在main函数include,在 LoadParams(inputsFile)函数中调用,那么最后提交的代码里面只需要有编译后的参数文件,就可以避免参数文件的直接泄露。

第一步,做出将参数文件转换为cpp文件的脚本

这里学长已经做好了,实现起来也很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <iostream>
#include <stdio.h>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

istream *input;
ofstream output;
ifstream infile;
istringstream inString;

void run();

int main()
{
output.open("namedParam.h");
output << "#ifndef PPP_H" << endl
<< "#define PPP_H" << endl << endl

<< "#include <map>" << endl
<< "#include <string>" << endl
<< "using namespace std;" << endl << endl

<< "void makeNamedParams(map<string, string> &namedParams);" << endl
<< "void makeNamedParams0(map<string, string> &namedParams);" << endl
<< "void makeNamedParams1(map<string, string> &namedParams);" << endl
<< "void makeNamedParams2(map<string, string> &namedParams);" << endl
<< "void makeNamedParams3(map<string, string> &namedParams);" << endl
<< "void makeNamedParams4(map<string, string> &namedParams);" << endl << endl

<< "#endif" << endl;
output.close();


//start the include
output.open("namedParam.cpp");
output << "#include \"namedParam.h\"" << endl;
output << endl;
//end

output << "void makeNamedParams(map<string, string> &namedParams){" << endl;
infile.open("defaultParams.txt", ifstream::in);
run();
output << "}" << endl;

//param0 start
output << "void makeNamedParams0(map<string, string> &namedParams){" << endl;
infile.open("defaultParams_t0.txt", ifstream::in);
run();
output << "}" << endl;

output << "void makeNamedParams1(map<string, string> &namedParams){" << endl;
infile.open("defaultParams_t1.txt", ifstream::in);
run();
output << "}" << endl;

output << "void makeNamedParams2(map<string, string> &namedParams){" << endl;
infile.open("defaultParams_t2.txt", ifstream::in);
run();
output << "}" << endl;

output << "void makeNamedParams3(map<string, string> &namedParams){" << endl;
infile.open("defaultParams_t3.txt", ifstream::in);
run();
output << "}" << endl;

output << "void makeNamedParams4(map<string, string> &namedParams){" << endl;
infile.open("defaultParams_t4.txt", ifstream::in);
run();
output << "}" << endl;

output.close();
return 0;
}

void run(){
input = &(infile);

string name;
bool fBlockComment = false;
while(!input->eof())
{

// Skip comments and empty lines
std::string str;
std::getline(*input, str);
if (str.length() >= 2 && str.substr(0,2) == "/*") {
fBlockComment = true;
} else if (str == "*/") {
fBlockComment = false;
}

if(fBlockComment || str == "" || str[0] == '#' ) {
continue;
}

// otherwise parse strings
stringstream s(str);
std::string key;
std::string value;
std::getline(s, key, '\t'); //read thru tab
std::getline(s, value); //read thru newline
if(value.empty()) {
continue;
}
output << " namedParams[\"" << key << "\"] = \"" << value << "\";" << endl;
}

infile.close();
}

它会将defaultParams_t×的文本文件转换为
namedParam.h

namedParam.cpp

第二步,将函数LoadParams(inputsFile)内容修改并将namedParam. namedParam.cpp include入main文件

#include “paramfiles/namedParam.h”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* Read in parameters from inputsFile, which should be formatted
* with a set of parameters as key value pairs from strings to
* floats. The parameter name should be separated from its value
* with a tab and parameters should be separated from each other
* with a single newline. Parameters will be loaded into the
* namedParams map.
*/
map<string, string> namedParams;
void LoadParams(const string &inputsFile)
{
if (inputsFile == "paramfiles/defaultParams.txt")
makeNamedParams(namedParams);
else if (inputsFile == "paramfiles/defaultParams_t0.txt")
makeNamedParams0(namedParams);
else if (inputsFile == "paramfiles/defaultParams_t1.txt")
makeNamedParams1(namedParams);
else if (inputsFile == "paramfiles/defaultParams_t2.txt")
makeNamedParams2(namedParams);
else if (inputsFile == "paramfiles/defaultParams_t3.txt")
makeNamedParams3(namedParams);
else if (inputsFile == "paramfiles/defaultParams_t4.txt")
makeNamedParams4(namedParams);
}

makeNamedParams是namedParam.cpp里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void makeNamedParams(map<string, string> &namedParams){
namedParams["utwalk_max_step_size_angle"] = "1.22";
namedParams["utwalk_max_step_size_x"] = "50";
namedParams["utwalk_max_step_size_y"] = "40";
namedParams["utwalk_shift_amount"] = "20";
namedParams["utwalk_walk_height"] = "175";
namedParams["utwalk_step_height"] = "20";
namedParams["utwalk_fraction_still"] = "0.2";
namedParams["utwalk_fraction_on_ground"] = "0.2";
namedParams["utwalk_fraction_moving"] = "0.6";
namedParams["utwalk_fraction_in_air"] = "0.6";
namedParams["utwalk_phase_length"] = "0.38";
namedParams["utwalk_default_com_pos_x"] = "0.0";
namedParams["utwalk_pid_step_size_x"] = "0.03";
namedParams["utwalk_pid_step_size_y"] = "0.03";
namedParams["utwalk_pid_step_size_rot"] = "0.03";
namedParams["utwalk_max_normal_com_error"] = "7.5";
namedParams["utwalk_max_acceptable_com_error"] = "12.5";
namedParams["utwalk_fwd_offset"] = "2.5";
namedParams["utwalk_fwd_offset_factor"] = "0.5";
namedParams["utwalk_swing_ankle_offset"] = "-0.087266463";
namedParams["utwalk_pid_tilt"] = "0.15";
namedParams["utwalk_pid_roll"] = "0.2";
namedParams["utwalk_pid_com_x"] = "1.0";
namedParams["utwalk_pid_com_y"] = "1.0";
namedParams["utwalk_pid_com_z"] = "0.0";
namedParams["utwalk_pid_arm_x"] = "0.0";
namedParams["utwalk_pid_arm_y"] = "0.0";
namedParams["utwalk_balance_hip_pitch"] = "0";
namedParams["utwalk_balance_knee_pitch"] = "0";
namedParams["utwalk_balance_hip_roll"] = " 0";
namedParams["utwalk_balance_ankle_roll"] = "0";
namedParams["utwalk_toe_const_offset"] = " 0";
....

这样的东西

第三步,将两个文件带入cmakelist中

在CMakelist.txt文件中,将paramfiles/namedParam.cpp
插入到 set(SRCS 里面
最后,编译并运行就完成了

CATALOG
  1. 1. 下面我们先进行分析
    1. 1.1. 我们不将参数文件通过sh文件引入,而是将其写成c++文件(通过一个将文本转换成为c++文件的脚本),然后将其编译,再将它在main函数include,在 LoadParams(inputsFile)函数中调用,那么最后提交的代码里面只需要有编译后的参数文件,就可以避免参数文件的直接泄露。
      1. 1.1.1. 第一步,做出将参数文件转换为cpp文件的脚本
      2. 1.1.2. 第二步,将函数LoadParams(inputsFile)内容修改并将namedParam. namedParam.cpp include入main文件
    2. 1.2. 第三步,将两个文件带入cmakelist中