Raspberry Pi and Go Programming
Go or GoLang is a compiled programming language developed by Google.
Go is widely used for Web Development and it is one of the fastest growing programming languages today. Unlike Java which is runs in a JVM (Java Virtual Machine) , Go compiles directly to Windows, OS X or Linux executable files.
In this blog we will look at creating two Go programs that talk to Raspberry Pi GPIO. The first will be a simple keyboard input program and the second will be a standalone Go web app to control GPIO pins.
Installation
To install go enter:
$ sudo apt-get install golang
To test that the install is working you can check the Go version number:
$ go version
go version go1.7.4 linux/arm
A “Hello World” example (hello.go) is:
package main
import "fmt"
func main() {
fmt.Println("Hello World");
}
The hello.go code is compiled and ran by:
$ go build hello.go # compile the go code
$ ./hello # run the go code
Hello World
Raspberry Pi GPIO
There are a number of different ways to have Go connect to the Pi General Purpose Inputs and Outputs (GPIO). For this example I am going to look at shelling out to the gpio command line utility, but there are also go rpi libaries that can be used.
For testing I like to use the gpio utility because it offers a good selection of commands and I can manually test and verify the command before I use them in my Go code. For help on gpio use the -h option.
The Raspberry Pi hardware setup used an LED with a resistor on physical pin 7 (BCM pin 4).
Our first go program (keyin.go) will read keyboard input and then to shell out twice to gpio, first time to write a value and the second time to read the value back.
package main
import (
"bufio"
"fmt"
"os/exec"
"os"
)
func main() {
// Get keyboard input
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter value for GPIO pin 7 : ")
pinval, _ := reader.ReadString('\n')
// Write to GPIO pin 7 using keyboard input
testCmd := exec.Command("gpio","write", "7", pinval)
testOut, err := testCmd.Output()
if err != nil {
println(err)
}
// Read back the GPIO pin 7 status
testCmd = exec.Command("gpio","read", "7")
testOut, err = testCmd.Output()
if err != nil {
println(err)
} else {
fmt.Print("GPIO Pin 4 value : ")
fmt.Println(string(testOut))
}
}
To compile and run the keyin.go program:
$ go build keyin.go
$ ./keyin
Enter value for GPIO pin 7 : 1
GPIO Pin 4 value : 1
Simple Go Web Application
For a starting example we’ll make a go web application (web_static.go) show a web page called web_static.html.
The web_static.html file will be :
<html>
<head>
<title>GO PI Static Page</title>
</head>
<body>
<h1>GO PI Static Page</h1>
<hr>
This is a static test page
</body>
</html>
The web_static.go program will need to import the “net/http” library. A http.HandleFunc call is used to look for the default address “/” and serve up our web_static.html file. The http.ListenAndServe function listens for web requests on port 8081.
package main
import (
"log"
"net/http"
)
func main() {
// Create default web handler, and call a starting web page
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "web_static.html")
println("Default Web Page")
})
// start a listening on port 8081
log.Fatal(http.ListenAndServe("8081", nil))
}
The Go code can be compiled and run by:
$ go build web_static.go
$ ./web_static
Default Web Page
From a web browse pointed at the Raspberry Pi on port 8081, our web page will show as:
Go Web App with Pi GPIO
The next step is to create a Web Page that can pass some parameters. For this application we’ll turn a GPIO output on and off.
A new web page (go_buttons.html) is created with two buttons. HTML anchor tags are used to pass /on and /off parameters to our Web app.
A CACHE-CONTROL meta tag set to NO-CACHE is needed to ensure that the web page always refreshes. I also included an EXPIRES meta tag (= 0) so that the browser always see the page as expired . If you don’t include meta tags the web page may only update once.
<html>
<head>
<title>GO PI GPIO</title>
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="0">
</head>
<body>
<h1>Go Raspberry Pi GPIO Test</h1>
<a href="/on"><button>Set LED ON</button></a><br>
<a href="/off"><button>Set LED OFF</button></a>
</body>
</html>
Our new Go Web app (go_buttons.go) now includes two more http.HandleFunc handler functions, one for /on and for /off. These handler functions call a new function called gpio that is used to write a outputs and read back the output status.
Our newly created gpio function shells out twice to the gpio command line utility, first time to write a value and the second time to read the value back.
package main
import (
"log"
"net/http"
"os/exec"
)
func gpio( pinval string) {
testCmd := exec.Command("gpio","write", "7", pinval)
testOut, err := testCmd.Output()
if err != nil {
println(err)
}
testCmd = exec.Command("gpio","read", "7")
testOut, err = testCmd.Output()
if err != nil {
println(err)
} else {
print("GPIO Pin 4 value : ")
println(string(testOut))
}
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "go_buttons.html")
println("Default Web Page")
})
http.HandleFunc("/on", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "go_buttons.html")
println("Web Page sent : ON")
gpio("1")
})
http.HandleFunc("/off", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "go_buttons.html")
println("Web Page sent : OFF")
gpio("0")
})
log.Fatal(http.ListenAndServe(":8081", nil))
}
To compile and run of web app go_buttons:
$ go build go_buttons.go
$ ./go_buttons
Default Web Page
Web Page sent : ON
GPIO Pin 4 value : 1
Default Web Page
Web Page sent : OFF
GPIO Pin 4 value : 0
The web page should look something like:
Summary
For a polished application I would rather use a native Go library for GPIO calls, but for prototyping I found that the gpio command line utility to be easier for trouble-shooting.
After getting a basic web page working for anchor tags for /on and /off, the next step will be to use some Javascript with AJAX to show dynamic values.