Procotol Specification for the LabView NTCP plugin
Paul Hubbard, Jose Calderon, Scott Gose
hubbard@sdsc.edu
calderon@mcs.anl.gov
gose@mcs.anl.gov
Revsion history
v1.0 11/11/03 Initial posting.
v1.1 11/12/03 Typos fixed, added overview of command sequence
v1.2 5/25/04 Added transaction IDs to get/setParameter, as per code.
v1.3 6/19/04 Added cancel and multiple ControlPoint support, new connection tracking.
v1.4 11/19/04 Small edits for post to nees.org
Background and Introduction
The Labview plugin (aka lvplugin) is a code plugin for the NEESGrid
Teleoperations Control Program (NTCP) (PDF) server. This plugin is
a simple one that converts NTCP to and from a simple ASCII format
designed for easy parsing. Communications occur over a single
persistent TCP connection, initiated by NTCP. Code is included to
perform all functions in LabVIEW, with several example control programs
and test harnesses.
Related documentation specific to the Mini-MOST demo can be found at http://www.mcs.anl.gov/neesgrid/mmost
Getting the code
The most recent version of the code is always in the
NEESGrid CVS archive (PDF)
, with package name 'ntcp_plugins'. As a side note, the code NTCP server is also in the
same archive, package name 'NTCP'.
Goals and Design Philosophy for the plugin
Our highest priority for the plugin was that it be reusable for other
languages and platforms other than LabVIEW. This implies simplicity and
consistency, which we hope that we have achieved. Your feedback is
welcomed, as are design discussions.
The first choice was the communications - we picked ASCII over a single
TCP connection, initiated by the NTCP server. Implications of this
include:
- Any system wishing to use this plugin must be capable of having a
process open and listen on a TCP port (i.e., have threading, or some
equivalent form of multitasking and interprocess communications)
- All messages are tab-delimited ASCII, on a single line, variable
length (Newline is the message delimiter)
- All messages should be human-readable.
- The plugin should, as much as possible, simply act as a
serialization layer, with all the work being done on the client side.
This means fewer assumption about client functionality, and higher
implementation flexibility. As a side benefit, simpler plugin code
reduces complexity and the number of bugs.
- Any language that can host a TCP connection and parse string can
be a full-fledged NTCP controller. This opens several doors to
lightweight control of small devices such as pan-tilt-zoom camera bases.
- We also chose to include the transaction ID in every message, so
that the client side can be asynchronous and multithreaded. (This is
how the LabVIEW control code was implemented)
By default, the connection is on TCP port 44000.
Connection tracking
It's worth explaining how the TCP connection is handled. Until 6/19/04, the TCP connection from
the plugin to the control system was established when openSession was called, and remained in place
untiil one end was stopped. This was a minor issue, and has been fixed.
Now, the TCP connection from plugin to control system is established with openSession, and
closed at closeSession.
Basic Message Format
The basic command format from the NTCP server to the client is
verb [tab delimiter] TransactionID {optional parameters, tab delimited} [newline]
where the verbs are the following
- open-session
- close-session
- propose
- execute
- cancel
- get-control-point
- get-parameter
- set-parameter
For example:
propose 1203 x displacement 2.71828 y rotation 3.142
Response format is
[OK|Error] [tab] ReturnCode [tab] TransactionID {optional error message] [newline]
For example:
OK 0 Transaction1203
Error 1 TransactionFoo Parameter out of range
Note the duplication - if successful, the OK and 0 are redundant.
However, I felt it useful for humans reading the protocol to have both
a Boolean error indicator as well as a more-computer-useful integer
denoting return code. Similarly, the optional error messages can be
useful - the LabVIEW code will return different return codes and error
strings for invalid axes and invalid parameters, for example. This is
often invaluable for debugging.
Basic Sequence of Commands
The normal sequence of commands from NTCP to the control system looks
like this:
- open-session
- set-parameter
- get-parameter
- Loop N times:
- propose
- execute
- get-control-point
- close-session
where steps 2 and 3 are semi-optional, and depend on the program
running NTCP. (This is sometimes called an 'NTCP client', or
'simulation coordinator, depending on the context).
With that in mind, let's delve into some details on each command.
Detailed syntax for each verb
This section explains the parameters for each verb. For more
information on the meaning and usage of each, please see the NTCP
specification (PDF) and the NTCP plugin
specification (PDF), as well as the NTCP helper
API (PDF).
open-session
Syntax:
open-session TransactionID {parameter} {parameter}
This can optionally initialize hardware or do
other system-specific work as required. This should be the very first
command of a connection. The parameters are control-system-specific,
meaning you can use this for whatever you need - they are optional. The
LabVIEW implementation ignores the transaction ID and any parameters
sent.
close-session
This mirrors open-session. Currently
performs no work, but can be used
as required. Should be the last command received in an NTCP session.
propose
New Feature: The latest
implementation of this plugin includes the ability to handle multiple
control points per propose request. The syntax of this new feature
includes the keyword
control-point to delimit between the multiple
control points specified in the request. The structure of a propose
request using this feature is as follows.
propose TransactionID ControlPoint GeomType ParameterType Parameter [ [control-point {ControlPoint GeomType ParameterType Parameter}] ... ]
Note: The original syntax
will still work so original code should not need to be modified.
Propose is really
the
key NTCP command. I recommend that you understand it well before
writing any control software that has significant value and/or stored
energy.
Syntax:
propose TransactionID ControlPoint GeomType ParameterType Parameter {GeomType ParameterType Parameter} {...}
where there can be zero to twelve
parameters. The spec also allows zero
parameters, for implied commands based on the control
point name. I tend to find this questionable practice, and prefer to
make my
parameters explicit, but it's optional either way.
GeomType mirrors the NTCP spec, and is a single character:
x,y, or z
ParamType also mirrors the
specification, and can be:
displacement, force, rotation or moment
Parameter is simple a scalar
floating-point number. Combining these for
a simple command, we have:
propose Tranaction0 ANCO-table x force 0.3 x displacement 3.1 y rotation 180.1
Note that order is not
significant for the parameter triplets.
This verb is designed such that the control system should validate the
proposal by its own means before returning. In the LabVIEW
implementation, validation is done as follows:
- Control daemon tokenizes the request, recognizes it as a
proposal, and puts it into a queue or pending proposals.
- Within the same code, a subroutine removes the proposal from
the
queue for validation. This was done so that proposals could be
validated by external code, e.g. in a users' control program.
- The proposal validator reads the file 'actuators.ini' to
determine which actuators are valid at present. From this file, it
searches for each GeomType in the request. If an actuator with that
geometry, e.g. 'x', is present, the validator compares the parameter
against the static ranges defined in 'actuators.ini.'
- Step 3 is repeated for each geometry in the request. All must
be accepted for the proposal to be succeed.
- Note that the total effect of this is to define a rectilinear
space, flat-sided. This was sufficient for our purposes; you may well
wish to enhance the validation for more interesting configurations. For
example, a spherical space would require coordinate
transformations and/or distance calculations to validate, rather than
axis-by-axis checking.
- If the proposal is validated, the validator splits it up into
one
move per axis, and puts those commands into a queue of pending commands.
Verb notes
Once an 'OK' response has been
returned, the NTCP server will usually
either execute or cancel it next, depending on what the other
components in the test have to say. Your code should be able to cancel
transactions without ill effect; in a shameless display of hypocrisy
ours does not yet do so, though the hooks are there. Neither, however,
does the NTCP server itself yet manage this.
Also note that if an execute is still running, you should not receive
another propose until after the move completes, otherwise you'll get
'control point busy' errors from within NTCP. Its core design
assumptions include 'one and only one in-flight transaction per control
point', which is rather a shame in that it disallows pipeline
optimization.
execute
This simply triggers execution of a
previously-accepted proposal.
Obviously, the transaction ID must have been both proposed and accepted
for this to be valid.
Syntax:
execute TransactionID
The control system should not
return until the execution is complete.
cancel
This command cancels a pending command,
usually due to a proposal being rejected by another control system
somewhere else. As noted above, we cannot currently handle cancel
requests. The plugin will throw an exception. The LabVIEW code has
skeleton code to deal with them, but does not yet do so - all you'd
have to
do is walk the pending-commands queue, and remove the one with a
matching transaction ID.
This should return OK if the transaction was cancelled successfully.
Syntax:
cancel TransactionID
get-control-point
This is the main feedback mechanism
used by NTCP. Since NTCP does not have access to the streaming DAQ
data, it needs some mechanism to get readings (e.g. force, position)
back to form a closed loop; this is the mechanism.
New Feature: The latest
implementation of this plugin includes the ability to query multiple
control-points. Each control-point queried results in separate replies
(shown below) from the plugin.
Syntax of the command is:
get-control-point TransactionID ControlPoint [ [ControlPoint] ... ]
where the transaction ID is usually
ignored, but required for consistent parsing. The return format has a
variable number of parameters, depending on what the given control
point supports. Mirroring the propose syntax, we return up to twelve
triplets of
GeomType ParamType Parameter
with the same types as 'propose' above,
e.g. 'x displacement 1.414'
An example:
get-control-point DummyTransactionID003 ANCO
replies
OK 0 DummyTransactionID003 x displacement 0.0 x force -0.113 y rotation 0.0 z rotation 0.0
Verb Notes
This is an often-called method and
should be asynchronous of the propose/execute logic if possible. In the
LabVIEW implementation, a separate loop in the control program handles
these requests and returns instant DAQ readings, enabling real-time
data as a move happens. We use a LabVIEW semaphore to mark the TCP send
as a critical section, so that the various threads don't collide in
communicating with NTCP.
get-parameter
This is mainly used by the MATLAB code
to pass simulation parameters around. The actual formatting of the
parameter string is not documented as of this writing, so be cautious
in your use of it. For example, MOST-SIM used this to pass both scalars
(number of simulation steps) and 3x3 matrices around, both
in MATLAB format. For Mini-MOST, the LabVIEW code returns a scalar
defined in the control program, which is the spring stiffness of the
main beam.
Syntax:
get-parameter TransactionID ParamName
Return syntax:
OK 0 ParamName Parameter
As noted above, the format of parameter
needs to be negotiated.
set-parameter
This is the mirror of get-parameter,
with the same notes and limitations. The plugin sends whatever it gets,
and LabVIEW duly ignores it with an OK response.
Syntax:
set-parameter TransactionID ParamName Parameter
Complete conversation
To supply an example, please see this
NTCP logfile. It contains a complete test run from the MCS shake
table, driven by a 100-point sine wave sweep.
Other Notes
More information on the LabVIEW implementation is presently included in
the Mini-MOST writeup.
None of the commands include units, which seems a significant omission.
0.5m is quite different than 0.5mm, so you must ensure that both sides
agree on these before coding. The LabVIEW code includes unit support,
but it'd need to be reconciled with any protocol changes to be useful.
Support
This work was supported primarily by the George E. Brown,
Jr. Network for Earthquake Engineering Simulation (NEES) Program of
the National Science Foundation under Award Number CMS-0117853.