This manual is designed to help you write motion capture servers for use with Maya. It describes the motion capture server library and gives some hints for writing motion capture servers.
The motion capture server library (libmocap.a) allows the server process maximum flexibility in dealing with the motion capture hardware while hiding communication details between the server and Maya.
Motion capture servers are separate processes that communicate with Maya using sockets. Because sockets are largely network transparent, the server can be running on the same machine as Maya or on a different machine. Using two machines allows the server machine to be dedicated to handling the input from the motion capture hardware while the client machine runs Maya.
A motion capture server creates a number of named channels. Each channel is an independent data stream that has a type and a usage. Magnetic sensors, such as the Flock of Birds or the Fastrak, each return a position and an orientation. Angular sensors in an armature may return a single angle. A 6d channel could be created for the magnetic sensor and a 1d channel for the armature sensor.
The server library handles the communications protocol between the server and Maya. The library parses the messages on the socket, handles error messages, and deals with byte ordering problems. The library also encapsulates the message passing protocol so that it can be changed without requiring changes to servers that have been built with it.
The server library has about 20 user-callable routines. These routines fall into four categories:
These routines are the heart of the server library. A good understanding of them is essential to writing good motion capture servers. The client/server communications routines are:
The serial line routines provide a simplified interface to the Unix terminal handling routines. These routines do not attempt to do everything but they should be sufficient to hook up most hardware over a serial line. The serial line routines are:
These routines are used for handling quaternions, mathematical entities that handle rotations or orientations without the problems associated with Euler angles. A quternion is like a simplified version of a matrix. Routines that handle Euler angles have a rotation order parameter, which defines the order in which the Euler angles are processed. In SGI's GL or OpenGL, the order CAP_ROT_XYZ is equivalent to multiplying the top of stack matrix by the x rotation, the y rotation and then the z rotation.
For more information on quaternions, see Graphics Gems I, II, or III, or Ken Shoemake's excellent paper in the 1985 Siggraph proceedings.
The quaternion handling routines are:
The general Unix server routines handle the Unix-specific requirements for running processes as daemons and for creating and connecting to sockets for communication. These routines are:
Function:
Return authorization information to Maya.
Usage:
int CapAuthorize(int client_fd, int authorized);
client_fd
The socket file descriptor to the client.
authorized
A logical value indicating whether the client is
allowed to use this server or not.
Description:
This routine is used by the server to return a response
to the CAP_CMD_AUTHORIZE command. If authorized is zero,
the client is not authorized to use this server. If
authorized is non-zero, the client considers itself
authorized to use the server and continues sending
commands. Generally the client will be authorized, but
you may want to use this function if your server is an
internet socket. It is not a major security breach, but
you may want to protect against someone outside your
company from connecting to your motion capture server.
Return Value:
Returns 0 if there was no error or -1 if an error
occurred. If there was an error, errno is set to an
appropriate value.
Function:
Define a data channel for motion capture data from the
server.
Usage:
CapChannel CapCreateChannel(char *name, CapChannelUsage usage,
int data_type);
name The channel name. The name can be up to 32 characters
and should not include spaces or other nonalphanumeric
characters. Since this name is visible in Maya, make it
something descriptive: "RWrist" is better than "bird_3",
for example.
usage
This defines how the data for the channel is meant to
be used.
data_type
This integer defines how many words of data are
available. Allowed values are 1, 3, 4, or 7. They
have the following meanings:
1 A 1-dimensional piece of data. The value of
usage determines how this data can be used by
Maya.
3 Three-dimensional data. Usage should always
be CAP_USAGE_POSITION.
4 Four-dimensional data. This is an orientation
quaternion. Usage should always be
CAP_USAGE_ORIENTATION.
7 Seven-dimensional data. This is always a position
and an orientation quaternion. Usage should be
CAP_USAGE_POS_ORIENT.
Description:
This routine defines a channel for motion capture data.
Channels are named and are used by Maya to refer to particular
data. The data for a channel has a usage and a data type. The
usage is one of:
Data
Usage Type
CAP_USAGE_UNKNOWN 1 A single scalar floating point value
that can be assigned to any single leaf
track
CAP_USAGE_POSITION 3 An (x,y,z) position value
CAP_USAGE_ORIENTATION 4 The data type is a quaternion passed
as q0+iq1+jq2+kq3. (See CapEuler2Quat().)
CAP_USAGE_XPOS 1 A single floating point x position.
It can be assigned to an xpos or a
position track.
CAP_USAGE_YPOS 1 A single floating point y position.
CAP_USAGE_ZPOS 1 A single floating point z position.
CAP_USAGE_XROT 1 A single floating point x rotation.
CAP_USAGE_YROT 1 A single floating point y rotation.
CAP_USAGE_ZROT 1 A single floating point z rotation.
CAP_USAGE_XSCALE 1 A single floating point x scale.
CAP_USAGE_YSCALE 1 A single floating point z scale.
CAP_USAGE_ZSCALE 1 A single floating point z scale.
CAP_USAGE_SCALE 1,3 If data_type is 1, the data is applied
to x, y, and z uniformly. If data_type
is 3, the data is separate x, y, and z
scale values.
CAP_USAGE_POS_ORIENT 7 The data is a position and an orientation
such as is returned from a magnetic
sensor. The data is an (x,y,z) position
followed by a quaternion passed as
q0+iq1+jq2+kq3.
These channels are attached to tracks in Maya. Basically, if the
attachment makes any sense at all, you can do it. For example,
you can attach a position channel to a position track or an xpos,
ypos, or zpos track. You can attach an xpos channel to a position
track or to an xpos track. The individual tracks find the
appropriate piece of the channel data, if there is one, and use it.
Return Value:
The routine returns a CapChannel, which is a pointer to a private
structure. The return value is used later in CapSetData() to
specify the channel for which the data is being set.
Function:
Send the data for all channels to Maya.
Usage:
int CapData(int client_fd);
client_fd
The socket file descriptor to the client.
Description:
CapData() takes a snapshot of the data currently set in the
channels by CapSetData() and sends it back to Maya. It is used
in response to a CAP_CMD_DATA command.
Return Value:
Returns 0 if there was no error or -1 if an error occurred. If
there was an error, errno is set to an appropriate value.
Function:
Send an error message back to Maya to be displayed.
Usage:
int CapError(int client_fd, CapSeverity sev, char *pgm,
char *fmt, ...);
client_fd
The socket file descriptor to the client.
sev This specifies the severity of the error message.
Severity levels are debug, info, warning, error,
and fatal. See below for details.
pgm The name of the server program.
fmt A printf() style format string for printing a message.
If fmt is NULL, the system error message specified by
errno is printed. Any additional arguments needed by
the format should follow this argument.
Description:
Error messages indicators have the following meanings:
CAP_SEV_DEBUG
A debug message that can be safely ignored.
CAP_SEV_INFO
An informational message such as "Flock recorded
7.2 seconds." These messages can be safely ignored.
CAP_SEV_WARNING
Some important condition exists but the server can
continue. For example, a missing configuration
file might be a warning, not an error.
CAP_SEV_ERROR
An error has occured in the current operation. The
current operation cannot complete.
CAP_SEV_FATAL
A fatal server error has occured. The server is
unable to recover.
Error and fatal messages are displayed in error dialogs
by Maya.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
If the last command was CAP_CMD_AUTHORIZE, retrieve the
authorization information provided with the command.
Usage:
int CapGetAuthInfo(int client_fd, char *user, char *host,
char *realhost);
client_fd
The socket file descriptor to the client.
user The user name as reported by the client. It is not
necessarily to be trusted.
host The host name as reported by the client. It is not
necessarily to be trusted either.
realhost
The name of the host on the other end of the socket.
If the name cannot be determined, an empty string is
returned.
Description:
It is assumed that user, host, and realhost point to enough
space to hold the corresponding string. Currently these
strings are no more than 64 characters long. If any of the
three arguments is NULL, the string is not set.
Return Value:
Returns 0 if there was no error or -1 if the previous
command was not CAP_CMD_AUTHORIZE.
Function:
Get the next command from Maya.
Usage:
CapCommand CapGetCommand(int client_fd);
client_fd
The socket file descriptor to the client.
Description:
This routine returns the next command from Maya. If there
is no command pending, it blocks until a command is sent.
Return Value:
Returns a command. CAP_CMD_ERROR is returned if there was
some error.
Function:
Get the frame number from the preceding CAP_CMD_DATA
command.
int CapGetRequestedFrame(int client_fd);
client_fd
The socket file descriptor to the client.
Description:
This command returns the frame number specified in the previous
CAP_CMD_DATA command.
Return Value:
Returns the frame number or -1 if the previous command was not
CAP_CMD_DATA.
Function:
Get the time in seconds from the preceding CAP_CMD_DATA
command.
Usage:
float CapGetRequestedTime(int client_fd);
client_fd
The socket file descriptor to the client.
Description:
This command returns the time in seconds specified in the
previous CAP_CMD_DATA command.
Return Value:
Returns the time in seconds or -1.0 if the previous command
was not CAP_CMD_DATA.
Function:
Return motion capture channel definitions and server
information to Maya.
Usage:
int CapInfo(int client_fd, float min_rate, float max_rate,
float def_rate, size_t buf_size, int dynamic);
client_fd
The socket file descriptor to the client.
min_rate
The slowest sample rate at which the server can
record (in samples per second). For example, a
Flock of Birds cannot record slower than 10 samples
per second.
max_rate
The fastest sample rate at which the server can
record (in samples per second). For example, a Flock
of Birds cannot record faster than 144 samples per
second. If this is zero, recording is not supported.
def_rate
The default sampling rate. For example, the Flock
of Birds default rate is 100 samples per second.
buf_size
The maximum buffer size for holding recorded data.
If this is zero, the server does not implement
recording. This buffer is generally dynamically
allocated at start record time. The special value
CAP_UNLIMITED means that the buffer is limited
only by available memory.
dynamic
The server provides dynamic, changing data. If the
server provides dynamic data, Maya queries the
server continuously for new data. If the server/data
is not dynamic, Maya queries only when the current
frame changes and only if it does not have that
frame's data buffered already.
Description:
CapInfo() returns a description of the channels and general
information about the server to Maya. Create all channels
first with CapCreateChannel() before calling CapInfo().
Once it has been called, no more channels can be created.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Do the initial handshake between the client and server.
Usage:
int CapInitialize(int client_fd, char *name);
client_fd
The socket file descriptor to the client.
name The name of the server program, used only for error
messages.
Description:
This routine responds to the CAP_CMD_INIT command and performs
the initial handshake between the server and Maya.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Set the data for a channel.
Usage:
int CapSetData(CapChannel channel, void *data);
channel
A channel that was returned by CapCreateChannel().
data A pointer to the data to set. The data is assumed
to be of the correct type (1, 3, 4, or 7 floating
point values depending on the data type of the channel).
Description:
This routine sets the data for a specific channel to
values that have (presumably) come from the motion capture
hardware. This data is stored until CapData() is called.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Returns server version information to Maya.
Usage:
int CapVersion(int client_fd, char *server_name, char *version,
char *description);
client_fd
The socket file descriptor to the client.
server_name
The name of the server. This will be displayed in Maya's
Object Browser. server_name is truncated to 64 characters.
version
A short version string. The version string is truncated
to 16 characters.
description
A one-line description of the server. This is truncated to
256 characters.
Description:
This version information is for the user's information.
Maya uses only the server name.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Open a serial line specifying the baud rate and other
serial line parameters.
Usage:
int CapSerialOpen(char *tty,
int baud,
int data,
CapParity parity,
int stop,
CapSerialMode mode,
struct termios *save_attr);
tty The name of the tty device (e.g., "/dev/ttyd1").
baud The baud rate. Currently supported values are 50,
75, 110, 134, 150, 200, 300, 600, 1200, 1800,
2400, 4800, 9600, 19200, and 38400.
parity
The parity. Legal values are CAP_PARITY_EVEN,
CAP_PARITY_ODD, and CAP_PARITY_NONE.
stop The number of stop bits. The value 1 is most common
but 2 is also allowed.
mode The mode does not change any single terminal
attribute but instead changes several to deal with
different types of connections. In CAP_SERIAL_ASCII
mode, the tty returns complete lines of text and
carriage returns ('\r' characters) are discarded. In
CAP_SERIAL_BINARY mode, characters are returned as
they become available, special characters are
treated as data, and reads time out after 0.2 seconds
to keep the server from hanging waiting for a
response from a slow or hung serial device.
save_attr
If save_attr is not NULL, it defines a place to
store the initial terminal attributes before this
routine starts changing them. The saved attributes
can later be passed to CapSerialReset() to restore
the terminal attributes to their original values. If
you do not care about the original attributes, pass
save_attr as NULL.
Description:
CapSerialOpen() opens a serial line and sets its initial
attributes. Even if you need more sophisticated
terminal handling, this routine is an easy way to
get the baud rate, parity, and other basic terminal
attributes set. You can then set the rest of them
yourself with the termio interface.
Return Value:
The file descriptor for the serial line, opened for
reading and writing. If an error occurred, -1 is
returned and errno is set appropriately.
Function:
Read data from a serial line
Usage:
int CapSerialRead(int tty_fd, void *buf, size_t nbytes);
tty_fdThe file descriptor of a serial line. (Actually
almost any file descriptor will work.)
buf A pointer to the buffer in which the data should
be stored. It is assumed to be at least nbytes
bytes long.
nbytesThe size of the buffer pointed to by buf.
Description:
This routine is a replacement for read() that works
particularly well on serial lines that have been opened
in binary mode. A normal read on such a serial line
may complete before all the characters have been read.
This routine will keep reading characters until the
read times out (set to 0.2 seconds in CapSerialOpen())
with zero characters read or until nbytes characters
have been read.
Return Value:
There are several different possible return values.
If all went well, the routine returns the number of
bytes read, which should equal nbytes.
If some characters were read but the timeout time passed
without any characters, the number of characters read is
returned. This is some value less than nbytes.
If the read timed out without returning any characters,
0 is returned. This probably indicates a hung device.
If an error was returned by read(), -1 is returned and
errno is set appropriately.
Function:
Reset the terminal attributes of a serial line to a
known state.
Usage:
int CapSerialReset(int tty_fd, struct termios *attr);
tty_fd
The file descriptor of a serial line. (Almost any
file descriptor works.)
attr The value returned as save_attr from an earlier
call to CapSerialOpen().
Description:
This routine restores the terminal line attributes to
the values stored in attr. This normally is the value
returned as save_attr from CapSerialOpen() but could be
any valid termios structure.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Write data to a serial line.
Usage:
int CapSerialWrite(int tty_fd, void *buf, size_t nbytes);
tty_fd
The file descriptor of a serial line. (Almost any
file descriptor works.)
buf A pointer to the buffer in which the data is stored.
It is assumed to be at least nbytes bytes long.
nbytes
The size of the buffer pointed to by buf.
Description:
This is the corresponding routine to CapSerialRead().
There is less reason to use it since writes to serial
lines do not suffer the same problems that reads do.
Nevertheless, it is included here for completeness.
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Convert Euler angles to a 4x4 rotation matrix.
Usage:
void CapEuler2Matrix(CapRotationOrder order, float x, float y,
float z, Matrix m);
order
The order in which the rotations are applied.
x The rotation about the x axis.
y The rotation about the y axis.
z The rotation about the z axis.
m The resulting 4x4 matrix.
Description:
This routine converts the Euler angles in the specified
order to an equivalent matrix representation.
Return Value:
None
Function:
Convert Euler angles to a quaternion.
Usage:
void CapEuler2Quat(CapRotationOrder order, float x, float y, float z,
CapQuaternion q);
order
The order in which the rotations are applied.
x The rotation about the x axis.
y The rotation about the y axis.
z The rotation about the z axis.
q The resulting quaternion.
Description:
This routine converts the Euler angles in the specified
order to an equivalent quaternion representation.
Return Value:
None
Function:
Convert a 4x4 rotation matrix to Euler angles.
Usage:
void CapMatrix2Euler(CapRotationOrder order, Matrix m,
float *x, float *y, float *z)
order
The order in which the rotations are applied.
m The 4x4 rotation matrix.
x The rotation about the x axis.
y The rotation about the y axis.
z The rotation about the z axis.
Description:
This routine converts the rotation matrix to an equivalent
set of Euler angles when applied in the specified order.
Return Value:
None
Function:
Convert a 4x4 rotation matrix to a quaternion.
Usage:
void CapMatrix2Quat(Matrix m, CapQuaternion q);
m The 4x4 rotation matrix.
q The resulting quaternion.
Description:
This routine converts the 4x4 rotation matrix to an
equivalent quaternion rotation.
Return Value:
None
Function:
Convert a quaternion to Euler angles.
Usage:
void CapMatrix2Euler(CapRotationOrder order, CapQuaternion q,
float *x, float *y, float *z)
order
The order in which the rotations are applied.
q The input quaternion.
x The rotation about the x axis.
y The rotation about the y axis.
z The rotation about the z axis.
Description:
This routine converts a quaternion to an equivalent set
of Euler angles when applied in the specified order.
Return Value:
None
Function:
Convert a quaternion to a 4x4 rotation matrix.
Usage:
void CapQuat2Matrix(CapQuaternion q, Matrix m);
q The input quaternion.
m The output 4x4 rotation matrix.
Description:
This routine converts the input quaternion to an equivalent
4x4 rotation matrix.
Return Value:
None
Function:
Multiply or composite two quaternions.
Usage:
void CapQuatMult(CapQuaternion q1, CapQuaternion q2,
CapQuaternion r);
q1 The quaternion on the left side of the multiplication.
q2 The quaternion on the right side of the multiplication.
r The resulting quaternion.
Description:
This routine computes r=q1xq2. If the resulting quaternion r
is used for rotations, it is equivalent to rotating by q1
followed by rotating by q2.
Return Value:
None
Function:
Create an internet domain socket for clients to connect
to.
Usage:
int CapCreateInetSocket(char *service, short def_port);
service
This is a service name as specified in /etc/services.
If the service is not found or is NULL then the
def_port is used instead.
def_port
The default port to use if serviceP is not valid
or not specified.
Description:
This routine creates an internet domain socket on the
port specified by the service name and /etc/services or
by the port specified by def_port. If the specified
port number is less than 1024, the server must be run
as root or the call will fail with errno set to EACCESS.
This routine is very low level. CapServe() provides a
much easier interface and is the recommended method of
creating server sockets.
Return Value:
Returns the socket file descriptor if all went well or
-1 if an error occurred. If there was an error, errno is
set to an appropriate value.
Function:
Create a Unix domain socket for clients to connect to.
Usage:
int CapCreateUnixSocket(char *name);
name The name of the unix domain socket. If the name is
not a full path name (that is, it does not start
with '/') then "/tmp/" is prepended to the name to
make a name in the directory /tmp.
Description:
This routine creates an Unix domain socket on the file-
name specified by name. The directory in which name is
to be created must be writable by the server process.
If the socket name is a full path name, that name is
used. If the name is not a full path name, it is
assumed to be relative to the directory /tmp and the
socket is created there.
This routine is very low level. CapServe() provides a
much easier interface and is the recommended method of
creating server sockets.
Return Value:
Returns the socket file descriptor if all went well or
-1 if an error occurred. If there was an error, errno is
set to an appropriate value.
Function:
Convert the current process into a daemon process.
Usage:
int CapDaemonize(void);
Description:
This routine actually creates a new process that is not
associated with the users terminal, current directory,
or process group. It does this by forking and calling
various system services to disassociate the process
from the controlling terminal. This prevents it from
getting signals when the user types control-C, for
example. Finally, the process changes its directory to
"/" to make sure that it is not on a mounted file system.
(This means that / has to be searchable by the server
process.)
Return Value:
Returns 0 if there was no error or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.
Function:
Create a socket and wait for a connection on it.
Usage:
int CapServe(char *server);
server
The name of the server. See below for details.
Description:
This routine creates an appropriate socket, waits for a
connection, cleans up the file system (if it was a Unix
domain socket), sets some socket options on internet
sockets for performance reasons, and returns the file
descriptor of a connection to a client if all went well.
This is a higher level but much simpler interface to
creating server sockets and connecting to clients.
The server name is the same name a user would provide to
Maya. There are two forms that this name can take. Unix
domain sockets are simply a filename on the disk. If
this name is not a full path name, it is taken to be
relative to /tmp. Internet domain sockets are a colon
followed by a port number specification. The port
number specification is either a service name or a
decimal port number. If the service name cannot be
found, it is assumed to be a decimal number.
The following are valid server names:
clock_server
This name creates a Unix domain socket named
/tmp/clock_server.
/usr/tmp/clock_server
The Unix domain socket is named /usr/tmp/clock_server.
:3001
This creates an internet socket on the local machine
at port 3001. If this machine is called host1, Maya
running on another machine can open the server
host1:3001 to connect to this socket.
:flock
This looks up the service name flock in
/etc/services and uses the port defined there to
create a socket. Maya running on a remote machine
can open the server host1:flock to connect to this
socket. This assumes that both hosts have an entry
for the service flock in their /etc/services files.
Return Value:
Returns a socket file descriptor that is connected to a
client if there were no errors or -1 if an error occurred.
If there was an error, errno is set to an appropriate value.