(本文适合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 (); output.open ("namedParam.cpp" ); output << "#include \"namedParam.h\"" << endl; output << endl; output << "void makeNamedParams(map<string, string> &namedParams){" << endl; infile.open ("defaultParams.txt" , ifstream::in); run (); output << "}" << endl; 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 ()) { 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 ; } stringstream s (str) ; std::string key; std::string value; std::getline (s, key, '\t' ); std::getline (s, value); 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 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 里面 最后,编译并运行就完成了