SF11-C Laser Rangefinder 120m Example Code in Golang / Python

True Story Follows

This is how hardcore my conversations generally go:
IMG_3823
That’s right. I’m here to pick up the laser.

The existing sample code on the internets really wasn’t too friendly; sample C code existed that had an absurd number of dependencies that I couldn’t figure out how to satisfy, when it turns out that all we’re really doing is reading from a serial port.

IMG_0837small

So, this is just a quick post that maybe someone else on the internets will find helpful to get a project going using a SF11-C Laser Rangefinder

Golang

package main

import (
    "fmt"
    "io"
    "github.com/tarm/goserial"
    "strings"
    "strconv"
)

const BAUD_RATE = 9600
const PORT = "/dev/tty.usbserial-DB00WD71"
const EXPECTED_LENGTH = 20

func blockIndefinitely() {
    select {}
}

func getRangeFinderSerialConnection() io.ReadWriteCloser {
    config := &serial.Config{Name: PORT, Baud: BAUD_RATE}
    serial_interface, err := serial.OpenPort(config)
    if err != nil {
        panic("Cannot continue without a serial connection")
    }
    return serial_interface
}

func parseMetersFromLaserString(rangeFinderValue string) (float64, error) {
    return strconv.ParseFloat(
        strings.Fields(rangeFinderValue)[0],
        64,
    )
}

func outputLaserDistanceMeters(outputChannel chan float64) {
    serial_interface := getRangeFinderSerialConnection()
    defer serial_interface.Close()

    buffer := make([]byte, 128)
    for ;true; {
        bytesRead, err := serial_interface.Read(buffer)
        if err != nil || bytesRead != EXPECTED_LENGTH {
            continue
        }
        distanceMeters, err := parseMetersFromLaserString(string(buffer[:bytesRead]))
        if err == nil {
            outputChannel <-distanceMeters
        }
    }
}

func doSomethingWithRangerFinderValues(inputChannel chan float64) {
    for ;true; {
        fmt.Println(<-inputChannel)
    }
}


func main() {
    rangeChannel := make(chan float64)
    go outputLaserDistanceMeters(rangeChannel)
    go doSomethingWithRangerFinderValues(rangeChannel)
    blockIndefinitely()
}

Python Code

import serial
BAUD_RATE = 9600
PORT = "/dev/tty.usbserial-DB00WD71"

SERIAL_INTERFACE = serial.Serial(PORT, BAUD_RATE)


def serial_output_string_to_meters(serial_string):
    """
    Example input:
       1.85 m  0.189 V

    Example output:
        1.85
    """
    return serial_string.split()[0]


if __name__ == "__main__":
    try:
        while True:
            print serial_output_string_to_meters(SERIAL_INTERFACE.readline())
    finally:
        SERIAL_INTERFACE.close()