当前位置:网站首页>Theory and practice of laser slam in dark blue College - Chapter 2 (odometer calibration)
Theory and practice of laser slam in dark blue College - Chapter 2 (odometer calibration)
2022-04-23 17:51:00 【ppipp1109】
direct method :
1. Job description :
-
This job is to use the direct linear method to correct the odometer of the robot .
-
The... Used in this operation bag data , Path is odom_ws/bag/odom.bag( It's too big , Not uploaded to github).
-
In this assignment , You need to implement three functions , Respectively :
-
main.cpp, The first 340 In a row cal_delta_distance() function , The function of this function is to give the position and attitude of two odometers , Calculate the pose difference between the two poses .
-
Odom_Calib.cpp, The first 23 That's ok Add_Data() function , The function of this function is to construct overdetermined equations Ax=b, Specific reference PPT.
-
Odom_Calib.cpp, The first 44 That's ok Solve() function , The function of this function is to 2 The overdetermined equations constructed in are solved .
2. The running process of this program is :
-
function launch file :roslaunch calib_odom odomCalib.launch.
-
stay 1 Under normal circumstances , function rviz,fix_frame Choose as odom_frame. stay Add Add three items to the tab Path news . A subscription topic by :odom_path_pub_; A subscription topic by :scan_path_pub_; The last one is :calib_path_pub_. Choose different colors .
-
Enter into odom_ws/bag Under the table of contents , Operation instruction :rosbag play - -clock odom.bag.( There is no space in the middle of the double horizontal line )
-
If everything goes well , You can see that the terminal running the correction program will print data , also rviz You can see two paths . When the printed data reaches a certain amount , Then you can start to correct .
-
The order of correction is , stay calib_flag Of topic Next data release :rostopic pub /calib_flag std_msgs/Empty “{}”.
-
After the program is corrected, the corresponding correction matrix will be output , And will be in rviz The third path is shown in , namely calib_path. You can observe the odometer path odom_path And correction path _calib_path To judge the effect of this correction .
3. result
4. Calibration results :
correct_matrix:
0.943991 0.133506 -0.000139669
-0.0142447 13.4325 0.000335469
0.000152577 40.2952 0.000234346
calibration over!!!!
5. Code :
cal_delta_distence function
// Solve the pose difference between the two frames of data
// That is to solve the current pose stay Last time Coordinates in a coordinate system
Eigen::Vector3d cal_delta_distence(Eigen::Vector3d odom_pose)
{
Eigen::Vector3d d_pos; //return value
now_pos = odom_pose;
//TODO:
// The way the vector rotates , Axis angle
d_pos = now_pos - last_pos;
Eigen::AngleAxisd temp(last_pos(2),Eigen::Vector3d(0,0,1));
Eigen::Matrix3d trans=temp.matrix().inverse();
d_pos = trans*d_pos;
last_pos = now_pos;
// Matrix method II
// Eigen::Matrix3d trans_temp;
// trans_temp<< cos(last_pos(2)), -sin(last_pos(2)), 0,
// sin(last_pos(2)), cos(last_pos(2)), 0,
// 0, 0, 1;
//
// d_pos = now_pos - last_pos;
// d_pos = trans_temp.transpose()*d_pos;
// last_pos = now_pos;
//end of TODO:
return d_pos;
}
Add_Data() function
The overdetermined equations needed to construct the least squares
Ax = b
*/
bool OdomCalib::Add_Data(Eigen::Vector3d Odom, Eigen::Vector3d scan)
{
if (now_len < INT_MAX) {
//TODO: Construct overdetermined equations
Eigen::Matrix<double,3,9> trans_a;
Eigen::Vector3d vector__b;
trans_a << Odom(0), Odom(1),Odom(2),0,0,0,0,0,0,
0,0,0,Odom(0), Odom(1),Odom(2),0,0,0,
0,0,0,0,0,0,Odom(0), Odom(1),Odom(2);
vector__b << scan(0),scan(1),scan(2);
// Give to the A and B
A.block<3,9>(3*now_len,0) = trans_a;
b.block<3,1>(3*now_len,0) = vector__b;
//end of TODO
now_len++;
return true;
} else {
return false;
}
}
Solve function , Generally, matrix decomposition is used , You can choose svd or QR Decomposition and other different ways , The difference was not significant .
Eigen::Matrix3d OdomCalib::Solve()
{
Eigen::Matrix3d correct_matrix;
//TODO: Solve linear least squares
// Eigen::Matrix<double, 9, 1> params;
// // params = (A.transpose() * A).inverse() * A.transpose() * b;
// params = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
// std::cout << params.transpose() << std::endl;
// for (size_t i = 0; i < 3; i++) {
// correct_matrix.block<1, 3>(i, 0) = params.block<3, 1>(i * 3, 0).transpose();
// }
Eigen::Matrix<double,9,1> X_ = A.colPivHouseholderQr().solve(b);
correct_matrix << X_(0),X_(1),X_(2),X_(3),X_(4),X_(5),X_(6),X_(7),X_(8);
//end of TODO
return correct_matrix;
}
A model-based approach :
Model form :
Code :
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
string scan_match_file = "./scan_match.txt";
string odom_file = "./odom.txt";
int main(int argc, char** argv)
{
// Time and matching value of placing lidar t_s s_x s_y s_th
vector<vector<double>> s_data;
// The time of placing the wheel speedometer and the angular speed of the left and right wheels t_r w_L w_R
vector<vector<double>> r_data;
ifstream fin_s(scan_match_file);
ifstream fin_r(odom_file);
if (!fin_s || !fin_r) {
cerr << " Please be there scan_match.txt and odom.txt Run this program in the directory of " << endl;
return 1;
}
// Read the matching value of lidar
while (!fin_s.eof()) {
double s_t, s_x, s_y, s_th;
fin_s >> s_t >> s_x >> s_y >> s_th;
s_data.push_back(vector<double>({ s_t, s_x, s_y, s_th }));
}
fin_s.close();
// Read the angular velocity of the two wheels
while (!fin_r.eof()) {
double t_r, w_L, w_R;
fin_r >> t_r >> w_L >> w_R;
r_data.push_back(vector<double>({ t_r, w_L, w_R }));
}
fin_r.close();
// First step : Calculate the intermediate variable J_21 and J_22
Eigen::MatrixXd A;
Eigen::VectorXd b;
// Set data length
A.conservativeResize(5000, 2);
b.conservativeResize(5000);
A.setZero();
b.setZero();
size_t id_r = 0;
size_t id_s = 0;
double last_rt = r_data[0][0];
double w_Lt = 0;
double w_Rt = 0;
while (id_s < 5000) {
// Laser matching information
const double& s_t = s_data[id_s][0];
const double& s_th = s_data[id_s][3];
// Odometer information
const double& r_t = r_data[id_r][0];
const double& w_L = r_data[id_r][1];
const double& w_R = r_data[id_r][2];
++id_r;
// stay 2 Carry out odometer angle integration within the frame laser matching time
if (r_t < s_t) {
double dt = r_t - last_rt;
w_Lt += w_L * dt;
w_Rt += w_R * dt;
last_rt = r_t;
} else {
double dt = s_t - last_rt;
w_Lt += w_L * dt;
w_Rt += w_R * dt;
last_rt = s_t;
// fill A, b matrix
//TODO: (3~5 lines)
A(id_s, 0) = w_Lt;
A(id_s, 1) = w_Rt;
b[id_s] = s_th;
//end of TODO
w_Lt = 0;
w_Rt = 0;
++id_s;
}
}
// Carry out the least square solution
Eigen::Vector2d J21J22;
//TODO: (1~2 lines)
J21J22 = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
// J21J22 = A.colPivHouseholderQr().solve(b);
//end of TODO
const double& J21 = J21J22(0);
const double& J22 = J21J22(1);
cout << "J21: " << J21 << endl;
cout << "J22: " << J22 << endl;
// The second step , Solving wheel spacing b
Eigen::VectorXd C;
Eigen::VectorXd S;
// Set data length
C.conservativeResize(10000);
S.conservativeResize(10000);
C.setZero();
S.setZero();
id_r = 0;
id_s = 0;
last_rt = r_data[0][0];
double th = 0;
double cx = 0;
double cy = 0;
while (id_s < 5000) {
// Laser matching information
const double& s_t = s_data[id_s][0];
const double& s_x = s_data[id_s][1];
const double& s_y = s_data[id_s][2];
// Odometer information
const double& r_t = r_data[id_r][0];
const double& w_L = r_data[id_r][1];
const double& w_R = r_data[id_r][2];
++id_r;
// stay 2 Odometer position integration is performed within the frame laser matching time
if (r_t < s_t) {
double dt = r_t - last_rt;
cx += 0.5 * (-J21 * w_L * dt + J22 * w_R * dt) * cos(th);
cy += 0.5 * (-J21 * w_L * dt + J22 * w_R * dt) * sin(th);
th += (J21 * w_L + J22 * w_R) * dt;
last_rt = r_t;
} else {
double dt = s_t - last_rt;
cx += 0.5 * (-J21 * w_L * dt + J22 * w_R * dt) * cos(th);
cy += 0.5 * (-J21 * w_L * dt + J22 * w_R * dt) * sin(th);
th += (J21 * w_L + J22 * w_R) * dt;
last_rt = s_t;
// fill C, S matrix
//TODO: (4~5 lines)
C[id_s * 2] = cx;
C[id_s * 2 + 1] = cy;
S[id_s * 2] = s_x;
S[id_s * 2 + 1] = s_y;
//end of TODO
cx = 0;
cy = 0;
th = 0;
++id_s;
}
}
// Carry out the least square solution , Calculation b, r_L, r_R
double b_wheel;
double r_L;
double r_R;
//TODO: (3~5 lines)
b_wheel = C.colPivHouseholderQr().solve(S)[0];
r_L = -J21 * b_wheel;
r_R = J22 * b_wheel;
//end of TODO
cout << "b: " << b_wheel << endl;
cout << "r_L: " << r_L << endl;
cout << "r_R: " << r_R << endl;
cout << " Refer to the answer : Wheel spacing b by 0.6m about , The radius of the two wheels is 0.1m about " << endl;
return 0;
}
Running results
J21: -0.163886
J22: 0.170575
b: 0.59796
r_L: 0.0979974
r_R: 0.101997
Refer to the answer : Wheel spacing b by 0.6m about , The radius of the two wheels is 0.1m about
cmakelist and odom.txt and scan_match.txt Follow up sorting and uploading
版权声明
本文为[ppipp1109]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230549076180.html
边栏推荐
- 剑指 Offer 22. 链表中倒数第k个节点-快慢指针
- 2022 judgment questions and answers for operation of refrigeration and air conditioning equipment
- 958. Complete binary tree test
- 209. 长度最小的子数组-滑动窗口
- Click Cancel to return to the previous page and modify the parameter value of the previous page, let pages = getcurrentpages() let prevpage = pages [pages. Length - 2] / / the data of the previous pag
- Leak detection and vacancy filling (VII)
- 122. 买卖股票的最佳时机 II-一次遍历
- 古代埃及希腊,数学用的什么进制
- 超分之TDAN
- Add animation to the picture under V-for timing
猜你喜欢
Learning record of uni app dark horse yougou project (Part 2)
958. Complete binary tree test
高德地图搜索、拖拽 查询地址
Comparison between xtask and kotlin coroutine
470. Rand10() is implemented with rand7()
Cross domain settings of Chrome browser -- including new and old versions
Compare the performance of query based on the number of paging data that meet the query conditions
Element calculation distance and event object
394. String decoding - auxiliary stack
为什么有些人说单片机简单,我学起来这么吃力?
随机推荐
Detailed deployment of flask project
[appium] write scripts by designing Keyword Driven files
Compare the performance of query based on the number of paging data that meet the query conditions
常用SQL语句总结
Uniapp custom search box adaptation applet alignment capsule
Land cover / use data product download
Chrome浏览器的跨域设置----包含新老版本两种设置
394. 字符串解码-辅助栈
vite配置proxy代理解决跨域
Click Cancel to return to the previous page and modify the parameter value of the previous page, let pages = getcurrentpages() let prevpage = pages [pages. Length - 2] / / the data of the previous pag
20222 return to the workplace
列錶的使用-增删改查
ES6 new method
The ultimate experience, the audio and video technology behind the tiktok
给 el-dialog 增加拖拽功能
01 - get to know the advantages of sketch sketch
Vite configure proxy proxy to solve cross domain
Kubernetes 服务发现 监控Endpoints
The method of changing a value in the array and a value in the object of wechat applet
云原生虚拟化:基于 Kubevirt 构建边缘计算实例