GPSリアルタイムトラッキングしてみた
秋月のGPS受信機 GT-730F/L と PHP を使い、id:hidep22:20080503:1209815231 のようなことができないかと悶々としていたが、シリアルポートProxyを使い実装できたのでメモしておく。
AIR-EDGEとの組み合わせで、やっとカーナビ?が使えるようになった。
- http://akizukidenshi.com/catalog/g/gM-02619/
- Arduino - Software (ページの一番下の Serial Proxy から serproxyを取得)
準備
手順
ブラウザでHTML(gps.html)を開くだけ。
HTML(gps.html)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>GPS</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="http://maps.google.com/maps?file=api&v=2&sensor=true_or_false&key=(API_KEY)"></script> </head> <body> <form action="#" method="get" onsubmit="return false"> 経度<input type="text" id="lat" size="10" /> 緯度<input type="text" id="lng" size="10" /> 速度<input type="text" id="speed" size="6" /> 向き<input type="text" id="course" size="6" /> <input type="checkbox" id="repeat" value="1"/><label for="repeat">繰り返し更新する</label> ※serproxyを起動すること! </form> <div id="map_canvas" style="width: 980px; height: 450px"></div> <script type="text/javascript"> var map; var zoom = 15; var poli; function set_center() { $.get("get_gps_log.php", function(data){ if (data.substr(0,2) != 'OK') return; va = data.split(","); //0:ステータス,1:経度,2:緯度,3:速度,4:向き $('#lat').val(va[1]); $('#lng').val(va[2]); $('#speed').val(va[3]); $('#course').val(va[4]); var p = new GLatLng(va[1], va[2]); map.setCenter(p, zoom); var latlngs = create_arrow(p, 60, 80, va[4]); if (typeof poli != 'undefined') map.removeOverlay(poli); poli = new GPolygon(latlngs, "#ff0000", 5, 0.5, "#ff6666", 0.1); map.addOverlay(poli); if ($('#repeat').attr('checked')) { setTimeout( "set_center()", 5000); } }); } /** * 矢印型の経緯度配列を返す。 * * @param GLatLng latlng 地図の中心経緯度 * @param ingeger w 矢印の幅。ピクセル数 * @param integer h 矢印の高さ。ピクセル数 * @param integer deg 矢印の向き。角度。上(北):0, 右(東):90,.. */ function create_arrow(latlng, w, h, deg) { //基準点の位置取得 var point = map.fromLatLngToContainerPixel(latlng); var x = point.x; var y = point.y; //回転角度をrad変換し、向きを逆転 var a = -2 * Math.PI * deg / 360; //右下 var latlng2 = map.fromContainerPixelToLatLng(point_rotate( w/2, h*.2, a, x, y)); //上 var latlng3 = map.fromContainerPixelToLatLng(point_rotate( 0, -h*.8, a, x, y)); //左下 var latlng4 = map.fromContainerPixelToLatLng(point_rotate(-w/2, h*.2, a, x, y)); var latlngs = []; latlngs.push(latlng); latlngs.push(latlng2); latlngs.push(latlng3); latlngs.push(latlng4); latlngs.push(latlng); return latlngs; } /** * (x1,y1) を a だけ回転させた結果を返す。 * * @param integer x1 * @param integer y1 * @param integer a 回転角rad * @param integer x0 X軸オフセット * @param integer y0 Y軸オフセット * @return GPoint */ function point_rotate(x1, y1, a, x0, y0) { var x = Math.round( x1 * Math.cos(a) + y1 * Math.sin(a)); var y = Math.round(-x1 * Math.sin(a) + y1 * Math.cos(a)); return new GPoint(x + x0, y + y0); } $(document).ready(function(){ if (GBrowserIsCompatible()) { map = new GMap2(document.getElementById("map_canvas")); map.addControl(new GLargeMapControl()); GEvent.addListener(map, "zoomend", function(old_zoom, new_zoom) { zoom = new_zoom; }); setTimeout( "set_center()", 5000); } }); $(document).unbind(function(){ GUnload(); }); $('#repeat').change(function(){ if ($(this).attr('checked')) { setTimeout( "set_center()", 5000); } }); </script> </body> </html>
PHPファイル(get_gps_log.php)
<?php // Arduino Serial Proxy 経由で GPS ログを取得する // http://www.arduino.cc/en/Main/Software // GPS受信機出力データ書式 // NMEA 0183 Standard Version 3.0 // http://ssro.ee.uec.ac.jp/ssro/uchuu-tsuushin/gps/GPS-data-format.html define('MY_HOST', 'localhost'); define('MY_PORT', 5332); //GPS出力 $out = getLog(MY_HOST, MY_PORT); if ($out) { $out = split(',', $out); //緯度[度] latitude $lat = calc($out[3]); if ($out[4] == 'S') $lat = -$lat; //経度[度] longitude $lng = calc($out[5]); if ($out[6] == 'W') $lng = -$lng; //速度[Km/h] 元はノット $speed = $out[7] * 1.852; //向き[度] 北:0度, 東:90度, ... $cource = $out[8]; echo "OK,{$lat},{$lng},{$speed},{$cource}"; } else { echo 'NG'; } exit; /** * NMEA-0813フォーマットの経緯度をGoogleMapで読める経緯度に変換する * GPS出力が「13443.6343」の場合、134度43分6343=134度43分38秒058を示す * GoogleMapでは度分秒でなく度だけ使用するため、秒換算の経緯度を3600で割る */ function calc($str) { if (!preg_match('/^(\d+)(\d\d)\.(\d+)$/', $str, $ma)) return false; $hour = $ma[1]; $min = $ma[2]; $sec = $ma[3] * 60 / 10000; return ($hour * 3600 + $min * 60 + $sec) / 3600; } /** * GPS LOGを得る * @param string $host Serproxy接続先IP * @param integer $port Serproxy接続先ポート */ function getLog($host, $port) { //ソケット作成 $mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($mysock == FALSE) return false; //ソケット・コネクト $result = socket_connect($mysock, $host, $port); if (!$result) { socket_clear_error($mysock); socket_close($mysock); return false; } //ソケット・リード while (true) { $buffer = socket_read($mysock, 1024, PHP_BINARY_READ); $pos = strpos($buffer, '$GPRMC'); if ($pos !== false) { $out = substr($buffer, $pos); break; } }; while (true) { $buffer = socket_read($mysock, 1024, PHP_BINARY_READ); $pos = strpos($buffer, '*'); if ($pos !== false) { $out .= substr($buffer, 0, $pos); break; } $out .= $buffer; } //ソケット・クローズ socket_close($mysock); return $out; } ?>