cartographer建图过程中,当json文件中map_builder_save属性的value置1,即接收到地图保存信号时,应实现结束建图且保存地图,同时将map_builder_save置0。保存地图完成后,将map_builder_exit置1,即发出结束建图进程的信号。对cartographer_ros源码做修改,新建监听json文件的线程,当json文件内容发生改变时,做出相应处理。
因为不需要对json文件进行深层次的处理,仅需查询和修改的功能。我选取了rapidjson作为c++处理json文件的工具。rapidjson是全头文件包含的,使用简单;而jsoncpp需要内置编译或库编译,我花费比较长时间也没成功将其应用于手头工程。从github上下载rapidjson代码,将/include/rapidjson放入工程中即可在头文件中引用,再一起编译即可。rapidjson的github链接:https://github.com/Tencent/rapidjson 。
对mode_main.cc的修改如下:
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
...
using namespace rapidjson;
using std::string;
...
namespace cartographer_ros {
namespace {
int save_signal = 0;
std::string json_filepath = "/home/cabin/Desktop/remote_communication/task_state.json";
...
void modify_json(int m_value){
rapidjson::Document m_newDoc;
char m_readbuffer[6556];
FILE* m_myFile = fopen(json_filepath.c_str(),"r");
FileReadStream m_frs(m_myFile,m_readbuffer,sizeof(m_readbuffer));
m_newDoc.ParseStream(m_frs);
fclose(m_myFile);
if( 0 == m_value ){
m_newDoc["map_builder"]["map_builder_save"] = 0;
}
else {
m_newDoc["map_builder"]["map_builder_exit"] = 1;
}
StringBuffer writebuffer;
Writer<StringBuffer> writer(writebuffer);
m_newDoc.Accept(writer);
std::string strJson(writebuffer.GetString(),writebuffer.GetSize());
std::ofstream outfile;
outfile.open(json_filepath.c_str());
outfile<<strJson;
outfile.close();
}
...
}}
modify_json(0)即将json文件中的map_build.map_build_save修改为0;modify_json(1)即将json文件中的map_build.map_build_exit修改为1。实际上对json文件的处理可以写得更灵活,更模块化,比如void modified_json(jsonpath,key,value)形式,即将jsonpath路径下的json文件中的key修改为value。按实际工程上述的写法已经满足需求。
namespace cartographer_ros{
namespace{
...
void sub_save_signal_thread(){
rapidjson::Document newDoc;
char readbuffer[6556];
while(1){
ros::Duration(1).sleep();
FILE* myFile = fopen(json_filepath.c_str(),"r");
FileReadStream frs(myFile,readbuffer,sizeof(readbuffer));
newDoc.ParseStream(frs);
fclose(myFile);
save_signal = newDoc["map_builder"]["map_builder_save"].GetInt();
}
}
...
}
}
监听json文件的线程,将json文件的map_builder_save的值赋予全局变量save_signal。注意对json文件的监听时,不能读取频率太高,应设一个时延,否则会报错。
namespace cartographer_ros{
namespace{
void Run(){
...
capture_input_id_ = new std::thread(&CaptureInputThread);
sub_save_signal_thread_id = new std::thread(&sub_save_signal_thread);
...
while(ros::ok()){
::ros::spinOnce();
if(1 == save_signal){
modify_json(0);
ros::Duration(2).sleep();
node.FinishAllTrajectories();
node.RunFinalOptimization();
if(node_options.flag_generate_pbstream_map){
time_t now;
struct tm *timenow;
time(&now);
timenow = localtime(&now);
char time_now_str[100];
strftime(time_now_str, 100, "%Y%m%d%H%M%S", timenow);
string time_now = time_now_str;
const string pbstream_filename_ = "/home/cabin/cartographer_map_file/"+time_now+".pbstream";
const string pgm_filename_ = "/home/cabin/cartographer_map_file/"+time_now;
node.SerializeState(pbstream_filename_);
Pbstream_to_ros_map pbstream_to_ros_map;
std::cout<<"generating the map files, please wait ..."<<&std::endl;
pbstream_to_ros_map.pgm_map_build(pbstream_filename_, pgm_filename_,0.05);
generate_map_flag = '\0';
std::cout<<"\n=====================map generate finished=============================\n"<<&std::endl;
modify_json(1);
} }
...
}
}
}
}
实现开头描述的功能。建图过程中监听map_builder_save,当其为1时,将其修改为0,结束建图且保存地图,将map_builder_exit修改为1。