Skip to content

Trick Integration

dbankieris edited this page Mar 11, 2022 · 16 revisions

IDF offers several conveniences to ease integration with a Trick simulation. They can all be found under the 3rdParty/trick directory.

Sim Makefile

3rdParty/trick/makefiles/core.mk handles all of the stuff you'd usually have to put in your sim's S_overrides.mk file:

  • including the path to header files in TRICK_CFLAGS and TRICK_CXXFLAGS
  • including the path to sim objects in TRICK_SFLAGS
  • including necessary (OS-specific) libraries in TRICK_USER_LINK_LIBS
  • setting (if not already set) and making IDF_HOME available as an environment variable at run time

A bunch of details about which you'd rather not worry! Rest easy, my friend, and simply include IDF's makefile from your sim's S_overrides.mk:

include <path to IDF>/3rdParty/trick/makefiles/core.mk

Sim Object

Frequent users of IDF will find themselves implementing the same infrastructure over and over again to manage IDF devices. For more than trivial uses, you usually need some sort of manager to handle maintaining a list of devices and performing operations on them as a group (like opening, updating, and closing). On top of that, you'll probably want to wrap it in a SimObject with appropriately-classed jobs that call manager functions. Most managers end up looking pretty similar with the same core structure and some additional application-specific extras. I have a special hatred in my heart for duplicated code, so IDF offers you a ready-to-use SimObject that takes care of all that boiler-plate code for you! Take a look at 3rdParty/trick/sim_objects/IdfInputDeviceManager.sm, and you'll find:

  • an initialization job that opens all devices
  • a shutdown job that closes all devices
  • a job (with a configurable phase, period, and class) to update all devices
  • functions for adding devices
  • functions for setting properties of all devices at once

Now that all the boring standard infrastructure stuff is taken care of, you're left with the decidedly more enjoyable task of adding your application-specific functionality by deriving your SimObject from IdfInputDeviceManager like so:

/**
 * make sure you include 3rdParty/trick/makefiles/core.mk from your
 * S_overrides.mk so this file can be found!
 */
#include "IdfInputDeviceManager.sm"

class MyInputDeviceManager : public IdfInputDeviceManager {

    public:

    /**
     * IdfInputDeviceManager's constructor requires the period at which you want
     * to run the update job. It has some optional arguments too, so be sure to
     * check it out!
     */
    MyInputDeviceManager() :
        IdfInputDeviceManager(<period>) {}

    // no boiler-plate code, only cool extra stuff!
};

IDF's own example simulations use this approach, so if you need a little more substance, head on over to 3rdParty/trick/examples and peruse an S_define or two.

Python Module

Are you still programming in the compiled side of Trick? Didn't you know that you can write entire simulations in the input file!? Type safety and proactive syntax checking be damned! If you like your errors at run time, 3rdParty/trick/python/idf is for you. It's primary feature is the idf.config.Configurator class which, in cooperation with an IdfInputDeviceManager, allows you to configure your input devices from the input file. It's constructor looks like this:

def __init__(self, deviceManager, vhcVariableName = None)

The required argument is an instance of an IdfInputDeviceManager or a derivative thereof (from the section above). The optional argument is a string containing the full name of an instance of VirtualLayout (see include/VirtualLayout.hh) and is used to enable automatic launching of the Virtual Hand Controller.

Specifying Input Devices

IDF searches for devices using the following algorithm:

  • If ~/.idf/config.py exists, IDF exec's it in the context of the Configurator instance. The use of this config file allows the specification of available devices to be independent of the simulation files. For instance, you could configure IDF right in your input file. But then that input file only works for developers who have your input device. If Bob in the cube across the hall has a different device, now he has to change the input file, which is surely tracked in your repository, breaking it for everyone who doesn't have his device. Since this sort of configuration is machine-specific, you should keep it with the machine and out of your repository. Because exec preserves the caller's context, you can access Configurator methods in your config file via self. For instance:
self.addMasterDevice(trick.UsbWingMan())
  • If ~/.idf/config.py does not exist, IDF tries ~/.idf_<hostname>/config.py instead. This can be useful if you have multiple machines that share the same home directory but need individual config files.
  • If neither of those files exist, IDF uses the first connected HID-class device (USB or Bluetooth) that it knows about and calls addMasterDevice, described below.
  • If no devices can be found, IDF launches the Virtual Hand Controller if support has been enabled as described above.

addMasterDevice

While the Configurator is pretty flexible as to how it searches for devices, once it's found them, someone has to tell it what to do with them. That someone, of course, is you! addMasterDevice is an abstract method that you must override, providing the logic necessary to connect the specified device to your simulation. This could be as simple as creating a single Controller and assigning it to a pointer in your IdfInputDeviceManager subclass or as complex as creating multiple Controllers and MutualExclusionGroups and adding them to CompositeControllers. It all depends on what you want a device added via this method to do.