Skip to content
Zoltan Derzsi edited this page Feb 13, 2019 · 26 revisions

The rigid body problem

Sometimes, tracing marker positions themselves is not enough. For instance, if a single marker is attached to a rod, the system will only determine the location of a singe point, and the rod can be any position going through the marker's coordinate. One solution to that is to use two markers attached to both ends of the rod, and the position of the rod can be calculated from the two coordinates. A plane would need at least three markers, and a simple object like a tetrahedron would need four markers.

However, the problem gets more and more complicated with adding more markers, as some of them might not be visible at all times. Also, in most cases the user is interested in the whereabouts of a solid object the user attached the markers too, as opposed to the marker coordinates themselves. Provided that the distances between the markers are constant, it is possible to assign a set of markers to a rigid body definition.

Why rigid bodies can be useful?

The system can be set to convert a specified set of markers to a single rigid body, so it can track the position and orientation of the rigid body itself, which can be used for further processing. This can make processing data easier, as you won't have to do this manually. Of course, the position data is always available, so you can do the conversion yourself using optotrak_calculate_centroid_and_orientation(), if you want to.

How to use rigid bodies?

Once you have a rigid body bought form NDI or assembled one yourself from the provided examples, connect all the markers to the strober. You can load the rigid body to the system by calling RigidBodyAddFromFile_euler(). Start the rigid body indexing from 0, and make sure that the first marker of it is properly set. Once this is done, you should be able to get the location coordinates and the orientation angles when calling DataGetLatestTransforms2_as_array().
You can use this function to get the marker coordinate data as well.


NOTE: When you fetch the rigid body's coordinates, the 'translation' is the location of the origin of the rigid body's own local coordinate system. It may or may not be the actual centroid, depending on the rigid body definition!


What do I need to create rigid bodies?

If you don't want to or can't use NDI's software, you can define a rigid body programmatically with the toolbox. A rigid body will need:

  • Marker positions, which tell the system where are the markers
  • Optionally, the normal vectors, which tell the system which way the markers point to
  • Tolerance, which specifies how precise the rigid body transform should be

If you have the required information, you can go and create a rigid body with optotrak_generate_rigid_body_file()

However, before diving into the subject, here are a few things to consider first:

  • Do you want to use your rigid body for registration and coordinate system alignment?

If you want to calibrate your system you can define a rigid body, and you can set the rigid body's coordinate system as the global coordinate system. This can be useful for example when the experimental table has some pre-installed markers. You can manually enter the coordinates of these markers, however, make 100% sure you are using the metric system, in millimetres to specify marker positions. Creating the normal vector array is are easy, because the markers usually are perpendicular to a plane.

  • Do you just want to define a rigid body only for tracking?

Perhaps the simplest way is to specify the marker coordinates from an existing recording of a stationary rigid body. This might not be a trivial task, depending on your design.

Stay with NDI's 6D architect software for the vast majority of cases. Use optotrak_generate_rigid_body_file() to create simple things.

How to create a rigid body: example

Please use NDI's 6D Architect to create your rigid body files for production-quality use. The function described here is to be used for specific applications, and most certainly not for virtual markers.

Let's assume you are working in a lab and you want to calibrate your system. You have a set of markers on the experimental rig, and you know their locations: For example, it's a square table with 4 markers on it: 3 markers are on the table's plane, and the fourth marker is in the very centre of the table, but elevated. Let's say that the markers are 1 m apart in the corners, and the fourth marker is 50 cm above in the middle.

Ideally, the coordinates of the marker will be, in X-Y-Z triplets: Marker 1: [0, 0, 0], Marker 2: [1000, 0, 0], Marker 3: [0, 1000, 0], and finally, Marker 4: [500, 500, 500] Realistically, these numbers will never be as round as described here, and you should use your own recording to determine this. You will also need to translate and rotate these coordinates so they would match your set-up.

Now, you need to define which direction the markers point to. The three markers on the table are pointing upwards (Z-axis, positive), and the fourth marker above the table point towards the camera (Y axis, negative).

The normal vectors the are also defined in X-Y-Z triplets: Normal 1: [0, 0, 1], Normal 2: [0, 0, 1], Normal 3: [0, 0, 1] and Normal 4: [0, -1, 0]

Note that optotrak_generate_rigid_body_file() is expecting these coordinates as an 1-by-N*3 array, where N is the the number of markers. So, in Matlab, define these as:

marker_coordinates = [0, 0, 0, 1000, 0, 0, 0, 1000, 0, 500, 500, 500]; %Note that we always work in millimetres!
normal_vectors = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0]; %The length of the vectors must be 1.

Since we entered the coordinates manually, we won't have to change the origin. But, for any reason, if you decide that Marker 3 should be the origin from now on, the function will modify the coordinates accordingly, so marker 3 will be exported as [0, 0, 0] in the rigid body file.

origin_marker = 0; %If you want to change the origin to a particular marker, select the it here.

You can also specify the minimum number of markers visible. You should keep all the markers visible all the time. This makes the calibration more accurate, and you can easily check whether the rigid body transform was successful, for example by calling DataGetLatestTransforms2_as_array() later-on. Also, you can specify how much conversion error you are allowing. So:

minimum_markers_visible = 4; %Can do it with 3, but you really shouldn't...
conversion_tolerance = 1; %Only 1 mm error is allowed. You can go down to 0.005mm!

And now, you are ready to call the function:

fail = optotrak_generate_rigid_body_file(marker_coordinates, origin_marker, 'my_first_rigid_body.rig', conversion_tolerance, normal_vectors, minimum_markers_visible);

Assuming nothing went wrong and you didn't see any error messages, fail should be 0, and you now have my_first_rigid_body.rig created. You can use it with RigidBodyAddFromFile() in a properly initialised system.

Then, you can execute the registration and alignment script, which aligns the position sensor's global coordinate system with the local coordinate system of the rigid body you just created. It's also worthwhile keeping the rigid body definition loaded during an experiment, so you can restore the alignment in the data, should the table have been accidentally moved. For instance, you can check if the table have been moved outside tolerance with optotrak_are_two_points_close().

Do I need to test my rigid body configuration?

Most certainly yes. The Optotrak system allows you to assign a cartesian coordinate system of any origin and any orientation. Nothing checks whether your axes are defined in the correct way or that your rotations even make sense.
Always check your own work, especially when you want to get data that relies on rigid body transforms!