freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

智能网联汽车开发篇:行驶轨迹跟踪
2020-05-01 08:00:13
所属地 辽宁省

严正声明:本文仅用于技术探讨,严禁用于其他非法途径

0×00 前言

有时,在老婆下班开车回家的路上,我总是需要打电话问你到哪里了。

真希望能有个程序能实时了解车的实时位置。

于是有了本篇文章。

0×01 所需材料

1.树莓派。

树莓派的系统下载地址为:

https://www.raspberrypi.org/downloads/raspbian/

2.GPS模块。

3.GPS天线。

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访问数据库,并建立如下数据库。

步骤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

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

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

0×06 结束

功能有许多可以优化的地方,比如可以追加轨迹播放、根据时间检索轨迹等功能。

最后,祝福祖国繁荣昌盛,疫情早日结束。

*本文作者:xutiejun,转载请注明来自FreeBuf.COM

# 树莓派 # 汽车 # 智能网联
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录