19

智能网联汽车开发篇:行驶轨迹跟踪

 4 years ago
source link: https://www.freebuf.com/geek/215912.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

4.VPS服务器(虚拟专用服务器)

我使用的是vultr的VPS服务器(最便宜的3.5美元/月就可以,不用买贵的。并且不使用时可以删除掉,不计费的),注册地址(打个广告,可以忽略):

https://www.vultr.com/?ref=7521512

安装的系统为:Ubuntu 18.04.4 LTS。

5.汽车一辆。

没有汽车的话,也可以用自行车等交通工具代替,可以将设备放在背包中测试。

0×03 设计方案

设计方案如下:

 1.首先将树莓派安置在目标小车上。
 2.树莓派通过GPS模块实时采集GPS情报,并将GPS情报实时上传到云端服务器。
 3.云端服务器将GPS信息存储在数据库中。
 4.通过访问云端服务器的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 访问数据库,并建立如下数据库。

fIry2ui.jpg!web

步骤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 ‘sIP/interface/updateGPS.php】需要正确设置为云端服务器的IP。

0×05 最终效果

开着汽车出去转了一大圈后,GPS信息会被实时上传到云端服务器。

在地球上任何有网络的地方,在浏览器中输入以下地址,就可以实时显示汽车的运行轨迹。

http://VPS 的IP地址/location/index.html

手机端的效果图,如下所示:

ZNfEN3a.jpg!web

PC端的效果图,如下所示:

IVbAbuM.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK