Ruby
Article

Control the Physical World with Ruby and Artoo

By Dhaivat Pandya

IoTWeek_Gray

It’s IoT Week at SitePoint! All week we’re publishing articles focused on the intersection of the internet and the physical world, so keep checking the IoT tag for the latest updates.

artoo

Ruby is a pretty slick language. But, in the past, whenever anyone mentioned “embedded” no one thought of the word “slick”. Instead, visions of terribly written C with lots of bit mashing or flashbacks to inordinate amounts of time spent with inadequate lighting trying to fight with a breadboard often came to mind. Fortunately, this is no longer the case with Artoo. Artoo is a cool library that allows Ruby to control and interact with lots of different hardware platforms (e.g. the Sphero, the Arduino, etc.). In this article, we’ll focus on getting Artoo up and running and check out a few different examples of Artoo in action using the Arduino and a standard keyboard.

Setting Up the Software

Assuming that you have a functional version of Ruby (preferably installed with RVM or rbenv), installing Artoo is super easy:

  gem install artoo

In addition, we also need separate gems for each bit of hardware we want to use. For this article, we will be using the Arduino as our primary platform. To get that working:

  gem install artoo-arduino

That’s all we need for the software to start ticking! The next step is getting the Arduino talking to us through Artoo.

Setting Up the Hardware

As you might have heard, the Arduino is based on a microcontroller platform called Atmel AVR. There used to be a time in AVR development where you’d generally get started with either a hacked together parallel port programmer or buy an STK500 and start writing some bit-banging code in C. Then, if you were on Windows, you could use AVRStudio with no issues. If you were on Linux, you’d have to use the gcc toolchain (which actually worked pretty well) to build your C code and then push it to the microcontroller using avrdude.

Generally, this process worked okay but when stuff broke, it was insanely hard to work out what was happening. I distinctly remember spending an insane amount of time trying to get a parallel port program working before giving in and getting myself an Arduino. The Arduino came along and made this whole process a million times easier, but it required using this graphical interface that was sort of annoying.

Fortunately, Artoo makes us go through none of that pain. Instead, we can use Gort which has a nice install page that works well for a variety of platforms. Gort makes it much easier to upload firmware to devices that are connected over serial ports (e.g. USB). It doesn’t reimplement the functionality that something like avrdude provides, but just wraps that functionality in a much easier-to-use interface. The first step is to plug in your Arduino into a USB port on your machine. Then, we can search for it with the gort scan command:

  gort scan serial

This will give you a list of serial ports and you can figure out which one has your Arduino connected to it. Gort can connect to all sorts of devices. Since we want it to talk to the Arduino in particular, we have to install the Arduino-related packages for gort:

  gort arduino install

And, that’s it! In a bit, we’ll use the gort arduino upload command in order to push our code to the Arduino.

The Artoo Architecture

Artoo isn’t just a library that will allow us to write code in Ruby that runs on the Arduino. Rather, it is a way to build devices in “groups” in a much more effective and clean way. Devices in the Artoo documentation are referred to as “robots.” These don’t necessarily have the characteristics we generally associate with robots (e.g. movement); they are just supposed to be devices that interact with the physical world in some way (e.g. an Arduino, a Sphero, etc). It receives events from these devices using “sockets”, although these may be over a serial connection for something like an Arduino. These events from the devices are handled by a piece of code called the Artoo Master Class. Basically, this piece of code exists to allow these devices to operate together rather than as totally independent units. You can think of it like a “master” node within a cluster.

So, the point of Artoo is to allow you to orchestrate multiple devices (“robots”) to do stuff together rather than all by themselves.

This would be cool enough to look into if Artoo stopped there. But, it doesn’t. Artoo allows you to expose an API over both HTTP and WebSockets so you can build a Web/iOS/Android/etc. application on top of these devices. For example, if you want to be able to control the lighting in a room with an Arduino, you don’t have to build all the stuff to communicate with the Arduino yourself anymore. Instead, using Artoo, you already have an exposed API that lets you do that. All you have to do is write the code that controls the lights (using Artoo’s helpers, etc. in Ruby) and write a slick user-facing app. Artoo will handle the rest. Considering how painful it has been to hook up a webserver with a hardware device in the past, this is a huge step forward. Especially if you’re using something like the Particle platform, you can build some pretty awesome, cloud-connected stuff.

LEDs

Now that we know how Artoo works at a higher level, let’s get into the nitty gritty. We’ll break down an example from Artoo that allows us to build a LED that responds to a button. Straight from the Artoo documentation, we have:

require 'artoo'

connection :arduino, adaptor: :firmata, port: '/dev/ttyACM0'

device :led, driver: :led, pin: 13
device :button, driver: :button, pin: 2, interval: 0.01

work do
  puts "Press the button connected on pin #{ button.pin }..."

  on button, :push    => proc { led.on }
  on button, :release => proc { led.off }
end

You should replace /dev/ttyACM0 with the serial port you found with gort scan serial. Although this code looks pretty simple, it is doing quite a bit behind the scenes and the documentation currently doesn’t do a great job explaining what the heck is actually going on. First of all, we set up the connection to the device with the following call:

connection :arduino, adaptor: :firmata, port: '/dev/ttyACM0'

To talk to the Arduino, Artoo uses a protocol called Firmata. The Firmata protocol has been implemented for all sorts of devices and allows Artoo to build an API, etc. on top of the Arduino.

device :led, driver: :led, pin: 13

Here we’re introducing an entirely new concept: device drivers. Artoo defines stuff that the Arduino can interact with using the concept of device drivers. These take arguments according to the function of the device. There are several device drivers that are included as part of the Artoo Arduino package and more can be added pretty easily. The led driver takes only one argument: the pin to which he LED is connected. At this point, you should connect an LED to pin 13 of the Arduino.

device :button, driver: :button, pin: 2, interval: 0.01

The button driver is a bit more complicated. It takes a pin, which is the pin on the Arduino where the push button is connected along with an interval. If you’ve read Arduino code before, this will look familiar: interval with which the event is fired.

work do
  ...
end

This is where the event loop starts. Within this block of code, we’re supposed to be handling events that devices can fire (e.g. a button being depressed). We do that with the two lines within the block:

on button, :push    => proc { led.on }
on button, :release => proc { led.off }

The device driver exposes two events that we code to: release and push. We then use the device called led (which we named earlier as part of the first argument to device) and turn it on and off for the respective action. In order to “deploy” this code, we need the Arduino to learn how to speak with the computer:

gort arduino upload /dev/ttyACM0

Of course, you should replace /dev/ttyACM0 with the device on which your Arduino is connected. This will allow the Arduino to talk in Firmata so that we can tell it what to do over USB. Let’s say we saved the code in arduino_pushbutton.rb. Then, we can run it with just standard Ruby:

ruby arduino_pushbutton.rb

That should connect to the Arduino and turn the LED on and off according to the state of the pushbutton.

The Keyboard

Turns out, we’re not limited to microcontroller boards as physical input devices. Instead, we can even use the keyboard because there’s a device driver for it. To get hold of the device driver, we just do:

gem install artoo-keyboard

Now, let’s check out an example using the keyboard as an input device:

require 'artoo'

connection :keyboard, adaptor: :keyboard
device :keyboard, driver: :keyboard, connection: :keyboard

work do
  on keyboard, :key => :got_key
end

def got_key(sender, key)
  puts sender
  puts key
end

Let’s break this code down.

connection :keyboard, adaptor: :keyboard
device :keyboard, driver: :keyboard, connection: :keyboard

Just like we told Artoo how to connect to the Arduino, we’re telling it that we want to connect to the keyboard here. Notice that all the keyboard needs is the name of the adaptor and it’ll figure out how to get a hold of keyboard input (i.e. no serial input device needed). Then, we register the device driver we want to use with the device so we can get the events that we want.

work do
  on keyboard, :key => :got_key
end

The :keyboard device driver exposes one event called key. We are hooking that up with a particular callback.

def got_key(sender, key)
  puts sender
  puts key
end

With the callback, we just print out the device that sent us that event (i.e. the keyboard) and the key value.

Putting It Together

Thus far, we’ve worked with one device at at a time. That’s a little bit boring and somewhat beats the point of using something like Artoo. We want these devices to be able to interact in order to produce something more meaningful than just an LED turned on by a pushbutton. So, we’ll build a “key logger” and try to steal people’s Gmail passwords.

Well, kind of. What we are going to do is use the keyboard driver to figure out when someone types in “gmail.com” and once they do, turn on an LED on the Arduino so we know to look for the password immediately after. Not terribly useful but should allow us to use the keyboard and Arduino together:

require 'artoo'

connection :keyboard, adaptor: :keyboard
device :keyboard, driver: :keyboard, connection: :keyboard

connection :arduino, adaptor: :firmata, port: '/dev/ttyACM0'
device :led, driver: :led, pin: 13

read_so_far = ""

work do
  on keyboard, :key => :got_key
end

def got_key(sender, key)
  read_so_far = read_so_far + key
  if read_so_far.end_with? "gmail.com"
    led.on
  end
end

And, that should get us some interaction! Let’s break down the code.

connection :keyboard, adaptor: :keyboard
device :keyboard, driver: :keyboard, connection: :keyboard

connection :arduino, adaptor: :firmata, port: '/dev/ttyACM0'
device :led, driver: :led, pin: 13

Again, we setup the connections and device drivers first. Then, onto the event loop:

work do
  on keyboard, :key => :got_key
end

The only thing that is really different here is the callback itself:

def got_key(sender, key)
  read_so_far = read_so_far + key
  if read_so_far.end_with? "gmail.com"
    led.on
  end
end

We turn the LED on when we notice that the user has typed in “gmail.com”! Of course, this serves only as an example. The keyboard device driver won’t work when your keyboard focus isn’t in the console window.

Wrapping It Up

We’ve only really brushed the surface of what is possible with Artoo. However, the documentation that comes with Artoo is sort of lacking and we’ve filled in the gaps to make it possible to do more exciting stuff with it. For some inspiration, check out this talk by one of the founders of the project. Excited to see what people will build with Artoo!

  • dgregd

    What do you think about mruby? It was designed by Matz to be used in embedded environments and compete with Lua.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Ruby, once a week, for free.