Skip to content

Commit 28a0cf3

Browse files
authored
Merge pull request #20 from KumarRobotics/feature/differential-gps
dgps starter, the regular version with IMU heading still works but this needs more testing. But I broke main so I need to merge this.
2 parents 1367a66 + fb2e50f commit 28a0cf3

File tree

6 files changed

+157
-25
lines changed

6 files changed

+157
-25
lines changed

glider/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ add_library(${PROJECT_NAME} SHARED
5959
src/parameters.cpp
6060
src/time.cpp
6161
src/gps_heading.cpp
62+
src/differential_gps.cpp
6263
src/odometry.cpp
6364
src/odometry_with_covariance.cpp
6465
src/factor_manager.cpp
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*!
2+
* Jason Hughes
3+
* October 2025
4+
*
5+
* Object that handles everything for differenctial gps
6+
* from motion
7+
*/
8+
9+
#pragma once
10+
11+
#include <cmath>
12+
#include <string>
13+
#include <Eigen/Dense>
14+
15+
namespace Glider
16+
{
17+
namespace Geodetics
18+
{
19+
class DifferentialGpsFromMotion
20+
{
21+
public:
22+
DifferentialGpsFromMotion() = default;
23+
DifferentialGpsFromMotion(const std::string& frame, const double& threshold);
24+
25+
double getHeading(const Eigen::Vector3d& gps);
26+
27+
double headingRadiansToDegrees(const double heading) const;
28+
29+
void setLastGps(const Eigen::Vector3d& gps);
30+
bool isInitialized() const;
31+
double getVelocityThreshold() const;
32+
33+
private:
34+
35+
double nedToEnu(const double heading) const;
36+
37+
Eigen::Vector3d last_gps_;
38+
std::string frame_;
39+
double vel_threshold_;
40+
bool initialized_{false};
41+
};
42+
} // namespace Geodetics
43+
} // namespace Glider

glider/include/glider/core/glider.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <glog/logging.h>
1414

1515
#include "glider/core/factor_manager.hpp"
16-
#include "glider/utils/gps_heading.hpp"
16+
#include "glider/core/differential_gps.hpp"
1717
#include "glider/utils/geodetics.hpp"
1818

1919
namespace Glider
@@ -35,6 +35,7 @@ class Glider
3535
* should be in degree decimal and altitude in meters. Altitude
3636
* frame does not matter */
3737
void addGps(int64_t timestamp, Eigen::Vector3d& gps);
38+
void addGpsWithHeading(int64_t timestamp, Eigen::Vector3d& gps);
3839
/*! @brief converts the imu measurements into the ENU frame if
3940
* they are not in that frame already.
4041
* @param timestamp: time the imu measurement was taken
@@ -81,12 +82,11 @@ class Glider
8182
// @brief whether or not to use differential gps
8283
// from motion for heading
8384
bool use_dgpsfm_;
85+
// @brief object to handle differential gps
86+
// from motion
87+
Geodetics::DifferentialGpsFromMotion dgps_;
8488
// @brief save the state estimate from
8589
// the optimizer
8690
OdometryWithCovariance current_odom_;
87-
// @brief save the previous gps measurement for
88-
// dgpsfm
89-
Eigen::Vector3d last_gps_;
90-
double del_threshold_;
9191
};
9292
}

glider/launch/glider-node.launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ def generate_launch_description():
6262
'use_odom': False}
6363
],
6464
remappings=[
65-
('/gps', '/ublox_gps_node/fix'),
66-
('/imu', '/vectornav/imu'),
65+
('/gps', '/ublox/fix'),
66+
('/imu', '/VN100T/imu'),
6767
('/odom', '/Odometry'),
6868
]
6969
)

glider/src/differential_gps.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*!
2+
* Jason Hughes
3+
* October 2025
4+
*
5+
*/
6+
7+
#include "glider/core/differential_gps.hpp"
8+
9+
using namespace Glider::Geodetics;
10+
11+
DifferentialGpsFromMotion::DifferentialGpsFromMotion(const std::string& frame, const double& threshold)
12+
{
13+
frame_ = frame;
14+
vel_threshold_ = threshold;
15+
}
16+
17+
double DifferentialGpsFromMotion::getHeading(const Eigen::Vector3d& gps)
18+
{
19+
if (!initialized_)
20+
{
21+
last_gps_ = gps;
22+
initialized_ = true;
23+
}
24+
25+
double lat1_rad = last_gps_(0) * M_PI / 180.0;
26+
double lon1_rad = last_gps_(1) * M_PI / 180.0;
27+
double lat2_rad = gps(0) * M_PI / 180.0;
28+
double lon2_rad = gps(1) * M_PI / 180.0;
29+
30+
double lon_diff = lon2_rad - lon1_rad;
31+
32+
double y = std::sin(lon_diff) * std::cos(lat2_rad);
33+
double x = std::cos(lat1_rad) * std::sin(lat2_rad) - std::sin(lat1_rad) * std::cos(lat2_rad) * std::cos(lon_diff);
34+
35+
double heading_rad = std::atan2(y,x);
36+
last_gps_ = gps;
37+
38+
if (frame_ == "enu") heading_rad = nedToEnu(heading_rad);
39+
40+
return heading_rad;
41+
}
42+
43+
bool DifferentialGpsFromMotion::isInitialized() const
44+
{
45+
return initialized_;
46+
}
47+
48+
double DifferentialGpsFromMotion::getVelocityThreshold() const
49+
{
50+
return vel_threshold_;
51+
}
52+
53+
void DifferentialGpsFromMotion::setLastGps(const Eigen::Vector3d& gps)
54+
{
55+
last_gps_ = gps;
56+
initialized_ = true;
57+
}
58+
59+
double DifferentialGpsFromMotion::nedToEnu(const double heading) const
60+
{
61+
double enu_heading = std::fmod((M_PI/2 - heading + (2*M_PI)), (2*M_PI));
62+
return enu_heading;
63+
}
64+
65+
double DifferentialGpsFromMotion::headingRadiansToDegrees(const double heading) const
66+
{
67+
double heading_deg = heading * (180.0 / M_PI);
68+
69+
heading_deg = std::fmod(std::fmod(heading_deg, 360.0) + 360.0, 360.0);
70+
return heading_deg;
71+
}

glider/src/glider.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Glider::Glider(const std::string& path)
1515
Parameters params = Parameters::Load(path);
1616
initializeLogging(params);
1717
factor_manager_ = FactorManager(params);
18-
18+
1919
frame_ = params.frame;
2020
t_imu_gps_ = params.t_imu_gps;
2121
r_enu_ned_ = Eigen::Matrix3d::Zero();
@@ -27,7 +27,7 @@ Glider::Glider(const std::string& path)
2727
LOG(INFO) << "[GLIDER] Using Fixed Lag Smoother: " << std::boolalpha << params.smooth;
2828
LOG(INFO) << "[GLIDER] Logging to: " << params.log_dir;
2929
use_dgpsfm_ = params.use_dgpsfm;
30-
vel_threshold_ = params.dgpsfm_threshold;
30+
dgps_ = Geodetics::DifferentialGpsFromMotion(params.frame, params.dgpsfm_threshold);
3131

3232
current_odom_ = OdometryWithCovariance::Uninitialized();
3333

@@ -46,7 +46,34 @@ void Glider::initializeLogging(const Parameters& params) const
4646
if (params.log) FLAGS_alsologtostderr = 1;
4747
}
4848

49+
4950
void Glider::addGps(int64_t timestamp, Eigen::Vector3d& gps)
51+
{
52+
// route the
53+
if (use_dgpsfm_)
54+
{
55+
addGpsWithHeading(timestamp, gps);
56+
return;
57+
}
58+
59+
// transform from lat lon To UTM
60+
Eigen::Vector3d meas = Eigen::Vector3d::Zero();
61+
62+
double easting, northing;
63+
char zone[4];
64+
geodetics::LLtoUTM(gps(0), gps(1), northing, easting, zone);
65+
66+
// keep everything in the enu frame
67+
meas.head(2) << easting, northing;
68+
meas(2) = gps(2);
69+
70+
// TODO t_imu_gps_ needs to be rotated!!
71+
meas = meas + t_imu_gps_;
72+
73+
factor_manager_.addGpsFactor(timestamp, meas);
74+
}
75+
76+
void Glider::addGpsWithHeading(int64_t timestamp, Eigen::Vector3d& gps)
5077
{
5178
// transform from lat lon To UTM
5279
Eigen::Vector3d meas = Eigen::Vector3d::Zero();
@@ -62,25 +89,17 @@ void Glider::addGps(int64_t timestamp, Eigen::Vector3d& gps)
6289
// TODO t_imu_gps_ needs to be rotated!!
6390
meas = meas + t_imu_gps_;
6491

65-
if (use_dgpsfm_ && current_odom_.isInitialized())
92+
if(factor_manager_.isSystemInitialized() && current_odom_.isMovingFasterThan(dgps_.getVelocityThreshold()))
6693
{
67-
if(factor_manager_.isSystemInitialized() && current_odom_.isMovingFasterThan(vel_threshold_))
68-
{
69-
LOG(INFO) << "[GLIDER] Adding DGPS heading";
70-
double heading_ne = geodetics::gpsHeading(last_gps_(0), last_gps_(1), gps(0), gps(1));
71-
double heading_en = geodetics::geodeticToENU(heading_ne);
72-
factor_manager_.addGpsFactor(timestamp, meas, heading_en, true);
73-
}
74-
else
75-
{
76-
factor_manager_.addGpsFactor(timestamp, meas, 0.0, false);
77-
}
94+
LOG(INFO) << "[GLIDER] Adding DGPS heading";
95+
double heading = dgps_.getHeading(gps);
96+
factor_manager_.addGpsFactor(timestamp, meas, heading, true);
7897
}
7998
else
8099
{
81-
factor_manager_.addGpsFactor(timestamp, meas);
100+
dgps_.setLastGps(gps);
101+
factor_manager_.addGpsFactor(timestamp, meas, 0.0, false);
82102
}
83-
last_gps_ = gps;
84103
}
85104

86105
void Glider::addImu(int64_t timestamp, Eigen::Vector3d& accel, Eigen::Vector3d& gyro, Eigen::Vector4d& quat)
@@ -92,8 +111,6 @@ void Glider::addImu(int64_t timestamp, Eigen::Vector3d& accel, Eigen::Vector3d&
92111
Eigen::Vector4d quat_enu = rotateQuaternion(r_enu_ned_, quat);
93112

94113
factor_manager_.addImuFactor(timestamp, accel_enu, gyro_enu, quat_enu);
95-
//factor_manager_.addImuFactor(timestamp, accel, gyro, quat);'
96-
LOG(FATAL) << "[GLIDER] NED frame not supported yet";
97114
}
98115
else if (frame_ == "enu")
99116
{

0 commit comments

Comments
 (0)