Lidar-Imu聯合標定工具lidar_align的數據接口改寫


  最近在做Lidar和imu的聯合標定,即通過算法給出安裝完成后Lidar和imu間的相對位姿(平移和旋轉)。使用github上的lidar_align標定工具。在參考博文https://blog.csdn.net/miracle629/article/details/87854450后,發現自己錄制的數據包中沒有lidar_align需要用到的geometry_msgs/TransformStamped數據類型。博文作者給出的方法:1、建議直接使用rosbag方式讀入數據,對於不發布TransformStamped類型數據的程序,只要稍微改動數據接口的幾處函數(全部在loader.cpp文件中)便可以正常使用。博文下的評論中還提供了另外兩種思路:2、自己寫一個ros節點,訂閱IMU的topic,把message里面的內容,重新按照geometry_msgs/TransformStamped 的格式賦值一遍,重新發布一次topic。3、不轉格式,可以存一個csv文件,把6dof姿態存下來。

  首先需要安裝nlopt非線性優化庫,報錯:could not find a package configuration file provided by "Nlopt" with any of: NloptConfig.cmake。博文的評論中將 NLOPTConfig.cmake 移到 catkin_ws/src 文件下的方法可行。搜到另外一種方法也可行:即讓系統按照Module模式進行查找,把nlopt/build下的NloptConfig.cmake文件重命名為FindNlopt.cmake,在CMakeLists.txt中添加set(CMAKE_MODULE_PATH /home/hjh/nlopt/build)。

  嘗試方法3,把imu話題保存到imu.csv文件中。運行命令$rostopic echo -b map.bag -p /imu/data >imu.csv ,這里的map.bag是我自己錄的rosbag。再改寫launch文件中的數據包路徑。運行失敗。查看csv文件后發現imu沒提供x,y,z三個軸上的位置變換。

  嘗試方法2,訂閱sensor_msgs/Imu,處理,發布geometry_msgs/TransformStamped。imu和TransformStamped的消息類型分別如下:

 1 #include "ros/ros.h"
 2 #include "sensor_msgs/Imu.h"
 3 #include "geometry_msgs/TransformStamped.h"
 4 #include "std_msgs/Time.h"
 5 #include "std_msgs/Float64.h"
 6 double shiftX=0,shiftY=0,shiftZ=0,velX=0,velY=0,velZ=0;
 7 class SubscribeAndPublish
 8 {
 9 public:
10     SubscribeAndPublish()
11     {
12         pub=n_.advertise<geometry_msgs::TransformStamped>("/geometry_msgs/TransformStamped",1);
13         sub_=n.subscribe("/imu/data",1,&SubscribeAndPublish::callback,this);
14     }
15     void callback(const sensor_msgs::Imu::ConstPtr& input)
16     {    
17         geometry_msgs::TransformStamped output;
18         if(firstT){
19             time=input->header.stamp;
20             timeDiff=0;
21             output.transform.rotation.x=input->orientation.x;
22             output.transform.rotation.y=input->orientation.y;
23             output.transform.rotation.z=input->orientation.z;
24             output.transform.rotation.w=input->orientation.w;            
25             firstT=false;
26         }
27         else{
28             output.header=input->header;
29 
30             output.transform.rotation.x=input->orientation.x;
31             output.transform.rotation.y=input->orientation.y;
32             output.transform.rotation.z=input->orientation.z;
33             output.transform.rotation.w=input->orientation.w;
34 
35             timeDiff=(input->header.stamp-time).toSec();
36             time=input->header.stamp;
37 
38             velX=velX+input->linear_acceleration.x*timeDiff;
39             velY=velX+input->linear_acceleration.y*timeDiff;
40             velZ=velZ+(input->linear_acceleration.z-9.801)*timeDiff;
41         
42             lastShiftX=shiftX;
43             lastShiftY=shiftY;
44             lastShiftZ=shiftZ;
45             shiftX=lastShiftX+velX*timeDiff+input->linear_acceleration.x*timeDiff*timeDiff/2;
46             shiftY=lastShiftY+velY*timeDiff+input->linear_acceleration.y*timeDiff*timeDiff/2;
47             shiftZ=lastShiftZ+velZ*timeDiff+(input->linear_acceleration.z-9.801)*timeDiff*timeDiff/2;
48 
49             output.transform.translation.x=lastShiftX+shiftX;
50             output.transform.translation.y=lastShiftY+shiftY;
51             output.transform.translation.z=lastShiftZ+shiftZ;
52             pub_.publish(output);
53         }
54     }
55 private:
56     ros::NodeHandle n_;
57     ros::Publisher pub_;
58     ros::Subscriber sub_;
59     ros::Time time;
60     double timeDiff,lastShiftX,lastShiftY,lastShiftZ;
61     bool firstT=true;
62 };
63 int main(int argc,char **argv)
64 {
65     ros::init(argc,argv,"subscribe_and_publish");
66     SubscribeAndPublish SAP;
67     ros::spin();
68     return 0;
69 }

編譯通過后再次運行失敗。報錯:No odom messages found. Error loading transforms from ROS bag.

嘗試方法1:看源碼。發現數據都應該從 bag中導入,前兩種方法方向錯了。修改loader.cpp文件

 1   std::vector<std::string> types;
 2   types.push_back(std::string("sensor_msgs/Imu"));
 3   rosbag::View view(bag, rosbag::TypeQuery(types));
 4   size_t imu_num = 0;
 5   double shiftX=0,shiftY=0,shiftZ=0,velX=0,velY=0,velZ=0;
 6   ros::Time time;
 7   double timeDiff,lastShiftX,lastShiftY,lastShiftZ;
 8   for (const rosbag::MessageInstance& m : view){
 9     std::cout <<"Loading imu: \e[1m"<< imu_num++<<"\e[0m from ros bag"<<'\r'<< std::flush;
10 
11     sensor_msgs::Imu imu=*(m.instantiate<sensor_msgs::Imu>());
12 
13     Timestamp stamp = imu.header.stamp.sec * 1000000ll +imu.header.stamp.nsec / 1000ll;
14     if(imu_num==1){
15         time=imu.header.stamp;
16             Transform T(Transform::Translation(0,0,0),Transform::Rotation(1,0,0,0));
17         odom->addTransformData(stamp, T);
18     }
19     else{
20         timeDiff=(imu.header.stamp-time).toSec();
21         time=imu.header.stamp;
22         velX=velX+imu.linear_acceleration.x*timeDiff;
23         velY=velX+imu.linear_acceleration.y*timeDiff;
24         velZ=velZ+(imu.linear_acceleration.z-9.801)*timeDiff;
25         
26         lastShiftX=shiftX;
27         lastShiftY=shiftY;
28         lastShiftZ=shiftZ;
29         shiftX=lastShiftX+velX*timeDiff+imu.linear_acceleration.x*timeDiff*timeDiff/2;
30         shiftY=lastShiftY+velY*timeDiff+imu.linear_acceleration.y*timeDiff*timeDiff/2;
31         shiftZ=lastShiftZ+velZ*timeDiff+(imu.linear_acceleration.z-9.801)*timeDiff*timeDiff/2;
32 
33         Transform T(Transform::Translation(shiftX,shiftY,shiftZ),
34                Transform::Rotation(imu.orientation.w,
35                         imu.orientation.x,
36                         imu.orientation.y,
37                         imu.orientation.z));
38         odom->addTransformData(stamp, T);
39     }
40   }

編譯運行成功,輸出變換矩陣。以后處理rosbag時可以參考loader.cpp的方法,作者的代碼功力挺強。

  如果要提高標定的精度需要做的改進:錄制變化幅度較大的rosbag。

  做這個做了將近一個禮拜,記錄些心得體會。1、傳感器方面,對於imu加深了理解。2、rosbag和ros中消息的訂閱與發布。3、提高C++編程能力果然還是得靠手撕源碼的能力!

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM