ubloxのGPSモジュールの測位間隔を変更するコマンドをgolangで作った


USBで接続するGPSモジュールを入手しました。
ubloxのチップセットを使用しているものです。
デフォルトで1秒間に1回の間隔で測位を行うようになっています。通常の用途ならばこのままでよいのですが、これを変更するコマンドを調べて、それを送り込むコマンドをgolangで作りました

ubloxの拡張コマンドを使っているので、ublox社製のチップのものでのみ使用できます。

使い方

$ ./gps_ublox
Usage: ./gps_ublox /dev/ttyACM0 rate
rate is in msec. (100 <= rate <= 65535)

500ms 間隔で測位するには、以下のようにします。( /dev/ttyACM0はGPSモジュールのデバイスファイル)

$ ./gps_ublox /dev/ttyACM0 500
$ cat /dev/ttyACM0 > gps.nmea

ビルド方法

$ go get .
$ go build

GOARCH=arm go build としてクロスビルドすればラズパイでも使えます。

ソースコード

gps_ublox.go

package main

import (
    "bufio"
    "fmt"
    "github.com/tarm/serial"
    "io"
    "log"
    "os"
    "strconv"
)

// Refer "u-blox 7 Receiver Description Including Protocol Specification V14"

func main() {
    if len(os.Args) < 3 {
        fmt.Fprintf(os.Stderr, "Usage: %s /dev/ttyACM0 rate\nrate is in msec. (100 <= rate <= 65535)\n", os.Args[0])
        os.Exit(1)
    }

    c := &serial.Config{Name: os.Args[1], Baud: 115200}
    s, err := serial.OpenPort(c)
    if err != nil {
        log.Fatal(err)
    }
    defer s.Close()

    rate, err := strconv.Atoi(os.Args[2])
    if err != nil {
        log.Fatal(err)
    }
    if rate < 100 {
        rate = 100
    }   
    if rate > 0xffff {
        rate = 0xffff
    }
    cmd := []byte{0x06, 0x08,
        0x06, 0x00, /* len */
        byte(rate & 0xff),
        byte((rate >> 8) & 0xff),
        0x01, 0x00, 0x00, 0x00}
    sendCmd(s, cmd)
    os.Exit(0)
}

func sendCmd(s io.ReadWriter, cmd []byte) {
    cmdbuf := []byte{0xb5, 0x62}
    cmdbuf = append(cmdbuf, cmd...)
    ck_a, ck_b := chksum(cmd)
    cmdbuf = append(cmdbuf, ck_a, ck_b)

    //fmt.Printf("cmdbuf = %x\n", cmdbuf)
    n, err := s.Write(cmdbuf)
    if err != nil {
        log.Fatal(err)
    }
    if n != len(cmdbuf) {
        log.Fatal(err)
    }

    waitAck(s, cmd[0], cmd[1])
}

func chksum(payload []byte) (ck_a, ck_b byte) {
    ck_a = 0
    ck_b = 0
    for _, b := range payload {
        ck_a += b
        ck_b += ck_a
    }
    return
}

func waitAck(s io.Reader, class_id, msg_id byte) {
    ack := []byte{0xb5, 0x62, 0x05, 0x01, 0x02, 0x00, class_id, msg_id}

    reader := bufio.NewReaderSize(s, 128)
loop:
    for {
        _, err := reader.ReadBytes(0xb5)
        if err != nil {
            log.Fatal(err)
        }
        for _, a := range ack[1:] {
            b, err := reader.ReadByte()
            if err != nil {
                log.Fatal(err)
            }
            //fmt.Printf("b = %x\n", b)
            if b != a {
                continue loop
            }
        }
        /* TODO: check check sum */
        //fmt.Printf("ack ok\n")
        return
    }
}