This readme was based on the readme for the open-source version of RTMA, Dragonfly (https://github.com/dragonfly-msg/dragonfly). It is possible that some of the setup instructions here are incorrect. Please report any issues by reporting on github or bugging your preferred RNEL engineer.
RTMA is a simple messaging system that helps programmers create modular distributed applications rapidly. It hides the complexities of socket programming and data translation, also provides a uniform high-level API in each of the supported programming languages (C++, C#, Python, Matlab) and operating systems (Windows, Linux). Therefore, programmers are able to write each part of their application in their programming language of choice and on their operating system of choice without having to worry about how the modules will communicate with each other.
RTMA consists of several components: a central message exchange daemon (MessageManager), a data logger daemon (Logger), and utilities to create message definitions in all supported programming languages.
RTMA uses a client-server architecture where MessageManager is the central server and software modules that would like to talk to each other are the clients. MessageManager keeps a listening socket for modules to connect to and start sending messages. All messages go through MessageManager which forwards them to the connected modules based on their subscriptions. Modules connect to MessageManager, subscribe to message types they care about, send messages that will be forwarded by MessageManager to all modules that have subscribed to those message types, and receive messages that they themselves have subscribed to. The modules remain independent of each other and do not have to know which modules will consume their messages or where the messages they consume originate.
The Real-Time Messaging Architecture (RTMA) was first developed by Meel Velliste and Sagi Perel for use in the development of brain-computer interface development.
Publications whose experiments utilized RTMA Messaging include:
- Velliste, M., Perel, S., Spalding, M. C., Whitford, A. S., & Schwartz, A. B. (2008). Cortical control of a prosthetic arm for self-feeding. Nature, 453(7198), 1098-101. doi:10.1038/nature06996
- Clanton, S. T., McMorland, A. J. C., Zohny, Z., Jeffries, S. M., Rasmussen, R. G., Flesher, S. N., & Velliste, M. (2013). Seven Degree of Freedom Cortical Control of a Robotic Arm. In C. Guger, B. Z. Allison, & G. Edlinger (Eds.), Brain-Computer Interface Research (pp. 73-81). Berlin, Heidelberg: Springer Berlin Heidelberg. doi:10.1007/978-3-642-36083-1
- Collinger, J. L., Wodlinger, B., Downey, J. E., Wang, W., Tyler-Kabara, E. C., Weber, D. J., McMorland, A. J. C., Velliste, M., Boninger, M. L., Schwartz, A. B. (2012). High-performance neuroprosthetic control by an individual with tetraplegia. The Lancet. doi:10.1016/S0140-6736(12)61816-9
Bare minimum requirement is that you have a C++ compiler installed. On linux/mac, you also need to have qt-qmake (from qt4 or qt5) installed (in a future release, this requirement may be eliminated). If you'd like to have support for other languages, see below further requirements:
- Version >= 2.6 (python3.7 preferred)
- Install swig >= 2.0.3 (make sure swig executable is on Path. Latest SWIG 4.1 works.) (http://www.swig.org/download.html)
- Install Clang and ctypeslib2 python packages (ctypeslib2 v2.2.2 known to work)
pip install clang
andpip install ctypeslib2==2.2.2
- Previously a package called "ctypesgen" was used instead of clang/ctypeslib2. This has recently been updated to support Python3 and can be used as an alternative to clang/ctypeslib2 if there are any issues with clang/ctypeslib2. This package can be found on GitHub.
- Install LLVM-Clang compiler (version 11.0 known to work)
- Windows/Linux: http://releases.llvm.org/download.html
- MacOS: Install XCode command line tools (Clang is default compiler on MacOS). You may also need to link libclang.dylib to a standard library location (e.g. ~/lib or where ever you copy libRTMA.dylib, see Linux/Mac Installation step 4. below)
- Note: the latest version of LLVM may not work with the clang python bindings. For best results, check python bindings version with
pip show clang
and install the same version of LLVM.
- Windows only, Visual Studio 2005 or later. Latest VS2022 preferred.
- Version >= 2007b
- Configure Matlab to recognize the Visual Studio C++ compiler
Clone the repository and compile the source as follows:
-
If planning to use the python interface, the makefile in
RTMA/lang/python
may need to be manually edited to correctly set variables (i.e. point to the correct python install location) -
In a terminal execute the following:
cd RTMA/build ./build_with_qmake.sh
-
Create
RTMA
environment variable and set it to where your RTMA folder is (optional but can be used when building C++ modules) -
Copy
RTMA/lib/libRTMA.so
to/usr/lib
or addRTMA/lib
toLD_LIBRARY_PATH
- On older versions of MacOS, setting DYLD_LIBRARY_PATH may work. On recent versions of Mac (>= El Capitan), this no longer works due to System Integrity Protection (SIP). Instead, the .so file can be moved, copied, or hard linked via the
ln
command (e.g.ln -s /path/to/original /path/to/link
) to standard library locations (~/lib, /usr/lib, or /usr/local/lib). - Installing the library with a symlink (
ln -s
) to /usr/local/lib works well on Linux as well. You will likely need to runsudo ldconfig
after linking the library so that the system recongnizes it.
- On older versions of MacOS, setting DYLD_LIBRARY_PATH may work. On recent versions of Mac (>= El Capitan), this no longer works due to System Integrity Protection (SIP). Instead, the .so file can be moved, copied, or hard linked via the
-
If you plan to use the matlab interface, start matlab and execute the following:
cd RTMA/lang/matlab make cd RTMA/src/modules/QuickLogger/LogReader make
-
If you plan to use the python interface, append
RTMA/lang/python
toPYTHONPATH
environment variable
If you'd like to compile from source, clone the repository and follow these instructions:
-
Build
RTMA/build/RTMA.sln
with Visual Studio (2005 or later) -
Create
RTMA
environment variable and set it to where your RTMA folder is (optional, but can be used to build C++ modules) -
If you plan to use the python 2/3 interfaces,
- Set
PYTHON2_BASE
andPYTHON3_BASE
environment variables to respective python 2 and 3 install locations (e.g. C:\Python\Anaconda3 and C:\Python\Anaconda3\envs\py27) - Set
PYTHON2_LIB
andPYTHON3_LIB
environment variables (ex: %PYTHON3_BASE%\libs) - Set
PYTHON2_INCLUDE
andPYTHON3_INCLUDE
environment variables (ex: %PYTHON3_BASE%\include) - Build
RTMA\lang\python\PyRTMA.sln
with Visual Studio (tested with VS 2019) - Add
%RTMA%\lang\python
toPYTHONPATH
environment variable
- Set
-
If you plan to use the Matlab interface, start matlab and execute the following:
cd RTMA\lang\matlab make cd RTMA\src\modules\QuickLogger\LogReader make
Note that 64-bit Windows mex files are tracked in the repo and this step is usually unecessary when running 64-bit Windows
bin
executable modulesbuild
source code build scriptsexamples
example programs showing how to use RTMAinclude
include files for the C++ APIlang
APIs for other languageslib
library files for the C++ APIsrc
source code for C++ API and executable modules
- ConnectToMMM(ModuleID, ServerAddress)
- DisconnectFromMMM()
- Subscribe(MessageType)
- Unsubscribe(MessageType)
- ReadMessage(Timeout)
- SendMessage(MessageType, MessageData)
- SendSignal(MessageType)
RTMA/examples
folder contains ready to run modules in all supported languages. See the README.txt file
in each example folder for further information.
RTMA uses standard C header files to describe message definitions.
Each message consists of a message type and an optional message body.
The message type is an integer that should be selected to uniquely identify each message.
It is set with a #define
statement and the name of the message needs to begin with MT_
.
Here is an example:
#define MT_ROBOT_FEEDBACK 100
The message body is a struct
composed of one or more data fields which can be standard C data types
and other structs. The struct has to have the same message name as the message type, and it needs to begin with MDF_
.
Here is an example:
typedef struct {
double position;
double velocity;
double force;
} MDF_ROBOT_FEEDBACK;
Here is a more complex example:
typedef struct {
int SerialNo;
int Flags;
double dt;
} SAMPLE_HEADER;
#define MAX_ROBOT_FEEDBACK_DIMS 10
typedef struct {
SAMPLE_HEADER sample_header;
double position[MAX_ROBOT_FEEDBACK_DIMS];
double velocity[MAX_ROBOT_FEEDBACK_DIMS];
double force[MAX_ROBOT_FEEDBACK_DIMS];
} MDF_ROBOT_FEEDBACK;
The message body fields need to be manually padded for data alignment as necessary. The following is an example of how to define the fields for 64-bit alignment:
typedef struct {
int source_index;
int reserved; // for 64-bit alignment
double source_timestamp;
} MDF_RAW_SAMPLE_RESPONSE;
If you are not sure how to align message fields on your system, it is safe to use 64-bit alignment. Even if your system is not 64-bit, or if you have a mixture of systems with different alignment requirements, this practice will ensure proper alignment.