4.VPS 服务器(虚拟专用服务器)
我使用的是 vultr 的 VPS 服务器(最便宜的 3.5 美元 / 月就可以, 不用买贵的. 并且不使用时可以删除掉, 不计费的), 注册地址(打个广告, 可以忽略):
https://www.vultr.com/?ref=7521512
安装的系统为: Ubuntu 18.04.4 LTS.
5. 汽车一辆.
没有汽车的话, 也可以用自行车等交通工具代替, 可以将设备放在背包中测试.
0*03 设计方案
设计方案如下:
首先将树莓派安置在目标小车上.
树莓派通过 GPS 模块实时采集 GPS 情报, 并将 GPS 情报实时上传到云端服务器.
云端服务器将 GPS 信息存储在数据库中.
通过访问云端服务器的 html 网页, 使用百度地图, 将目标小车的轨迹描画出来.
0*04 部署过程
整个部署过程可以分为两部分: 云端服务器部署和树莓派部署.
Part1: 云端服务器部署
步骤 1: 搭建 PHP 环境.
(1)安装 MySQL.
sudo apt-get install MySQL-server
(2)安装 Apache.
sudo apt-get install apache2
(3)安装 php7.0.
sudo apt-get install php7.0
检测是否安装成功:
php7.0 -v
(4)其他模块安装.
sudo apt-get install PHP-mbstring php7.0-mbstring PHP-gettext libapache2-mod-php7.0
(5)安装 phpMyAdmin.
sudo apt-get install phpmyadmin
安装过程会提示输入 MySQL 的 root 账号的密码, 密码一定记住.
此时的 phpmyadmin 文件夹被安装在 / usr/share/phpmyadmin 下, 为了能在浏览器中访问到 phpmyadmin, 需要在 / var/www/HTML 下做一个软连接到该文件夹:
进入 / var/www/HTML 文件夹, 在该目录下执行如下操作:
sudo ln -s /usr/share/phpmyadmin
此时在浏览器中键入 http://localhost/phpmyadmin , 进入管理界面.
(6)重启 MySQL 和 Apache
- sudo service MySQL restart
- sudo service apache2 restart
步骤 2: 创建数据库.
通过 http://localhost/phpmyadmin 访问数据库, 并建立如下数据库.
步骤 3: 创建更新经纬度的 PHP 接口.
进入 / var/www/HTML 文件夹, 创建 interface 文件夹.
进入 / var/www/HTML/interface 文件夹, 创建 updateGPS.PHP 文件.
功能: 更新 GPS 信息到数据库.
- <?PHP
- function isInvalidKey() {
- $session = @$_GET['session'] ? $_GET['session'] : '';
- if (empty($session)) {
- return true;
- }
- // 防止 SQL 注入
- if (false==ctype_alnum($session)) {
- return true;
- }
- if (isDeadKey($session)) {
- return true;
- }
- else {
- return false;
- }
- }
- function isDeadKey(&$session) {
- $mysql_server_name='localhost'; //MySQL 数据库服务器
- $mysql_username='root'; // user
- $mysql_password='password'; // [注意, 请设置为正确的密码.]
- $mysql_database='infos'; // 数据库名
- $con=mysqli_connect($mysql_server_name,$mysql_username,$mysql_password,$mysql_database);
- if(!$con){
- die("连接失败:" . mysql_error());
- }
- $sqldata="SELECT * FROM session_info WHERE session ='$session'";
- echo $sqldata;
- echo "<br>";
- $result=mysqli_query($con,$sqldata);
- mysqli_close($con);
- //echo mysqli_num_rows($result);
- if (mysqli_num_rows($result) == 0) {
- return true;
- }
- else {
- return false;
- }
- }
- function updateGPS() {
- $session = @$_GET['session'] ? $_GET['session'] : '';
- $mysql_server_name='localhost'; //MySQL 数据库服务器
- $mysql_username='root'; // user
- $mysql_password='password'; // [注意, 请设置为正确的密码.]
- $mysql_database='infos'; // 数据库名
- $connent=new mysqli($mysql_server_name,$mysql_username,$mysql_password,$mysql_database);
- if($connent->connect_error){
- die("连接失败:" . $connent->connect_error);
- }
- // 插入数据
- date_default_timezone_set('PRC');
- $time = date("Y/m/d H:i:s");
- $lat = $_GET['lat'];
- $lon = $_GET['lon'];
- $insertdata="insert into map_route(session,time,lat,lon) values('$session','$time','$lat','$lon')";
- echo $insertdata;
- if($connent->query($insertdata)==true){
- echo "插入数据成功";
- }else{
- echo "插入数据失败:" . $connent->error;
- }
- echo "<br>";
- // 关闭数据库
- mysqli_close($connent);
- }
- if(isInvalidKey()) {
- exit("session is invalid");
- }
- // 更新 GPS
- updateGPS();
- ?>
步骤 4: 创建地图显示模块
进入 / var/www/HTML 文件夹, 创建 location 文件夹.
location 文件夹内的文件, 见 baidu 网盘, 如下:
链接: https://pan.baidu.com/s/1zamZax-S36paXvl04_tc9g
提取码: 3biu
主要功能:
读取数据库中的 GPS 信息, 并用百度地图显示出来.
Part2: 树莓派部署
创建 updateGPS.py 文件, 代码如下, 并使之在系统启动后自动运行.
代码功能: 通过 GPS 模块, 自动采集 GPS 信息, 并将 GPS 信息转换为百度坐标系信息上传到云端服务器.
- # -*- coding: utf-8 -*-
- import serial
- import pynmea2
- import time
- import requests
- import urllib
- import JSON
- import math
- x_pi = 3.14159265358979324 * 3000.0 / 180.0
- pi = 3.1415926535897932384626 # π
- a = 6378245.0 # 长半轴
- ee = 0.00669342162296594323 # 偏心率平方
- def gcj02_to_bd09(lng, lat):
- """
- 火星坐标系 (GCJ-02) 转百度坐标系(BD-09)
- """
- z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_pi)
- theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_pi)
- bd_lng = z * math.cos(theta) + 0.0065
- bd_lat = z * math.sin(theta) + 0.006
- return [bd_lng, bd_lat]
- def bd09_to_gcj02(bd_lon, bd_lat):
- """
- 百度坐标系 (BD-09) 转火星坐标系(GCJ-02)
- """
- x = bd_lon - 0.0065
- y = bd_lat - 0.006
- z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
- theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
- gg_lng = z * math.cos(theta)
- gg_lat = z * math.sin(theta)
- return [gg_lng, gg_lat]
- def wgs84_to_gcj02(lng, lat):
- """
- WGS84 转 GCJ02(火星坐标系)
- """
- if out_of_china(lng, lat): # 判断是否在国内
- return [lng, lat]
- dlat = _transformlat(lng - 105.0, lat - 35.0)
- dlng = _transformlng(lng - 105.0, lat - 35.0)
- radlat = lat / 180.0 * pi
- magic = math.sin(radlat)
- magic = 1 - ee * magic * magic
- sqrtmagic = math.sqrt(magic)
- dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
- dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
- mglat = lat + dlat
- mglng = lng + dlng
- return [mglng, mglat]
- def gcj02_to_wgs84(lng, lat):
- """
- GCJ02(火星坐标系)转 GPS84
- """
- if out_of_china(lng, lat):
- return [lng, lat]
- dlat = _transformlat(lng - 105.0, lat - 35.0)
- dlng = _transformlng(lng - 105.0, lat - 35.0)
- radlat = lat / 180.0 * pi
- magic = math.sin(radlat)
- magic = 1 - ee * magic * magic
- sqrtmagic = math.sqrt(magic)
- dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
- dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
- mglat = lat + dlat
- mglng = lng + dlng
- return [lng * 2 - mglng, lat * 2 - mglat]
- def bd09_to_wgs84(bd_lon, bd_lat):
- lon, lat = bd09_to_gcj02(bd_lon, bd_lat)
- return gcj02_to_wgs84(lon, lat)
- def wgs84_to_bd09(lon, lat):
- lon, lat = wgs84_to_gcj02(lon, lat)
- return gcj02_to_bd09(lon, lat)
- def _transformlat(lng, lat):
- ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
- 0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
- ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
- math.sin(2.0 * lng * pi)) * 2.0 / 3.0
- ret += (20.0 * math.sin(lat * pi) + 40.0 *
- math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
- ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
- math.sin(lat * pi / 30.0)) * 2.0 / 3.0
- return ret
- def _transformlng(lng, lat):
- ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
- 0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
- ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
- math.sin(2.0 * lng * pi)) * 2.0 / 3.0
- ret += (20.0 * math.sin(lng * pi) + 40.0 *
- math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
- ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
- math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
- return ret
- def out_of_china(lng, lat):
- return not (lng> 73.66 and lng <135.05 and lat> 3.86 and lat <53.55)
- def report_GPS_to_server():
- ser = serial.Serial("/dev/ttyAMA0",9600)
- while True:
- line = ser.readline()
- if line.startswith('$GNRMC'):
- # The sentence has lat/long
- print line
- rmc = pynmea2.parse(line)
- #if len(rmc.lon)>0 and len(rmc.lat)>0:
- if rmc.status =='A':
- lon = int(float(rmc.lon)/100)+(float(rmc.lon)*10000%1000000)/10000/60
- lon = round(lon,6)
- lat = int(float(rmc.lat)/100)+(float(rmc.lat)*10000%1000000)/10000/60
- lat = round(lat,6)
- lon,lat = wgs84_to_bd09(lon,lat)
- print lon,lat
- params = {'session' : 'Y8bhFnBJ7sePopR1','lat' : lat,'lon' : lon}
- try:
- r = requests.post("http://VPS'sIP/interface/updateGPS.php", params=params)
- except Exception , e:
- print e
- #print (r.text)
- print "---------------------------------"
- if __name__ == '__main__':
- report_GPS_to_server()
注意:
代码中的[ http://VPS http://VPS/ 'sIP/interface/updateGPS.PHP] 需要正确设置为云端服务器的 IP.
0*05 最终效果
开着汽车出去转了一大圈后, GPS 信息会被实时上传到云端服务器.
在地球上任何有网络的地方, 在浏览器中输入以下地址, 就可以实时显示汽车的运行轨迹.
http://VPS http://VPS/ 的 IP 地址 / location/index.HTML
手机端的效果图, 如下所示:
PC 端的效果图, 如下所示:
来源: http://www.tuicool.com/articles/b22iyuB