tfirmata

tfirmata is a Tcl implementation of Arduino Firmata 2.5.

Firmata is a communications protocol for direct control and reading back of Arduino hardware from another system, such as a PC. Software running on a host, to control Arduino hardware, can be written in any language that the host system supports, including high level scripting languages such as Tcl.

The StandardFirmata project, which is included with the Arduino IDE, implements the Firmata protocol. An Arduino can be programmed with StandardFirmata, and then controlled from scripts running on a PC, for a quick and easy method of controlling hardware. See the Firmata page in the Tcl'ers Wiki for more information and references to examples.

tfirmata is a complete implementation of Firmata, including board capability querying. As a result tfirmata should work with all boards supported by Firmata.

Usage

The tfirmata library provides a number of commands and subcommands to support control of Arduino I/O using Tcl. Available commands and subcommands are described below. As a brief introduction, here is a complete example script showing how tfirmata can be used:

package require tfirmata

set bd [tfirmata::open /dev/ttyUSB0]
$bd mode 13 out

while {1} {
    $bd dset 13 1
    tfirmata::sleep 250
    $bd dset 13 0
    tfirmata::sleep 250
}

The tfirmata::open command opens a connection to an Arduino, and returns a reference command. The reference command is then used with the mode subcommand to configure pin 13, which is connected to an LED on the Arduino board, to an output. The LED is then flashed, 250ms on and 250ms off, using tfirmata::sleep to provide the delays.

Commands and Subcommands

tfirmata provides the following commands:

The chan command uses a pre-opened Tcl channel for communicating with the Arduino. The open command opens that channel explicitely and takes an argument specifying the serial port that the Arduino is connected on. chan and open also return a reference command for calling subcommands.

The sleep command delays a script for the number of milliseconds specified. sleep is the recommended way of delaying a script, because it passes control to the Tcl event loop, allowing tfirmata to continue to service open connections.

The handles command returns a list of all currently open Firmata communication channels.

See above for an example of open and sleep being used.

tfirmata subcommands are as follows:

The mode subcommand is used to configure the mode of operation of Arduino pins. The mode can be any of in, out, analog, pwm, or servo (to put TWI capable pins in TWI mode, use twiconfig). The mode subcommand may be used to set the mode of a single pin, or set the modes of several pins. On Firmata 2.5 additional known modes are shift, onewire, stepper, encoder, serial, and input_pullup.

$bd mode 13 out
$bd mode 4 5 6 7 in 9 pwm 10 11 12 13 out

The dget subcommand gets the digital value of input pins, retrieving values from a local cache. Before the dget subcommand is used, the dstream subcommand should be called to set up the Arduino, so that when a digital input changes it's new value is sent for the local tfirmata cache. dget may be used to get the digital value of one pin, or multiple pins. When getting the value of multiple pins, values are returned as a list.

puts [$bd dget 13]
puts [$bd dget 4 5 6 7]

The dset subcommand sets the value of digital output pins. dset may be used to set the value of a single pin, or to set the value of multiple pins. The alternate form dset25 requires Firmata version 2.5 and uses a different protocol on the serial port.

$bd dset 13 1
$bd dset 10 0 11 0 12 1
$bd dset25 10 0 11 0 12 1

The aget subcommand gets the analog value of analog input channels, retrieving values from a local cache. Before the aget subcommand is used, the astream subcommand should be called to set up the Arduino, so that it reports analog values at regular intervals for storing in the local tfirmata cache. The interval between updates can be set with the period subcommand. aget may be used to get the analog value of one pin, or multiple pins. When requesting the value of multiple pins, values are returned as a list.

puts [$bd aget 0]
puts [$bd aget 0 1 2 3]

The aset subcommand sets the value of pwm or servo configured output pins. aset may be used to set the value of a single pin, or to set the value of multiple pins.

$bd aset 11 1
$bd aset 9 128 10 0 11 255

The dstream subcommand configures an Arduino to stream digital port values from Arduino to host when a port value changes. Firmata considers 8 pins to make up a port so, for example, enabling streaming on port 0 will result in a port update being sent to the host if any of pins 0 to 7 change value. dstream can be used to turn streaming on or off. In addition, streaming can be configured for a single port or multiple ports.

$bd dstream 0 on
$bd dstream 0 1 on 2 off

The astream subcommand configures an Arduino to stream analog channel values from Arduino to tfirmata at regular intervals set by the period subcommand. astream can be used to turn streaming on or off. In addition, streaming can be configured for a single analog channel or for multiple analog channels.

$bd astream 0 on
$bd astream 1 2 3 on 4 5 off

The dcommand subcommand is used to set code that's run when tfirmata receives an update message after a port, that has been configured with dstream for streaming, has changed value. The port number and port value that is part of an update message can be substituted into a code block by using '%P' and '%V'.

$bd dcommand {puts "digital port update"}
$bd dcommand {puts "digital port update, port: %P, value: %V"}

The acommand subcommand is used to set code that's run when tfirmata receives an update message for an analog channel that's been configured by astream for streaming. The analog channel and analog value that is part of an update message can be substituted into a code block by using '%C' and '%V'.

$bd acommand {puts "analog channel update"}
$bd acommand {puts "analog channel update, channel: %C, value: %V"}

The servolimits subcommand sets the lower and upper limits for servo outputs in microseconds. Limits are provided as a two element list. Limits can be set for a single pin or for multiple pins.

$bd servolimits 12 {850 2250}
$bd servolimits 10 11 {900 2100} 12 {850 2250}

The amapping subcommand returns pin numbers that analog channel numbers map to. Mappings for a single analog channel or multiple analog channels can be retreived.

puts [$bd amapping 0]
puts [$bd amapping 0 1 2]

The twiconfig subcommand configures an Arduino's TWI capable pins to TWI mode. In addition, a delay in microseconds may be specified for reads. The delay is inserted between a TWI message that requests data from a TWI device and a TWI message that reads out the data. Most TWI devices will not require a delay, and if not specified, the delay will default to 0us.

$bd twiconfig 
$bd twiconfig 5000

The twiget subcommand can be used to retreive data from a TWI device, and also used to stop repeated TWI reads. For reading from a TWI device, the address of the TWI device, any command bytes to send to the device before reading, and the number of bytes to read, are supplied as arguments. The subcommand will block if a -command argument isn't provided. If it is provided, the subcommand will not block, and once data has been retrieved, code specified by -command is run. Data bytes read from the TWI device may be substituted into a code block with '%D'. If -repeat is specified, the read message to the TWI device is repeated at regular intervals, set by the period subcommand. To stop repeated reads, -stop is specified along with device address.

puts [$bd twiget 0x50 0 1] 
$bd twiget 0x50 1 -command {puts "Data: %D"}
$bd twiget -repeat 0x50 1 -command {myTwiCallback %D}
$bd twiget -stop 0x50

The twiset subcommand is used to initiate a TWI write message. The subcommand takes the address of a target TWI device, followed by the bytes to send to it.

$bd twiset 0x50 0 0 0x55

The period subcommand sets the number of milliseconds between analog samples and repeated TWI read messages.

$bd period 500

The state subcommand returns the current configuration state of Arduino pins. The state is returned as a dictionary, where dictionary keys are the requested pin numbers, and values are a list of state values. Configuration state can be retrieved for a single pin, multiple pins, or all pins.

puts [$bd state 13]
puts [$bd state 10 11 12 13]
puts [$bd state all]

The firmware subcommand returns the name and version of the firmware programmed into an Arduino.

puts [$bd firmware]

The errors subcommand returns a count of the number of errors detected when tfirmata parses messages received from an Arduino.

puts [$bd errors]

The close subcommand closes a connection to an Arduino.

$bd close

The errcommand subcommand adds a Tcl command to be called when an error on the connection to the Arduino is detected. That command's single argument is the connection reference.

proc errproc {bd} {
    puts stderr "I/O error on $bd"
    $bd close
    exit
}

$bd errcommand eproc

The stepconfig subcommand configures a stepper motor with given motor number (between 0 and 5), delay (1 or 2 microseconds), interface (2 or 4 wires, number of steps for one revolution, and corresponding pin numbers.

# 4-wire stepper on pins 9..11
$bd stepconfig 0 1 4 2050 10 12 9 11

The stepoff subcommand switches the pins of the stepper motor given its motor number (between 0 and 5) to zero.

# turn stepper 0 off
$bd stepoff 0

The step subcommand controls the stepper motor given its motor number to turn a specified number of steps with given speed and optional acceleration and deceleration.

$bd step 0 4100 150 120 120

The stepwait subcommand waits for zero or more stepper motors to reach their programmed number of steps or for a maximum amount of time. The motors 0..5 are expressed as bits in a bit mask. The subcommand returns the bits for the motors which are at position or zero on timeout.

# wait for stepper 1 up to 10 seconds
if {[$bd stepwait 1 10000] == 0} {
    # force stop
    $bd step 0 0 0
}

The eattach subcommand attaches an encoder given encoder number (between 0 and 4) on the given two pins. For best results, interrupt capable input pins should be used.

$bd eattach 0 2 3

The equery subcommand dispatches an encoder query of a specific or all encoders. The encoder value is reported in the callback function.

$bd equery 0

The eresets subcommand sets the value of the given encoder back to zero.

$bd ereset 0

The ereport subcommand turns encoder event reports on or off.

$bd ereport on

The ecommand subcommand sets a callback command which gets called on encoder events. Substitutions performed are '%C' for the encoder number, and '%V' for the encoder value.

$bd ecommand {puts "encoder %C is on position %V"}

The edetach subcommand releases the encoder pins and closes the encoder.

$bd edetach 0

The eget subcommand returns the last known encoder value without further communication with the Arduino

set value [$bd eget 0]

The serconfig subcommand configures a hardware or software serial port given port number (0..4 are HW ports, 8..11 are SW ports) with a baud rate and optional receiver and transmitter pin numbers for SW ports.

# RX on pin 2, TX on pin 4
$bd serconfig 8 115200 2 4

The sercommand subcommand adds a receive callback for serial ports. Substitutions performed are '%C' for the number of the serial port, and '%V' for the received data from that port.

$bd sercommand {puts "port %C received '%V'"}

The serwrite subcommand sends data on the given serial port.

$bd serwrite 8 "Hello world!\r\n"

The serclose subcommand releases a serial port given number.

$bd serclose 8

The serflush subcommand flushes transmit data on HW serial ports or empties the receive buffer on SW serial ports.

$bd serflush 8

The serlisten subcommand arranges for receiver start of a SW serial port given its number. According to the Arduino documentation only one SW serial port can be listening at any one time.

$bd serlisten 8

The owconfig subcommand configures the given pin for a 1-Wire bus which by default is externally powered unless the power argument is one for parasitic power.

$bd owconfig 4

The owsearch subcommand performs a normal or alarm search for 1-Wire devices on the bus identified by a pin number. An alarm search is performed when the option "-alarms" is present. A Tcl command (option "-command") is invoked for all detected 1-Wire devices on the bus. Substitutions on the command are '%C' for the pin, '%S' for alarms (0 or 1), and '%A' for the 1-Wire address. Onewire adresses are expressed in the format used by Linux, i.e. two hex digits for the device identification, followed by a dot, followed by 14 hex digits with unique id and CRC.

proc print_ow {pin alarm address} {
    puts "pin=$pin alarm=$alarm address=$address"
}

$bd owsearch 4 -command {print_ow %C %S %A}

The owtrans subcommand performs a transaction on the 1-Wire bus identified by a pin number. The option '-reset' issues a bus reset at the begin of the transaction. The option '-skip' allows to skip the address phase. The option '-address' specifies the 1-Wire address of the target device. The option '-write' specifies a list with bytes to be written to the device, the option '-read' the number of bytes to read from the device. The option '-tid' allows to specify a transaction identifier. If omitted, it is chosen automatically. The option '-delay' can be used in combination with the scheduler to delay the next scheduled message by the specified number of milliseconds. When the transaction is complete the Tcl command specified with the '-command' option is invoked with the substitutions '%C' for the pin number, '%V' for the data bytes read, and '%T' for the transaction identifier.

proc read_ow {pin data} {
    lassign $data lo hi
    puts "lo=$lo hi=$hi"
}

# read a DS18B20
$bd owtrans 4 -reset -address 28.xxxxxxxxxxxxxx -write 0xbe
    -read 9 -command {read_ow %C %V}

The owcallback subcommand is used to set a callback procedure which catches all unmatched 1-wire read transactions without a specific callback.

The taskdata subcommand is used to create a buffer to gather Firmata commands for creating a scheduler task using the createtask subcommand. It creates a virtual connection similar to tfirmata::open and captures the output of subcommands into that virtual connection.

The createtask subcommand creates a scheduler task given a task number (0..127) and fills the task's message buffer with the given taskdata virtual channel. That virtual channel is then closed automatically. The task itself is created in suspended state.

The deletetask subcommand deletes a task given the task number (0..127).

The delaytask subcommand is used in the context of a task message buffer (see taskdata) in order to delay the containing task for a specified amount of milliseconds.

The scheduletask subcommand is used to activate a task given the task number (0..127) and the activation time relative to now in milliseconds.

The resettasks subcommand can be used to delete all currently defined tasks with a single command.

Multiple Arduinos

More than one Arduino can be controlled at a time. The following example is a variation on the flashing LED script above, but this time LEDs on two boards are flashed, one the inverse of the other.

package require tfirmata

set bd1 [tfirmata::open /dev/ttyUSB0]
set bd2 [tfirmata::open /dev/ttyUSB1]
$bd1 mode 13 out
$bd2 mode 13 out

while {1} {
    $bd1 dset 13 1
    $bd2 dset 13 0
    tfirmata::sleep 250
    $bd1 dset 13 0
    $bd2 dset 13 1
    tfirmata::sleep 250
}