How to use SpaceOrb under Linux.
-- or --
Unsupported Secrets of the SpaceOrb Protocol
For those who do not know, the orb is a serial device that provides 10
bit digitization of 3 translational and 3 rotational movements, or 6
degrees of freedom. SpaceTec has come up with an excellent game
controller for 3D games like Quake, Descent, etc. Unfortunately...
SpaceTec hasn't released the protocol that the orb uses, and can't
currently support cool OSes, like Linux. This protocol is needed to
write 3rd party free (in the GPL sense) software. SpaceTec's lack of
Un*x support in general, and Linux in particular, leaves out a large
number of potential users, but this is a business decision and I am
definitely not one to understand the making of money. So this is
(thankfully) their problem.
My problem, is that I thought it might be a cool thing to write a
3D event display program for the research experiment I am getting
my PhD on (ie, an excellent way to waste time I should be spending
on my research, not to mention eating and sleeping).
So I set out to see what work on this (at the time) new controller has
been done out in net land. I didn't find much except for a few other
interested people. With their help and a lot of staring at the output
of the serial port, the orb's protocol has been understood. What to do
with it now, is another story, but I thought others would be
interested in this first chapter.
Below is the results of this work. The information was obtained by
treating the Orb as a black box (or, better yet, a black ball). The
protocol was figured out with out any input from SpaceTec, so it is
free from any legal restraints. However, I don't guarantee
anything. See the GPL for law-crud specifics, and have fun.
So on to how the SpaceOrb works.
The below is from my experiences. If this information is incorrect
for you or has other errors, please let me know. Also, if you have
more information, I would like to hear of it.
The orb's packet structure:
The very first byte of a newly initialized orb is `\r'. After this,
the orb will send three kind of packets:
These packets are usually delimited by a Carriage Return. However,
sometimes there will be more than one packet before a terminating
CR. Also, usually it will take more than one call to read(2) before an
entire packet is read from the serial port.
- A one time only greeting giving version info and SpaceTec's
trade mark. This, I call an `R' packet. (For why, see below.)
- A button press/release with out any orb motion. This is a `K'
- Orb motion with current button state. This is a `D' packet.
The packets are of, so called, type `R', `K' or `D' because their
first byte is one of these values when printed as ASCII characters.
It is this byte that can be used to anticipate what will follow,
when reading in the packet.
The structure of each packet type is expanded on below:
This is the format of the data, but one must be able to read the data
from a correctly configured serial port. Below is how to do that.
- `R' packet
- The greeting packet is 52 bytes long, including the
terminating CR. For instance, my orb prints:
R Spaceball (R) V4.26 28-Jun-96 Copyright (C) 1996z\r
The `R' is the packet flag.
- `K' packet
- The button press/release packet is a 6 byte packet, including
the terminating CR. This packet contains information about a button
press or release event. There is no information about
motion. It's flag is 75, or ASCII `K'. The values
of the packet are as such:
[`K'] [t] [buttons]  [??check sum??]
Each element in a [ ] pair is a byte. Here are the meanings:
- The packet flag.
- The time, in milliseconds from the last button event. Values
are 0 - 100, although, usually > 3. If there is no button press
in 100 ms, a packet showing current button state and 100 ms
elapsed time will be sent.
- The state of the buttons just before, and triggering, the
packet. The state of buttons is an OR of all buttons pressed.
The value of individual buttons are as follows:
- 0: No buttons
- 1: Button A
- 2: Button B
- 4: Button C
- 8: Button D
- 16: Button E
- 32: Button F
- 64: Reset Button. (This button is on the bottom and will
reset the current orb position to zero.)
- This byte is always zero, as far as I can tell. Maybe reserved
for future expansion.
- This byte appears to be a check sum, although I haven't really
looked into this. (Anyone?)
- `D' packet
- The motion packet has been the most difficult packet to
figure out. This is mostly due to the fact that the 6 degrees
of motion data is encoded into 10 bits spread out over 9 bytes.
To further complicate matters, the string ``SpaceWare'' is
XORed into the data. However, armed with this information
and a bit of bit twiddling, one can gain access to the motion
The packet is laid out like this:
[`D] [buttons] [(9 bytes of data)] [??check sum??]
Here are the explanations of the individual bytes.
- The packet flag.
- The state of the buttons. See above for button explanation.
If this state changes while there is motion, it will
trigger a `K' packet.
[(9 bytes of motion data)]
- This is the meat of the packet. It contains 9 7bit bytes,
with the MSB unneeded. To turn these into translations and
rotations, one needs to XOR these 9 bytes with the 9 characters
from the string
ignore the MSB of each bytes and strip
off 10 bits for each d.o.f. Here is an attempt to show the
c c c c c c c c c
xdddddddxddd dxdddddddxdd ddxdddddddxd
t ddddxdddddd t dddddxddddd r ddddddxdddd ddd
t r r
c are the
9 7bit bytes. An
x signifies a MSB that
should be ignored but is left in the diagram to show
the structure. A
d is a data bit. The
are the translational degrees of freedom and the
r are the
rotational. Again, the bit marked
not included in to the d.o.f. value but is
only showed in the diagram to show the structure. All
bits more significant than the bit at the
are right shifted (>> in C). Once the 10 bit values
are formed, any value over 511 should have 1024 subtracted
from it in order to express the negative range of motion.
This will then give values -512 to 511 for
- Again, this byte appears to be a check sum and seems to be
Mored with the character `!'.
Format of serial data:
The orb sends data in 7bit characters, at 9600 bps, however, I have
found that setting the serial port to 8bit, no parity, I am able to
distinguish CR from a data character that accidentally is 13. After
reading in a packet, all data characters can be ANDed with 0177
(octal) to mask off the high bit.
To figure out how to do this, I looked in the source code to
Miquel van Smoorenburg's minicom and basically did cut and paste
programming. Much appreciation goes out to van Smoorenburg for placing
minicom under a license that lets me do this (GPL)! Because of this,
I suppose the code that I append to this page is also covered by
such a license. I am no lawyer, nor do I want to be so I will also
say that in addition to GPL I grant anyone the right to do anything
with this code that suits their desire as long as it doesn't infringe
on the GPL. Basically have fun, but be cool.
Anyways, I still don't understand everything, and new nothing
when I started this, about serial ports,
so I will just let the code explain for those that care (see below).
I would like to thank some of the people who helped me get this code
working, with out whom, I would have had a much tougher time
finishing, if I finished it at all. So in no particular order, Jason
Lyons (JasonL@warwick.net, http://www.geocities.com/SiliconValley/Lab/2353) for helpful email and suggesting to use
minicom to read the orb directly. This led to tearing out minicom code
to set up the serial port. Mickael Sweet (firstname.lastname@example.org) for his
helpful serial page:
http://www.easysw.com/~mike/serial/ and suggestions. My office
mate, Eric Sharkey (email@example.com) for general
unix hacking solutions. And as I say above, much thanks go to Miquel
van Smoorenburg for the serial port initialization code. If I have
forgotten anyone, my apologies.
Well, enough of the drivel, here is the code. It is in 2 parts,
the routines that do the work and a test program. To compile, just
gcc -I./ -g -Wall -c -o sorb.o sorb.c
gcc -I./ -g -Wall -c -o sorbT.o sorbT.c
gcc -I./ -g -Wall -o sorb sorb.o sorbT.o
(You can, of course, skip the debugging/warning flags)
If you want to browse the code,
the routines for initializing and reading are in sorb.c, the test program is in sorbT.c and this header
file, sorb.h is needed. If you want to
download this source, a Makefile and
a precompiled Linux ELF
executable, grab, sorb.tgz
To use, plug in your SpaceOrb to a free serial port.
will default to
/dev/ttyS0, to use another device use
-d /dev/ttyxx option. For other options, see
the sorbT.c source.
You don't have to, but if anyone uses/improves on this code I would
be interested to hear about your work.
This was developed on Linux, and may or may not work on other flavors
Last modified: Fri Apr 30 18:30:57 EDT 1999