Firmata - Standard Libraries - Arduino Sketches: Tools and Techniques for Programming Wizardry (2015)

Arduino Sketches: Tools and Techniques for Programming Wizardry (2015)

Part II. Standard Libraries

Chapter 16. Firmata

This chapter discusses the following functions of the Firmata library:

· begin()

· sendAnalog()

· sendDigitalPorts()

· sendDigital()

· sendString()

· available()

· processInput()

· attach()

· detach()

The hardware needed to use the example in this chapter includes:

· Arduino Uno

· Computer

· USB cable

· Breadboard

· 4.7-kΩ resistor

· LED

Introducing Firmata

Arduinos are used in a wide variety of projects, from the most simple to some extremely complex devices. In most cases, their exact use is known; you know beforehand that digital pin 3 will be used to light an LED, and that analog input 4 will read the value of a light sensor. For some projects, you may not know what is connected, but you will still need to set pins as input or output, depending on the situation. Imagine a laboratory setup, one where you can study how new components work before deciding to use them in your projects. You could write a quick sketch each time to see how a component works, but this isn't always the best solution and certainly not the easiest. One way to easily set up your laboratory is to use Firmata.

Firmata is a protocol that communicates between computers and microcontrollers to easily access the Arduino hardware from software on a host machine. It uses standard serial commands and as such can be used on several different Arduino models. Messages are sent serially to and from the host computer, indicating pin status or requesting a pin to change state.

Firmata Library

To use the Firmata library, you must first import it. You can import the Firmata library from the Arduino IDE automatically, by going to the Sketch imageImport Library imageFirmata menu entry. Alternatively, you can write the lines manually:

#include <Firmata.h>

#include <Boards.h>

The Firmata protocol has several revisions, and if two devices use different revisions, that can lead to errors. To prevent this, you can specify which protocol revision to use with setFirmwareVersion():

setFirmwareVersion(major, minor);

The major and minor parameters are bytes, which specify the revision to use. For most Arduino applications, this is set to major version 0 and minor version 1.

To begin using the Firmata library, you must first call begin():

Firmata.begin();

Firmata.begin(speed);

This function opens a serial connection. By default, the speed is set to 57600 baud, but this can be changed by the optional speed parameter.

Sending Messages

The status of pins is sent as messages to and from the software on the host machine. Messages can be addressed to digital and analog pins. To send the status of an analog pin, use sendAnalog():

Firmata.sendAnalog(byte pin, int value);

The pin parameter is the analog pin you are requesting information about. The value parameter is the value read from the pin. This function does not read the pin value directly; you must explicitly read the value first:

analogValue = analogRead(pin);

Firmata.sendAnalog(pin, analogValue);

Digital pins are sent differently. Because serial connections are slow, relative to the speed of a microprocessor, something had to be done to speed up the transfer. Digital pins are either on or off, 1 or 0. To send the maximum amount of information in the minimum packet size, multiple pins are sent in a single message.

Firmata.sendDigitalPorts(pin, firstPort, secondPort);

Up to eight pins can be sent in the pin parameter, sent as a byte. The pins must be sent in order; when starting at pin 6, it must be followed by pin 7, pin 8, and so on. To set the first pin, use the firstPort parameter sent as a byte. To set the number of pins sent, use the secondPort parameter. The pin data will be sent to the computer, specifying that the data received is the data of the pins from firstPort to secondPort.

This works well when sending a range of pin data but is not efficient if you want to send the status of a single pin or if the pins are not linear. You can also send the data of a single pin using sendDigitalPort():

Firmata.sendDigital(pin, value);

This function sends the status of the pin and sends the pin input as value.

To send a string to the host computer, use sendString():

Firmata.SendString(string);

This sends the String string to the host computer.

Receiving Messages

Receiving messages on an Arduino is the same as working with other types of serial information; first, you must wait until you have received data and then process that data. Data is received directly on the serial port. To see if data is waiting, use available():

result = Firmata.available();

This function does not take any parameters and returns true if one or more bytes are waiting to be processed. To process data, use processInput():

Firmata.processInput();

Typically, you would use both functions together:

while(Firmata.available())

{

Firmata.processInput();

}

The Firmata library hides all the complicated parts of receiving data, including the data storage and processing. The library automatically decodes messages and enables you to perform actions on the data received using a system of callbacks.

Callbacks

Firmata works by using a system of callbacks, routines that are called when a specific action is performed, or in this case, when a specific message is received. Callbacks are highly customizable, and you can write a callback to perform almost any action you want simply by creating a function. Callbacks are put in place using an attach function; in the case of the Firmata library, it is called attach():

Firmata.attach(messagetype, function);

Table 16.1 lists the messagetype parameter, which is one of the constants. The function parameter is the callback function that you have written.

Table 16.1 Callback Constants

Constant

Use

ANALOG_MESSAGE

Analog value of a single pin

DIGITAL_MESSAGE

Digital value of a digital port

REPORT_ANALOG

Enables or disables the reporting of an analog pin

REPORT_DIGITAL

Enables or disables the reporting of a digital port

SET_PIN_MODE

Change the mode of the selected pin (input, output, and so on)

FIRMATA_STRING

Used for receiving text messages

SYSEX_START

Used for sending generic messages

SYSTEM_RESET

Used to reset firmware to default state

A callback requires a certain number of parameters to be defined, which is extremely specific as to the datatypes to use. The system restart callback does not require any parameters:

void systemResetCallback(void);

To receive strings, the stringCallback function requires one parameter:

void stringCallback(char *datastring);

SysEx messages require more information and have three parameters:

void sysexCallback(byte pin, byte count, byte *array);

Finally, all other callbacks use a generic format:

void genericCallback(byte pin, int value);

Callbacks must have different names. If you use both digital and analog pins, you will have two functions: one for handling digital data and the other for analog input. For example, code will allow you to receive both digital and analog instructions:

void analogWriteCallback(byte pin, int value)

{

// Code goes here

}

void digitalWriteCallback(byte pin, int value)

{

// Code goes here

}

Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);

A note on handling digital data: Analog data is sent one pin at a time, but this is not the case with digital pins. As seen previously, digital pin data is sent in groups of 8. This is known as a port. Port 1 will send the data of pins 1 to 8, and port 2 will send the data of pins 9 to 16, and so on. It is up to you to control if the pins should be written. To write all pins from a specified port, use this code:

void digitalWriteCallback(byte port, int value)

{

byte i;

byte pinValue;

if (port < TOTAL_PORTS)

{

for(i=0; i<8; i++)

{

pinValue = (byte) value & (1 << i);

digitalWrite(i + (port*8), currentPinValue);

}

}

}

To set a pin input or output, the mode parameter corresponds directly to the Arduino pinMode() constants. However, the trick is to know what pin corresponds to what sort of input/output. To do this, you can use some predefined data for each board. The Boards.h file details how many digital and analog pins a board has. For example, the Arduino Mega has the following line defined in the source code:

#define TOTAL_PINS 70 // 54 digital + 16 analog

To know if a pin is digital, use IS_PIN_DIGITAL() and IS_PIN_ANALOG(). To convert a pin to a digital or analog equivalent, use PIN_TO_DIGITAL() and PIN_TO_ANALOG(). You can use the following code to set the state of a digital pin:

void setPinModeCallback(byte pin, int mode)

{

if (IS_PIN_DIGITAL(pin))

{

pinMode(PIN_TO_DIGITAL(pin), mode);

}

}

To remove a callback, use detach():

Firmata.detach(callback);

The callback parameter is one of the constants used to attach a callback (refer to Table 16.1).

SysEx

One of the messages that the Firmata protocol can exchange is called SysEx. Short for System Excusive, SysEx was originally used in synthesizers using the MIDI protocol to include custom commands. When writing a protocol, it is almost impossible to imagine every scenario, and to make sure that the MIDI protocol could handle just about everything, SysEx was developed. The idea was to exchange information and change settings that could not be accessed by other means. In extreme cases, memory was transferred (partitions or instruments, for example). In the Firmata protocol, it allows users to exchange information such as I2C bus data and the servo motor configuration.

To receive SysEx data, you must first create a SysEx callback, as explained in the “Callbacks” section.

An example callback might look like this:

void sysexCallback(byte command, byte argc, byte *argv)

{

// Code goes here

}

The SysEx instruction identifier is sent as a byte, called command. The Arduino Firmata library defines a series of constants to describe a received message; as listed in Table 16.2.

Table 16.2 SysEx Constants

Constant

Function

RESERVED_COMMAND

Reserved chip-specific instructions.

ANALOG_MAPPING_QUERY

Ask for analog to pin number mapping.

ANALOG_MAPPING_RESPONSE

Reply with mapping data.

CAPABILITY_QUERY

Ask for supported modes of all pins.

CAPABILITY_RESPONSE

Reply with capability data.

PIN_STATE_QUERY

Ask for a pin's current mode and value.

PIN_STATE_RESPONSE

Reply with pin mode and value.

EXTENDED_ANALOG

Analog write to any pin, including PWM and servo.

SERVO_CONFIG

Set servo parameters (angle, pulse, and such).

STRING_DATA

Send a string message.

SHIFT_DATA

34-bit shift out data.

I2C_REQUEST

Request I2C data.

I2C_REPLY

Respond with I2C data.

I2C_CONFIG

I2C parameters.

REPORT_FIRMWARE

Report version number of Firmata firmware.

SAMPLING_INTERVAL

Set sampling interval.

SYSEX_NON_REALTIME

MIDI reserved.

SYSEX_REALTIME

MIDI reserved.

These constants are kept up to date at the Firmata website at http://firmata.org/wiki/V2.2ProtocolDetails.

Example Program

The beauty of Firmata is that it can adapt to so many situations. It is, of course, up to you to choose which pins will be used. If you want to expose only some pins, for example, to allow Firmata to control them, you can choose to enable just those relevant to your project. The sketch might receive Firmata instructions to update pins, but ultimately it is up to you, the developer, to decide if you should allow these instructions on all pins. Maybe you do not want a Firmata program to be able to modify certain pins. If a pressure sensor is connected to two pins, you do not want Firmata to change the pins to output and potentially damage the component.

The Arduino IDE has an excellent sketch that lets you begin working with Firmata: the StandardFirmata program. To access this program, go to Files imageExamples imageFirmata imageStandardFirmata, and upload the sketch to your board. However, uploading the sketch to your Arduino is only one-half the project; you also need a Firmata program on your computer. Several programs exist, and one is available on the Firmata website at http://www.firmata.org/wiki/Main_Page#Firmata_Test_Program.

Download the version for your system (Windows, Mac OS, and Linux binaries are available), and run the program. You need to know which serial port your Arduino is connected to. After this is done, you are presented with the Firmata screen, where the status of every pin is presented. This works by sending data to the Arduino as quickly as possible; the faster the data transfer, the more responsive the output will be. The Arduino also sends data to the computer, using a clever sampling rate technique, which is described next.

Using this system, you can instruct your Arduino to perform advanced features such as turning LEDs on and off without the need to write a sketch or reading input lines without knowing in advance what will be connected (if anything). However, this has its limitations. As explained previously, if you require a device to be present on specific pins, you might want to edit the Standard Firmata sketch to not poll or update those pins. It is up to you, the programmer, to know which pins you want to expose and to create or modify a sketch to make sure that only the pins that are usable can be accessed by Firmata.

The Standard Firmata sketch is complicated and is one of the larger sketches that you will see on an Arduino, but it is well structured and can be used as the basis for your own sketches. By looking at setup(), you can see this:

Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION,

FIRMATA_MINOR_VERSION);

Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);

Firmata.attach(REPORT_ANALOG, reportAnalogCallback);

Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);

Firmata.attach(SET_PIN_MODE, setPinModeCallback);

Firmata.attach(START_SYSEX, sysexCallback);

Firmata.attach(SYSTEM_RESET, systemResetCallback);

The first line sets the Firmata version, something that the Firmata application checks. It is defined using two constants: FIRMATA_MAJOR_REVISION and FIRMATA_MINOR_REVISION. These constants are set by the Arduino Firmata library. Next, a series of callbacks are defined; all seven possible callbacks are present in this sketch. This sketch can therefore react to every sort of Firmata message, or at least call a specific function when the message is received. It is then up to you to fill in the callbacks using the Standard Firmata sketch as an example.

In loop() the sketch receives and processes messages from the computer:

while(Firmata.available())

Firmata.processInput();

One of the variables in the program is samplingInterval. This defines the rate at which Firmata polls the pins. The sketch then has a clever technique to make sure that the wanted sampling rate is maintained. Following is the code that is used:

currentMillis = millis();

if (currentMillis - previousMillis > samplingInterval)

{

previousMillis += samplingInterval;

// Code goes here

}

The variables currentMillis and previousMillis are each defined as an unsigned long. Each time Arduino enters loop(), the millis() function will be called, returning the number of milliseconds that the sketch has been running for. This value is then placed inside the variable currentMillis. Then, a comparison is made between currentMillis minus previousMillis and the samplingInterval. If the value of currentMillis minus previousMillis is larger than samplingInterval, previousMillis is increased by the value contained insamplingInterval, and the sketch is free to send all the pin data.

Summary

In this chapter, I have shown you the Firmata library and how it interacts with an Arduino. You have seen the different messages and the callbacks used to react to them. In the next chapter, you see how to use the Arduino GSM shield and connect to mobile data networks, transfer data to and from servers, and create your own wireless server. You also see how to place and receive telephone calls.