Skip to content

Commit 60db1ae

Browse files
committed
code for comparing with GT
1 parent 461d05e commit 60db1ae

6 files changed

Lines changed: 200 additions & 12 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ add_executable( keyframe_pose_graph_slam
6868
src/VizPoseGraph.cpp
6969
src/utils/PoseManipUtils.cpp
7070
src/utils/RosMarkerUtils.cpp
71+
src/utils/RawFileIO.cpp
7172
src/Worlds.cpp
7273
)
7374

src/NodeDataManager.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ worlds_handle_raw_ptr = new Worlds();
1818

1919
}
2020

21-
22-
2321
void NodeDataManager::camera_pose_callback( const nav_msgs::Odometry::ConstPtr& msg )
2422
{
2523
// ROS_INFO( "NodeDataManager::camera_pose_callback");
@@ -221,7 +219,7 @@ void NodeDataManager::print_nodes_lengths() const
221219
/////////////////////// Utility
222220
// Loop over each node and return the index of the node which is clossest to the specified stamp
223221
// This function is not thread-safe. You need to assure thread safety yourself for this.
224-
int NodeDataManager::find_indexof_node( const vector<ros::Time>& global_nodes_stamps, const ros::Time& stamp )
222+
int NodeDataManager::find_indexof_node( const vector<ros::Time>& global_nodes_stamps, const ros::Time& stamp ) const
225223
{
226224
ros::Duration diff;
227225
// cout << "find stamp=" << std::setprecision(20) << stamp.toSec();

src/NodeDataManager.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <visualization_msgs/Marker.h>
4545
#include <std_msgs/ColorRGBA.h>
4646
#include <std_msgs/Bool.h>
47+
#include <geometry_msgs/PointStamped.h>
4748

4849
#include <Eigen/Dense>
4950
#include <Eigen/Geometry>
@@ -131,7 +132,7 @@ class NodeDataManager
131132

132133

133134
// Utilities
134-
int find_indexof_node( const vector<ros::Time>& global_nodes_stamps, const ros::Time& stamp );
135+
int find_indexof_node( const vector<ros::Time>& global_nodes_stamps, const ros::Time& stamp ) const;
135136

136137
// void _print_info_on_npyarray( const cnpy::NpyArray& arr );
137138

src/PoseGraphSLAM.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,20 +1357,20 @@ bool PoseGraphSLAM::saveAsJSON(const string base_path)
13571357
// #define __reint_odom_cout(msg) msg;
13581358
#define __reint_odom_cout(msg) ;
13591359

1360-
#define __reinit_loopedge_cout( msg ) msg;
1361-
// #define __reinit_loopedge_cout( msg ) ;
1360+
// #define __reinit_loopedge_cout( msg ) msg;
1361+
#define __reinit_loopedge_cout( msg ) ;
13621362

13631363

1364-
#define __reint_gueses_short_info(msg) msg;
1365-
// #define __reint_gueses_short_info(msg) ;
1364+
// #define __reint_gueses_short_info(msg) msg;
1365+
#define __reint_gueses_short_info(msg) ;
13661366

13671367

13681368
// Print info on node regularization. I use node regularization to set
13691369
// the start of each worlds as constant. You can tune this as need be.
13701370
// The reason I do not use ceres::SetParameterBlockConstant() is that it cannot be
13711371
// set to not constant which hinders when the initial guess moves.
1372-
#define __reint_node_regularization_info( msg ) msg;
1373-
// #define __reint_node_regularization_info( msg ) ;
1372+
// #define __reint_node_regularization_info( msg ) msg;
1373+
#define __reint_node_regularization_info( msg ) ;
13741374

13751375

13761376
// Print Ceres Brief Report and other info on solving
@@ -1911,7 +1911,7 @@ void PoseGraphSLAM::reinit_ceres_problem_onnewloopedge_optimize6DOF()
19111911
// Functionally similar to marking it as constant
19121912
double regularization_weight = max( 1.1, log( 1+ww_end - ww_start )/2. );
19131913

1914-
for( int s=0; s<3 ; s++ )
1914+
for( int s=0; s<1 ; s++ )
19151915
{
19161916
__reint_node_regularization_info( cout << "s="<< s << " "; )
19171917
Matrix4d ww_start_pose = this->getNodePose(ww_start+s);

src/PoseGraphSLAM.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ class SixDOFErrorWithSwitchingConstraints
369369
residuals.block(3,0, 3,1) = T(2.0) * delta_q.vec();
370370
residuals(6) = T(1.0) * ( T(1.0) - switching_var[0] ); //switching constraint penalty
371371

372+
// pitch and roll aka residuals(5) and residuals(4) are observable witht he IMU, so
373+
// increase the penalty for changing those. This will make them to be nearer to initial estimates.
374+
// residuals(4) *= T(5.);
375+
// residuals(5) *= T(5.);
372376

373377

374378
T s = switching_var[0];

src/keyframe_pose_graph_slam_node.cpp

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ using namespace Eigen;
5555
#include "NodeDataManager.h"
5656
#include "PoseGraphSLAM.h"
5757
#include "VizPoseGraph.h"
58+
#include "utils/RawFileIO.h"
5859

5960
void periodic_print_len( const NodeDataManager * manager )
6061
{
@@ -352,6 +353,35 @@ void monitor_disjoint_set_datastructure( const NodeDataManager * manager, const
352353
}
353354

354355

356+
357+
// set this to 0 to remove the gt code
358+
#define __CODE___GT__ 0
359+
///////////////////
360+
#if __CODE___GT__
361+
std::map< ros::Time, Vector3d > gt_map;
362+
void ground_truth_callback( const geometry_msgs::PointStamped::ConstPtr msg )
363+
{
364+
cout << TermColor::YELLOW() << "ground_truth_callback " << msg->header.stamp;
365+
cout << "\t" << msg->point.x << ", " << msg->point.y << ", "<< msg->point.z << " ";
366+
cout << TermColor::RESET() << endl;
367+
368+
gt_map[ msg->header.stamp ] = Vector3d( msg->point.x , msg->point.y , msg->point.z );
369+
}
370+
371+
372+
struct assoc_s
373+
{
374+
ros::Time node_timestamp;
375+
Matrix4d corrected_pose;
376+
Matrix4d vio_pose;
377+
378+
Vector3d gt_pose;
379+
ros::Time gt_pose_timestamp;
380+
};
381+
/////////////////////
382+
#endif
383+
384+
355385
// plots the corrected trajectories, different worlds will have different colored lines
356386

357387
#define opt_traj_publisher_colored_by_world_LINE_COLOR_STYLE 10 //< color the line with worldID
@@ -389,6 +419,7 @@ void opt_traj_publisher_colored_by_world( const NodeDataManager * manager, const
389419
// ros::Rate loop_rate(5);
390420
map<int, vector<Matrix4d> > jmb;
391421
vector< Vector3d > lbm; // a corrected poses. Same index as the node. These are used for loopedges.
422+
vector< Matrix4d > lbm_fullpose;
392423
bool published_axis = true;
393424
while( ros::ok() )
394425
{
@@ -402,6 +433,7 @@ void opt_traj_publisher_colored_by_world( const NodeDataManager * manager, const
402433
//clear map
403434
jmb.clear();
404435
lbm.clear();
436+
lbm_fullpose.clear();
405437

406438
// cerr << "[opt_traj_publisher_colored_by_world]i=0 ; i<"<< manager->getNodeLen() << " ; solvedUntil=" << slam->solvedUntil() <<"\n";
407439
int latest_pose_worldid = -1;
@@ -478,6 +510,7 @@ void opt_traj_publisher_colored_by_world( const NodeDataManager * manager, const
478510

479511
jmb[ world_id ].push_back( w_T_c );
480512
lbm.push_back( w_T_c.col(3).topRows(3) );
513+
lbm_fullpose.push_back( w_T_c );
481514
latest_pose_worldid = world_id;
482515

483516
#ifdef __opt_traj_publisher_colored_by_world___print_on_file_exist
@@ -545,6 +578,7 @@ void opt_traj_publisher_colored_by_world( const NodeDataManager * manager, const
545578

546579
jmb[ world_id ].push_back( w_TM_i );
547580
lbm.push_back( w_TM_i.col(3).topRows(3) );
581+
lbm_fullpose.push_back( w_TM_i );
548582
latest_pose_worldid = world_id;
549583

550584
#ifdef __opt_traj_publisher_colored_by_world___print_on_file_exist
@@ -659,6 +693,135 @@ void opt_traj_publisher_colored_by_world( const NodeDataManager * manager, const
659693
// cerr << "\nSLEEP\n";
660694
loop_rate.sleep();
661695
}
696+
697+
698+
#if __CODE___GT__
699+
700+
// Set this to 1 to enable loggin of final poses,
701+
#define __LOGGING___LBM__ 1
702+
#if __LOGGING___LBM__
703+
// Log LMB
704+
vector<assoc_s> _RESULT_;
705+
cout << "========[opt_traj_publisher_colored_by_world] logging ========\n";
706+
cout << "loop on gt_map\n";
707+
int _gt_map_i = 0;
708+
//---a
709+
for( auto it=gt_map.begin() ; it!= gt_map.end() ; it++ ) {
710+
cout << _gt_map_i++ << " : " << it->first << " : " << (it->second).transpose() << endl;
711+
}
712+
713+
///---b
714+
cout << "loop on lbm lbm.size() = " << lbm.size() << " lbm_fullpose.size= "<< lbm_fullpose.size() <<"\n";
715+
assert( lbm.size() == lbm_fullpose.size() );
716+
for( auto k=0 ; k<lbm.size() ; k++ ) {
717+
ros::Time _t = manager->getNodeTimestamp(k);
718+
Matrix4d _viopose = manager->getNodePose(k);
719+
cout << k << ": " << _t << ": "<< lbm[k].transpose() << "\t" ;
720+
cout << PoseManipUtils::prettyprintMatrix4d(lbm_fullpose[k]) << endl;
721+
722+
723+
assoc_s tmp;
724+
tmp.corrected_pose = lbm_fullpose[k];
725+
tmp.vio_pose = _viopose;
726+
tmp.node_timestamp = _t;
727+
728+
729+
//---------------
730+
// loop through gt_map and find the gt_pose at this t.
731+
// search for `_t` in gt_map.
732+
{
733+
cout << "\tsearch for `_t`= "<< _t << " in gt_map.\n";
734+
int it_i = -1;
735+
ros::Duration smallest_diff = ros::Duration( 100000 );
736+
int smallest_diff_i = -1;
737+
auto gt_map_iterator = gt_map.begin();
738+
bool found = false;
739+
for( auto it=gt_map.begin() ; it!= gt_map.end() ; it++ ) {
740+
it_i++;
741+
ros::Duration diff = it->first - _t;
742+
if( diff.sec < 0 ) { diff.sec = - diff.sec; diff.nsec = 1000000000 - diff.nsec; }
743+
// cout << "\t\tit_i=" << it_i << " diff=" << diff.sec << " " << diff.nsec << " >>>>>> smallest_diff_i=" << smallest_diff_i << endl;
744+
745+
if( diff.sec < smallest_diff.sec || (diff.sec == smallest_diff.sec && abs(diff.nsec) < abs(smallest_diff.nsec) ) ) {
746+
smallest_diff = diff;
747+
smallest_diff_i = it_i;
748+
gt_map_iterator = it;
749+
}
750+
if( (diff.sec == 0 && abs(diff.nsec) < 10000000) || (diff.sec == -1 && diff.nsec > (1000000000-10000000) ) ) {
751+
// cout << "NodeDataManager::find_indexof_node " << i << " "<< diff.sec << " " << diff.nsec << endl
752+
cout << TermColor::GREEN() << "\tfound " << it->first << " at idx=" << it_i << endl << TermColor::RESET();
753+
found = true;
754+
755+
tmp.gt_pose_timestamp = it->first;
756+
tmp.gt_pose = it->second;
757+
break;
758+
}
759+
760+
}
761+
762+
if( found == false ) {
763+
cout << TermColor::RED() << "\tNOT found, however, smallest_diff=" << smallest_diff << " at idx="<< smallest_diff_i;
764+
cout << endl << TermColor::RESET();
765+
tmp.gt_pose_timestamp = gt_map_iterator->first;
766+
tmp.gt_pose = gt_map_iterator->second;
767+
}
768+
}
769+
//---------
770+
// END of search onn gt_map
771+
//---------
772+
773+
774+
775+
// Result:"
776+
_RESULT_.push_back( tmp );
777+
cout << TermColor::CYAN() << "Result: \n";
778+
cout << "node_timestamp " << tmp.node_timestamp << endl;
779+
cout << "gt_pose_timestamp " << tmp.gt_pose_timestamp << endl;
780+
cout << "gt_pose " << (tmp.gt_pose).transpose() << endl;
781+
cout << "vio_pose " << PoseManipUtils::prettyprintMatrix4d(tmp.vio_pose) << endl;
782+
cout << "corrected_pose " << PoseManipUtils::prettyprintMatrix4d(tmp.corrected_pose) << endl;
783+
cout << TermColor::RESET();
784+
785+
}
786+
787+
788+
// write CSV:
789+
std::stringstream buffer_gt;
790+
std::stringstream buffer_corrected;
791+
std::stringstream buffer_vio;
792+
793+
for( int j=0 ; j<_RESULT_.size() ; j++ )
794+
{
795+
// stamp, tx, ty, tz
796+
buffer_gt << long(_RESULT_[j].node_timestamp.toSec() * 1E9) << "," << _RESULT_[j].gt_pose(0) << "," << _RESULT_[j].gt_pose(1)<< "," << _RESULT_[j].gt_pose(2) <<endl;
797+
798+
799+
// stamp, tx, ty, tz, qw, qx, qy, qz
800+
buffer_corrected << long(_RESULT_[j].node_timestamp.toSec() * 1E9) << "," << _RESULT_[j].corrected_pose(0,3) << "," << _RESULT_[j].corrected_pose(1,3)<< "," << _RESULT_[j].corrected_pose(2,3) << ",";
801+
Matrix3d __R = _RESULT_[j].corrected_pose.topLeftCorner(3,3);
802+
Quaterniond quat( __R );
803+
buffer_corrected << quat.w() << "," << quat.x() << ","<< quat.y() << "," << quat.z() << endl;
804+
805+
806+
buffer_vio << long(_RESULT_[j].node_timestamp.toSec() * 1E9) << "," << _RESULT_[j].vio_pose(0,3) << "," << _RESULT_[j].vio_pose(1,3)<< "," << _RESULT_[j].vio_pose(2,3) << ",";
807+
Matrix3d __R2 = _RESULT_[j].vio_pose.topLeftCorner(3,3);
808+
Quaterniond quat2( __R );
809+
buffer_vio << quat2.w() << "," << quat2.x() << ","<< quat2.y() << "," << quat2.z() << endl;
810+
}
811+
const string DATA_PATH = "/Bulk_Data/_tmp_posegraph/";
812+
RawFileIO::write_string( DATA_PATH+"/gt.csv", buffer_gt.str() );
813+
RawFileIO::write_string( DATA_PATH+"/corrected.csv", buffer_corrected.str() );
814+
RawFileIO::write_string( DATA_PATH+"/vio_pose.csv", buffer_vio.str() );
815+
816+
817+
818+
#endif // __LOGGING___LBM__
819+
820+
#endif //__CODE___GT__
821+
822+
823+
824+
662825
}
663826

664827

@@ -685,14 +848,23 @@ int main( int argc, char ** argv)
685848
ros::Subscriber sub_loopclosure = nh.subscribe( loopclosure_camera_rel_pose_topic, 1000, &NodeDataManager::loopclosure_pose_callback, manager );
686849

687850

688-
//-- TODO: Also subscribe to tracked features to know if I have been kidnaped.
851+
//-- subscribe to tracked features to know if I have been kidnaped. --//
689852
// False indicates -> I got kidnapped now
690853
// True indicates --> I got unkidnapped.
691854
string rcvd_kidnap_indicator_topic = string( "/feature_tracker/rcvd_flag_header" );
692855
ROS_INFO( "Subscribed to kidnap_indicator aka %s", rcvd_kidnap_indicator_topic.c_str() );
693856
ros::Subscriber sub_kidnap_indicator = nh.subscribe( rcvd_kidnap_indicator_topic, 100, &NodeDataManager::rcvd_kidnap_indicator_callback, manager );
694857

695858

859+
#if __CODE___GT__
860+
//--- ground_truth_callback. Sometimes bags may contain GT data, ---//
861+
// this will associate the GT data to the pose graph for analysis.
862+
string ground_truth_topic = string( "/leica/position" );
863+
ROS_INFO( "Subscribed to ground_truth_topic: %s", ground_truth_topic.c_str() );
864+
ros::Subscriber sub_gt_ = nh.subscribe( ground_truth_topic, 100, ground_truth_callback );
865+
#endif
866+
867+
696868

697869
// Setup publishers
698870
//--- Marker ---//
@@ -773,6 +945,18 @@ int main( int argc, char ** argv)
773945

774946
#define __LOGGING__ 0 // make this 1 to enable logging. 0 to disable logging. rememeber to catkin_make after this change
775947
#if __LOGGING__
948+
// Note: If using roslaunch to launch this node and when LOGGING is enabled,
949+
// roslaunch sends a sigterm and kills this thread when ros::ok() returns false ie.
950+
// when you press CTRL+C. The timeout is governed by roslaunch.
951+
//
952+
// If you wish to increase this timeout, you need to edit "/opt/ros/kinetic/lib/python2.7/dist-packages/roslaunch/nodeprocess.py"
953+
// then edit these two vars.
954+
// _TIMEOUT_SIGINT = 15.0 #seconds
955+
// _TIMEOUT_SIGTERM = 2.0 #seconds
956+
// ^^^^ Borrowed from : https://answers.ros.org/question/11353/how-to-delay-escalation-to-sig-term-after-sending-sig-int-to-roslaunch/
957+
958+
959+
776960
///// Save Pose Graph for Debugging
777961
const string DATA_PATH = "/Bulk_Data/_tmp_posegraph/";
778962

0 commit comments

Comments
 (0)