地面站开发教程 第一篇 - 地图纠偏

飞控开发

看到社区里有很多朋友对开发地面站很感兴趣,要求楼主上传源代码,楼主已经上传了 Mission Planner PlayUAV 版的代码, 接下去也会上传DroidPlanner 的代码, 本想把地图纠偏部分去掉, 既然已经把全部代码上传了,那么索性就写个一系列的教程,和大家分享地面站开发经验。如果能得到大家支持这个教程会继续写下去, 第一篇就教大家怎么做地图纠偏, 这是所有使用国内地图都需要用到的。
首先简单讲一下怎么在地面站里面使用地图, 对于手机上的APP 来说,国内各大地图厂商都提供了SDK, 只要把SDK 包含到你的工程里面,就可以方便的调用地图功能,而且SDK里面也都自带纠偏函数,只要调用就可以了。而对于PC 地面站来说,没有SDK 可以用, 需要用到第三方控件,这个比较有名的开源地图控件就是 GMap.Net, 这是用C# 写成的, MissionPlanner 用的就是这个控件, 还有一个是用Qt 写的,叫opmap, QGroundControl 用的就是这个。 这两个地图控件原理是一样的,都是通过HTTP 方式去服务器上下载地图瓦片图片,然后在本地拼接起来,最后显示在屏幕上。
这些地图控件都集成了国外地图厂商的服务,比如google, Bing 之类的, 但要用到国内地图,那就要纠偏了,接下去就是本文的重点了,如何纠偏。实际上纠偏算法是非常简单的,没有几行代码, 下面的这个纠偏函数就可以把GPS坐标转成 火星坐标, 这个算法适用于 国内的 高德,腾讯,谷歌中国 。

final static double pi = 3.14159265358979324;
final static double a = 6378245.0;
final static double ee = 0.00669342162296594323;
static double x_pi = pi * 3000.0 / 180.0;

private static boolean outOfChina(double lat, double lon)
{
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}

public static void transform(double wgLat, double wgLon, double[] latlng)
{
if (outOfChina(wgLat, wgLon))
{ //判断有没有在中国范围内
latlng[0] = wgLat;
latlng[1] = wgLon;
return;
}
double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
double radLat = wgLat / 180.0 * pi;
double magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
latlng[0] = wgLat + dLat;
latlng[1] = wgLon + dLon;
}

double wgLat, double wgLon 这两个参数是需要转换的经纬度, double[] latlng 是转换后的坐标。
代码够简单吧, 反向转换也很简单,只要采用逆推法就可以了:

public static void untransform(double wgLat, double wgLon, double[] latlng)
{
double d[] = new double[2];
transform(wgLat,wgLon,d);
latlng[0] = wgLat+(wgLat-d[0]);
latlng[1] = wgLon+(wgLon-d[1]);
}

以上简单的两个函数就解决了 高德,腾讯,Google 中国的纠偏, 对于百度地图,则稍微麻烦一点,需要进行二次转换,也就是说在调用transform 函数后,还需要再进行一次纠偏, 代码如下:

public static void transformBaidu(double wgLat, double wgLon, double[] latlng)
{
double d[] = new double[2];
transform(wgLat,wgLon,d);
double x = d[1], y = d[0];
double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
latlng[1] = z * Math.cos(theta) + 0.0065;
latlng[0] = z * Math.sin(theta) + 0.006;
}

对于百度反纠偏, 也同样采用逆推法:

public static void untransformBaidu(double wgLat, double wgLon, double[] latlng)
{
double x = wgLon - 0.0065, y = wgLat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
double gg_lon = z * Math.cos(theta);
double gg_lat = z * Math.sin(theta);
untransform(gg_lat,gg_lon,latlng);
}

本人声明: 以上代码纯属技术交流使用, 请勿用于非法用途, 本社区概不负责!

23 个评论

支持
话说社区版的Pixhawk神马时候再次开抢?哈哈 什么时候有货呢
春节一过,马上开抢!
话说还有那个 安卓地面站什么时候能够公开
虽然不太熟悉代码,但是又长见识了。赞一个
我一直想问问,地图偏移的问题是地图商有意而为之还是别的特殊需要?
必须顶起来!最近也在搞地面站项目
是中国政府为了保密需要,在所有支持地图显示坐标的GPS设备上必须引入偏移。而且还是非线性的。
百度“地图偏移”以后第一个条目C站的帖子就讲得非常详细了
确实是非线性的,当时搞百度地图二次开发时,我都莫名其妙很久
原来学过单片机,勉强能看懂几句代码,呵呵!楼主技术厉害
虽然详细的不是很明白,但是支持分享学习~(≧▽≦)/~
支持
比较想要那个安卓的地面站
力挺
严重正常
楼主,什么时候上传DroidPlanner 的代码。也改个百度地图吧、
请问楼主,MissionPlanner,QGroundControl 这两个地面站目前都支持什么类型的地图?
怎么不继续写了
transformLat() ,transformLon()这两个函数在哪里
请问android手机和apm通信的代码有吗,能给点资料啥的吗,做apm开发,到这个问题有点迷茫,不太懂
求函数transformLat(),transformLon()

要回复文章请先登录注册