The OI is cool, mainly because it has lots of switches and flashing lights and can be connected to even more switches and lights. It's a useful input box since it has many analog and digital inputs and is easy to connect to anything with a serial port.

In order to use the OI for your own nefarious purposes, you need to build a tether adapter. This consists of two female DB-9 connectors with pins 2, 3, and 5 wired straight through and pins 8 and 9 connected together on the OI side (it's safe to connect them on both sides since they are inputs on the computer, but don't connect them if you make a null-modem or connect them to any device that drives those pins). All other pins should be left unconnected. The tether uses normal RS-232 signal levels so no conversion circuitry is required.

Tether Adapter
My tether adapter

The two connectors on my adapter look different because they were bought from different places and have different plating. Otherwise they are identical. I used two one-inch hex standoffs to hold it together.

Tether pinout:

Pin Description
1 OI power from robot
2 TXD (to robot)
3 RXD (from robot)
8 RC tether sense
9 OI tether sense

Tether 8 (RC tether sense) is 220 ohms to Vcc. Tether 9 (OI tether sense) is 10k to GND, diode clamp to Vcc/GND (no Ri), U3 /RE, MCU RD3/PSP3.

When tether is not present (low), U3 receiver is enabled. When tether is present (high), tether pin 9 is driven high to disable U3 receiver.

The tether data is just the 26-byte packets that would have been sent to and received from the radio if it were plugged in.

Packet formats

The dashboard spec describes only the packets sent from the RC, and it labels the CRC bytes as "Reserved". The following packet formats are based on actual observations of a 2001(?) OI and RC.

I number bytes from 0 instead of 1 (like the IFI docs) because I usually program in C and it's easier this way.

Packets sent from the OI to the RC:

Offset Description
0 Packet header, always 0xff
1 Packet header, always 0xff
2 Port 2 X
3 Bits:
7: Port 3 aux switch 2
6: Port 3 aux switch 1
5: Port 3 thumb
4: Port 3 trigger
3: Port 1 aux switch 2
2: Port 1 aux switch 1
1: Port 1 thumb
0: Port 1 trigger
4 Port 1 X
5 Bits:
7: Port 4 aux switch 2
6: Port 4 aux switch 1
5: Port 4 thumb
4: Port 4 trigger
3: Port 2 aux switch 2
2: Port 2 aux switch 1
1: Port 2 thumb
0: Port 2 trigger
6 Port 4 X
7 Bits:
7-5: ???
4: Robot reset (1=Normal operation, 0=Reset)
3-0: Team number bits 11-8
8 Port 3 X
9 Team number bits 7-0
10 Port 2 Y
11 Bits:
7: Disabled
6: Autonomous
5-0: Channel number
12 Port 1 Y
13 Packet number
14 Port 4 Y
15 CRC low
16 Port 3 Y
17 CRC high
18 Port 2 wheel
19 Port 1 wheel
20 Port 4 wheel
21 Port 3 wheel
22 Port 2 aux analog
23 Port 1 aux analog
24 Port 4 aux analog
25 Port 3 aux analog

Packets sent from the RC to the OI:

Offset Description
0 Packet header, always 0xff
1 Packet header, always 0xff
3 Bits:
7-3: ???
2: Switch 3
1: Switch 2
0: Switch 1
7 Bits:
7-4: ???
3-0: Team number bits 11-8
9 Team number bits 7-0
11 Bits:
7-6: ???
5-0: Channel number
13 Packet number
15 CRC low
16 Battery level
17 CRC high
18 OI Port 2 Y
19 Bits:
7: Relay 2 green
6: Relay 2 red
5: Relay 1 green
4: Relay 1 red
3: PWM 2 red
2: PWM 2 green
1: PWM 1 red
0: PWM 1 green
20 OI Port 1 Y
21 OI Port 4 Y
22 OI Port 3 Y
23 OI Port 2 Wheel
24 OI Port 1 X
25 Bits:
7: Aux fuse
6: BASIC run
5: BASIC run error
4: Low battery
3: BASIC init
2: Valid RX
1: No data
0: Tether detect

The unlabelled bytes in the RC packet are probably as documented by IFI, but I haven't checked them.

The RC sends back several OI inputs. I guess this is done so you can monitor both OI and RC activity from the dashboard port.

The packet number always increases by one from one packet to the next. This can be used to detect dropped packets.

The mapping from battery voltage to the value of RC byte 16 appears to be nonlinear.

The OI to RC packet format appears to be unchanged as of 2006, but the CRC has changed (see below).


All packets sent by the OI and RC have a 16-bit CRC for error detection. Each device will ignore any packet with the wrong CRC. If you are just using the OI for input and you have a hard connection to the OI (no radios), then you can ignore the CRC. If you are using radios, then you should check the CRC to make sure the data was not corrupted in transit.

If you want to send data to the OI, you must set bytes 15 and 17 (counting from 0) of the packet to the lower and upper 8 bits of the CRC respectively.

There are many CRC implementations on the Internet, and some of them are not mathematically correct (they don't actually calculate a CRC). The OI CRC is a correct LSB-first CRC which can be calculated with this code:

#include <stdint.h>

#define CRC_START 0xffff
#define CRC_POLY 0xc6f6

uint16_t crc_packet(uint8_t *data)
    int i, bit;

    uint16_t crc = CRC_START;
    for (i = 0; i < 26; i++)
        if (i == 15 || i == 17)

        crc ^= data[i];

        for (bit = 0; bit < 8; bit++)
            if (crc & 1)
                crc = (crc >> 1) ^ CRC_POLY;
            } else {
                crc >>= 1;

    return crc;

The CRC was different in 2006, and was probably changed when the control system changed in 2004.


Here's an example of code that talks to the OI: xmms_oi.tar.gz.

This is an XMMS plugin that uses an OI joystick port to control playback and volume. The robot feedback LEDs indicate volume. Three of the robot controller LEDs indicate playback status:

Color Label Description
Green Valid RX Playing
Yellow Low Battery Paused
Red Aux Fuse Stopped

This code shows how to interpret packets received from the OI and how to build correct packets to send to the OI.

Code to dump and generate OI packets in Linux: tether.c
This is another good example. This program is useful for monitoring data from the OI or RC.