graph slam tutorial :從推導到應用3(g2o+ceres實現)

目錄

圖的數據格式  

讀取數據

使用g2o中slam2d數據格式的優化

優化結果

定義頂點和邊


 

我們不生產代碼,我們只是代碼的搬運工。


圖的數據格式  

圖優化前端處理以後產生的頂點和邊的數據格式,這是寫程序時特別關注的,也是衆多優化包如g2o的數據格式。

matlab程序及數據戳這裏

killian-v.dat 數據爲頂點vertex2: id,pose.x,pose.y,pose.theta 其中id表示位姿的序號,後面三個是位姿參數(如下所示)

VERTEX2 0 1.008240 -0.016781 0.005957
VERTEX2 1 2.090063 0.008002 0.015650
VERTEX2 2 3.117849 -0.027274 0.023100
VERTEX2 3 4.198081 0.087164 0.035227
VERTEX2 4 5.279355 0.111386 0.045086
VERTEX2 5 6.263466 0.126602 -0.005163
VERTEX2 6 7.283441 0.076036 -0.015700
VERTEX2 7 8.357930 0.058120 -0.015358
VERTEX2 8 9.390035 -0.012710 0.017520
VERTEX2 9 10.408369 -0.056070 -0.208266
VERTEX2 10 11.431652 -0.393503 -0.373306
VERTEX2 11 12.421098 -0.716382 -0.409338
VERTEX2 12 12.938025 -1.136982 -0.920065
VERTEX2 13 13.179887 -1.862584 -1.469585
VERTEX2 14 13.122046 -2.788254 -1.652690

killian-e.dat 數據爲 邊EDGE2: idFrom idTo mean.x mean.y mean.theta inf.xx inf.xy inf.xt inf.yy inf.yt  inf.tt 其中idfrom,idTo表示連接邊的兩個位姿頂點序號,mean.xytheta表示測量的位姿變換矩陣。inf表示邊的信息矩陣即權重。

EDGE2 1 0 -1.082078 -0.007851 -0.009693 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 2 1 -1.026697 0.059006 -0.007450 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 3 2 -1.083593 -0.076320 -0.012128 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 4 3 -1.081267 0.024536 -0.009858 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 5 4 -0.984019 -0.020296 0.050248 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 6 5 -1.020643 0.034546 0.010538 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 7 6 -1.074638 0.001413 -0.000343 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 8 7 -1.030705 0.088901 -0.032878 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 9 8 -1.005294 -0.168131 0.225786 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 10 9 -1.075867 -0.058994 0.165040 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 11 10 -1.036209 -0.097597 0.036032 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000
EDGE2 12 11 -0.647785 -0.156502 0.510727 20.000000 0.000000 20.000000 100000.000 0.000000 0.000000

讀取數據

讀取代碼很簡單,直接上代碼

if (!getline(fin, temp_line))
			break;
		sscanf_s(temp_line.c_str(), "VERTEX2 %d %lf %lf %lf",
			&vertexID, &vertexX, &vertexY, &vertexTheta);
		sVertex vertex;
		vertex.id = vertexID;
		vertex.vx = vertexX, vertex.vy = vertexY, vertex.vt = vertexTheta;

使用g2o中slam2d數據格式的優化

頂點g2o::VertexSE2

for (int i = 0; i < vecVertex.size(); i++)
	{
		g2o::VertexSE2* vertex = new g2o::VertexSE2;
		vertex->setId(i);
		if (i == 0)
			vertex->setFixed(true);
		vertex->setEstimate(g2o::SE2(vecVertex[i].vx, vecVertex[i].vy, vecVertex[i].vt));
		optimizer.addVertex(vertex);
	}

邊g2o::EdgeSE2

for (int i = 0; i < vecEdge.size(); i++)
	{
		sEdge e = vecEdge[i];
		g2o::EdgeSE2* edge = new g2o::EdgeSE2;
		edge->vertices()[0] = optimizer.vertex(e.from);
		edge->vertices()[1] = optimizer.vertex(e.to);
		edge->setMeasurement(g2o::SE2(e.mx, e.my, e.mt));
		Eigen::Matrix<double, 3, 3> information = Eigen::Matrix< double, 3, 3 >::Identity();
		information(0, 0) = e.infm1; information(1, 0) = information(0, 1) = e.infm2;
		information(1, 1) = e.infm3; information(2, 2) = e.infm4;
		information(0, 2) = information(2, 0) = e.infm5;
		information(2, 1) = information(1, 2) = e.infm6;
		edge->setInformation(information);
		optimizer.addEdge(edge);
	}

優化結果

g2o優化前

 g2o優化後

完整代碼戳這裏  

代碼裏默認使用稠密的增量方程,稀疏的增量方程也已經給出。稠密的增量方程運行太慢,建議使用稀疏的增量方程

這裏只是做了一個簡單的嘗試,也有一些取巧;後續準備自己定義頂點和邊,寫一個完整的優化。敬請期待。。。


定義頂點和邊

嘗試自定義頂點和邊,但是無法直接調用save("*.g2o")保存可供g2o_viewer觀看的數據了,還不知道爲什麼。做了個取巧的辦法,保存優化前後每個頂點的座標值,用matlab顯示效果如下。

update2019-11-07:g2o格式數據無法直接保存,(猜測)原因爲自定義頂點和邊,save函數並不能識別;可以自己仿照g2o內部格式,直接寫到文本里;也可以在頂點和邊裏實現read和write函數,然後直接write。(僅爲猜測,未去驗證)

由於還沒有理清楚,就先不寫出來了,後面理清楚了,會更新此博客。

利用ceres優化

代碼如下:

for (auto vec : vecEdge)
	{
		if (vec.from >= vecVertex.size() || vec.from < 0)
			std::cout << "Pose with ID: " << vec.from << " not found." << std::endl;
		if (vec.to >= vecVertex.size() || vec.to < 0)
			std::cout << "Pose with ID: " << vec.to << " not found." << std::endl;
		Eigen::Matrix3d sqrt_information = Eigen::Matrix3d::Identity();
		sqrt_information(0, 0) = vec.infm1; sqrt_information(1, 0) = sqrt_information(0, 1) = vec.infm2;
		sqrt_information(1, 1) = vec.infm3; sqrt_information(2, 2) = vec.infm4;
		sqrt_information(0, 2) = sqrt_information(2, 0) = vec.infm5;
		sqrt_information(2, 1) = sqrt_information(1, 2) = vec.infm6;
		ceres::CostFunction* cost_function = ceres::examples::PoseGraph2dErrorTerm::Create(
			vec.mx, vec.my, vec.mt, sqrt_information);
		problem.AddResidualBlock(
			cost_function, loss_function, &vecVertex[vec.from].vx,
			&vecVertex[vec.from].vy, &vecVertex[vec.from].vt,
			&vecVertex[vec.to].vx, &vecVertex[vec.to].vy,
			&vecVertex[vec.to].vt);
		problem.SetParameterization(&vecVertex[vec.from].vt,
			angle_local_parameterization);
		problem.SetParameterization(&vecVertex[vec.to].vt,
			angle_local_parameterization);
	}

生成結果如下:

 

對比g2o和ceres優化結果:

有些細微的差異,應該是跟參數配置有關。 


 參考:

https://blog.csdn.net/heyijia0327/article/details/47428553

https://github.com/versatran01/graphslam

http://www.dis.uniroma1.it/~grisetti/teaching/lectures-ls-slam-master/web/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章