When the theme for our latest company hackathon was revealed to be “Need for Speed”, I went straight to Best Buy after work and picked up a DJI Tello drone. I had been wanting one ever since I went to GopherCon and saw the presentation by Ron Evans where he used Gobot and GoCV to make a Tello drone follow his friend’s face around. Now that I had a drone, I needed to figure out what to do with it.

I knew I wanted to do something with Gobot, because I’ve always been interested in robotics and was curious how difficult it would be to connect to the drone and issue commands. The other thing I was interested in checking out was the embeddable scripting language Lua. Why? Well, I know World of Warcraft uses Lua and even though that is the one Blizzard game I do not play, it piqued my curiousity. If Blizzard used Lua for scripting, there must be something to the language. There were also some rumblings at work about one of our teams perhaps using Lua to script their workflows. So I was curious how difficult it would be to embed Lua in Go. I decided that I would create a Go engine to control the drone via Gobot and use Lua as a scripting language to issue commands to the Go engine. Is it super practical? No. Was it a lot of fun to create? Absolutely yes.

I started with Gobot and ran some of their examples to connect to the drone. It turned out to be surprisingly easy and I had the drone responding to keyboard commands in no time at all. I even fixed a panic and submitted a pull request to the Gobot repo. Receiving video from the drone was a bit more difficult. They had two examples to receive video: one using FFmpeg/OpenCV and the other using MPlayer. I started with the FFmpeg/OpenCV example, since I was more familiar with that. It didn’t work for me; the video was lagging horribly behind. Turns out the MPlayer example suffered from the same issue. After a little fiddling, I realized the drone was sending video frame events at 60 fps and MPlayer was only processing them at 25 fps, so the events were just piling up. I submitted another pull request to fix the MPlayer example, so some other poor soul wouldn’t have to mess with it like I did. At this point, I had working Go code that could control the drone and receive video.

Next up was figuring out how to embed Lua into Go. I found a package that would allow me to do just that. The github.com/yuin/gopher-lua package makes it a really simple task to execute Lua scripts from Go and declare Lua functions that call Go code.

// initialize lua engine
L := lua.NewState()
defer L.Close()

// one example of registering a function with lua
forward := func(L *lua.LState) int {
	speed := L.ToInt(1)
	e.Forward(speed)
	return 0
}
L.SetGlobal("forward", L.NewFunction(forward))
// ...and on and on for all functions

// execute script
err := L.DoFile(script)

I ended up with some rather simple mapping code from Lua functions to my engine functions and was soon able to run a Lua script with a number of preset actions.

log("initiating take off")
takeoff()
log("hovering")

sleep(1000)

log("fly in a circle")
forward(20)
rotateleft(70)
sleep(6500)
stop()

sleep(1000)

log("front flip")
frontflip()
log("back flip")
backflip()

Finally, I created a Lua function to get the last key pressed via the Gobot keyboard driver. Using this new Lua function, I was able to make a Lua script that allows for control of the drone in real time using the keyboard. And with that, I had accomplished both of my goals: learning how to communicate with a drone using Go/Gobot and learning how to embed Lua into a Go program. The full code for my project can be found here:

https://github.com/eleniums/tello-engine

The whole learning process was a ton of fun! Now I need to figure out what else to do with the drone. At the very least, it’s fun to fly around the house.