Skip to content

Commit b43f936

Browse files
committed
implemented a 4DOF workaround using quaternion, now implementing a real 4DOF
1 parent e5bf9e3 commit b43f936

5 files changed

Lines changed: 213 additions & 19 deletions

File tree

src/PoseGraphSLAM.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,6 @@ bool PoseGraphSLAM::nodePoseExists( int i ) const //< returns if ith node pose e
111111

112112
}
113113

114-
bool PoseGraphSLAM::nodePoseExists__nolock( int i ) const //< returns if ith node pose exist
115-
{
116-
#if defined(___OPT_AS_DOUBLE_STAR )
117-
// std::lock_guard<std::mutex> lk(mutex_opt_vars);
118-
if( i>= 0 && i<_opt_len_ )
119-
return true;
120-
return false;
121-
#else
122-
// std::lock_guard<std::mutex> lk(mutex_opt_vars);
123-
if( i>=0 && i <opt_quat.size() )
124-
return true;
125-
return false;
126-
#endif
127-
128-
}
129-
130114
void PoseGraphSLAM::allocate_and_append_new_opt_variable_withpose( const Matrix4d& pose )
131115
{
132116
#if defined(___OPT_AS_DOUBLE_STAR )
@@ -1662,6 +1646,7 @@ void PoseGraphSLAM::reinit_ceres_problem_onnewloopedge_optimize6DOF()
16621646

16631647
// simply add edge residue
16641648
ceres::CostFunction * cost_function = SixDOFErrorWithSwitchingConstraints::Create( bTa, weight );
1649+
// ceres::CostFunction * cost_function = FourDOFErrorWithSwitchingConstraints::Create( bTa, weight );
16651650
reint_problem.AddResidualBlock( cost_function, NULL,
16661651
get_raw_ptr_to_opt_variable_q(paur.second), get_raw_ptr_to_opt_variable_t(paur.second),
16671652
get_raw_ptr_to_opt_variable_q(paur.first), get_raw_ptr_to_opt_variable_t(paur.first),
@@ -1719,6 +1704,7 @@ void PoseGraphSLAM::reinit_ceres_problem_onnewloopedge_optimize6DOF()
17191704

17201705
// cost
17211706
ceres::CostFunction * cost_function = SixDOFError::Create( u_M_umf, odom_edge_weight );
1707+
// ceres::CostFunction * cost_function = FourDOFError::Create( u_M_umf, odom_edge_weight );
17221708
reint_problem.AddResidualBlock( cost_function, NULL,
17231709
get_raw_ptr_to_opt_variable_q(u), get_raw_ptr_to_opt_variable_t(u),
17241710
get_raw_ptr_to_opt_variable_q(u-f), get_raw_ptr_to_opt_variable_t(u-f) );

src/PoseGraphSLAM.h

Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ class PoseGraphSLAM
9797
// Get the optimized pose at node i. This function is thread-safe
9898
const Matrix4d getNodePose( int i ) const; //< this gives the pose from the optimization variable
9999
bool nodePoseExists( int i ) const; //< returns if ith node pose exist
100-
bool nodePoseExists__nolock( int i ) const; //< returns if ith node pose exist
101100
// bool getNodePose( int i, Matrix4d& ) const; //TODO: removal
102101
int nNodes() const;
103102
void getAllNodePose( vector<Matrix4d>& vec_w_T_ci ) const;
@@ -402,3 +401,201 @@ class SixDOFErrorWithSwitchingConstraints
402401

403402
double weight;
404403
};
404+
405+
406+
// output is in degrees
407+
template <typename T>
408+
Matrix<T,3,1> R2ypr( const Matrix<T,3,3>& R)
409+
{
410+
Matrix<T,3,1> n = R.col(0);
411+
Matrix<T,3,1> o = R.col(1);
412+
Matrix<T,3,1> a = R.col(2);
413+
414+
Matrix<T,3,1> ypr(3);
415+
T y = atan2(n(1), n(0));
416+
T p = atan2(-n(2), n(0) * cos(y) + n(1) * sin(y));
417+
T r = atan2(a(0) * sin(y) - a(1) * cos(y), -o(0) * sin(y) + o(1) * cos(y));
418+
ypr(0) = y;
419+
ypr(1) = p;
420+
ypr(2) = r;
421+
422+
return ypr / T(M_PI) * T(180.0);
423+
}
424+
425+
426+
427+
428+
429+
// In this residue function, internally we rely on the
430+
// Euler angle representation and not Quaternions as before.
431+
class FourDOFError
432+
{
433+
public:
434+
FourDOFError( const Matrix4d& _observed__c1_T_c2, const double _weight=1.0 ) : observed__c1_T_c2( _observed__c1_T_c2 )
435+
{
436+
// Convert c1_T_c2 to Euler Angle representation
437+
PoseManipUtils::eigenmat_to_rawyprt( _observed__c1_T_c2, observed_c1_ypr_c2, observed_c1_t_c2 );
438+
observed_c1_q_c2 = Quaterniond( _observed__c1_T_c2.topLeftCorner<3,3>() );
439+
440+
weight = _weight;
441+
}
442+
443+
// q1, t1 : w_T_c1
444+
// q2, t2 : w_T_c2
445+
template <typename T>
446+
bool operator() ( const T* const q1, const T* const t1,
447+
const T* const q2, const T* const t2,
448+
T* residue_ptr ) const
449+
{
450+
// Eigen:
451+
// Note the order of the arguments: the real w coefficient first,
452+
// while internally the coefficients are stored in the following order: [x, y, z, w]
453+
454+
// q1,t1 --> w_T_c1
455+
Eigen::Map<const Eigen::Matrix<T,3,1> > p_1( t1 );
456+
Eigen::Map<const Eigen::Quaternion<T> > q_1( q1 );
457+
458+
// q2,t2 --> w_T_c2
459+
Eigen::Map<const Eigen::Matrix<T,3,1> > p_2( t2 );
460+
Eigen::Map<const Eigen::Quaternion<T> > q_2( q2 );
461+
462+
// relative transforms between the 2 frames
463+
Quaternion<T> q_1_inverse = q_1.conjugate();
464+
Quaternion<T> q_12_estimated = q_1_inverse * q_2;
465+
Matrix<T,3,1> p_12_estimated = q_1_inverse * (p_2 - p_1);
466+
467+
// compute error between orientations estimates
468+
Quaternion<T> delta_q = q_12_estimated.conjugate() * observed_c1_q_c2.cast<T>();
469+
Matrix<T,3,1> delta_t = q_12_estimated.conjugate() * ( observed_c1_t_c2.cast<T>() - p_12_estimated );
470+
471+
// penalty - A
472+
Eigen::Map<Matrix<T,4,1> > residuals( residue_ptr );
473+
// residuals.block(0,0, 3,1) = delta_t; // translation error
474+
residuals(0) = delta_t(0);
475+
residuals(1) = delta_t(1);
476+
residuals(2) = delta_t(2);
477+
478+
479+
// convert Quaternion to euler angle using rotation matrix as intermediate
480+
Matrix<T,3,3> delta_Rot = delta_q.toRotationMatrix();
481+
Matrix<T,3,1> delta_ypr = R2ypr( delta_Rot );
482+
residuals(3) = T(4.) * delta_ypr(0);
483+
// residuals(4) = T(10.0);
484+
// residuals(5) = T(10.0);
485+
486+
residuals *= T(weight);
487+
488+
return true;
489+
490+
}
491+
492+
493+
static ceres::CostFunction* Create( const Matrix4d& _observed__c1_T_c2, const double weight=1.0 )
494+
{
495+
return ( new ceres::AutoDiffCostFunction<FourDOFError,4,4,3,4,3>
496+
(
497+
new FourDOFError(_observed__c1_T_c2, weight )
498+
)
499+
);
500+
}
501+
502+
503+
private:
504+
505+
506+
Matrix4d observed__c1_T_c2;
507+
Quaterniond observed_c1_q_c2;
508+
Vector3d observed_c1_ypr_c2;
509+
Vector3d observed_c1_t_c2;
510+
511+
double weight;
512+
};
513+
514+
515+
// In this residue function, internally we rely on the
516+
// Euler angle representation and not Quaternions as before.
517+
class FourDOFErrorWithSwitchingConstraints
518+
{
519+
public:
520+
FourDOFErrorWithSwitchingConstraints( const Matrix4d& _observed__c1_T_c2, const double _weight=1.0 ) : observed__c1_T_c2( _observed__c1_T_c2 )
521+
{
522+
// Convert c1_T_c2 to Euler Angle representation
523+
PoseManipUtils::eigenmat_to_rawyprt( _observed__c1_T_c2, observed_c1_ypr_c2, observed_c1_t_c2 );
524+
observed_c1_q_c2 = Quaterniond( _observed__c1_T_c2.topLeftCorner<3,3>() );
525+
526+
weight = _weight;
527+
}
528+
529+
// q1, t1 : w_T_c1
530+
// q2, t2 : w_T_c2
531+
template <typename T>
532+
bool operator() ( const T* const q1, const T* const t1,
533+
const T* const q2, const T* const t2,
534+
const T* const switching_var,
535+
T* residue_ptr ) const
536+
{
537+
// Eigen:
538+
// Note the order of the arguments: the real w coefficient first,
539+
// while internally the coefficients are stored in the following order: [x, y, z, w]
540+
541+
// q1,t1 --> w_T_c1
542+
Eigen::Map<const Eigen::Matrix<T,3,1> > p_1( t1 );
543+
Eigen::Map<const Eigen::Quaternion<T> > q_1( q1 );
544+
545+
// q2,t2 --> w_T_c2
546+
Eigen::Map<const Eigen::Matrix<T,3,1> > p_2( t2 );
547+
Eigen::Map<const Eigen::Quaternion<T> > q_2( q2 );
548+
549+
// relative transforms between the 2 frames
550+
Quaternion<T> q_1_inverse = q_1.conjugate();
551+
Quaternion<T> q_12_estimated = q_1_inverse * q_2;
552+
Matrix<T,3,1> p_12_estimated = q_1_inverse * (p_2 - p_1);
553+
554+
// compute error between orientations estimates
555+
Quaternion<T> delta_q = q_12_estimated.conjugate() * observed_c1_q_c2.cast<T>();
556+
Matrix<T,3,1> delta_t = q_12_estimated.conjugate() * ( observed_c1_t_c2.cast<T>() - p_12_estimated );
557+
558+
// penalty - A
559+
Eigen::Map<Matrix<T,5,1> > residuals( residue_ptr );
560+
// residuals.block(0,0, 3,1) = delta_t; // translation error
561+
residuals(0) = delta_t(0);
562+
residuals(1) = delta_t(1);
563+
residuals(2) = delta_t(2);
564+
565+
residuals(4) = T(1.0) * ( T(1.0) - switching_var[0] ); //switching constraint penalty
566+
567+
// convert Quaternion to euler angle using rotation matrix as intermediate
568+
Matrix<T,3,3> delta_Rot = delta_q.toRotationMatrix();
569+
Matrix<T,3,1> delta_ypr = R2ypr( delta_Rot );
570+
residuals(3) = T(4.) * delta_ypr(0);
571+
// residuals(4) = T(10.0);
572+
// residuals(5) = T(10.0);
573+
574+
575+
T s = switching_var[0];
576+
residuals *= s; //* T(weight);
577+
return true;
578+
579+
}
580+
581+
582+
static ceres::CostFunction* Create( const Matrix4d& _observed__c1_T_c2, const double weight=1.0 )
583+
{
584+
return ( new ceres::AutoDiffCostFunction<FourDOFErrorWithSwitchingConstraints,5,4,3,4,3,1>
585+
(
586+
new FourDOFErrorWithSwitchingConstraints(_observed__c1_T_c2, weight )
587+
)
588+
);
589+
}
590+
591+
592+
private:
593+
594+
595+
Matrix4d observed__c1_T_c2;
596+
Quaterniond observed_c1_q_c2;
597+
Vector3d observed_c1_ypr_c2;
598+
Vector3d observed_c1_t_c2;
599+
600+
double weight;
601+
};

src/keyframe_pose_graph_slam_node.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ int main( int argc, char ** argv)
13551355
// 10 //< color the line with worldID
13561356
// 12 //< color the line with setID( worldID )
13571357
options.line_color_style = 10;
1358-
options.linewidth_multiplier = 2.0;
1358+
options.linewidth_multiplier = 0.25;
13591359
std::thread th6( opt_traj_publisher_colored_by_world, manager, slam, viz, options );
13601360

13611361

@@ -1384,7 +1384,7 @@ int main( int argc, char ** argv)
13841384

13851385

13861386

1387-
#define __LOGGING__ 0 // make this 1 to enable logging. 0 to disable logging. rememeber to catkin_make after this change
1387+
#define __LOGGING__ 1 // make this 1 to enable logging. 0 to disable logging. rememeber to catkin_make after this change
13881388
#if __LOGGING__
13891389
// Note: If using roslaunch to launch this node and when LOGGING is enabled,
13901390
// roslaunch sends a sigterm and kills this thread when ros::ok() returns false ie.

src/utils/PoseManipUtils.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ void PoseManipUtils::eigenmat_to_rawyprt( const Matrix4d& T, double * ypr, doubl
132132
t[2] = T(2,3);
133133
}
134134

135+
136+
void PoseManipUtils::eigenmat_to_rawyprt( const Matrix4d& T, Vector3d& ypr, Vector3d& t) // input ypr must be in degrees.
137+
{
138+
assert( T(3,3) == 1 );
139+
ypr = R2ypr( T.topLeftCorner<3,3>() );
140+
t << T(0,3), T(1,3), T(2,3);
141+
}
142+
135143
Vector3d PoseManipUtils::R2ypr( const Matrix3d& R)
136144
{
137145
Eigen::Vector3d n = R.col(0);
@@ -150,6 +158,7 @@ Vector3d PoseManipUtils::R2ypr( const Matrix3d& R)
150158
}
151159

152160

161+
153162
Matrix3d PoseManipUtils::ypr2R( const Vector3d& ypr)
154163
{
155164
double y = ypr(0) / 180.0 * M_PI;

src/utils/PoseManipUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class PoseManipUtils
3232
static void rawyprt_to_eigenmat( const Vector3d& eigen_ypr_degrees, const Vector3d& t, Matrix4d& dstT );
3333

3434
static void eigenmat_to_rawyprt( const Matrix4d& T, double * ypr, double * t); // input ypr must be in degrees.
35+
static void eigenmat_to_rawyprt( const Matrix4d& T, Vector3d& ypr, Vector3d& t); // input ypr must be in degrees.
3536
static Vector3d R2ypr( const Matrix3d& R);
3637
static Matrix3d ypr2R( const Vector3d& ypr); // input ypr must be in degrees.
3738
static void prettyprintPoseMatrix( const Matrix4d& M );
@@ -64,6 +65,7 @@ class PoseManipUtils
6465
// static bool string_to_eigenmat( const string mat_string, MatrixXd& mat );
6566

6667

68+
6769
private:
6870
static std::vector<std::string>
6971
split( std::string const& original, char separator );

0 commit comments

Comments
 (0)