Page 1 of 1

Natnet SDK 2.7 PacketClient.cpp issues

Posted: Thu May 28, 2015 3:45 pm
by luis.gonzalez
Hello to everyone, I'm new to the forum.

My university recently acquired two OptiTrack systems, with the Motive:Body license, and I'm in charge of starting them up, as well as developing the code needed to get the data available on the client machines (mostly Linux).
Therefore, I'm implementing the NatNet API in Qt, in order to make it available across platforms (Linux and Windows users). The project is open source, I encourage it's use and feedback, and the client can be found here:
https://bitbucket.org/lcgonzalez/natnet_client_qt

While this project is on an early stage, I've found some issues, that I think are bugs, in the PacketClient.cpp file, of the NatNet SDK version 2.7, which I'm using as the NatNet communication protocol source.
The NatNet server app that I'm using is Motive:Body version 1.73.0.0.
I would like to flag these issues in order to help the community.
  1. The first one has to do with obtaining the sending app's NatNet version number, while the PacketClient.cpp does the job with a structure, there are problems regarding the structure's bytes padding that compilers add at their discretion.
    One possible fix, that I propose, is this:

    Code: Select all

    // PacketClient.cpp
    DWORD WINAPI CommandListenThread(void* dummy)
    {
    ...
            // handle command
            switch (PacketIn.iMessage)
            {
            case NAT_MODELDEF:
                Unpack((char*)&PacketIn);
                break;
            case NAT_FRAMEOFDATA:
                Unpack((char*)&PacketIn);
                break;
            case NAT_PINGRESPONSE:
    //          // This can be used in conjunction with precompiler directive:
    //          // #pragma pack(push, 1)
    //          for(int i=0; i<4; i++)
    //          {
    //              NatNetVersion[i] = (int)PacketIn.Data.Sender.NatNetVersion[i];
    //              ServerVersion[i] = (int)PacketIn.Data.Sender.Version[i];
    //          }
    
                // This is the alternative: Directly access the sPacket structure fields
                // The pointer needs to traverse the datagram manually.
                char *ptr = (char*)&PacketIn;
                // message ID
                ptr += 2;
                // payload size
                ptr += 2;
                // sending app's name
                ptr += MAX_NAMELENGTH;
                // sending app's version [major.minor.build.revision]
                // sending app's NatNet version [major.minor.build.revision]
                for(int i=0; i<4; i++){
                    ServerVersion[i] = (int)*ptr;
                    NatNetVersion[i] = (int)*(ptr+4); ptr++;
                }
                break;
    ....
    
    For more information regarding this fix, and the Open Source project, follow this link:
    https://bitbucket.org/lcgonzalez/natnet ... 2effbaa85e
  2. The other issue is more tricky, because it is only displayed when a skeleton is being streamed. The unpack() function of PacketClient.cpp seems to loose synchrony with the datagram, when decoding the skeleton's rigid bodies info (position, orientation, etc.).
    The source problem seems to be the same, a structure padding that is happening in the NatNet server app (Motive version 1.73.0.0), because there is an extra 2 bytes padding between each rigid body info.
    One possible fix, that I propose, is this:

    Code: Select all

    // PacketClient.cpp
    void Unpack(char* pData) {
    ...
        // skeletons (version 2.1 and later)
            if( ((major == 2)&&(minor>0)) || (major>2)) {
                ...
                       // Mean marker error
                       float fError = 0.0f; memcpy(&fError, ptr, 4); ptr += 4;
                       printf("Mean marker error: %3.2f\n", fError);
    
                       // release resources
                       if(markerIDs)
                           free(markerIDs);
                       if(markerSizes)
                           free(markerSizes);
                       if(markerData)
                           free(markerData);
    
                       // Issue #5 Fix : Motive:body is appending 2 bytes of zero data
                       // to the end of each rigid body (belonging to a skeleton) data.
                       // The problem may be caused by structure padding on the
                       // Motive:body software.
                       // NOTE: Please contact NaturalPoint, Inc to solve the issue at the source.
                       ptr += 2;   // Issue #5 Fix.
    
                     } // next rigid body
    
                 } // next skeleton
    
            }
            
    	// labeled markers (version 2.3 and later)
    	if( ((major == 2)&&(minor>=3)) || (major>2))
    	{
    ....
    
    For more information regarding this fix, and the Open Source project, follow this link:
    https://bitbucket.org/lcgonzalez/natnet ... fea501ac98
By the way, it would be very useful if you could help me with the NatNet protocol documentation, besides that of the PacketClient.cpp, because I've sought throughout the forum and website, and I haven't found any documentation. I would really appreciate it.

Greetings,
-Luis

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Tue Jun 02, 2015 11:29 am
by NaturalPoint-Dustin
Hi Luis,

Thank you for reporting this. I will forward your post to our dev team to have a look.

Best Regards,

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Tue Jun 02, 2015 2:53 pm
by morgan
Thanks for the great post - it looks like the new tracking flags for the skeleton bone's rigid body were getting overlooked in the skeleton depacketization causing the alignment issue you found. We've checked in a fix for this in the PacketClient, which will be available in the next release.

The code should look like this:

Code: Select all


 ...
 ...
    // Mean marker error (2.0 and later)
    if(major >= 2)
    {
        float fError = 0.0f; memcpy(&fError, ptr, 4); ptr += 4;
        printf("Mean marker error: %3.2f\n", fError);
    }

    // Tracking flags (2.6 and later)
    if( ((major == 2)&&(minor >= 6)) || (major > 2) || (major == 0) ) 
    {
          // params
          short params = 0; memcpy(&params, ptr, 2); ptr += 2;
          bool bTrackingValid = params & 0x01; // 0x01 : rigid body was successfully tracked in this frame
     }

     // release resources
     if(markerIDs)
         free(markerIDs);

     ...
     ...


Regarding docs for the bitstream syntax, we don't have any specific doc describing the syntax specifically, as the working code typically will be more up to date. The direct depacketization however follows the FrameOfMocap structure in the NatNet SDK, so the description for those fields will apply.

Hope this helps,

Morgan

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Fri Jun 12, 2015 5:07 pm
by fgraffagnino
I've integrated these fixes, but I still get crashes in packetclient, both in the one distributed and in one that I've modified to work in linux.

Can someone confirm that the packetclient.cpp runs with simpleserver out of the box on windows? Or, that it runs with the fix suggested by naturalpoint? I get a crash and it appears to always be on the second RigidBody that it is processing, and it always seems to print ID "13172736". The numbers are all garbage and I eventually get a seg fault. Obviously there is still a misalignment somewhere.

Here's my output:

Multicast Group: 239.255.42.99
Packet Client started

Commands:
s send data descriptions
f send frame of data
t send test request
q quit

Begin Packet
-------
Message ID : 7
Byte count : 3476
Frame # : 496045
Marker Set Count : 1
Model Name: Katie
Marker Count : 10
Marker 0 : [x=0.64,y=0.77,z=0.84]
Marker 1 : [x=10.66,y=20.75,z=30.87]
Marker 2 : [x=20.67,y=40.74,z=60.90]
Marker 3 : [x=30.68,y=60.73,z=90.93]
Marker 4 : [x=40.69,y=80.72,z=120.97]
Marker 5 : [x=50.71,y=100.71,z=151.00]
Marker 6 : [x=60.72,y=120.69,z=181.04]
Marker 7 : [x=70.73,y=140.68,z=211.07]
Marker 8 : [x=80.74,y=160.67,z=241.11]
Marker 9 : [x=90.75,y=180.66,z=271.15]
Unidentified Marker Count : 0
Rigid Body Count : 20
ID : 0
pos: [0.77,0.64,1.19]
ori: [0.13,0.44,0.40,0.79]
Marker Count: 3
Marker 0: pos = [0.10,0.20,0.30]
Marker 1: pos = [1.10,1.20,1.30]
Marker 2: pos = [2.10,2.20,2.30]
ID : 13172736
pos: [0.00,0.00,0.00]
ori: [0.00,0.00,0.00,0.00]
Marker Count: 1061614346
<seg fault>

FG

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Tue Jun 16, 2015 2:39 pm
by morgan
The output looks like the stream is coming form the simpleserver app, which has been deprecated. We now provide trial versions of Motive and sample TAK files, which represent a much more accurate test.

Can you confirm the packetclient is crashing against Motive or TrackingTools, and if so which version you are using?

We can then test against that version here and try to reproduce.

thx

Morgan

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Thu Jun 18, 2015 12:27 pm
by fgraffagnino
Ahh. I didn't know simpleserver had been deprecated.

I can definitely try out Motive. I don't see a trial version anywhere, do I just download a version off the downloads page and run it without a license? (I'm not near a windows machine to try it out right now) Also, can I run that without any hardware hooked up?

Thanks!

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Thu Jun 18, 2015 3:59 pm
by luis.gonzalez
I confirm that the packetclient.exe (out of the box) of the NatNet SKD version 2.7 is crashing against Motive version 1.73.
packetclient.exe (out of the box) of the NatNet SKD version 2.7 is crashing against Motive version 1.73.
packetclient.exe (out of the box) of the NatNet SKD version 2.7 is crashing against Motive version 1.73.
natnet_1.png (239.33 KiB) Viewed 23349 times
The problem is not Motive, but the way packetclient.cpp is implemented.
Probably, the misalignment problem is due to packetclient not recognizing the appropriate NatNet version number, and this is because packetclient.cpp uses a structure to access the elements of the income packet in order to get the NatNet and Server versions.
The problem with structures accessing arrays in this way, is that, if the elements of the structure are of different types, odds are that the compiler will add padding bytes to the structure, in order to make it multiple of the host computer architecture.
This practice of structure padding is applied at the compiler's discretion, and can be overridden by the #pragma pack(push,1) pre-compiler directive, but it's still not portable.

This structure padding problem can be easily solved by accessing the elements inside the packet "by hand", which means that you have to traverse the packet, using a pointer, until you reach the place where the NatNet and Server versions are stored, then, one number at a time, retrieve those versions.
I have mentioned this problem, and the fix, in my first post on this thread, please read it. Anyway, here is the packetclient.cpp code again:

Code: Select all

//file: packetclient.cpp
...
// command response listener thread
DWORD WINAPI CommandListenThread(void* dummy)
{
    ...
    while (1)
    {
        ...
        // handle command
        switch (PacketIn.iMessage)
        {
        ...
        case NAT_PINGRESPONSE:
            for(int i=0; i<4; i++)
            {
                // This is the alternative to directly accessing the sPacket structure fields.
                // The pointer needs to traverse the datagram manually.
                char *ptr = (char*)&PacketIn;
                // message ID
                ptr += 2;
                // payload size
                ptr += 2;
                // sending app's name
                serverName_ = std::string(ptr);
                ptr += MAX_NAMELENGTH;

                // sending app's version [major.minor.build.revision]
                for(int i=0; i<4; i++){
                    ServerVersion[i] = (int)*ptr; ptr++;
                     NatNetVersion[i] = (int)*(ptr+4); ptr++;
                }
            break;
            ...
I'm developing a Qt cross platform library for NatNet, and I've experienced these problems on packetclient.cpp. You can have a look at how I solved this NatNet version problem here:
https://bitbucket.org/lcgonzalez/natnet ... 2effbaa85e

When packetclient misreads the NatNet version, the pieces of code like this:

Code: Select all

//file: packetclient.cpp
...
void Unpack(char* pData)
{
...
        // rigid bodies
        int nRigidBodies = 0;
        memcpy(&nRigidBodies, ptr, 4); ptr += 4;
        printf("Rigid Body Count : %d\n", nRigidBodies);
        for (int j=0; j < nRigidBodies; j++)
        {
        ...
            if(major >= 2)
            {
            // Some code used in version 2 of NatNet
            ...
Are not executed, because major is 0 (or any other random number), thus, packetclient thinks that this is a packet that uses a NatNet version lower than 2, but in reality it is a packet of NatNet version 2, thus, because there are differences on the packet's layout of these two versions, the misalignment problem becomes arises.

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Thu Jun 18, 2015 7:23 pm
by fgraffagnino
ok, i've downloaded Motive but after installation it just stops asking for a license. Maybe I've missed where the trial version is on the website. Can you point me to how I can install a trial version and run it without any hardware attached?

Thanks.

Re: Natnet SDK 2.7 PacketClient.cpp issues

Posted: Fri Jun 19, 2015 1:47 pm
by steven.andrews
Hi fgraffagnino,

I've confirmed that to acquire a trial license you can reach out to our sales representatives to let them know you are trying to develop off of the NatNet SDK.

If we were in a support ticket I could rout you to them, but this public forum does not afford me the same capabilities. Please feel free to reach out to sales@optitrack.com

If you need further assistance, or if you have any issues reaching our sales reps, please feel free to reach out to us by opening a support ticket at help.naturalpoint.com

Cheers,
Steven