We use the QNX real-time operating system,
by QNX Software Systems, Ltd (version 4.25).
The QNX OS is a UNIX derivative, which means it has all the glories of pre-emptive
multitasking, priority scheduling, and protected memory which we have come
to expect from modern operating systems. In addition, QNX provides convenient
facilities for inter-process communication and, because it is a real-time
OS, timing capabilities. With these abilities, it becomes easy to construct
a system which can run multiple time-critical operations simultaneously.
Process Based Structure
Because the structure of our system is
so complex, writing a single program to control all the various peripherals
and take care of the computational aspects is a huge task. Instead, we created
a multi-process structure, in which each process functions as some type of
device driver. Because of the facilities available in QNX, we were able to
implement a two node system which performs all these tasks.
Node 1 - Pentium II 233 MHz processor:
- Perform all robot I/O, kinematics computation, control, and
force sensing, using an 4-axis servo board installed on the ISA bus @ 1000
- Perform I/O and simple computations to drive the CyberGrasp
force-feedback system @ 1000 Hz
- Interacte with user through command line interface that allows realtime
gain modification and data capture.
- Communicate with Node 2 at 250 Hz through a Ethernet Socket.
Node 2 - Pentium III 500 MHz processor:
- Communicate with the CyberGlove Interface Unit over a serial line @ 250
- Compute the kinematics of the human hand @ 250 Hz
- Update the Graphical User Interface @ 7 Hz
- Communicate over Ethernet with an AdeptOne robot controller @ 62.5 Hz
- Communicate with a Logitech 6 DOF tracker @ 50 Hz
- Perform calculations to intuitively map motions from the 3-D human hand
model to the planar robotic manipulator @ 250Hz.
- Manage process creation, communication, and do miscellaneous
- Spawn additional sub-tasks which capture data or calibrate
the kinematic hand model
- Communicate with Node 1 at 250 Hz through a Ethernet Socket
Each of these tasks is performed by a
separate executable process. By scheduling the processes with different priorities,
we can control which tasks are the most time-critical, such as the robot control,
and guarantee that these tasks receive CPU resources when needed. In general,
the QNX operating system has excelled in providing a stable, robust, reliable
base for our system.
Inter-Process Communication (IPC)
We use three primary modes of inter-process
communication in our system: QNX messages, shared memory, and signals.
QNX messages provide a convenient, control-transfer
mechanism of communication. If process #1 sends a message to process #2, it
halts execution until process #2 replies. This provides a method of controlling
program flow across multiple processes, and is most useful when the 'reply'
data must be complete and takes a relatively short time to compute.
POSIX shared memory provides a way of
sharing physical memory across multiple process spaces. It is therefore lightning-fast
for data transfer, but suffers from all the problems associated with 'global'
variables, because its state can change at any time. Therefore, if a set of
data is 'grabbed' from shared memory, there is no way to tell a priori that
it is a complete set of data, rather than a partial update, AND there
is no way to tell which process changed the data. These limitations can be
overcome using semaphores; we determined that incomplete data sets were of
little importance since most of our data is transferred or updated at 250
or 1000 Hz between processes, and the 'off-by-one-sample' effect can be interpreted
as a short time lag. This time lag is well within the lag tolerance associated
with our tasks.
Signals are similar to software interrupts
in that they immediately transfer program control to a small subroutine. We
use signals only to handle some exception conditions, such as process termination
and catastrophic error. Due to their limited number and lack of data transferred,
signals are unsuitable for periodic process communication.
The object-oriented programming paradigm
has proven invaluable in creating an expandable base for implementing various
calibration and mapping ideas, as well as providing convenience in simplifying
the syntax for shared memory, child processes, timers, and other QNX facilities.
We've posted our (unsupported) publicly
accessible code for simplifying some of the QNX facilities.