[PYTHON] Get your current location with a USB GPS receiver

I have a USB receiver at hand, so I'll attach it to a Raspberry Pi to get my current location. [BU-353S4](https://www.amazon.co.jp/GlobalSat-BU-353S4-GLOBALSAT-BU-353S4-SiRFstarIV%E6%90%AD%E8%BC%89-GPS%E3%83% AC% E3% 82% B7% E3% 83% BC% E3% 83% 90USB-% E6% 9D% B1% E4% BA% AC% E9% 80% 9A% E5% 95% 86% E6% AD% A3 % E8% A6% 8F% E8% B2% A9% E5% A3% B2 / dp / B00HZCQYLU) was used.

Although it is an analog method, execute the following command before and after inserting and removing the GPS receiver to identify the target device.

$ ls /dev/ttyUSB*
/dev/ttyUSB0  /dev/ttyUSB1  /dev/ttyUSB2  /dev/ttyUSB3  /dev/ttyUSB4

This time, we will proceed on the assumption that it is recognized as / dev / ttyUSB4.

Script to get GPS value

gps.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import serial

#Device specification
DEV = '/dev/ttyUSB4'

#Latitude and longitude fractional notation ⇒ conversion function to frequency notation
def convert(x):
    result = (float(x[0:-7])+(float(x[-7:])/60))
    return result

#A function that returns the required value as a string
def get_str(x):
    result =""
    if (x[2] == "A") and (x[2] != ""):
        result += "state:"+"ok "
    elif (x[2] == "V") and (x[2] != ""):
        result += "state:"+"alert "
    else:
        result += "state:"+"no data "
    if x[7] != "":
        result += 'speed:'+ '%.1f' % (float(x[7])*1.852) + "km/h "
    else:
        result += "speed:"+"no data "
    if (x[4] == "N")  and ( x[4] != "" ):
        result += "north latitude:" + '%.4f' % convert(x[3]) +' '
    elif (x[4] == "S")  and ( x[4] != "" ):
        result += "south latitude:" + '%.4f' % convert(x[3]) +' '
    else:
        result += "latitude:"+"no data "
    if (x[6] == "E") and ( x[6] != ""):
        result += "east longitude:" + '%.4f' % convert(x[5]) +' '
    elif (x[6] == "W") and ( x[6] != ""):
        result += "west longitude" + '%.4f' % convert(x[5]) +' '
    else:
        result += "logitude:"+"no data "
    return result

#Checksum verification
def checksum_verify(c_sum,data):
    c_data = '0x00'
    for i in range(1,len(data)-3):
        c_data = hex(int(c_data,16) ^ int(hex(ord(data[i])),16))
    if int(c_sum,16) == int(c_data,16):
        return True
    else:
        return False


#Main loop
#Process only the GPRMC value, do not process if the number of elements of that value is less than 13 and it is not acquired well
try:
    #Get serial
    sr = serial.Serial(DEV, 4800)
    while 1:
        #Line feed code excluded
        tmp = sr.readline().rstrip()
        #Checksum confirmation
        if checksum_verify(tmp[-2:],tmp):
            tmp2 = tmp.split(",")
            #Process only GPRMC
            if (tmp2[0] == '$GPRMC'):
                line = get_str(tmp2)
                print 'OK:'+tmp
                print line
                time.sleep(0.5)
        else:
            print 'NG:'+tmp
finally:
    print 'serial_close'
    sr.close()

Supplementary explanation

Each value of GPRMC is as follows

tmp2[1]UTC time Japan standard time-9 hours
tmp2[2]Status A is normal V is warning
tmp2[3]latitude(Fractional notation)
tmp2[4](N)North latitude(S)South latitude
tmp2[5]longitude(Fractional notation)
tmp2[6](E)East(W)Is it Nishikei?
tmp2[7]Movement speed knot
tmp2[8]True bearing
tmp2[9]Coordinated Universal Time(UTC)ddmmyy format
tmp2[12]Checksum

※Moving Speed knot is 1.852 times and km / h

※Checksum XOR the characters between $ to * and check if they are the same value  $GPRMC,034357.279,V,,,,,,,020117,,,N*42 If above,  GPRMC,034357.279,V,,,,,,,020117,,,N Is the calculation target

How to fix when referencing the device

It is inconvenient that it changes to / dev / ttyUSB0 or / dev / ttyUSB4 each time depending on the connected device and environment. It cannot be used in the auto-start script. It is a countermeasure in such a case.

Use of device ID

If you have decided which USB port to plug in, check the information below and use it.

$ ls -al /dev/serial/by-path
total 0
drwxr-xr-x 2 root root 140 Jan  2 01:30 .
drwxr-xr-x 4 root root  80 Jan  1 20:03 ..
lrwxrwxrwx 1 root root  13 Jan  2 01:30 platform-3f980000.usb-usb-0:1.3:1.0-port0 -> ../../ttyUSB4
lrwxrwxrwx 1 root root  13 Jan  1 20:03 platform-3f980000.usb-usb-0:1.4:1.0-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root  13 Jan  1 20:03 platform-3f980000.usb-usb-0:1.4:1.1-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root  13 Jan  1 20:03 platform-3f980000.usb-usb-0:1.4:1.2-port0 -> ../../ttyUSB2
lrwxrwxrwx 1 root root  13 Jan  1 20:03 platform-3f980000.usb-usb-0:1.4:1.3-port0 -> ../../ttyUSB3

If the target device is / dev / ttyUSB4, fix it as follows

#Device specification
DEV = '/dev/ttyUSB4'
↓
DEV = '/dev/serial/by-path/platform-3f980000.usb-usb-0:1.3:1.0-port0'

Description in udev rule (USB port can be changed)

See Oracle's About udev rules for udev` rules.

Execute the following command to check the information (when / dev / ttyUSB4 is the target device) udevadm info -a -p $(sudo udevadm info -q path -n /dev/ttyUSB4) Check the following from the displayed

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3':
    KERNELS=="1-1.3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="1.3"
    ATTRS{idVendor}=="067b"
    ATTRS{speed}=="12"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="21"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="100mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0400"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{version}==" 1.10"
    ATTRS{urbnum}=="65169"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Prolific Technology Inc. "
    ATTRS{removable}=="removable"
    ATTRS{idProduct}=="2303"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="USB-Serial Controller D"

Extract the following three points

ATTRS{idProduct}=="2303"
ATTRS{idVendor}=="067b"
ATTRS{product}=="USB-Serial Controller D"

Create a file such as 70-bu353s4.rules under /etc/udev/rules.d and enter the following information.

70-bu353s4.rules


ATTRS{idProduct}=="2303",ATTRS{idVendor}=="067b",ATTRS{product}=="USB-Serial Controller D",SYMLINK+="bu353s4"

After creating the file, insert and remove the GPS receiver Now you can connect to the GPS receiver with / dev / bu353s4, so fix it as follows

#Device specification
DEV = '/dev/ttyUSB4'
↓
DEV = '/dev/bu353s4'

Recommended Posts

Get your current location with a USB GPS receiver
Get a list of packages installed in your current environment with python
Get your current location and user agent in Python
Get a local DynamoDB environment with Docker
Get lots of your tweets with Tweepy
[Python] Get the files in a folder with Python
Get a ticket for a theme park with python
I get a UnicodeDecodeError when running with mod_wsgi
Get a list of IAM users with Boto3
A layman wants to get started with Python
Get a quick Python development environment with Poetry