39 #include <sensor_msgs/NavSatFix.h> 40 #include <sensor_msgs/Imu.h> 41 #include <sensor_msgs/TimeReference.h> 42 #include <geometry_msgs/TwistWithCovarianceStamped.h> 43 #include <nav_msgs/Odometry.h> 44 #include <std_msgs/String.h> 57 #include <arpa/inet.h> 61 #define UINT16_MAX (65535) 66 #define GPS_LEAP_SECONDS 18 // Offset to account for UTC leap seconds (need to increment when UTC changes) 67 #define GPS_EPOCH_OFFSET 315964800 // Offset to account for GPS / UTC epoch difference 70 static inline bool openSocket(
const std::string &interface,
const std::string &ip_addr, uint16_t port,
int *fd_ptr, sockaddr_in *sock_ptr)
74 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
76 if (interface.length()) {
77 if (!setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface.c_str(), interface.length()) == 0) {
82 memset(sock_ptr, 0,
sizeof(sockaddr_in));
83 sock_ptr->sin_family = AF_INET;
84 sock_ptr->sin_port = htons(port);
85 if (!inet_aton(ip_addr.c_str(), &sock_ptr->sin_addr)) {
86 sock_ptr->sin_addr.s_addr = INADDR_ANY;
88 if (bind(fd, (sockaddr*)sock_ptr,
sizeof(sockaddr)) == 0) {
96 static inline int readSocket(
int fd,
unsigned int timeout,
void *data,
size_t size, sockaddr *source_ptr = NULL)
105 tv.tv_sec = timeout / 1000;
106 tv.tv_usec = (timeout * 1000) % 1000000;
108 if (select(fd + 1, &fds, NULL, NULL, &tv) > 0) {
109 socklen_t socklen = source_ptr ?
sizeof(*source_ptr) : 0;
110 socklen_t *socklen_ptr = source_ptr ? &socklen : NULL;
111 return recvfrom(fd, data, size, 0, source_ptr, socklen_ptr);
120 static inline double SQUARE(
double x) {
return x * x; }
122 #ifndef OXFORD_DISPLAY_INFO 123 #define OXFORD_DISPLAY_INFO 0 125 #if OXFORD_DISPLAY_INFO 126 #define OXTS_INFO(...) ROS_INFO(__VA_ARGS__) 127 #define OXTS_WARN(...) ROS_WARN(__VA_ARGS__) 129 #define OXTS_INFO(...) ROS_DEBUG(__VA_ARGS__) 130 #define OXTS_WARN(...) ROS_DEBUG(__VA_ARGS__) 177 static inline void mapLookup(
const std::map<uint8_t, std::string>& map, uint8_t key, std::string& val) {
178 std::map<uint8_t, std::string>::const_iterator it = map.find(key);
179 if (it != map.end()) {
188 int zone_number = std::atoi(utm_zone.substr(0,2).c_str());
189 return (zone_number == 0) ? 0.0 : (zone_number - 1) * 6.0 - 177.0;
192 static inline double toUtcTime(uint32_t gps_minutes, uint16_t gps_ms)
199 std::stringstream msg;
200 std::stringstream gga_payload;
202 int lat_deg = (int)fabs(latitude);
203 float lat_min = 60.0 * fmod(fabs(latitude), 1.0);
204 int lon_deg = (int)fabs(longitude);
205 float lon_min = 60.0 * fmod(fabs(longitude), 1.0);
207 double utc_timestamp = utc_time.
toSec();
208 uint8_t utc_hours = (uint8_t)(fmod(utc_timestamp / 3600.0, 24.0));
209 uint8_t utc_minutes = (uint8_t)(60.0 * fmod(utc_timestamp / 3600.0, 1.0));
210 uint8_t utc_secs = (uint8_t)(3600.0 * fmod(utc_timestamp / 3600.0, 24.0) - 3600.0 * utc_hours - 60.0 * utc_minutes);
212 gga_payload.precision(3);
213 gga_payload << std::setfill(
'0');
214 gga_payload <<
"GPGGA," << std::setw(2) << (int)utc_hours << std::setw(2) << (int)utc_minutes << std::setw(2) << (int)utc_secs <<
",";
215 gga_payload << std::setw(2) << lat_deg << std::fixed << std::setw(6) << lat_min;
218 gga_payload <<
",N,";
220 gga_payload <<
",S,";
223 gga_payload << std::setw(3) << lon_deg << std::fixed << std::setw(6) << lon_min;
225 gga_payload <<
",E,";
227 gga_payload <<
",W,";
230 gga_payload.precision(1);
231 gga_payload <<
"1,4,1.5,";
232 gga_payload << std::setfill(
'0');
233 gga_payload << std::fixed << std::setw(4) << altitude;
234 gga_payload <<
",M,0,M,,";
236 uint8_t checksum = 0;
237 for (
size_t i = 0; i < gga_payload.str().size(); i++) {
238 checksum ^= gga_payload.str()[i];
241 msg <<
"$" << gga_payload.str() <<
"*" << std::hex << std::setfill(
'0') << std::setw(2) << std::uppercase << (int)checksum <<
"\r\n";
248 const std::string & frame_id_gps,
const std::string &frame_id_vel,
const std::string &frame_id_odom)
250 static uint8_t fix_status = sensor_msgs::NavSatStatus::STATUS_FIX;
251 static uint8_t position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
252 static double position_stddev[3];
253 static uint8_t velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
254 static double velocity_stddev[3];
255 static uint8_t orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
256 static double orientation_stddev[3];
257 static uint8_t pos_mode = 0;
258 static int none_type_count = 0;
268 if (none_type_count > 2) {
277 sensor_msgs::TimeReference gps_time_ref_msg;
278 gps_time_ref_msg.source =
"gps";
279 gps_time_ref_msg.header.stamp = stamp;
282 pub_gps_time_ref.
publish(gps_time_ref_msg);
298 fix_status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX;
305 fix_status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX;
311 fix_status = sensor_msgs::NavSatStatus::STATUS_FIX;
321 fix_status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
324 OXTS_INFO(
"Num Sats: %u, Position mode: %u, Velocity mode: %u, Orientation mode: %u",
335 position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
336 OXTS_INFO(
"Position accuracy: North: %umm, East: %umm, Down: %umm",
341 position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
349 velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
350 OXTS_INFO(
"Velocity accuracy: North: %umm/s, East: %umm/s, Down: %umm/s",
355 velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
364 orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
365 OXTS_INFO(
"Velocity accuracy: Heading: %frad, Pitch: %frad, Roll: %frad",
370 orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
381 OXTS_INFO(
"Heading Misalignment: Angle: %frad, Accuracy: %frad",
392 std_msgs::String str_msg;
396 pub_nav_status.
publish(str_msg);
402 std::string utm_zone;
406 std_msgs::String gga_msg;
412 double convergence_angle = atan(tan(packet->
longitude - central_meridian) * sin(packet->
latitude));
413 double enu_heading = M_PI_2 - (double)packet->
heading * 1e-6;
414 double grid_heading = enu_heading + convergence_angle;
417 double east_vel = (
double)packet->
vel_east * 1e-4;
418 double north_vel = (double)packet->
vel_north * 1e-4;
419 double local_x_vel = east_vel * cos(enu_heading) + north_vel * sin(enu_heading);
420 double local_y_vel = -east_vel * sin(enu_heading) + north_vel * cos(enu_heading);
422 sensor_msgs::NavSatFix msg_fix;
423 msg_fix.header.stamp = stamp;
424 msg_fix.header.frame_id = frame_id_gps;
425 msg_fix.latitude = packet->
latitude * (180 / M_PI);
426 msg_fix.longitude = packet->
longitude * (180 / M_PI);
427 msg_fix.altitude = packet->
altitude;
428 msg_fix.status.status = fix_status;
429 msg_fix.status.service = sensor_msgs::NavSatStatus::SERVICE_GPS;
430 msg_fix.position_covariance_type = position_covariance_type;
431 if (position_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
432 msg_fix.position_covariance[0] =
SQUARE(position_stddev[0]);
433 msg_fix.position_covariance[4] =
SQUARE(position_stddev[1]);
434 msg_fix.position_covariance[8] =
SQUARE(position_stddev[2]);
438 geometry_msgs::TwistWithCovarianceStamped msg_vel;
439 msg_vel.header.stamp = stamp;
440 msg_vel.header.frame_id = frame_id_vel;
441 msg_vel.twist.twist.linear.x = east_vel;
442 msg_vel.twist.twist.linear.y = north_vel;
443 msg_vel.twist.twist.linear.z = (double)packet->
vel_down * -1e-4;
444 if (velocity_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
445 msg_vel.twist.covariance[0] =
SQUARE(velocity_stddev[0]);
446 msg_vel.twist.covariance[7] =
SQUARE(velocity_stddev[1]);
447 msg_vel.twist.covariance[14] =
SQUARE(velocity_stddev[2]);
452 q.
setRPY((
double)packet->
roll * 1e-6, (
double)packet->
pitch * 1e-6, enu_heading);
453 sensor_msgs::Imu msg_imu;
454 msg_imu.header.stamp = stamp;
455 msg_imu.header.frame_id = frame_id_gps;
456 msg_imu.linear_acceleration.x = (double)packet->
accel_x * 1e-4;
457 msg_imu.linear_acceleration.y = (
double)packet->
accel_y * 1e-4;
458 msg_imu.linear_acceleration.z = (double)packet->
accel_z * -1e-4;
459 msg_imu.angular_velocity.x = (
double)packet->
gyro_x * 1e-5;
460 msg_imu.angular_velocity.y = (double)packet->
gyro_y * 1e-5;
461 msg_imu.angular_velocity.z = (
double)packet->
gyro_z * -1e-5;
462 msg_imu.orientation.w = q.w();
463 msg_imu.orientation.x = q.x();
464 msg_imu.orientation.y = q.y();
465 msg_imu.orientation.z = q.z();
466 if (orientation_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
467 msg_imu.orientation_covariance[0] =
SQUARE(orientation_stddev[0]);
468 msg_imu.orientation_covariance[4] =
SQUARE(orientation_stddev[1]);
469 msg_imu.orientation_covariance[8] =
SQUARE(orientation_stddev[2]);
474 double std_east = position_stddev[0];
475 double std_north = position_stddev[1];
476 double std_x = std_east * cos(convergence_angle) - std_north * sin(convergence_angle);
477 double std_y = std_north * sin(convergence_angle) + std_east * cos(convergence_angle);
480 double std_east_vel = velocity_stddev[0];
481 double std_north_vel = velocity_stddev[1];
482 double std_x_vel = std_east_vel * cos(enu_heading) + std_north_vel * sin(enu_heading);
483 double std_y_vel = -std_east_vel * cos(enu_heading) + std_north_vel * sin(enu_heading);
485 nav_msgs::Odometry msg_odom;
486 msg_odom.header.stamp = stamp;
487 msg_odom.header.frame_id =
"utm";
488 msg_odom.child_frame_id = frame_id_odom;
489 msg_odom.pose.pose.position.x = utm_x;
490 msg_odom.pose.pose.position.y = utm_y;
492 if (position_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
493 msg_odom.pose.covariance[0*6 + 0] =
SQUARE(std_x);
494 msg_odom.pose.covariance[1*6 + 1] =
SQUARE(std_y);
495 msg_odom.pose.covariance[5*6 + 5] =
SQUARE(orientation_stddev[2]);
497 msg_odom.twist.twist.linear.x = local_x_vel;
498 msg_odom.twist.twist.linear.y = local_y_vel;
499 msg_odom.twist.twist.angular.z = msg_imu.angular_velocity.z;
500 if (velocity_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
501 msg_odom.twist.covariance[0*6 + 0] =
SQUARE(std_x_vel);
502 msg_odom.twist.covariance[1*6 + 1] =
SQUARE(std_y_vel);
511 int main(
int argc,
char **argv)
517 std::string
interface = "";
518 priv_nh.
getParam(
"interface", interface);
520 std::string ip_addr =
"";
521 priv_nh.
getParam(
"ip_address", ip_addr);
526 std::string frame_id_gps =
"gps";
527 priv_nh.
getParam(
"frame_id_gps", frame_id_gps);
529 std::string frame_id_vel =
"enu";
530 priv_nh.
getParam(
"frame_id_vel", frame_id_vel);
532 std::string frame_id_odom =
"base_footprint";
533 priv_nh.
getParam(
"frame_id_odom", frame_id_odom);
539 if (interface.length() && ip_addr.length()) {
540 ROS_INFO(
"Preparing to listen on interface %s port %u and IP %s", interface.c_str(), port, ip_addr.c_str());
541 }
else if (interface.length()) {
542 ROS_INFO(
"Preparing to listen on interface %s port %u", interface.c_str(), port);
543 }
else if (ip_addr.length()) {
544 ROS_INFO(
"Preparing to listen on %s:%u", ip_addr.c_str(), port);
546 ROS_INFO(
"Preparing to listen on port %u", port);
551 if (
openSocket(interface, ip_addr, port, &fd, &sock)) {
569 if (
readSocket(fd, 10, &packet,
sizeof(packet), &source) >=
sizeof(packet)) {
573 ROS_INFO(
"Connected to Oxford GPS at %s:%u", inet_ntoa(((sockaddr_in*)&source)->sin_addr), htons(((sockaddr_in*)&source)->sin_port));
575 handlePacket(&packet, pub_fix, pub_vel, pub_imu, pub_odom, pub_pos_type, pub_nav_status, pub_gps_time_ref, pub_gga, frame_id_gps, frame_id_vel, frame_id_odom);
uint16_t acc_position_down
void publish(const boost::shared_ptr< M > &message) const
uint16_t acc_position_north
static void generateGGAString(double latitude, double longitude, double altitude, const ros::Time &utc_time, std::string &gga_msg)
static double toUtcTime(uint32_t gps_minutes, uint16_t gps_ms)
struct Channel::@9 chan48
static const std::map< uint8_t, std::string > POS_MODE_MAP
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
static double getZoneMeridian(const std::string &utm_zone)
static void handlePacket(const Packet *packet, ros::Publisher &pub_fix, ros::Publisher &pub_vel, ros::Publisher &pub_imu, ros::Publisher &pub_odom, ros::Publisher &pub_pos_type, ros::Publisher &pub_nav_status, ros::Publisher &pub_gps_time_ref, ros::Publisher &pub_gga, const std::string &frame_id_gps, const std::string &frame_id_vel, const std::string &frame_id_odom)
uint16_t acc_velocity_east
struct Channel::@6 chan23
static double SQUARE(double x)
static void LLtoUTM(const double Lat, const double Long, double &UTMNorthing, double &UTMEasting, char *UTMZone)
static bool validatePacket(const Packet *packet)
uint16_t acc_position_east
struct Channel::@8 chan37
static const std::map< uint8_t, std::string > NAV_STATUS_MAP
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
int16_t heading_misalignment_angle
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
uint16_t acc_velocity_down
uint16_t acc_velocity_north
struct Channel::@7 chan27
static void mapLookup(const std::map< uint8_t, std::string > &map, uint8_t key, std::string &val)
uint16_t heading_misalignment_accuracy
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
bool getParam(const std::string &key, std::string &s) const
int main(int argc, char **argv)
static bool openSocket(const std::string &interface, const std::string &ip_addr, uint16_t port, int *fd_ptr, sockaddr_in *sock_ptr)
static int readSocket(int fd, unsigned int timeout, void *data, size_t size, sockaddr *source_ptr=NULL)
ROSCPP_DECL void spinOnce()