경상북도 구미시 봉곡북로 65

명품빌딩 3층, (주)네오텍

Send Your Mail At:

semineotech@gmail.com

Archive

저장된 항목을 표시합니다.

Monthly Archive 9월 2019

GPS Timeline

개요

GPS 센서를 이용하여 GPS 디바이스를 제작하고 Lora 를 이용해 이동경로를 서버에 저장 또는 지도에 표시 하는 시스템을 제작해 봅니다. 구글 클라우드로 서버를 구축하는 것은 덤.

시스템 구성

시스템 구성은 크게 3가지로 나뉩니다.

  • GPS 보드 : GPS 센서, MCU 보드, Lora 모듈
  • 구글 클라우드 가상 서버 : 구글 클라우드, Node.js 서버
  • 네오텍 서버 : MongoDB

어떻게 GPS 데이터를 저장하게 되나요.

먼저 MCU 보드가 GPS 센서로 부터 GPS 데이터를 받아 LoRa 모듈에게 전달합니다. Lora 모듈은 GPS 데이터를 SKT 서버인 ThingPlug 로 전달 하죠. 그러면 구글 클라우드에서 구축한 Node.js 서버가 GPS 데이터를 ThingPlug로부터 전달 받고 마지막으로 네오텍 서버에 GPS 데이터를 저장시킵니다.


LoRa에 대해서 알아볼까요?

1. LoRa란?

Long Range의 약자로 LoRa Alliance 사에서 만든 비면허 통신 기술입니다. IoT 통신을 위해 만들어진 통신규격으로 초장거리연결과 저전력으로 좋은 환경에서 최대 10마일(16km) 정도의 통신이 가능하며 별도의 유심이 필요없이 센서에 할당된 노드번호를 기반으로 통신합니다.

국내에서는 SK텔레콤만 서비스하며 대역은 915Mhz대역을 통해 서비스합니다.

2. LoRa 데이터 수집 방법

LoRa 디바이스의 데이터는 LoRa GW와 N/W서버를 거쳐 ThingPlug에 기록되며 ThingPlug 에서 데이터를 가져 오는 방식은 기본적으로 Polling 방식과 Subscription 방식 2가지가 있으며 둘 중 Subscription 방식을 택하여 데이터를 가져오도록 하겠습니다. Subscription 방식은 LoRa 디바이스에서 ThingPlug 로 값 전달 시 ThingPlug에 저장된 값이 달라질 경우 데이터를 가져오는 방식입니다.

3. LoRa모듈 선택

LoRa는 국내에서 SKT만 서비스한다고 알려드렸습니다. 그러면 LoRa를 사용하기 위해 SKT에서 지원하는 LoRa 모듈을 사용하려고 하는데 크게 성지산업과 솔루엠의 Lora모듈이 있습니다. 두 회사의 모듈은 차이점이 4가지가 있는데 간단히 알아봅시다.

  • Baud rate가 다르다. 성지산업:115200, 솔루엠:38400
  • 메시지 형식이 다르다. 성지산업:ASCII, 솔루엠:Hex
  • Command 형식이 다르다. 성지산업: CLI, 솔루엠:AT
  • Wake-up 처리 방식이 다르다. 성지산업: sleep 모드에서 UART 사용X, 솔루엠: 사용O

둘 중 성지산업(방식)의 LoRa 모듈인 F1PLM-01-A(외장형 LoRa 모뎀)을 선택하여 GPS 보드를 제작하도록 하겠습니다.

참고 사이트: SKT IoT Portal


GPS 보드

1.구성

  • GY-GPSV3-NEO(GPS 센서)
  • F1PLM-01-A(외장형 LoRa 모뎀)
  • WEMOS 보드(MCU 보드)

2. 연결도

3. 연결 조건 및 기타 사항

  • GPS 센서
  • LoRa 모듈
    • Baud rate는 115200bps 이다.
    • 1분 간격으로 GPS 데이터를 전달한다.
    • UART 통신 프로토콜로 CLI Command를 사용한다.
    • 구조는 ‘LRW [Command ID] [Option] CR LF’로 구성된다.
    • LoRa 모듈은 CLI Command를 받을 준비가 되면 “READ” 를 전달한다.
    • LoRa 모듈은 CLI Command를 받아 처리 후 “READ”를 전달 하기 까지 대략 5~6초의 시간이 소요된다.

Node.js

Node.js로 웹 서버를 제작하여 인터넷으로 GPS 이동경로를 표시한 지도를 확인해 봅시다.

1. 개발 환경

  • Node.js를 설치합니다.
  • Visual Studio 2017-2019를 설치합니다. Visual Studio 2017 이상에서는 Node.js 서버의 개발을 지원합니다.
  • 기본 Node.js Express 4 애플리케이션(javaScript)으로 프로젝트를 생성합니다.
  • 웹 서버가 동작하는지 실행시켜 봅니다.

2. 기능 구현

  • MQTT 통신 코드 작성
  • MongoDB에 GPS 데이터 저장
  • 메인페이지에서 날짜를 선택하여 해당 날짜의 GPS 데이터를 지도에 표시
    • 메인페이지에서 달력으로 날짜 선택
    • MongoDB GPS 데이터 읽어오기
    • Google 지도에 GPS 데이터 마커로 표시하여 보여주기

3. MQTT 통신 코드 작성

  • npm(node package manager) 을 이용하여 mqtt 패키지를 설치합니다.
  • mqtt 초기화
var mqtt = require('mqtt');
var PORT = 8883;   // mqtts 포트
var HOST = 'thingplugpf.sktiot.com';

var options = {
    host: HOST,
    port: PORT,
    protocol: 'mqtts',
    protocolId: 'MQIsdp',
    secureProtocol: 'TLSv1_2_method',   // TLSv1.2
    protocolVersion: 3,
    rejectUnauthorized: false,
    username: '****',   // ThingPlug 계정
    password: '****',   // ThingPlug 계정 사용자 인증키
    clientId: '****'   // ThingPlug clientId
};
  • mqtt 연결
var client = mqtt.connect(options);

client.on('connect', function () {
    console.log('MQTT Connected:' + client.connected);
    client.subscribe("/oneM2M/resp/[clientId]/+", { qos: 0 });  // mqtt subscribe
});
  • mqtt 메시지 확인
client.on('message', function (topic, message) {
    console.log(message.toString());
});

4. MongoDB에 GPS 데이터 저장

  • npm(node package manager) 을 이용하여 express-session, connect-mongo, mongoose 패키지를 설치합니다.
  • mongoDB 초기화 > app.js
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);

var conf = {
    db: {
        url: '****',  // mongoDB url
        collection: 'sessions'
    },
    secret: '****'
};

app.use(session({
    secret: conf.secret,
    resave: false,
    saveUninitialized: true,
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(conf.db)
}));
  • mongoDB 연결
var mongoose = require('mongoose');
var db = mongoose.connection;

db.once('open', function () {
    dbg.log('DB connection opened!');
});

db.on('connected', function () {
    dbg.log('DB Connected!');
});

mongoose.connect('[mongoDB url]', {
    useNewUrlParser: true,
    auth: {
        user: '****',   // mongoDB user
        password: '****'   // mongoDB password
    },
    auto_reconnect: true
 });
  • mongoDB 연결이 잘되는지 웹서버 실행
  • mongoDB에 GPS 데이터 삽입 및 얻기
var gpsSchema = mongoose.Schema({
    date: String,
    time: String,
    speed: String,
    latitude: String,
    longitude: String
});

var GpsData = mongoose.model('gpsSchema', gpsSchema);

exports.insertGpsData = function (date, time, speed, latitude, longitude, callback) {
    let gpsData = new GpsData();
    gpsData.date = date;
    gpsData.time = time;
    gpsData.speed = speed;
    gpsData.latitude = latitude;
    gpsData.longitude = longitude;
    gpsData.save(function (err, gpsData) {
        if (typeof callback === "function") {
            callback(err, gpsData);
        }
    });
}

exports.getGpsData = function (date) {
    return new Promise(function (resolved, rejected) {
        GpsData.find({ date: date }, function (err, results) {
            if (err === null) {
                resolved(results);
            } else {
                resolved(0);
            }
        });
    });  
}

5. 메인 페이지에서 달력으로 날짜 선택

이제 메인 웹 페이지를 만들어 봅시다. 웹 언어인 HTML 기반으로 작성하되Bootstrap 웹 프레임워크를 사용하여 간단하게 웹 페이지 를 제작해봅시다.

  • 헤더에 Bootstrap, jquery, DateTimePicker, 스타일을 포함 시킵니다.
  • 바디에 날짜 정보를 post로 전달 받을 수 있는 form 태그를 작성합니다.
  • javaScript로 달력의 UI와 동작을 추가합니다.
  • 작성된 main.html 파일을 실행해 봅시다.
  • Node.js Express4 프로젝트에서는 기본 view engine을 pug로 setting 하기 때문에 html 파일을 pug 형태로 변환하여 포함 시킵니다.
  • 변환사이트: pugHtml.com

6. Google 지도에 GPS 데이터 마커로 표시하여 보여주기

Google 지도에서 위치를 표시하여 보여주는 HTML 파일을 작성해 봅시다.

  • Google API console 에서 API key를 생성합니다.
  • 생성된 api key를 포함하여 google maps api와 markerclusterer 를 포함시킵니다. markerclusterer 는 gps 위치에 따라 찍힌 marker 가 모여있을 시 간략하게 표시해주는 역할을 합니다.
<!DOCTYPE html>
<head>
</body>
    ...
    <script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js"></script>
    <script async defer
            src="https://maps.googleapis.com/maps/api/js?key=[API Key]&callback=initMap">
    </script>
</head>
  • Google Map 초기화, 대한민국 서울을 기준으로 합니다.
<script>
        var map;
        let markers = [];  
        var dronePath;
        var markerCluster;
        let markersIndex = 0;
        var SOUTH_KOREA_BOUNDS = {
            north: 38.81,
            south: 31.97,
            west: 123.75,
            east: 132.19,
        };
        var SEOUL = { lat: 37.56, lng: 126.97 };

        function initMap() {
            map = new google.maps.Map(document.getElementById('map'), {
                center: SEOUL,
                restriction: {
                    latLngBounds: SOUTH_KOREA_BOUNDS,
                    strictBounds: false,
                },
                zoom: 7,
            });
        ...
</script>
  • 원하는 위치에 마커를 찍고 지우는 함수
       function makeMarker(position, label) {
            return new google.maps.Marker({
                position: position,
                label: label,
                map: map
            });
        }
  
        function deleteMarkers() {
            for (var i = 0; i < markers.length; i++)
                markers[i].setMap(null);
            dronePath.setMap(null);
            markers = [];
            markerCluster.clearMarkers();
        }
  • 마커를 선택할 경우 메시지 표시
        function attachMessage(marker, message) {
            var infowindow = new google.maps.InfoWindow({
                content: message
            });

            marker.addListener('click', function() {
                infowindow.open(marker.get('map'), marker);
            });
        }
  • 마커를 따라 라인을 그립니다.
        function drawPloyline(arrDroneRoute, map) {
            dronePath = new google.maps.Polyline({
                path: arrDroneRoute,
                geodesic: true,
                strokeColor: '#FF0000',
                strokeOpacity: 1.0,
                strokeWeight: 2
            });

            dronePath.setMap(map);
        }
  • 다음과 같은 gps 데이터가 기록된 텍스트 문서를 읽고 파싱하여 지도에 그려봅시다.

[09:50:32,36.148524,128.330920]
[09:50:33,36.148524,128.330920]
[09:50:34,36.148528,128.330920]
[09:50:35,36.148524,128.330920]
[09:50:36,36.148520,128.330920]

        function openTextFile() {
            var input = document.createElement("input");
        
            input.type = "file";
            input.accept = "text/plain";
        
            input.onchange = function (event) {
                processFile(event.target.files[0]);
            };
        
            input.click();
        }
function processFile(file) {
    var reader = new FileReader();

    reader.onload = function () {
        //output.innerText = reader.result;
        var text = reader.result;
        let arrData = text.split(']');
        var position = [];
        for(var idx = 0; idx < arrData.length - 1; idx++)
        {
            var arrGpsData = [];
            arrGpsData = arrData[idx].trim().substring(1).split(',');
            position[idx] = new google.maps.LatLng(arrGpsData[1], arrGpsData[2]);
            markers[idx] = makeMarker(position[idx], null);

            attachMessage(markers[idx], arrGpsData[0]); // 시간 표시
        }
        
        drawPloyline(position, map);    // 라인 그리기
        map.setZoom(15);                // 지도 확대
        map.setCenter(position[0]);     // 시작 지점으로 맵 이동

        markerCluster = new MarkerClusterer(map, markers,
            {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});     // 마커 클러스터화
    };

    reader.readAsText(file, /* optional */ "euc-kr");
}
  • 결과물
  • 마찬가지로 작성한 html 파일을 pug 형태로 변환하여 프로젝트에 포함시킵니다.

7. 정리

  • GPS 데이터를 MQTT로 전달 받아 MongoDB 저장
  • main 페이지에서 날짜를 form > post로 전달
  • MongoDB 에서 해당 날짜의 GPS 데이터를 얻음
  • GPS 데이터를 파싱하여 지도에 그림

구글 클라우드 가상 서버

이제 제작한 Node.js 웹 서버를 운영할 서버가 필요합니다. 보기에 간단한 역할을 하는 서버인데 개인 컴퓨터로 웹서버를 운영하기에는 비용과 관리 측면에서 부담이 되는 것은 사실입니다. 그래서 이러한 부분들을 해결해 줄 수 있는 클라우드 서비스를 이용하여 웹 서버를 운영해 봅시다.

1. 가상 머신 생성

구글 클라우드의 Google Compute Engine을 사용하면 Google 인프라에서 가상 머신을 만들고 실행할 수 있습니다.

  • 새 VM 인스턴스를 생성합니다. Ubuntu 18.04 LTS 버전으로 설치합니다.

구글 클라우드에서는 f1-micro 머신을 생성하면 가상서버 1개 기준으로 한달(744시간) 무료입니다. 또한 디스크 용량은 30GB가 무료입니다.

참조 : https://cloud.google.com/compute/pricing?hl=ko

  • 가상머신 생성완료

2. Node.js 웹 서버 실행

가상서버에서 Node.js 웹 서버를 운영해봅시다.

  • 연결 > SSH 부분을 누르면 터미널 창이 띄워집니다.
  • Node.js, npm 을 설치합니다.
    • $ sudo apt-get update
    • $ sudo apt-get install nodejs npm
  • 터미널을 종료하여도 웹 서버 실행 유지를 위한 forever 패키지를 설치합니다.
    • $ sudo npm install forever –global
  • 이제 Visual studio 에서 작성하였던 Node.js 웹 서버 코드를 가상 서버에 가져 옵니다.
    • 코드를 가상 서버로 옮기는 방법은 여러가지이나 압축하여 압축파일을 터미널 창으로 옮기면 가상서버로 파일이 복사됩니다.
    • 압축 해제 zip
    • $ sudo apt-get install unzip
    • $ unzip 파일명.zip
  • 압축을 풀고 프로젝트 내 경로로 이동하여 npm 패키지들을 설치해 줍니다.
    • $ sudo npm install
  • app.js 를 실행합니다
    • $ forever start app.js

3. 웹 사이트 접속하기

웹 사이트에 접속해 봅시다.

  • 가상 서버의 외부 IP와 웹 서버의 PORT로 접속 시도
    • 기본 Node.js Express4 프로젝트 생성시 포트번호는 3000
  • http://외부IP:포트번호 로 접속 시도
    • 접속 안됨
  • 가상 서버 SSH 접속 후 포트를 열어준다
    • $ sudo iptables -I INPUT -p tcp –dport 3000 -j ACCEPT
    • 다시 접속 시도
    • 접속 안됨
  • Google Cloud > VPC 네트워크 > 방화벽 규칙
  • 방화벽 규칙 만들기
    • 모든 포트와 IP를 허용하고 확인해 봅니다.
  • 접속 성공

Thanks for reading our blogs.

👋

UART To Network Module

개요

장비를 서버와 연결하여 정보를 주고 받을 수 있도록 하기 위한 module 이다.

Module은 MQTT 와 HTTPS을 이용하여 서버와 통신을 한다.

기본 동작 구성

Board와 Module간의 통신은 UART를 통하여 Data를 주고 받는다. .

Module은 Data Type에 따라 통신 방식(MQTT, HTTPS)을 선택하여 전송한다.

서버에서 명령어는 MQTT를 기반으로 한다.

Arduino 기본 설정

Module의 Main Chip은 ESP8266으로 개발 툴은 Arduino를 이용 합니다.

ESP8266 board 패킷은 Ver2.5를 사용 합니다.

2.5이상부터 HTTPS 및 MQTT 통신의 SSL 인증이 강화 됩니다.

MQTT 적용

AWS 경우 3개의 인증서를 통하여 인증을 하도록 되어 있습니다.

사내 서버의 경우 인증서 없이 USER ID 와 P/W를 통한 인증을 합니다.

하위 version에도 동작 가능하나 HTTPS 인증이 불가능 하여 Ver2.5 사용 합니다.

MQTT 통신을 위한 Library가 따로 있으며 대중적으로 2가지 종류를 사용 합니다.

MQTT and HTTPS 동시 사용시 문제점

ESP8266은 SDK Ver에 따라 <50Kbyte 정도 사용자에게 메모리가 할당 됩니다.

SSL library 사용시 기본 21Kbyte가 소모되어 메모리 overflow 발생 하였습니다.

SSL의 송수신 Buff 사이즈와 MQTT Buff size 변경으로 문제점 수정 하였습니다.