Matt Rajca

Programming LEGO Mindstorms EV3 with golang

May 01, 2014

In 2013, LEGO introduced its third-generation Mindstorms robotics set, the EV3. Unlike its predecessors, the EV3 runs Linux, giving hackers and hobbyists the opportunity to create robots more capable than ever before.

The ev3dev project maintains open source, hacker-friendly releases of EV3’s operating system. Distributions include built-in ssh support and custom drivers for EV3’s hardware. In fact, a simple file system-based interface can be used to interact with EV3’s motors, sensors, buttons, and LEDs. Directories under /sys/class represent various device classes, and setting attributes is as simple as writing to files.

For example, executing the following shell commands will run a motor at 50% speed:

echo  50 > /sys/class/tacho-motor/outA:motor:tacho/speed_setpoint
echo   1 > /sys/class/tacho-motor/outA:motor:tacho/run

This enables third-party developers to write EV3 bindings for any programming language that has a file system IO API.

Last month, I started exploring and learning Google’s Go programming language. I liked its modern syntax, the ideas behind its concurrency model, and some of the performance advantages it provides over other dynamic languages. Moreover, Go felt like a great language to use to program robots.

So I wrote GoEV3, a package that provides EV3 bindings for Go. It includes interfaces to EV3’s motors, sensors, buttons, and LEDs; it even has a text-to-speech library! Go programs can be compiled directly on the EV3 with an ARMv5 build of Go.

Check out GoEV3’s website for more information on how to install Go on your EV3 and write your first program!

This is all it takes to drive forward as long as there are no obstacles:

package main

import (
	"github.com/mattrajca/GoEV3/Motor"
	"github.com/mattrajca/GoEV3/Sensors"
	"time"
)

func main() {
	sensor := Sensors.FindInfraredSensor(Sensors.InPort2)
	
	Motor.Run(Motor.OutPortA, 40)
	Motor.Run(Motor.OutPortB, 40)
	
	for {
		value := sensor.ReadProximity()
		
		if value < 50 {
			break
		}
		
		time.Sleep(time.Millisecond * 100)
	}
	
	Motor.Stop(Motor.OutPortA)
	Motor.Stop(Motor.OutPortB)
}