(6)GPS坐标与UTM坐标的转换

2023-05-16

1 简介

1.1 消息

gps_common定义了两个通用消息,供GPS驱动程序输出:gps_common/GPSFix和gps_common/GPSStatus。

在大多数情况下,这些消息应同时发布,并带有相同的时间戳。

1.2 utm_odometry_node节点

utm_odometry_node将经纬度坐标转换为UTM坐标。

1.3 订阅的话题

fix (sensor_msgs/NavSatFix):GPS测量和状态

1.4 发布的话题

odom (nav_msgs/Odometry):UTM编码的位置

1.5 参数

  • ~rot_covariance (double, default: 99999):指定旋转测量的方差(以米为单位)
  • ~frame_id (string, default: Copy frame_id from fix message): Frame to specify in header of outgoing Odometry message
  • ~child_frame_id (string): Child frame to specify in header of outgoing Odometry message

2 安装

mkdir -p ~/gps_ws/src
cd ~/gps_ws/src
git clone https://github.com/swri-robotics/gps_umd.git
cd ..
catkin_make

报错:

CMake Error at /usr/share/cmake-3.5/Modules/FindPkgConfig.cmake:367 (message):
A required package was not found
Call Stack (most recent call first):
/usr/share/cmake-3.5/Modules/FindPkgConfig.cmake:532 (_pkg_check_modules_internal)
gps_umd/gpsd_client/CMakeLists.txt:15 (pkg_check_modules)

– Configuring incomplete, errors occurred!

解决办法:

sudo apt-get install libgps-dev

最后,重新编译:

catkin_make

3 GPS坐标与UTM坐标的转换

先写这个,个人认为用得比较多。

3.1 GPS坐标转换为UTM坐标

源文件utm_odometry_node.cpp:

/*
 * Translates sensor_msgs/NavSat{Fix,Status} into nav_msgs/Odometry using UTM
 */

#include <ros/ros.h>
#include <message_filters/subscriber.h>
#include <message_filters/time_synchronizer.h>
#include <sensor_msgs/NavSatStatus.h>
#include <sensor_msgs/NavSatFix.h>
#include <gps_common/conversions.h>
#include <nav_msgs/Odometry.h>

using namespace gps_common;

static ros::Publisher odom_pub;
std::string frame_id, child_frame_id;
double rot_cov;
bool append_zone = false;

void callback(const sensor_msgs::NavSatFixConstPtr& fix) {
  if (fix->status.status == sensor_msgs::NavSatStatus::STATUS_NO_FIX) {
    ROS_DEBUG_THROTTLE(60,"No fix.");
    return;
  }

  if (fix->header.stamp == ros::Time(0)) {
    return;
  }

  double northing, easting;
  std::string zone;

  LLtoUTM(fix->latitude, fix->longitude, northing, easting, zone);

  if (odom_pub) {
    nav_msgs::Odometry odom;
    odom.header.stamp = fix->header.stamp;

    if (frame_id.empty()) {
      if(append_zone) {
        odom.header.frame_id = fix->header.frame_id + "/utm_" + zone;
      } else {
        odom.header.frame_id = fix->header.frame_id;
      }
    } else {
      if(append_zone) {
        odom.header.frame_id = frame_id + "/utm_" + zone;
      } else {
        odom.header.frame_id = frame_id;
      }
    }

    odom.child_frame_id = child_frame_id;

    odom.pose.pose.position.x = easting;
    odom.pose.pose.position.y = northing;
    odom.pose.pose.position.z = fix->altitude;
    
    odom.pose.pose.orientation.x = 0;
    odom.pose.pose.orientation.y = 0;
    odom.pose.pose.orientation.z = 0;
    odom.pose.pose.orientation.w = 1;
    
    // Use ENU covariance to build XYZRPY covariance
    boost::array<double, 36> covariance = {{
      fix->position_covariance[0],
      fix->position_covariance[1],
      fix->position_covariance[2],
      0, 0, 0,
      fix->position_covariance[3],
      fix->position_covariance[4],
      fix->position_covariance[5],
      0, 0, 0,
      fix->position_covariance[6],
      fix->position_covariance[7],
      fix->position_covariance[8],
      0, 0, 0,
      0, 0, 0, rot_cov, 0, 0,
      0, 0, 0, 0, rot_cov, 0,
      0, 0, 0, 0, 0, rot_cov
    }};

    odom.pose.covariance = covariance;

    odom_pub.publish(odom);
  }
}

int main (int argc, char **argv) {
  ros::init(argc, argv, "utm_odometry_node");
  ros::NodeHandle node;
  ros::NodeHandle priv_node("~");

  priv_node.param<std::string>("frame_id", frame_id, "");
  priv_node.param<std::string>("child_frame_id", child_frame_id, "");
  priv_node.param<double>("rot_covariance", rot_cov, 99999.0);
  priv_node.param<bool>("append_zone", append_zone, false);

  odom_pub = node.advertise<nav_msgs::Odometry>("odom", 10);

  ros::Subscriber fix_sub = node.subscribe("fix", 10, callback);

  ros::spin();
}

坐标转换函数所在的头文件conversion.h:

/* Taken from utexas-art-ros-pkg:art_vehicle/applanix */

/*
 * Conversions between coordinate systems.
 *
 * Includes LatLong<->UTM.
 */

#ifndef _UTM_H
#define _UTM_H

/**  @file

     @brief Universal Transverse Mercator transforms.

     Functions to convert (spherical) latitude and longitude to and
     from (Euclidean) UTM coordinates.

     @author Chuck Gantz- chuck.gantz@globalstar.com

 */

#include <cmath>
#include <cstdio>
#include <cstdlib>

namespace gps_common
{

const double RADIANS_PER_DEGREE = M_PI/180.0;
const double DEGREES_PER_RADIAN = 180.0/M_PI;

// WGS84 Parameters
const double WGS84_A = 6378137.0;		// major axis
const double WGS84_B = 6356752.31424518;	// minor axis
const double WGS84_F = 0.0033528107;		// ellipsoid flattening
const double WGS84_E = 0.0818191908;		// first eccentricity
const double WGS84_EP = 0.0820944379;		// second eccentricity

// UTM Parameters
const double UTM_K0 = 0.9996;			// scale factor
const double UTM_FE = 500000.0;		// false easting
const double UTM_FN_N = 0.0;			// false northing on north hemisphere
const double UTM_FN_S = 10000000.0;		// false northing on south hemisphere
const double UTM_E2 = (WGS84_E*WGS84_E);	// e^2
const double UTM_E4 = (UTM_E2*UTM_E2);		// e^4
const double UTM_E6 = (UTM_E4*UTM_E2);		// e^6
const double UTM_EP2 = (UTM_E2/(1-UTM_E2));	// e'^2

/**
 * Utility function to convert geodetic to UTM position
 *
 * Units in are floating point degrees (sign for east/west)
 *
 * Units out are meters
 */
static inline void UTM(double lat, double lon, double *x, double *y)
{
  // constants
  const static double m0 = (1 - UTM_E2/4 - 3*UTM_E4/64 - 5*UTM_E6/256);
  const static double m1 = -(3*UTM_E2/8 + 3*UTM_E4/32 + 45*UTM_E6/1024);
  const static double m2 = (15*UTM_E4/256 + 45*UTM_E6/1024);
  const static double m3 = -(35*UTM_E6/3072);

  // compute the central meridian
  int cm = ((lon >= 0.0)
	    ? ((int)lon - ((int)lon)%6 + 3)
	    : ((int)lon - ((int)lon)%6 - 3));

  // convert degrees into radians
  double rlat = lat * RADIANS_PER_DEGREE;
  double rlon = lon * RADIANS_PER_DEGREE;
  double rlon0 = cm * RADIANS_PER_DEGREE;

  // compute trigonometric functions
  double slat = sin(rlat);
  double clat = cos(rlat);
  double tlat = tan(rlat);

  // decide the false northing at origin
  double fn = (lat > 0) ? UTM_FN_N : UTM_FN_S;

  double T = tlat * tlat;
  double C = UTM_EP2 * clat * clat;
  double A = (rlon - rlon0) * clat;
  double M = WGS84_A * (m0*rlat + m1*sin(2*rlat)
			+ m2*sin(4*rlat) + m3*sin(6*rlat));
  double V = WGS84_A / sqrt(1 - UTM_E2*slat*slat);

  // compute the easting-northing coordinates
  *x = UTM_FE + UTM_K0 * V * (A + (1-T+C)*pow(A,3)/6
			      + (5-18*T+T*T+72*C-58*UTM_EP2)*pow(A,5)/120);
  *y = fn + UTM_K0 * (M + V * tlat * (A*A/2
				      + (5-T+9*C+4*C*C)*pow(A,4)/24
				      + ((61-58*T+T*T+600*C-330*UTM_EP2)
					 * pow(A,6)/720)));

  return;
}

/**
 * Determine the correct UTM letter designator for the
 * given latitude
 *
 * @returns 'Z' if latitude is outside the UTM limits of 84N to 80S
 *
 * Written by Chuck Gantz- chuck.gantz@globalstar.com
 */
static inline char UTMLetterDesignator(double Lat)
{
	char LetterDesignator;

	if     ((84 >= Lat) && (Lat >= 72))  LetterDesignator = 'X';
	else if ((72 > Lat) && (Lat >= 64))  LetterDesignator = 'W';
	else if ((64 > Lat) && (Lat >= 56))  LetterDesignator = 'V';
	else if ((56 > Lat) && (Lat >= 48))  LetterDesignator = 'U';
	else if ((48 > Lat) && (Lat >= 40))  LetterDesignator = 'T';
	else if ((40 > Lat) && (Lat >= 32))  LetterDesignator = 'S';
	else if ((32 > Lat) && (Lat >= 24))  LetterDesignator = 'R';
	else if ((24 > Lat) && (Lat >= 16))  LetterDesignator = 'Q';
	else if ((16 > Lat) && (Lat >= 8))   LetterDesignator = 'P';
	else if (( 8 > Lat) && (Lat >= 0))   LetterDesignator = 'N';
	else if (( 0 > Lat) && (Lat >= -8))  LetterDesignator = 'M';
	else if ((-8 > Lat) && (Lat >= -16)) LetterDesignator = 'L';
	else if((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
	else if((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
	else if((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
	else if((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
	else if((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
	else if((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
	else if((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
	else if((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
        // 'Z' is an error flag, the Latitude is outside the UTM limits
	else LetterDesignator = 'Z';
	return LetterDesignator;
}

/**
 * Convert lat/long to UTM coords.  Equations from USGS Bulletin 1532
 *
 * East Longitudes are positive, West longitudes are negative.
 * North latitudes are positive, South latitudes are negative
 * Lat and Long are in fractional degrees
 *
 * Written by Chuck Gantz- chuck.gantz@globalstar.com
 */
static inline void LLtoUTM(const double Lat, const double Long,
                           double &UTMNorthing, double &UTMEasting,
                           char* UTMZone)
{
	double a = WGS84_A;
	double eccSquared = UTM_E2;
	double k0 = UTM_K0;

	double LongOrigin;
	double eccPrimeSquared;
	double N, T, C, A, M;

        //Make sure the longitude is between -180.00 .. 179.9
	double LongTemp = (Long+180)-int((Long+180)/360)*360-180;

	double LatRad = Lat*RADIANS_PER_DEGREE;
	double LongRad = LongTemp*RADIANS_PER_DEGREE;
	double LongOriginRad;
	int    ZoneNumber;

	ZoneNumber = int((LongTemp + 180)/6) + 1;

	if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
		ZoneNumber = 32;

        // Special zones for Svalbard
	if( Lat >= 72.0 && Lat < 84.0 )
	{
	  if(      LongTemp >= 0.0  && LongTemp <  9.0 ) ZoneNumber = 31;
	  else if( LongTemp >= 9.0  && LongTemp < 21.0 ) ZoneNumber = 33;
	  else if( LongTemp >= 21.0 && LongTemp < 33.0 ) ZoneNumber = 35;
	  else if( LongTemp >= 33.0 && LongTemp < 42.0 ) ZoneNumber = 37;
	 }
        // +3 puts origin in middle of zone
	LongOrigin = (ZoneNumber - 1)*6 - 180 + 3;
	LongOriginRad = LongOrigin * RADIANS_PER_DEGREE;

	//compute the UTM Zone from the latitude and longitude
	snprintf(UTMZone, 4, "%d%c", ZoneNumber, UTMLetterDesignator(Lat));

	eccPrimeSquared = (eccSquared)/(1-eccSquared);

	N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
	T = tan(LatRad)*tan(LatRad);
	C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
	A = cos(LatRad)*(LongRad-LongOriginRad);

	M = a*((1	- eccSquared/4		- 3*eccSquared*eccSquared/64	- 5*eccSquared*eccSquared*eccSquared/256)*LatRad
				- (3*eccSquared/8	+ 3*eccSquared*eccSquared/32	+ 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
									+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
									- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));

	UTMEasting = (double)(k0*N*(A+(1-T+C)*A*A*A/6
					+ (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
					+ 500000.0);

	UTMNorthing = (double)(k0*(M+N*tan(LatRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
				 + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
	if(Lat < 0)
		UTMNorthing += 10000000.0; //10000000 meter offset for southern hemisphere
}

static inline void LLtoUTM(const double Lat, const double Long,
                           double &UTMNorthing, double &UTMEasting,
                           std::string &UTMZone) {
  char zone_buf[] = {0, 0, 0, 0};

  LLtoUTM(Lat, Long, UTMNorthing, UTMEasting, zone_buf);

  UTMZone = zone_buf;
}

/**
 * Converts UTM coords to lat/long.  Equations from USGS Bulletin 1532
 *
 * East Longitudes are positive, West longitudes are negative.
 * North latitudes are positive, South latitudes are negative
 * Lat and Long are in fractional degrees.
 *
 * Written by Chuck Gantz- chuck.gantz@globalstar.com
 */
static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting,
                           const char* UTMZone, double& Lat,  double& Long )
{
	double k0 = UTM_K0;
	double a = WGS84_A;
	double eccSquared = UTM_E2;
	double eccPrimeSquared;
	double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
	double N1, T1, C1, R1, D, M;
	double LongOrigin;
	double mu, phi1Rad;
	double x, y;
	int ZoneNumber;
	char* ZoneLetter;

	x = UTMEasting - 500000.0; //remove 500,000 meter offset for longitude
	y = UTMNorthing;

	ZoneNumber = strtoul(UTMZone, &ZoneLetter, 10);
	if((*ZoneLetter - 'N') < 0)
	{
		y -= 10000000.0;//remove 10,000,000 meter offset used for southern hemisphere
	}

	LongOrigin = (ZoneNumber - 1)*6 - 180 + 3;  //+3 puts origin in middle of zone

	eccPrimeSquared = (eccSquared)/(1-eccSquared);

	M = y / k0;
	mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64-5*eccSquared*eccSquared*eccSquared/256));

	phi1Rad = mu	+ (3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
				+ (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
				+(151*e1*e1*e1/96)*sin(6*mu);

	N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
	T1 = tan(phi1Rad)*tan(phi1Rad);
	C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad);
	R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5);
	D = x/(N1*k0);

	Lat = phi1Rad - (N1*tan(phi1Rad)/R1)*(D*D/2-(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24
					+(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared-3*C1*C1)*D*D*D*D*D*D/720);
	Lat = Lat * DEGREES_PER_RADIAN;

	Long = (D-(1+2*T1+C1)*D*D*D/6+(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1)
					*D*D*D*D*D/120)/cos(phi1Rad);
	Long = LongOrigin + Long * DEGREES_PER_RADIAN;

}

static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting,
    std::string UTMZone, double& Lat, double& Long) {
  UTMtoLL(UTMNorthing, UTMEasting, UTMZone.c_str(), Lat, Long);
}
} // end namespace UTM

#endif // _UTM_H

运行:

rosrun gps_common utm_odometry_node

或者,创建launch文件utm_odometry_node.launch

<launch>
<node name="gps_conv" pkg="gps_common" type="utm_odometry_node">
  <remap from="odom" to="vo"/>
  <remap from="fix" to="/gps/fix" />
  <param name="rot_covariance" value="99999" />
  <param name="frame_id" value="base_footprint" />
</node>
</launch>

注意:参数根据自己的需求自定义。

然后运行:

roslaunch gps_common utm_odometry_node.launch

3.2 UTM坐标转换为GPS坐标

代码在~/gps_ws/src/gps_umd/gps_common/src/utm_odometry_to_navsatfix_node.cpp,这里就不贴了。

注:代码写得标准又易读,值得学习,这也是我在这里贴代码的原因。

4 sensor_msgs/NavSatFix与gps_common/GPSFix的转换

sensor_msgs/NavSatFix的内容见:http://docs.ros.org/api/sensor_msgs/html/msg/NavSatFix.html

gps_common/GPSFix的路径为~/tingjiandan/gps_ws/src/gps_umd/gps_common/msg/GPSFix.msg,描述如下:

# A more complete GPS fix to supplement sensor_msgs/NavSatFix.

主函数fix_translator.py:

#!/usr/bin/env python

# Translates from NavSatFix to GPSFix and back

import rospy
from sensor_msgs.msg import NavSatFix
from gps_common.msg import GPSFix
import gps_common.gps_message_converter as converter

navsat_pub = rospy.Publisher('navsat_fix_out', NavSatFix, queue_size=10)
gps_pub = rospy.Publisher('gps_fix_out', GPSFix, queue_size=10)

def navsat_callback(navsat_msg):
    gps_msg = converter.navsatfix_to_gpsfix(navsat_msg)
    gps_pub.publish(gps_msg)

# Translates from GPSFix to NavSatFix.
# As GPSFix can store much more information than NavSatFix, 
# a lot of this additional information might get lost.
def gps_callback(gps_msg):
    navsat_msg = converter.gpsfix_to_navsatfix(gps_msg)
    navsat_pub.publish(navsat_msg)

if __name__ == '__main__':
    rospy.init_node('fix_translator', anonymous=True)
    navsat_sub = rospy.Subscriber("navsat_fix_in", NavSatFix, navsat_callback)
    gps_sub = rospy.Subscriber("gps_fix_in", GPSFix, gps_callback)
    rospy.spin()

消息转换函数gps_message_converter.py:

from sensor_msgs.msg import NavSatFix
from sensor_msgs.msg import NavSatStatus
from gps_common.msg import GPSFix
from gps_common.msg import GPSStatus

def navsatfix_to_gpsfix(navsat_msg):
    # Convert sensor_msgs/NavSatFix messages to gps_common/GPSFix messages
    gpsfix_msg = GPSFix()
    gpsfix_msg.header = navsat_msg.header
    gpsfix_msg.status.status = navsat_msg.status.status

    gpsfix_msg.status.motion_source = GPSStatus.SOURCE_NONE
    gpsfix_msg.status.orientation_source = GPSStatus.SOURCE_NONE
    gpsfix_msg.status.position_source = GPSStatus.SOURCE_NONE
    if ((navsat_msg.status.service & NavSatStatus.SERVICE_GPS) or
            (navsat_msg.status.service & NavSatStatus.SERVICE_GLONASS) or
            (navsat_msg.status.service & NavSatStatus.SERVICE_GALILEO)):
        gpsfix_msg.status.motion_source = \
            gpsfix_msg.status.motion_source | GPSStatus.SOURCE_GPS
        gpsfix_msg.status.orientation_source = \
            gpsfix_msg.status.orientation_source | GPSStatus.SOURCE_GPS
        gpsfix_msg.status.position_source = \
            gpsfix_msg.status.position_source | GPSStatus.SOURCE_GPS

    if navsat_msg.status.service & NavSatStatus.SERVICE_COMPASS:
        gpsfix_msg.status.orientation_source = \
            gpsfix_msg.status.orientation_source | GPSStatus.SOURCE_MAGNETIC

    gpsfix_msg.latitude = navsat_msg.latitude
    gpsfix_msg.longitude = navsat_msg.longitude
    gpsfix_msg.altitude = navsat_msg.altitude
    gpsfix_msg.position_covariance = navsat_msg.position_covariance
    gpsfix_msg.position_covariance_type = navsat_msg.position_covariance_type

    return gpsfix_msg

def gpsfix_to_navsatfix(gpsfix_msg):
    # Convert gps_common/GPSFix messages to sensor_msgs/NavSatFix messages
    navsat_msg = NavSatFix()
    navsat_msg.header = gpsfix_msg.header

    # Caution: GPSFix has defined some additional status constants, which are
    # not defined in NavSatFix.
    navsat_msg.status.status = gpsfix_msg.status.status

    navsat_msg.status.service = 0
    if gpsfix_msg.status.position_source & GPSStatus.SOURCE_GPS:
        navsat_msg.status.service = \
            navsat_msg.status.service | NavSatStatus.SERVICE_GPS
    if gpsfix_msg.status.orientation_source & GPSStatus.SOURCE_MAGNETIC:
        navsat_msg.status.service = \
            navsat_msg.status.service | NavSatStatus.SERVICE_COMPASS

    navsat_msg.latitude = gpsfix_msg.latitude
    navsat_msg.longitude = gpsfix_msg.longitude
    navsat_msg.altitude = gpsfix_msg.altitude
    navsat_msg.position_covariance = gpsfix_msg.position_covariance
    navsat_msg.position_covariance_type = gpsfix_msg.position_covariance_type

    return navsat_msg

launch文件fix_translator.launch:

<launch>

<!--
    fix_translator translates to and from NatSatFix 
    and GPSFix messages.

    If you want to translate from NavSatFix to GPSFix,
    you have to modify the first two remap lines.
   
    If you want to translate from GPSFix to NavSatFix,
    you have to uncomment and modify the last two remap 
    lines.

    Only adjust topic names after "to=" in each remap line.
-->

  <node name="fix_translator" pkg="gps_common" type="fix_translator">
    <!-- Translate from NavSatFix to GPSFix //-->
      <remap from="/navsat_fix_in"  to="/fix"/>       
      <remap from="/gps_fix_out"    to="/gps_fix"/>

    <!-- Translate from GPSFix to NavSatFix //-->
     <!--
       <remap from="/gps_fix_in"     to="/YOUR_GPSFIX_TOPIC"/>   
       <remap from="/navsat_fix_out" to="/YOUR_NAVSATFIX_TOPIC"/>   
     //-->
  </node>

</launch>

注释写得很详细,就不翻译了。

运行:

roslaunch gps_common fix_translator.launch

注:ROS支持Python,这个项目同时使用了C++和Python,值得学习一下哦。

5 参考

[1] Github: http://wiki.ros.org/gps_common
[2] ROS wiki: http://wiki.ros.org/gps_common

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(6)GPS坐标与UTM坐标的转换 的相关文章

  • C++笔试题

    1 用预处理指令 define声明一个常数 xff0c 用以表明1年中有多少秒 xff1f define SECONDS PER YEAR 60 60 24 365 UL 2 写一个标准宏MIN xff0c 这个宏输入两个参数并返回较小的一
  • C++ Primer第五版学习 第十章

    泛型算法为什么叫泛型 可以运用在多种容器类型之上 xff0c 而容器内的元素类型也可以多样化 标准库算法对迭代器而不是容器进行操作 因此 xff0c 算法不能直接添加或删除元素 find iter1 iter2 value 搜索算法 前两个
  • kindle操作:传输下载的书籍、更改书籍封面

    kindle 可以使用 calibre 软件进行电子书的管理 xff0c 官网下载地址为 xff1a https calibre ebook com download calibre 是一款电子书管理的开源软件 xff0c 支持Window
  • C++ Primer第五版学习 第十一章

    一 关联容器类型 按关键字有序保存元素 map关联数组 xff0c 保存关键字 值对set关键字即值 xff0c 即只保存关键字的容器multimap关键字可重复出现的mapmultiset关键字可重复出现的set 无序集合 unorder
  • C++ Primer第五版学习 第十二章

    一 三种内存 静态内存 xff1a 保存局部static对象 类static数据成员以及定义在任何函数之外的变量 栈内存 xff1a 保存定义在函数内的非static对象 分配在静态内存和栈内存中的对象由编译器自动创建和销毁 对于栈对象 x
  • EC20、RM500Q在TX2上或其他设备上模块识别不到

    首先本人使用的是minipcie接口 xff0c RM500Q也是转成minipcie接口接入设备的 xff0c 然后运行命令lsusb xff0c 看不到这些模块 曾尝试在两个设备上移植过EC20和RM500都遇到同样的问题 xff0c
  • 【NVIDIA】显卡报错:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver

    输入nvidia smi报错如下 xff1a NVIDIA SMI has failed because it couldn 39 t communicate with the NVIDIA driver Make sure that th
  • 笑容逐渐消失? shader 编程入门实战 ! Cocos Creator!

    编程斗图 xff01 随手拈来 xff01 文章底部获取完整代码 xff01 效果预览 为了实现这个效果 xff0c 需要准备两张相近的图片 在 Cocos Creator 编辑器中 xff0c 新建一个材质 Material xff0c
  • Windows安装TensorFlow教程(国内源安装附上各大镜像网站网址)

    安装TensorFlow TensorFlow由Google公司打包成一个 pip 安装包 xff0c 可以用正常安装包的方式安装 TensorFlow xff0c 即进入命令行执行下面这一条简单的语句 正常安装 xff1a pip ins
  • Openstack-Rocky 一键安装(多节点搭建)~步骤超详细

    本次openstack多节点自动化安装 xff0c 采用4台虚拟机节点为演示环境 xff0c 首先演示如何自动化快速搭建一套openstack云平台 实验环境 xff1a 1 控制节点 CPU xff1a 双核双线程 CPU虚拟化开启 内存
  • python 更新pip报错 解决方法大全

    python 更新pip报错 解决方法大全 在使用Python的pip安装第三方库时会提示当前pip版本低 xff0c 要求更新 xff0c 但更新时会报错 xff0c 请依次尝试以下几种方法 xff1a 在使用Python的pip安装第三
  • 获取百度主页和系统调用

    获取百度主页 span class token function exec span 8 span class token operator lt span span class token operator gt span dev tcp
  • 文本编辑工具vim-及特殊用法,alias别名

    文章目录 简介打开文件 一 vim三种模式模式转换关闭文件特殊用法 xff1a 二 命令模式1 命令模式查找2 命令模式光标跳转3 命令模式翻屏操作4 字符编辑 xff1a 5 替换命令 r replace 6 删除命令 xff1a 7 复
  • 企业竞争分析的几种方法:SWOT、波特五力、PEST

    最近实验室要申报一个互联网 43 的项目 xff0c 项目中有关企业经营部分的内容着实令我们这些工科生无从下手 xff0c 在咨询了某专业相关的学妹后稍微有了点头绪 此处手动感谢学妹的协助哈哈哈 xff0c 本着学科交叉 xff0c 多学无
  • 解决E: 仓库 “http://ppa.launchpad.net/fcitx-team/nightly/ubuntu bionic Release” 没有 Release 文件。

    今天 xff0c 在更新软件时 xff0c 使用以下命令时 sudo apt get update sudo apt get upgrade 抛出错误 E 仓库 http ppa launchpad net fcitx team night
  • (仿牛客社区项目)Java开发笔记3.5:添加评论

    文章目录 添加评论1 dao层2 service层3 controller层4 view层5 功能测试 添加评论 根据上节的开发安排 xff1a 显示评论功能完成后 xff0c 开始实现添加评论功能 1 dao层 CommentMapper
  • js_事件

    一 常用的事件 onload 加载完成事件 页面加载完成之后 常用于做页面js代码初始化操作 onclick 单击事件 常用于按钮的点击相应操作 onblur 失去焦点事件 常用于输入框失去焦点后验证其输入内容是否合法 onchange 内
  • 操作系统学习

    目录 2 1 操作系统的启动 3 1 内存分层结构 3 2 地址空间与地址生成 3 3 内存分配 3 4 压缩式与交换式碎片整理 4 1 非连续内存 分段 4 2 非连续内存 分页 4 3 页表概述 4 4 多级页表 4 5 反向页表 5
  • 更改 tr 背景颜色无效问题

    更改tr背景颜色无效问题 x1f4c3 在更改tr背景颜色时 xff0c 我们肯定是想要整行颜色改变 xff0c 但有时会出现只有部分改变 或 全都不改变的情况 这时我们就需要去看一下自己是否在之前设计的 CSS 样式中已经给定了tr中的t
  • 【以例为引】gtsam简单入门(上)--理论和认识

    如有错漏 xff0c 请评论或者私信指出 xff0c 感谢 xff01 xff01 GTSAM简介 GTSAM xff08 Georgia Tech Smoothing and Mapping xff09 是基于因子图的C 43 43 库

随机推荐

  • 基于51单片机的门禁卡设计

    1 设计思路 RFID门禁系统主要采用了STC89C52RC单片机作为控制模块及读卡器RFID RC522作为识别模块 本设计实现了自动 准确的识别卡序列号 当有卡进入到读卡器读卡的范围内时就会读取到相应的卡序列号 xff0c 并根据得到的
  • STM8S程序烧录失败?调试?ST-Link方式新手向教程IAR

    首先我们要接线 xff0c 以上为某块STM8S的原理图 xff0c 我们要SWIM接SWIM xff0c NSET接RESET xff0c GND接GND xff0c 3 3接3 3 接线完成后就是软件部分了 软件部分首先要下载ST li
  • 机器学习算法——K-近邻算法(代码实现手写数字识别)

    0 引言 xff0c K 近邻算法是一种非常有效的分类算法 xff0c 它非常有效且易于掌握 原理 xff1a K 近邻算法通过计算不同样本之间的距离来分类物品 使用前 xff0c 我们需要有一个训练样本集 xff0c 并且样本集中每个数据
  • 为Navigation 2创建自定义behavior tree plugin

    系列文章目录 思岚激光雷达rplidar从ROS 1到ROS 2的移植 ROS 2下navigation 2 stack的构建 订阅rviz2的导航目标位置消息 goal pose 打断behavior tree的异步动作节点 xff0c
  • ubuntu20:/usr/bin/env: ‘python’: No such file or directory

    参考 xff1a https stackoverflow com questions 3655306 ubuntu usr bin env python no such file or directory 第一种可能 xff1a 如果没装p
  • 四轴无人飞行器 之 上位机

  • c/c++编程学习:空指针是什么?

    什么是空指针 xff1f 对于每一种指针类型 xff0c 都有一个特殊的值 空指针 xff0c 空指针与其他所有指针值区分开来 xff0c 保证其不会指向任何函数或者对象等有意义的数据 因此 xff0c 取地址运算符 amp 永远不会产生空
  • 基于ESP32的智能车WiFi图传模块实现

    基于 ESP32 C3 的多协议 WiFi 透传模块 xff08 可用作智能车图传 xff09 本项目为基于乐鑫公司的 ESP32 C3 芯片制作的无线透传模块 xff0c 具有多个通信协议接口 xff1a UART SPI 设计初衷是为了
  • 云服务器下载的镜像文件raw格式转vmdk

    使用软件qemu img https qemu weilnetz de w64 2021 下载之后安装 xff0c 然后进入安装的文件夹 xff0c 打开命令行工具然后执行下面命令 qemu img exe convert p f raw
  • keil5使用Arm Compiler 6编译出错

    Using Compiler 39 V6 15 39 folder 39 D Keil v5 ARM ARMCLANG Bin 39 main c 16 warning In file included from USER stm32f4x
  • 浏览器的相关知识

    今天在网上找到了一些需要大致了解的有关浏览器的相关知识分享 xff0c 原文链接在下方 1 浏览器的主要组成部分是什么 xff1f 用户界面 包括地址栏 前进 后退按钮 书签菜单等 除了浏览器主窗口显示的您请求的页面外 xff0c 其他显示
  • MySQL--用Navicat连接MySQL8.0报错1251问题解决

    文章目录 一 安装后直接用Navicat连接1251报错二 仍报错为 39 mysql 39 不是内部或外部命令 1 环境变量配置 三 找不到MySQL Server 8 0 bin路径四 解决上述全部问题 一 安装后直接用Navicat连
  • 10 分钟让你明白 MySQL 是如何利用索引的

    一 前言 在MySQL中进行SQL优化的时候 xff0c 经常会在一些情况下 xff0c 对 MySQL 能否利用索引有一些迷惑 譬如 MySQL 在遇到范围查询条件的时候就停止匹配了 xff0c 那么到底是哪些范围条件 xff1f MyS
  • 吊炸天的 Docker 图形化工具 —— Portainer

    一 Docker图形化工具二 DockerUI三 船坞四 搬运工1 查看portainer平均值2 选择喜欢的portainer风格整合 xff0c 下载3 启动dockerui容器4 xff0c 网页管理 一 Docker图形化工具 Do
  • 为提高面试通过率,技术岗可以提前做好哪些面试准备?

    Hi xff0c 大家好 xff0c 我是小庄 目前2023届秋招提前批已经陆续开始了 xff0c 考虑到一些校招的同学可能是第一次接触面试 xff08 该文章适用于校招 社招 xff09 xff0c 所以这篇文章就是为了记录一些面试技巧
  • GNU Radio自定义模块:Embedded Python Block的使用

    GNU Radio 学习使用 OOT 系列教程 xff1a GNU Radio3 8创建OOT的详细过程 基础 C 43 43 GNU Radio3 8创建OOT的详细过程 进阶 C 43 43 GNU Radio3 8创建OOT的详细过程
  • 中文分词

    本文首先介绍下中文分词的基本原理 xff0c 然后介绍下国内比较流行的中文分词工具 xff0c 如jieba SnowNLP THULAC NLPIR xff0c 上述分词工具都已经在github上开源 xff0c 后续也会附上github
  • (1)GNSS驱动nmea_navsat_driver 功能包的使用

    总览 该软件包为输出兼容NMEA语句的GPS设备提供了ROS接口 有关原始格式的详细信息 xff0c 请参见NMEA句子的GPSD文档 在成千上万的NMEA兼容GPS设备中 xff0c 我们正在汇编已知支持的设备列表 这个包是与兼容geog
  • (2)ROS传感器之GPS实践

    一 GPS接口类型 GPS接口大体可以分为两类 xff0c 一是单独的GPS接收器 xff0c 通常为USB接口 xff1b 二是与其他传感器集成 xff0c 例如激光雷达或者imu xff0c 大多是USB或者网络接口 xff0c 本文主
  • (6)GPS坐标与UTM坐标的转换

    1 简介 1 1 消息 gps common定义了两个通用消息 xff0c 供GPS驱动程序输出 xff1a gps common GPSFix和gps common GPSStatus 在大多数情况下 xff0c 这些消息应同时发布 xf