Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This guide covers essential points to developing a native client application using the NatNet SDK. The guideline uses sample codes in the SampleClient.cpp application in the \NatNet SDK\Sample
folder, please refer to this project as an additional reference.
SDK/API Support Disclaimer
We provide developer tools to enable OptiTrack customers across a broad set of applications to utilize their systems in the ways that best suit them. Our Motive API through the NatNet SDK and Camera SDK is designed to enable experienced software developers to integrate data transfer and/or system operation with their preferred systems and pipelines. Sample projects are provided alongside each tool, and we strongly recommend the users to reference or use the samples as reliable starting points. The following list specifies the range of support that will be provided for the SDK tools:
Using the SDK tools requires background knowledge on software development; therefore, we do not provide support for basic project setup, compiling, and linking when using the SDK/API to create your own applications.
Although we ensure the SDK tools and their libraries work as intended, we do not provide support for custom developed applications that have been programmed or modified by users using the SDK tools.
Ticketed support will be provided for licensed Motive users using the Motive API and/or the NatNet SDK tools from the included libraries and sample source codes only.
The Camera SDK is a free product, and therefore we do not provide free ticketed support for it.
For other questions, please check out the NaturalPoint forums. Very often, similar development issues get reported and solved there.
a. Link the Library
When developing a native NatNet client application, NatNetLib.dll file needs to be linked to the project and placed alongside its executable in order to utilize the library classes and functions. Make sure the project is linked to DLL files with matching architecture (32-bit/64-bit).
b. Include the Header Files
After linking the library, include the header files within your application and import required library declarations. The header files are located in the NatNet SDK/include
folder.
include "NatNetTypes.h"
include "NatNetClient.h"
Connection to a NatNet server application is accomplished through an instance of NatNetClient object. The client object is instantiated by calling the NatNetClient constructor with desired connection protocol (Multicast/Unicast) as its argument. Designate a desired connection protocol and instantiate the client object. In the SampleClient example, this step is done within the CreateClient function.
ConnectionType_Multicast = 0
ConnectionType_Unicast = 1
The NatNet SDK includes functions for discovering available tracking servers. While client applications can connect to a tracking server by simply inputting the matching IP address, the auto-detection feature provides easier use.The NatNet_BroadcastServerDiscovery function searches the network for a given amount of time and reports IP addresses of the available servers. The reported server information can be used to establish the connection. The NatNet_CreateAsyncServerDiscovery function continuously searches for available tracking servers by repeatedly calling a callback function. This is all demonstrated in the SampleClient application.
[C++] SampleClient.cpp : Server Discovery
Now that you have instantiated a NatNetClient object, connect the client to the server application at the designated IP address by calling the NatNetClient::Connect method.The Connect method requires a sNatNetClientConnectParams struct for the communication information; including the local IP address that the client is running on and the server IP address that the tracking data is streamed to. It is important that the client connects to appropriate IP addresses; otherwise, the data will not be received.Once the connection is established, you can use methods within the NatNetClient object to send commands and query data.
[C++] SampleClient.cpp : Connect to the Server
Now that the NatNetClient object is connected, let’s confirm the connection by querying the server for its descriptions. This can be obtained by calling the NatNetClient::GetServerDescription method and the information gets saved in the provided instance of sServerDescriptions. This is also demonstrated in the CreateClient function of the SampleClient project.
[C++] SampleClient.cpp : Request Server Description
You can also confirm connection by sending a NatNet remote command to the server. NatNet commands are sent by calling the NatNetClient::SendMessageAndWait method with supported NatNet Command as one of its input arguments. The following sample sends a command for querying the number of analog sample for each of the mocap frames. If the client is successfully connected to the server, this method will save the data and return 0.
[C++] SampleClient.cpp : Send NatNet Commands
Now that the client application is connected, data descriptions for the streamed capture session can be obtained from the server. This can be done by calling the NatNetClient::GetDataDescriptionList method and saving the descriptions list into an instance of sDataDescriptions. From this instance, the client application can figure out how many assets are in the scene as well as their descriptions.This is done by the following line in the SampleClient project:Collapse
[C++] SampleClient.cpp : Get Data Descriptions
After an sDataDescriptions instance has been saved, data descriptions for each of the assets (marker, Rigid Body, Skeleton, and force plate from the server) can be accessed from it.Collapse
[C++] SampleClient.cpp : Parsing Data Descriptions
When you are finished using the data description structure, you should free the memory resources allocated by GetDataDescription using the NatNet helper routine NatNet_FreeDescriptions().
Now that we have data descriptions, let's fetch the corresponding frame-specific tracking data. To do this, a callback handler function needs to be set for processing the incoming frames. First, create a NatNetFrameReceivedCallback function that has the matching input arguments and the return values as described in the NatNetTypes.h file:typedef void (NATNET_CALLCONV* NatNetFrameReceivedCallback)(sFrameOfMocapData* pFrameOfData, void* pUserData);
The SampleClient.cpp project sets DataHandler function as the frame handler function.void NATNET_CALLCONV DataHandler(sFrameOfMocapData* data, void* pUserData)
The NatNetClient::SetFrameReceivedCallback method creates a new thread and assigns the frame handler function. Call this method with the created function and the NatNetClient object as its arguments. In the SampleClient application, this is called within the CreateClient function:
Once you call the SetDataCallback method to link a data handler callback function, this function will receive a packet of sFrameOfMocapData each time a frame is received. The sFrameOfMocapData contains a single frame data for all of the streamed assets. This allows prompt processing of the capture frames within the handler function.
When exiting the program, call Disconnect method to disconnect the client application from the server.
This page provides an overview of the general data structure used in the NatNet software development kit (SDK) and how the library is used to parse received tracking information.
For specific details on each of the data types, please refer to the NatNetTypes.h header file.
When receiving streamed data using the NatNet SDK library, its data descriptions should be received before receiving the tracking data. NatNet data is packaged mainly into two different formats: data descriptions and frame-specific tracking data. Utilizing this format, the client application can discover which data are streamed out from the server application in advance to accessing the actual tracking data.
For every asset (e.g. reconstructed markers, Rigid Bodies, Skeletons, force plates) included within streamed capture sessions, their descriptions and tracking data are stored separately. This format allows frame-independent parameters (e.g. name, size, and number) to be stored within instances of the description structs, and frame-dependent values (e.g. position and orientation) to be stored within instances of the frame data structs. When needed, two different packets of an asset can be correlated by referencing to its unique identifier values.
Dataset Descriptions contains descriptions of the motion capture data sets for which a frame of motion capture data will be generated. (e.g. sSkeletonDescription, sRigidBodyDescription)
Frame of Mocap Data contains a single frame of motion capture data for all the datasets described from the Dataset Descriptions. (e.g. sSkeletonData, sRigidBodyData)
When streaming from Motive, received NatNet data will contain only the assets that are enabled in the Assets pane and the asset types that are set to true under Streaming Settings in the Data Streaming tab in Motive Settings.
To receive data descriptions from a connected server, use the NatNetClient::GetDataDescriptionList method. Calling this function saves a list of available descriptions in an instance of sDataSetDescriptions.
The sDataSetDescriptions structure stores an array of multiple descriptions for each of assets (Marker Sets, RigidBodies, Skeletons, and Force Plates) involved in a capture and necessary information can be parsed from it. The following table lists out the main data description structs that are available through the SDK.
Refer to the NatNetTypes.h header file for more information on each data type and members of each description struct.
Description Struct
Server Description
sServerDescription
ServerDescription
Contains basic network information of the connected server application and the host computer that it is running on. Server descriptions are obtained by calling the GetServerDescription method from the NatNetClient class.
Host connection status
Host information (computer name, IP, server app name)
NatNet version
Host's high resolution clock frequency. Used for calculating the latency
Connection status
Data Descriptions
sDataDescriptions
List<DataDescriptor>
Contains an array of data descriptions for each active asset in a capture, and basic information about corresponding asset is stored in each description packet. Data descriptions are obtained by calling the GetDataDescriptions method from the NatNetClient class. Descriptions of each asset type is explained below.
Marker Sets Description
sMarkerSetDescription
MarkerSet
Marker Set description contains a total number of markers in a Marker Set and each of their labels. Note that Rigid Body and Skeleton assets are included in the Marker Set as well. Also, for every mocap session, there is a special MarkerSet named all, which contains a list of all of the labeled markers from the capture.
Name of the Marker Set
Number of markers in the set
Marker names
Rigid Body Description
sRigidBodyDescription
RigidBody
Rigid Body description contains corresponding Rigid Body names. Skeleton bones are also considered as Rigid Bodies, and in this case, the description also contains hierarchical relationship for parent/child Rigid Bodies.
Rigid Body name
Rigid Body streaming ID
Rigid Body parent ID (when streaming Skeleton as Rigid Bodies)
Offset displacement from the parent Rigid Body
Array of marker locations that represent the expected marker locations of the Rigid Body asset.
Skeleton Description
sSkeletonDescription
Skeleton
Skeleton description contains corresponding Skeleton asset name, Skeleton ID, and total number of Rigid Bodies (bones) involved in the asset. The Skeleton description also contains an array of Rigid Body descriptions which relates to individual bones of the corresponding Skeleton.
Name of the Skeleton
Skeleton ID: Unique identifier
Number of Rigid Bodies (bones)
Array of bone descriptions'
Update Note: In NatNet 3.0, Skeleton bone data description packet has been changed from left-handed convention to right-handed convention to be consistent with the convention used in all other data packets. For older versions of NatNet clients, the server, Motive, will detect the client version and stream out Skeleton data in the matching convention. This change will only affect direct-depacketization clients as well as clients that have the NatNet library upgraded to 3.0 from previous versions; for those clients, corresponding changes must be made to work with Motive 2.0.
Force Plate Description
sForcePlateDescription
ForcePlate
Force plate ID and serial number
Force plate dimensions
Electrical offset
Number of channels
Channel info
More. See NatNetTypes.h file for more information
Camera Description
sCameraDescription
Camera
An instance of the sCameraDescription contains information regarding the camera name, its position, and orientation.
Camera Name (can be used with Get/Set property commands)
Camera Position (x, y, z float variables)
Camera Orientation (qx, qy, qz, qw float variables)
For more info, see the NatnetTypes.h file.
Device Description
sDeviceDescription
Device
Device ID. Used only for identification of devices in the stream.
Device Name
Device serial number
Device Type
Channel count
Channel Names
As mentioned in the beginning, frame-specific tracking data are stored separately from the DataDescription instances as this cannot be known ahead of time or out of band but only by per frame basis. These data gets saved into instances of sFrameOfMocapData for corresponding frames, and they will contain arrays of frame-specific data structs (e.g.sRigidBodyData, sSkeletonData) for each types of assets included in the capture. Respective frame number, timecode, and streaming latency values are also saved in these packets.
The sFrameOfMocapData can be obtained by setting up a frame handler function using the NatNetClient::SetFrameReceivedCallback method. In most cases, a frame handler function must be assigned in order to make sure every frames are promptly processed. Refer to the provided SampleClient project for an exemplary setup.
FrameOfMocapData
One reconstructed 3D marker can be stored in two different places (e.g. in LabeledMarkers and in RigidBody) within a frame of mocap data. In those cases, unique identifier values of the marker can be used to correlate them in the client application if necessary.
Declarations for these data types are listed in the NatNetTypes.h header files within the SDK. The SampleClient project included in the \NatNet SDK\Sample
folder illustrates how to retrieve and interpret the data descriptions and frame data.
Refer to the NatNetTypes.h header file or the NatNetML.dll assembly for the most up to date descriptions of the types.
Most of the NatNet SDK data packets contain ID values. This value is assigned uniquely to individual markers as well as each of assets within a capture. These values can be used to figure out which asset a given data packet is associated with. One common use is for correlating data descriptions and frame data packets of an asset.
Decoding Member IDs
For each member object that is included within a parental model, its unique ID value points to both its parental model and the member itself. Thus, the ID value of a member object needs to be decoded in order to parse which objects and the parent models they are referencing to.
For example, a Skeleton asset is a hierarchical collection of bone Rigid Bodies, and each of its bone Rigid Bodies has unique ID that references to the involved Skeleton model and the Rigid Body itself. When analyzing Skeleton bones, its ID value needs to be decoded in order to extract the segment Rigid Body ID, and only then, it can be used to reference its descriptions.
NatNet SDK provides a C++ helper function, NatNet_DecodeID, for decoding member ID and model ID of an member object. You can also decode by manually parsing the ID as demonstrated in the WinFormSample or the SampleClientML sample.
To ease your use of NatNet data in MATLAB applications, we provide a wrapper class (natnet.p) for using real-time streamed NatNet data. Using this class, you can easily connect/disconnect to the server, receive the tracking data, and parse each component.
The Matlab-NatNet wrapper class is a wrapper for the NatNet assembly and provides a simplified interface for managing the native members in MATLAB. Ther class definition and supporting code should be placed within the MATLAB PATH. The implementation automatically disposes running connections when ending a streaming session, along with basic object management. In order to use the Matlab wrapper class, the NatNetML assembly must be loaded into the MATLAB session. This is handled automatically and the first time the class is used the user is prompted to find the NatNetML.dll file in the Windows file browser. A reference to this location is used in future MATLAB sessions.
To create an instance of the natnet wrapper class, simply call the class with no input arguments and store it in a variable.
Class Properties: The available properties to the class can be seen with the following command, properties('natnet').
Class Methods: And Available methods
Creating an instance of the class does not automatically connect the object to a host application. After enabling the broadcast frame data under the Data Streaming pane in Motive or in any other server, configure the connection type and IP addresses for the client and host to reflect your network setup.
Then enter the following line to call the connect method for connecting to the natnet object to the host.
When creating a natnet class instance, the default host and client IP address is set to '127.0.0.1', which is the local loopback address of the computer. Ther natnet object will fail to connect if the network address of the host or client is incorrect.
The natnet wrapper class interface has a method to poll mocap data called getFrame. getFrame method returns the data structure of the streamed data packet. Polling is supported but not recommended due to accessing errors. The function, poll.m, provides a simple exmple showing out to poll the frames of mocap data. After connecting the natnet object to the host server, run the polling script to acquire the data packets in the main workspace.
The natnet class implements a simple interface to use event callbacks. The natnet method, addlistener, requires two input arguments. The first input is which listener slot to use, and the second is the name of the m-function file to be attached to the listener. Once the function is attached using addlistener method, it will be called each time a frame is received. When the callback function is first created, the listener is turned off by default. This is to ensure the user had control of the execution of the even callback function.
Enabling Listener: Start receiving streamed data by enabling the callback function by calling the enable method. The input of the enable method indicates the index value of the listener to enable. Multiple functions can be attached to the listener, and you can enable a specific listener by inputing its index value. Entering 0 will enable all listeners.
Disabling Listener: There are three types of callback functions that ships with the natnet class. IF they are added to the natnet listener list and enabled, they will execute each time the host sends a frame of data. The setup.m file, contains an example of how to operate the class. To stop streaming, use the disable method and be sure to enter a value of 0 to disable all listeners.
The natnet class also has functionality to control the Motive application. To enable recording use the startRcord and stopRecord methods, and for playback, use the startPlayback and stopPlayback methods. There are a number of additional commands as shown below.
To display the actions of the class, set the IsReporting property to true. This displays operations of the class to the Command Window.
The NatNet SDK is a networking software development kit (SDK) for receiving NaturalPoint data across networks. It allows streaming of live or recorded motion capture data from a tracking server (e.g. Motive) into various client applications. Using the SDK, you can develop custom client applications that receive data packets containing real-time tracking information and send remote commands to the connected server. NatNet uses the UDP protocol in conjunction with either Point-To-Point Unicast or IP Multicasting for sending and receiving data. The following diagram outlines the major components of a typical NatNet network setup and how they establish communication between NatNet server and client application.
For previous versions of NatNet, please refer to the provided PDF user guide that ships with the SDK.
Please read through the for key changes in this version.
NatNet is backwards compatible with any version of Motive, however, in older versions there may be missing features that are present in newer versions.
The NatNet SDK consists of the following:
NatNet Library: Native C++ networking library contents, including the static library file (.lib), the dynamic library file (.dll), and the corresponding header files.
NatNet Assembly: Managed .NET assembly (NatNetML.dll) for use in .NET compatible clients.
NatNet Samples: Sample projects and compiled executables designed to be quickly integrated into your code.
A NatNet server (e.g. Motive) has 2 threads and 2 sockets: one for sending tracking data to a client and one for sending/receiving commands.
NatNet servers and clients can exist either on a same machine or on separate machines.
Multiple NatNet clients can connect to a single NatNet server.
When a NatNet server is configured to use IP Multicast, the data is broadcasted only once, to the Multicast group.
Default multicast IP address: 239.255.42.99 and Port: 1511.
IP address for unicast is defined by a server application.
The NatNet SDK is shipped in a compressed ZIP file format. Within the unzipped NatNet SDK directory, the following contents are included:
Sample Projects: NatNet SDK\Samples
Library Header Files: NatNet SDK\include
The include folder contains headers files for using the NatNet SDK library.
Library DLL Files: NatNet SDK\lib
NatNet library files are contained in the lib folder. When running applications that are developed against the NatNet SDK library, corresponding DLL files must be placed alongside the executables.
NatNet class and function references for the NatNetClient object.
List of tracking data types available in the NatNet SDK streaming protocol.
NatNet commands for remote triggering the server application
NatNet commands for subscribing to specific data types only.
Tip: Code samples are the quickest path to towards getting familiar with the NatNet SDK. Please check out the NatNet samples page.
List of NatNet sample projects and the instructions.
Timecode representation in OptiTrack systems and NatNet SDK tools.
A general guideline to using the NatNet SDK for developing a native client application.
A general guideline to using the NatNet SDK for developing a managed client application.
To convert from provided quaternion orientation representation, the following aspects of desired Euler angle convention must be accounted:
Rotation Order
Handedness: Left handed or Right handed
Axes: Static (Global) or relative (local) axes.
For example, Motive uses the following convention to display the Euler orientation of an object:
Rotation Order: X (Pitch), Y (Yaw), Z (Roll)
Handedness: Right-handed (RHS)
Axes: Relative Axes (aka 'local')
Important Note: Use of the direct depacketization is not recommended. The syntax of the bit-stream packets is subject to change, requiring an application to update its parsing routines to be compatible with the new format. The direct depacketization approach should be used only where the use of the NatNet library is not applicable.
In situations where the use of the NatNet library is not applicable (e.g. developing on unsupported platforms such as Unix), you can also depacketize the streamed data directly from the raw bit-stream without using the NatNet library. In order to provide the most current bitstream syntax, the NatNet SDK includes a testable working depacketization sample (PacketClient, PythonClient) that decodes NatNet Packets directly without using the NatNet client class.
For the most up-to-date syntax, please refer to either the PacketClient sample or the PythonClient sample to use them as a template for depacketizing NatNet data packets.
Adapt the PacketClient sample (PacketClient.cpp) or the PythonClient sample (NatNetClient.py) to your application's code.
Regularly update your code with each revision to the NatNet bitstream syntax.
The 4.0 update includes bit-stream syntax changes to allow up to 32 force plates to be streamed at once. This requires corresponding updates for each program that uses the direct depacketization approach for parsing streamed data. A system under 32 force plates should still avoid using direct depacketization. See the Important Note above in the Direct Depacketization section for more information.
Starting from Motive 3.0, you can send NatNet remote commands to Motive and select the version of bitstream syntax to be outputted from Motive. This is accomplished by sending a command through the command port. For details on doing this, please refer to the SetNatNetVersion function demonstrated in the PacketClient.
Bit-Stream NatNet Versions
NatNet 4.0 (Motive 3.0)
NatNet 3.1 (Motive 2.1)
NatNet 3.0 (Motive 2.0)
NatNet 2.10 (Motive 1.10)
NatNet 2.9 (Motive 1.9)
Force plate description contains names and IDs of the plate and its channels as well as other hardware parameter settings. Please refer to the header file for specific details.
An instance of the sDeviceDescription contains information of the data acquisition (NI-DAQ) devices. It includes information on both the DAQ device (ID, name , serial number) as well as its corresponding channels (channel count, channel data type, channel names). Please refer to the header file for specific details.
The Sample folder, contains Visual Studio 2013 projects that use the NatNetSDK libraries for various applications. These samples are the quickest path towards getting NatNet data into your application. We strongly recommend taking a close look into these samples and adapt applicable codes into your application. More information on these samples are covered in the page.
In streamed NatNet data packets, orientation data is represented in the quaternion format (qx, qy, qz, qw). In contrast to Euler angles, Quaternion orientation convention is order independent, however, it indicates the handedness. When converting quaternion orientation into Euler angles, it is important to consider and decide which coordinate convention that you want to convert into. Some of the provided NatNet samples demonstrate quaternion to Euler conversion routines. Please refer to the included for specific implementation details and usage examples.
\include\NatNetTypes.h
NatNetTypes.h header file contains the type declaration for all of the data formats that are communicated via the NatNet protocol.
\include\NatNetClient.h
NetNetClient.h header file contains declaration of the NatNetClient class, which is the key object used in the SDK. This object must be initialized in order to run a client application for receiving the data packets.
\include\NatNetRequests.h
NatNetRequest.h header file contains a list of NatNet commands that can be sent over to a server application using the SendMessageAndWait function.
\include\NatNetRepeater.h
NatNetRepeater.h header file controls how big the packet sizes can be.
\include\NatNetCAPI.h
NatNetCAPI.h header file contains declaration for the NatNet API helper functions. These functions are featured for use with native client applications only.
\lib\x64
This folder contains NatNet SDK library files for 64-bit architecture.
\lib\x64\NatNetLib.dll
Native NatNet library for 64-bit platform architecture. These libraries are used for working with NatNet native clients.
\lib\x64\NatNetML.dll
Managed NatNet assembly files for 64-bit platform architecture. These libraries are used for working with NatNet managed clients, including applications that use .NET assemblies.
Note that this assembly is derived from the native library, and to use the NatNetML.dll, NatNetLib.dll must be linked as well.
\lib\x64\NatNetML.xml
Includes XML documentations for use with the NatNetML.dll assembly. Place this alongside the DLL file to view the assembly reference.
\lib\x86
No longer supported in 4.0
\lib\x86\NatNetLib.dll
No longer supported in 4.0.
\lib\x86\NatNetML.dll
No longer supported in 4.0.
\lib\x86\NatNetML.xml
No longer supported in 4.0.
This page provides function and class references of the NatNet SDK library.
The NatNetClient class (or NatNetClientML from the managed assembly) is the key object of the SDK. An instance of this client class allows an application to connect to a server application and query data. API helper functions are provided with the C++ library for a more convenient use of the SDK tools. For additional information, refer to the provided headers files (native) or reference the NatNatML.dll file (managed).
Note:
NatNet SDK is backwards compatible.
Deprecated methods from previous SDK versions are not documented on this page, and their use in new applications is discouraged. They are subject to removal in a future version of the SDK. Refer to the header files for complete descriptions.
The NatNetServer class has been deprecated for versions 3.0 and above.
Note that some parts of the managed .NET assembly may be slightly different from the native library reference provided here. Refer to the NatNetML.dll file using an object browser for detailed information.
Most of the NatNet SDK functions return their operation results in an integer type representation named ErrorType, which is just an enumerator that describes operation results as the following:
ErrorCode_OK
0
Operation successful
ErrorCode_Internal
1
Suspect internal errors. Contact support.
ErrorCode_External
2
External errors. Make sure correct parameters are used for input arguments when calling the methods.
ErrorCode_Network
3
The error occurred on the network side.
ErrorCode_Other
4
Unlisted error is conflicting the method call.
ErrorCode_InvalidArgument
5
Invalid input arguments have been inputted.
ErrorCode_InvalidOperation
6
Invalid operation.
The NatNetClient class is the main component of the NatNet SDK. Using an instance of the NatNetClient class, you can establish a network connection with a server application (e.g. Motive) and query data descriptions, tracking data, and send/receive remote commands. For detailed declarations, refer to the NatNetClient.h header file included in the SDK.
NatNetClient::NatNetClient()
Constructor: Creates a new instance of a NatNetClient class. Defaults to multicast connection if no input is given.
NatNetClient::NatNetClient(iConnectionType)
Constructor: Creates a new instance of a NatNet Client using the specified connection protocol; either unicast or multicast.
Input: iConnectionType: (0 = Multicast, 1 = Unicast).
This approach is being deprecated. The NatNetClient class now determines the connection type through sNatNetClientConnectParams input when calling the NatNetClient::Connect method.
NatNetClient::~NatNetClient()
Destructor: Destructor
Description
This method connects an instantiated NatNetClient object to a server application (e.g. Motive) at the inputted IP address.
Input Parameters:
Connection parameters object.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
sNatNetClientConenectParams:
Declared under the NatNetTypes.h file.
Local address. IP address of the localhost where the client application is running.
Server address. IP address where the server application is streaming to.
(Optional) Command port. Defaults to 1510.
(Optional) Data port. Defaults to 1511.
(Optional) Multicast IP address. Defaults to 239.255.42.99:1511.
Description
Calling this method disconnects the client from the Motive server application.
Input Parameters:
None
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
This method sets a frame handler function and creates a new thread for receiving and processing each frame of capture data.
Managed Assembly: Use OnFrameReady event type to add a function delegate.
Input Parameters:
pfnDataCallback: A NatNetFrameReceivedCallback function. NatNetFrameReceivedCallback is a type of a pointer to a frame handler function which processes each incoming frame of tracking data. Format of the inputted function must agree with the following type definition:
typedef void (NATNET_CALLCONV* NatNetFrameReceivedCallback)(sFrameOfMocapData* pFrameOfData, void* pUserData);
User definable data: the Client object.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Sends a NatNet command to the NatNet server and waits for a response. See NatNet: Remote Requests/Commands for more details.
Input Parameters:
szRequest: NatNet command.
tries: Number of attempts to send the command. Default: 10.
timeout: Number of milliseconds to wait for a response from the server before the call times out. Default: 20.
ppServerResponse: Application defined response.
pResponseSize: Number of bytes in response
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Requests a description of the current NatNet server that a client object is connected to and saves it into an instance of sServerDescription. This call is blocked until the request is responded or times out.
Input Parameters:
Declared sServerDescription object.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Requests a list of dataset descriptions of the capture session and saves onto the declared instance of sDataDescriptions.
Input Parameters:
Pointer to an sDataDescriptions pointer which receives the address of the client's internal sDataDescriptions object. This pointer is valid until the client is destroyed or until the next call to GetDataDescriptions.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
This method calculates and returns the time difference between a specific event in the processing pipeline and when the NatNet client application receives the tracking data. For example, if sFrameOfMocapData::CameraMideExposureTimestamp is inputted, it will return the latency from the camera exposure to when the tracking data is received. For more information on how it is used, read through the Latency Measurements page.
Input Parameters:
(uint64_t) A timestamp value from a sFrameOfMocapData struct.
Returns:
(double) The time, in seconds, past since the provided timestamp.
Once the NatNetSDK library has been imported into a client application, the following helper functions can be used.
These functions are available ONLY for C++ applications.
Description
This function gets the version (#.#.#.#) of the NatNet SDK and saves it into an array.
Input Parameters:
Unsigned char array with a array length of 4.
Returns:
Void
Description
This function assignes a callback handler function for receiving and reporting error/debug messages.
Input Parameters:
pfnLogCallback: NatNetLogCallback function. NatNetLogCallback is a type of a pointer to a callback function that is used to handle the log messages sent from the server application. Format of the linked function must agree with the following type definition:
typedef void (NATNET_CALLCONV* NatNetLogCallback)(Verbosity level, const char* message);
Returns:
Void
Description
Takes an ID of a data set (a marker, a Rigid Body, a Skeleton, or a force plate), and decodes its model ID and member ID into the provided integer variables. For example, ID of a Skeleton bone segment will be decoded into its model ID (Skeleton) and Rigid Body ID (bone). See NatNet: Data Types.
Input Parameters:
An ID value for a respective data set (sRigidBodyData, sSkeletonData, sMarker, or sFrocePLateData) from a sFrameOfMocapData packet.
Pointer to declared integer value for saving the entity ID and the member ID (e.g. Skeleton ID and its bone Rigid Body ID).
Returns:
Void
Description
Helper function to decode OptiTrack timecode data into individual components.
Input Parameters:
Timecode integer from a packet of sFrameOfMocapData. (timecode)
TimecodeSubframe integer from a packet of sFrameOfMocapData. (timecodeSubframe)
Pointers to declared integer variables for saving the hours (pOutHour), minutes (pOutMinute), seconds (pOutSecond), frames (pOutFrame), and subframes (pOutSubframe) values.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Helper function to parse OptiTrack timecode into a user friendly string in the form hh:mm:ss:ff:yy
Input Parameters:
timecode: Timecode integer from a packet of sFrameOfMocapData. (timecode)
timecodeSubframe: TimecodeSubframe integer from a packet of sFrameOfMocapData. (timecodeSubframe)
outBuffer: Declared char for saving the output.
outBufferSize: size of the character array buffer (outBuffer).
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
This helper function performs a deep copy of frame data from pSrc into pDst. Some members of pDst will be dynamically allocated; use NatNet_FreeFrame( pDst ) to clean them up.
Input Parameters:
Pointer to two sFrameOfMocapData variables to copy from (pSrc) and copy to (pDst).
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Frees the dynamically allocated members of a frame copy created using NatNet_CopyFrame function. Note that the object pointed to by pFrame itself is NOT de-allocated, but only its nested members which were dynamically allocated are freed.
Input Parameters:
sFrameOfMocapData that has been copied using the NatNet_CopyFrame function.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Do not call this on any pFrame data that was not the destination of a call to NatNet_CopyFrame.
Description
Deallocates data descriptions pDesc and all of its members; after this call, this object is no longer valid.
Input Parameters:
Data descriptions (sDataDescriptions).
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Sends broadcast messages to discover active NatNet servers and blocks for a specified time to gather responses.
Input Parameters:
outServers: An array of length equal to the input value of pInOutNumServers. This array will receive the details of all servers discovered by the broadcast.
pInOutNumServers: A pointer to an integer containing the length of the array. After this function returns, the integer is modified to contain the total number of servers that responded to the broadcast inquiry. If the modified number is larger than the original number passed to the function, there was insufficient space for those additional servers.
timeoutMillisec: Amount of time, in milliseconds, to wait for server responses to the broadcast before returning.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Begin sending periodic broadcast messages to discover active NatNet servers in the background.
Input Parameters:
pOutDiscovery: Out pointer that will receive a handle representing the asynchronous discovery process. The handle returned should be passed to NatNet_FreeAsyncServerDiscovery method later for clean up.
pfnCallback: A NatNetServerDiscoveryCallback function pointer that will be invoked once for every new server that's discovered by the asynchronous search. The callback will also be passed onto the provided pUserContext argument.
pUserContext: User-specified context data to be passed to the provided pfnCallback when invoked.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Description
Begin sending periodic broadcast messages to continuously search and discover active NatNet servers in the background.
Input Parameters:
pOutDiscovery: Out pointer that will receive a handle representing the asynchronous discovery process. The handle returned should be passed to NatNet_FreeAsyncServerDiscovery method later for clean up.
pfnCallback: A NatNetServerDiscoveryCallback function pointer that will be invoked once for every new server that's discovered by the asynchronous search. The callback will also be passed onto the provided pUserContext argument.
pUserContext: User-specified context data to be passed to the provided pfnCallback when invoked.
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
This page is created to guide help users migrating their NatNet projects onto NatNet 3.0 libraries.
NatNet 3.0 no longer allows static linking of the libraries. If a NatNet project was utilizing NatNetLibStatic.lib to accomplish static linking, you will need to make changes to the project configurations, so that it links dynamically instead.
This is only an example. Required configuration changes may be different depending on how the projects were setup.
Visual Studio Example
Project Settings → Configuration Properties → C/C++ → Preprocessor Definitions: Add "NATNATLIB_IMPORTS"
Project Settings → Configuration Properties → Linker → Input → Additional Dependencies: Change "NatNetLibStatic.lib" to "NatNetLib.lib"
Project Settings → Configuration Properties → Linker → General: Make sure the additional library directories includes the directory where the library files are locate.
In NatNet 3.0, the structure of Rigid Body descriptions and Rigid Body frame data has been slightly modified. The sRigidBodyData:Markers member has been removed, and instead, the Rigid Body description (sRigidBodyDescription) now includes the expected Rigid Body marker positions in respect to the corresponding RB orientation axis.
Per-frame positions of Rigid Body markers have to be derived using the Rigid Body tracking data and the expected Rigid Body markers positions included in the description packet.
This page lists out the NatNet sample applications provided with the SDK and provides instructions for some of the samples. The code samples are the quickest path towards getting NatNet data into your application. We typically recommend you:
1. Identify your application’s development/interface requirements (managed, native, etc).2. Adapt the NatNet sample code from the corresponding NatNet sample application in the samples folder into your application.3. Use the API reference in the next page for additional information.
The Visual Studio solution file \Samples\NatNetSamples.sln
will open and build all of the NatNet sample projects. If you are creating an application from scratch, please refer to the following sections for application specific requirements.
The following projects are located in the NatNet SDK\Samples
folder.
The following sample projects utilizes NatNet SDK library for obtaining tracking data from a connected server application.
Managed: Matlab
Native: C++
Sample NatNet console app that connects to a NatNet server, receives a data stream, and writes that data stream to an ASCII file. This sample
Native: C++
Sample NatNet application that connects to a NatNet server, receives a data stream, and displays that data in an OpenGL 3D window.
SampleClientML
Managed: .NET (C#)
Managed: C# .NET
Simple C# .NET sample showing how to use the NatNet managed assembly (NatNetML.dll). This sample also demonstrates how to send and receive the NatNet commands.
The following sample projects do not use the NatNet SDK library. Client/Server connection is established at a low-level by creating sockets and threads within the program, and the streamed data are depacketized directly from the bit-stream syntax. The following sample approaches should be used only when the use of NatNet SDK library is not applicable (e.g. streaming into UNIX clients).
PacketClient
C++
Simple example showing how to connect to a NatNet multicast stream and decode NatNet packets directly without using the NatNet SDK.
PythonClient
Python
Sample Python code file (.py) for using Python with NatNet streaming. This sample depacketizes data directly from the bit-stream without using the library.
The following samples demonstrate how to use remote triggering in Motive using the XML formatted UDP broadcast packets.
BroadcastSample
C++
XML broadcast. Sample application illustrating how to use remote record trigger in Motive using XML formatted UDP broadcast packets.
1. [Motive] Start the Optitrack Server (e.g. Motive) and begin streaming data via the Streaming Panel.
2. [SampleClient] Start the client application from the command prompt or directly from the NatNet SDK/Samples/bin
folder.
3. [SampleClient] Once the sample application starts up, it will search the local network and list out IP addresses of available tracking servers where tracking data is streamed from. Select a server address by pressing the corresponding number key.
4. [SampleClient] The client application is connected to the local loopback address (127.0.0.1) and receiving tracking data.
The Rigid Body sample (SampleClient3D) illustrates how to decode NatNet 6DOF Rigid Body and Skeleton Segment data from OptiTrack quaternion format to euler angles and display them in a simple OpenGL 3D viewer. This sample also illustrates how to associate RigidBody/Skeleton Segment names and IDs from the data descriptions with the IDs streamed in the FrameOfMocapData packet.
1. [Motive] Load a dataset with Rigid Body or Skeleton definitions
2. [Motive] Enable network streaming ( Data Streaming Pane -> Check Broadcast Frame Data )
3. [Motive] Enable streaming Rigid Body data (check Stream Options -> Stream Rigid Bodies = True)
4. [Sample3D] File -> Connect
1. [Motive] Load a dataset with Rigid Body or Skeleton definitions
2. [Motive] Set IP address to stream from (Network Interface Selection -> Local Interface)
3. [Motive] Enable network streaming ( Data Streaming Pane -> Check Broadcast Frame Data )
4. [Motive] Enable streaming Rigid Body data (check Stream Options -> Stream Rigid Bodies = True)
5. [Sample3D] Set Client and Server IP addresses
6. [Sample3D] File -> Connect
IP Address IP Address of client NIC card you wish to use.
Server IP Address IP Address of server entered in step 2 above.
1. [Motive] Start a NatNet server application (e.g. Motive).
2. [Motive] Enable NatNet streaming from the Server application.
3. [WinFormTestApp] Start the WinForms sample application from the NatNet Samples folder.
4. [WinFormTestApp] Update the “Local” and “Server” IP Addresses as necessary.
5. [WinFormTestApp] Press the “Connect” button to connect to the server.
6. [WinFormTestApp] Press the “Get Data Descriptions” button to request and display a detailed description of the Server’s currently streamed objects.
7. [WinFormTestApp] Select a Row in the DataGrid to display that value in the graph.
1. [Motive] Start a NatNet server application (e.g. Motive).
2. [Motive] Enable NatNet streaming from the Server application.
3. [Matlab] Start Matlab
4. [Matlab] Open the NatNetPollingSample.m file.
5. [Matlab] From the editor window, press Run
Rebroadcast Motive Data sample. This is a sample NatNet application that receives tracking data from a NatNet Server (Motive) and redistributes it in other formats.
Currently, there are two supported protocols in this sample; Unity and LightCraft. The Unity protocol repackages mocap data into XML packets and delivers it to the unity game engine. The LightCraft protocol takes definitions for a single Rigid Body and sends them over a serial port in a format called the Spydercam protocol. The LightCraft protocol in addition to being a demonstration of serial port communication, it allows Motive and Previzion to be completely compatible, using Mocap data to track the Previzion camera.
Unity Protocol
Rebroadcasts data into a XML format compatible for unity.
Previzion Protocol
Rebroadcasts data via Spyder Cam protocol which
The following third-party library must be linked in order to build and run this sample application
Asio library () : Required for communicating tracking data through serial port communication.
Download the asio C++ library.
In the RebroadcastMotiveData VS project, link the downloaded library.
Build the sample project.
You can run the app from the command line with appropriate input arguments. For example: RebroadcastMotiveData.exe 127.0.0.1 127.0.0.1 unity
There are total four arguments that can be inputed when running the sample application.
argument 1: IP address of the server, Motive, machine
argument 2: When streaming to unity, input the IP address of the local machine. When streaming to the lightcraft protocol, input local serial port name (e.g. COM1)
argument 3: Protocol type [unity/lightcraft]
argument 4 (optional): Input test, to run in the test mode.
The NatNet SDK features sending remote commands/requests from a client application over to a connected server application (i.e. Motive).
The SendMessageAndWait method under NatNetClient class is the core method for sending remote commands. This function takes in a string value of the command and sends it over to the connected Motive server each time it's called, and once the server receives the remote command, corresponding actions will be performed. Please note that only a selected set of commands can be understood by the server, which are listed under the chart below.
NatNet commands are sent via the UDP connection, 1510 port by default.
For a sample use of NatNet commands, refer to the provided .
Description
Sends a NatNet command to the NatNet server and waits for a response.
Input Parameters:
szRequest: NatNet command string, which is one of the commands listed on the below chart. If the command requires input parameters, corresponding parameters should be included in the command with comma delimiters. (e.g. string strCommand = "SetPlaybackTakeName," + TakeName;).
tries: Number of attempts to send the command. Default: 10.
timeout: Number of milliseconds to wait for a response from the server before the call times out. Default: 20.
ppServerResponse: Server response for the remote command. The response format depends on which command is sent out.
pResponseSize: Number of bytes in response
Returns:
ErrorCode, On success, it returns 0 or ErrorCode_OK.
Motive Supported NatNet Commands/Requests
Supported for Motive 3.0 or above.
Following is a general format used for the subscription command strings:
SubscribeToData,[DataType],[All or specific asset]
SubscribeByID,[DataType],[ID]
Start Recording
Framerate Query
Setting name of the recorded Take
Setting Motive Properties
Sample MATLAB code file (.m) for using MATLAB with the NatNet managed assembly (NatNetML.dll) using the provided class. Works in Matlab version 2014 or above.
Sample NatNet C# console appication that connects to a NatNet server on the local IP address, receives data stream, and outputs the received data. Note: must be set to false.
Subscription commands work with Unicast streaming protocol only. When needed, unicast clients can send subscription commands to receive only specific data types through the data stream. This allows users to minimize the size of streaming packets. For more information, read through the page.
Below is a sample use of the NatNet commands from the application.
UnitsToMillimeters
Sending this command requests current system’s measurement units, in terms of millimeters.
Sample command string:
none
float
FrameRate
Queries for the tracking framerate of the system. Returns a float value representing the system framerate.
Sample command string:
none
float
CurrentMode
Requests current mode that Motive is in. Returns 0 if Motive is in Live mode. Returns 1 if Motive is in Edit mode.
Sample command string:
none
int
StartRecording
This command initiates recording in Motive
Sample command string:
none
none
StopRecording
This command stops recording in Motive
Sample command string:
none
none
LiveMode
This command switches Motive to Live mode
Sample command string:
none
none
EditMode
This command switches Motive to Edit mode.
Sample command string:
none
None
TimelinePlay
Starts playback of a Take that is loaded in Motive
Sample command string:
none
none
TimelineStop
Stops playback of the loaded Take
Sample command string:
none
none
SetPlaybackTakeName
Set playback take
Sample command string:
Take name
None
SetRecordTakeName
Set a take name to record.
Sample command string:
Take name
None
SetCurrentSession
Set current session. If the session name already exists, Motive switches to that session. If the session does not exist, Motive will create a new session. You can use absolute paths to define folder locations.
Sample command string:
Session name
None
CurrentSessionPath
Gets the unix-style path to the current session folder as a string value, including trailing delimiter.
Sample command string:
none
string
SetPlaybackStartFrame
Set start frame
Sample command string:
Frame number
None
SetPlaybackStopFrame
Sets stop frame.
Sample command string:
Frame number
None
SetPlaybackCurrentFrame
Set current frame
Sample command string:
Frame number
none
SetPlaybackLooping
Enable or disable looping in the playback. To disable, zero must be sent along with the command.
Sample command string:
none
none
EnableAsset
Enables tracking of corresponding asset (rigid body / skeleton) from Motive
Sample command string:
Asset name
None
DisableAsset
Disables tracking of a corresponding asset (rigid body / skeleton) from Motive.
Sample command string:
Asset name
None
GetProperty
Queries the server for configured value of a property in Motive. The property name must exactly match the displayed name. This request string must have the following inputs along with the command, each of them separated by a comma.
Node name
Property name
Sample command string:
For rigid body assets, Streaming ID of rigid bodies can be used in place of the stringNodeName. For example, string command for getting name of a rigid body with streaming ID of 3 would be:
eSync:2:
Accessing the eSync 2 requires '#' to be included at the beginning of the eSync 2's serial number. If the '#' is not present, it will make the eSync 2 inaccessible. ie. GetProperty, eSync 2 #ES002005, Source Value
Node name (if applicable)
Property name
int
SetProperty
Requests Motive to configure specified properties. The property name must exactly match the respective name of setting displayed in Motive. Please refer to the Properties pane page for the list of properties. Master Rate can be used for controlling the frame rate of the camera system. For configuring camera settings remotely, use the "model #[serial]" string format.
Sample command string:
For rigid body assets, Streaming ID of rigid bodies can be used in place of the stringNodeName. For example, string command for enabling rigid body with streaming ID of 3 would be:
eSync:2:
Accessing the eSync 2 requires '#' to be included at the beginning of the eSync 2's serial number. If the '#' is not present, it will make the eSync 2 inaccessible. ie. GetProperty, eSync 2 #ES002005, Source Value
Node name. (Leave it empty if not applicable.)
Property name
Desired value
int
GetTakeProperty
Request property of a Take. You can query property of a specific Take by entering the name, or enter empty string to query the currently loaded take. Most of the properties available in the Properties: Take can be queried through this command.
Sample command string:
Take Name. Leave empty for currently loaded take.
Name of the property. See Properties: Take.
Depends on the property type.
CurrentTakeLength
Request length of current take.
Sample command string:
None
int
RecalibrateAsset
Recalibrates the asset. Returns integer indicating if command was successful. Zero if successful. Sample command string:
Asset Name
int
ResetAssetOrientation
Reorients the asset. Returns integer indicating if command was successful. Zero if successful. Sample command string:
Asset Name
int
The following guide references SampleClientML.cs client application that is provided with the SDK. This sample demonstrates the use of .NET NatNet assembly for connecting to a NatNet server, receiving a data stream, and parsing and printing out the received data.
SDK/API Support Disclaimer
We provide developer tools to enable OptiTrack customers across a broad set of applications to utilize their systems in the ways that best suit them. Our Motive API through the NatNet SDK and Camera SDK is designed to enable experienced software developers to integrate data transfer and/or system operation with their preferred systems and pipelines. Sample projects are provided alongside each tool, and we strongly recommend the users to reference or use the samples as reliable starting points. The following list specifies the range of support that will be provided for the SDK tools:
Using the SDK tools requires background knowledge on software development; therefore, we do not provide support for basic project setup, compiling, and linking when using the SDK/API to create your own applications.
Although we ensure the SDK tools and their libraries work as intended, we do not provide support for custom developed applications that have been programmed or modified by users using the SDK tools.
Ticketed support will be provided for licensed Motive users using the Motive API and/or the NatNet SDK tools from the included libraries and sample source codes only.
The Camera SDK is a free product, and therefore we do not provide free ticketed support for it.
For other questions, please check out the NaturalPoint forums. Very often, similar development issues get reported and solved there.
When developing a managed client applications, you will need to link both native and managed DLL files(NatNetLib.dll and NatNetML.dll). The managed NatNet assembly is derived from the native library, so without the NatNetLib.dll, NatNetML.dll will not be imported properly. These library files can be found in the NatNetSDK\lib
folder for 32-bit platform and in the NatNetSDK\lib\x64
folder for 64-bit platform. Make sure these DLL files are properly linked and placed alongside the executables.
Also, when using the NatNetML assembly, place the NatNetML.xml file alongside imported DLL file. This allows XML documentation to be included as a reference. These library files can be found in the NatNetSDK\lib
folder for 32-bit platform and in the NatNetSDK\lib\x64
folder for 64-bit platform. Make sure these DLL files are properly linked and placed alongside the executables.
Tracking server and client network is established through an instance of NatNet client object (NatNetML.NatNetClientML). Also, this NatNetClientML object will be used for receiving tracking data and sending NatNet commands to and from the server application. When instantiating the NatNetClientML object, input an integer value for determining the desired type of UDP connection; whether it connects via multicast (0) or unicast (1).
To connect to the server, use the Initialize method from the instantiated NatNetClientML object. When calling this method, input the proper Local IP address and the Server IP address. The local IP address must match the IP address of the host PC, and the server IP address must match the address that the server is streaming onto, which is defined in the Data Streaming panel in Motive.
Server Discovery
You can also use the NatNetServerDiscover class to auto-detect available servers to connect to. This is demonstrated in the WinFromSamplesApp**.**
To confirm whether the client has successfully connected to the server application, let's try querying for a ServerDescriptor packet using the GetServerDescription method. If the server is connected, the corresponding server descriptions will be obtained. This method returns an ErrorCode value, and when successfully operated it will return a value of 0.
As explained in the NatNet: Data Types page, there are two kinds of data formats included in streamed NatNet packets; one of which is Data Descriptions. In managed NatNet assembly, data descriptions for each of the assets (Marker Sets, Rigid Bodies, Skeletons, and force plates) included in the capture session is stored in a DataDescriptor class. A single capture take (or live streaming) may contain more than one assets, and respectively, there may be more than one data descriptions. For this reason, data descriptions are stored in a list format.
GetDataDescriptions method in the NatNetClientML class queries a list of DataDescriptors from the connected server and saves it in a declared list of NatNetML.DataDescriptions. In the SampleClientML sample, the following lines are executed to accomplish this:
After obtaining a list of data descriptions, use the saved DataDescriptor objects to access and output data descriptions as needed. In many cases, it is better to re-organize and save the received descriptor objects into separate lists, or into hashtables, of corresponding data types, so that they can be referenced later in the program.
Now, let's obtain the tracking data from the connected server. Tracking data for a captured frame is stored in an instance of NatNetML.FrameOfMocapData. As explained in the Data Types page, every FrameOfMocapData contains tracking data of the corresponding frame. There are two approaches for obtaining frame data using the client object; by calling the GetLastFrameOfData method or by linking a callback handler function using the OnFrameReady method. In general, creating a callback function is recommended because this approach ensures that every frame of tracking data gets received.
The best way to receive tracking data without losing any of its frames is to create a callback handler function for processing the data. The OnFrameReady event type from the client object can be used to declare a callback event, and the linked function gets called each time a frame is received from the server. Setting up a frame handler function will ensure that every frame gets processed promptly. However, these handler functions should return as quickly as possible to prevent accumulation of frames due to processing latency within the handler.
OnFrameReady2: Alternate function signatured frame ready callback handler for .NET applications/hosts that don't support the OnFrameReady event type defined above (e.g. MATLAB)
Calling the GetLastFrameOfData method returns a FrameOfMocapData of the most recent frame that was streamed out from the connected server application. This approach is should only be used for .NET applications/hosts that do not support the OnFrameReady callback handler function.
This function is supported in NatNetML only. Native implementations should always use the callback handlers.
When exiting the program, call Uninitialize method using the connected client object and disconnect the client application from the server.
This page provides detailed information on the definition of latency measurements in Motive and the NatNet SDK streaming protocol.
The OptiTrack systems combine state of art technologies to provide swift processing of captured frame data in order to accomplish 3D tracking in real-time. However, minimal processing latencies are inevitably introduced throughout processing pipelines. For timing-sensitive applications, these latency metrics can be monitored from the Status Panel of Motive or in the NatNet SDK 4.0 streaming protocol.
The latency in an OptiTrack system can be broken down in the the components described in the image below.
With Motive 3.0+ PrimeX cameras now can go at up to 1000 Hz. In order to do this the image size processes reduces as the frequency goes over the native frame rate for a particular camera. Because less camera data is being process at higher rates, the latency also decreases. The image below shows how the latency changed from the previous image by going from 240 Hz to 500 Hz with PrimeX 13 cameras.
Example frame rates vs the latency added by the camera for a PrimeX 41 camera....
20 Hz - 180 Hz
5.56 ms
240 Hz
4.17 ms
360 Hz
2.78 ms
500 Hz
2.00 ms
1000 Hz
1.00 ms
A
This point represents the center of the camera exposure window
B
This is when Motive receives the 2D data from the cameras
C
This is when tracking data is fully solved in Motive.
D
This is when the tracking data is all processed and ready to be streamed out.
E
This is when the Client application receives the streamed tracking data.
This measurement is reported in the Status Panel in Motive.
(Available for Ethernet camera systems only) This value represents current system latency. This is reported under the Status Panel, and it represents the total time taken from when the cameras expose and when the data is fully solved.
This measurement is reported in the Status Panel in Motive.
It represents the amount of time it takes Motive to process each frame of captured data. This includes the time taken for reconstructing the 2D data into 3D data, labeling and modeling the trackable assets, displaying in the viewport, and other processes configured in Motive.
Please note that this does not include the time it takes for Motive to convert the solved data into the NatNet streaming protocol format. This conversion accounts for a slight additional latency (≈ 0.2 ms) which is only reflected in the software latency value reported via NatNet SDK 4.0, therefore resulting in a small delta between the software latency values as reported by Motive and NatNet.
Latencies from the point cloud reconstruction engine, Rigid Body solver, and Skeleton solver are reported individually on the Status Panel in Motive.
This is available only in NatNet version 3.0 or above.
Exemplary latency calculations are demonstrated in the SampleClient project and the WinFormSample project. Please refer to these sources to find more about how these latency values are derived.
In NatNet 3.0, new data types have been introduced to allow users to monitor measured timestamps from specific points in the pipeline. From sFrameOfMocapData received in the NatNet client applications, the following timestamps can be obtained:
Timestamp of Point A: sFrameOfMocapData::CameraMidExposureTimestamp. Available for Ethernet cameras only (Prime / Slim13E).
Timestamp of Point B: sFrameOfMocapData::CameraDataReceivedTimestamp.
Timestamp of Point D: sFrameOfMocapData::TransmitTimestamp.
Refer to the NatNet:_Data_Types page or the NatNetTypes.h file for more information
These timestamps are reported in “ticks” that are provided by the host computer clock. When computing latencies, you need to divide the timestamp values by the clock frequency in order to obtain the time values in seconds. The clock frequency is included in the server description packet: sServerDescriptionPacket::HighResClockFrequency. To calculate the time that has elapsed since a specific timestamp, you can simply call the NatNetClient::SecondsSinceHostTimestamp method, passing the desired timestamp as its input. Using clock synchronization between the client and server, this will return the time in seconds since the corresponding timestamp.
System Latency (NatNet)
(Available for Ethernet camera systems only)
This is the latency introduced by both hardware and software component of the system. This represents the time difference between when the cameras expose and when the capture data is all processed and prepared to be streamed out.
This value needs to be derived from the NatNet SDK 4.0 streaming protocol by subtracting two timestamp values that are reported in NatNet:
System Latency may not always be available for all system configurations. Thus, it is suggested to enclose this calculation within a conditional statement.
Software Latency (NatNet)
This value needs be derived from the NatNet streaming protocol.
This latency value represents the time it takes Motive to process the captured data and have it fully ready to be streamed out. This measurement also covers the data packaging time.
This can be derived by subtracting two timestamp values that are reported in NatNet:
In the older versions of NatNet, the software latency was roughly estimated and reported as fLatency data, which is now deprecated. The derived software latency described in this can be used to replace the fLatency values.
Transmission Latency
This value must be derived from the NatNet SDK 4.0 streaming protocol.
The transmission latency represents the time difference between when Motive streams out the packaged tracking data and when the data reaches the client application(s) through a selected network.
This value can be obtained by calling the SecondsSinceHostTimestampmethod using sFrameOfMocapData::TransmitTimestamp as the input.
Client Latency
This value must be derived from the NatNet SDK 4.0 streaming protocol.
The client latency is the time difference between when the cameras expose and when the NatNet client applications receive the processed data. This is basically the total time it takes for a client application(s) to receive the tracking data from a mocap system.
This value can be obtained by calling the SecondsSinceHostTimestamp method using sFrameOfMocapData::CameraMidExposureTimestamp as the input.
In previous versions of Motive (prior to 2.0), the only reported latency metric was the software latency. This was an estimation of the software latency derived from the sum of the processing times taken from each of the individual solvers in Motive. The latency calculation in Motive 2.0 is a more accurate representation and will be slightly larger by comparison than the latency reported in the older versions.
This page provides instructions on how to use the subscribe commands in natNet. This feature is supported for Unicast streaming clients only.
Starting from Motive 3.0, the size of the data packets that are streamed over Unicast can be configured from each NatNet client. More specifically, each client can now send commands to the Motive server and subscribe to only the data types that they need to receive. For situations where we must stream to multiple wireless clients through Unicast, this will greatly reduce the size of individual frame data packets, and help to ensure that each client continuously receives frame data packets streamed out from Motive.
Notes
Supported for Unicast only.
Supported for Motive versions 3.0 or above.
This configuration is not necessary when streaming over a wired network since streaming packets are less likely to be dropped.
To make sure the packet size is minimized, it is recommended to clear out the filter at the beginning.
In order to set which type of tracking data gets included in the streamed packets, a filter must be set by sending subscription commands to Motive. This filter will allow client applications to receive only the desired data over a wireless Unicast network. To setup the filter, each NatNet client application(s) needs to call the method and send one of the following subscribe subscription command to the Motive server:
“SubscribeToData, [Data Type], [Name of the Asset]”
“SubscribeByID, RigidBody, [StreamingID]”
“SubscribedDataOnly”
Examples:
Type
In the Type field, you will be specifying which data type to subscribe to. The following values are accepted:
RigidBody
Skeleton
ForcePlate
Device
LabeledMarkers
MarkersetMarkers
LegacyUnlabeledMarkers
AllTypes
Name
Once the type field is specified, you can also subscribe to a specific asset by inputting the name of the rigid body. You can also input "All" or leave the name field empty to subscribe to all of the assets in that data type.
Examples
If you wish to subscribe to a Rigid Bodynamed Bat, you will be sending the following string command:
You can also subscribe to specific Skeleton also. The following command subscribes to Player Skeleton only:
To subscribe to all rigid bodies in the data stream:
Please note that Motive will not validate the presence of the requested asset, please make sure they are present on the server side.
Examples
For subscribing to a Rigid Bodywith streaming ID 3: <source>string command = "SubscribeByID,RigidBody,3";</source>
Subscription filters are additive. When needed, you can send multiple subscription commands to set multiple filters. If a subscription filter contradicts one another, the order of precedence listed (high-to-low) below is followed:
Filter Precedence Order:
Specified asset, either by name or the streaming ID.
Specified data type, all
Specified data type, none
All types, all
All types, none
Unspecified – respects Motive settings.
To clear the subscription filter, a client application can send an empty subscribe command OR disconnect and reconnect entirely. It’s suggested to clear the filter at the beginning to make sure the client application(s) is subscribing only to the data that’s necessary.
If you subscribe to a Rigid Bodywith a specific name or specific streaming ID, commands for unsubscribing to all will not unsubscribe to that specific object. To stop receiving data for a particular object, whether it's a Rigid Bodyor a Skeleton, the client will need to send an unsubscribe command for that specific object also.
The SubscribeToData command allows you set up the filter so that NatNet client receives only the data types that it has subscribed to. Using this command, each client can subscribe to specific data types included in NatNet data packets. To set up the filter, the following string command must be sent to the Motive server using method:
Another option for subscribing to a specific data is by providing the asset ID. This works only with rigid bodies that has values. This command may be easier to use when streaming to multiple clients with many rigid bodies.
For quickly testing the NatNet commands, you can utilize the program provided in the NatNet SDK package. This program has commands tab which can be used for calling the SendMessageAndWait method. Using this input field, you can test the command string to test out its results.