-
Notifications
You must be signed in to change notification settings - Fork 15
ProgrammingWithSteerLib
# Programming with SteerLib
The previous chapter described how to use steersim and steerbench to simulate and analyze steering behaviors. The real fun begins when you want to develop and simulate your own steering algorithms. You can test your algorithm with the SteerSuite test cases, make recordings of your AI to share with others, benchmark your AI, experiment with your own benchmarking and debugging techniques, or even write SteerSim plugins. SteerLib is a C++ library that provides easy-to-use functionality to accomplish these tasks.
## Including and Linking SteerLib
Integrating SteerLib into your own code is straightforward, just follow
the steps given below. However, there is one catch: SteerLib is a shared
library, but by default it is not "installed" into standard system
locations where libraries are expected to be found. Therefore there is
one extra step so that your program can find SteerLib at run-time.
For
g++
on Unix platforms:
Include
SteerLib.h
:
Remember to
#include "SteerLib.h"
in any source file that uses SteerLib.
Specify the include path of SteerLib:
Use the
-I
option of
g++
. The include path should point to the
steerlib/include/
directory in SteerSuite. For example, if SteerSuite is located in
/tmp/steersuite/
, then use:
g++ -I/tmp/steersuite/steerlib/include/ (all your other options...)
Specify the library path:
Use the
-L
option to specify the path where
libsteer.so
is located. By default, this is the
build/lib/
directory in SteerSuite.
Specify the library to link:
Use the
-l
option (that's a lowercase 'L'). For example, if SteerSuite is located
in
/tmp/steersuite/
, then use:
g++ (all your other options...) -L/tmp/steersuite/build/bin/ -lsteer
Specify an rpath:
As mentioned above, SteerLib is a shared library. This means that your
program needs to be able to find the SteerLib library at run-time, not
just at compile-time. To do this, specify an
-rpath
option (for Linux and OS X) or a
-R
option (for Solaris). This option tells the executable to add a
directory to the list of locations to search when looking for
libsteer.so
at run-time. Refer to the
g++
documentation of your platform to learn how to use the rpath option.
For Visual Studio 2008 on Windows platforms:
Include
SteerLib.h
:
Remember to
#include "SteerLib.h"
in any source file that uses SteerLib.
Specify the include path of SteerLib:
In the
Project Properties
→
C/C++
→
General
menu, add the SteerLib path in the option "Additional Include
Directories". The path is
"<steersuite-directory>steerlib\include"
.
You may need to put quotes around the path, if the path name has spaces
in it.
Specify the library to link:
In the
Project Properties
→
Linker
→
Input
menu, add
"<path-to-steerlib>\steerlib.lib"
to the "Additional Dependencies". By default, the steerlib path will be
the
Debug
or
Release
directory where all of SteerSuite was compiled. For example, if
SteerSuite was located in
C:\steersuite\
, then the path would be
C:\steersuite\build\win32\Release\.
You may need to put quotes around the path, if the path name has spaces
in it.
Copy
steerlib.dll
:
Copy
steerlib.dll
to the same directory as your program's executables. To our knowledge
(we have not verified this, however) Windows searches the executable's
directory for its dll dependencies before it searches the standard
system directories.
## Error Handling in SteerLib
Errors in SteerLib are handled by throwing C++ exceptions. If you need to refresh your memory on C++ exceptions, refer to this introduction and this FAQ . It is strongly recommended that you catch these exceptions, and look at the associated human-readable string that explains the error. In many cases these error messages are very simple but informative, such as telling you that a file cannot be found, or if there was an incorrect usage of a class. Seeing these error messages can save you hours of debugging. The following is an example of catching SteerLib exceptions in the top-level main function of a program.
Example 4.1. Catching exceptions to handle SteerLib errors
int main(int argc, char\*\* argv)
{
try { // put all your code here... }
catch (std::exception &e)
{
std::cerr \<\< "\\nERROR: exception caught in main:\\n" \<\< e.what() \<\< "\\n"; return 1;
}
return 0;
}
The specific exception class used by SteerLib is Util::GenericException. Refer to the Code Reference for more documentation.
As mentioned before, test cases define a variety of challenging scenarios for agent steering, and are very useful for developing, debugging, evaluating your own steering algorithms. Each test case defines initial conditions of agents and obstacles, including a list of goals for each agent. To "run" a test case in your own code, you will need to load the initial conditions into your own data structures, and then simulate agents that try to accomplish the given goals. SteerLib makes it easy to load these initial conditions into your own code, with the SteerLib::TestCaseReader class. Create an instance of this class, and and then call the readTestCaseFromFile() member function (refer to the code example shown below). This function parses the XML test case, expands all "agent regions" and "obstacle regions" into individual agents and obstacles, and initializes initial conditions for all agents and obstacles, all automatically for you. After calling readTestCaseFromFile() , the rest of the TestCaseReader class functions can be used to get the initial conditions and meta information from the test case. The most important functions are getAgentInitialConditions() and getObstacleInitialConditions() , which allow you to copy the test case initial conditions into your own code.
Example 4.2. Using the SteerLib::TestCaseReader class to load a test case.
SteerLib::TestCaseReader \* testCaseReader;
std::string testCasePath = "../../../testcases/simple-1.xml"; // open the test case
testCaseReader = new SteerLib::TestCaseReader();
testCaseReader-\>readTestCaseFromFile(testCasePath);
for (unsigned int i=0; i \< testCaseReader-\>getNumObstacles(); i++)
{
const SteerLib::ObstacleInitialConditions & initialConditions = testCaseReader-\>getObstacleInitialConditions(i); // use data inside of
initialConditions to initialize your obstacle // make sure you \*copy\*
the data, don't refer to it, since you may want to delete the
testCaseReader.
}
for (unsigned int i=0; i \<testCaseReader-\>getNumAgents(); i++)
{
const SteerLib::AgentInitialConditions & initialConditions = testCaseReader-\>getAgentInitialConditions(i); // use data inside of
initialConditions to initialize your agents // make sure you \*copy\*
the data, don't refer to it, since you may want to delete the
testCaseReader.
}
delete testCaseReader;
The data structure returned by getAgentInitialConditions is a fully initialized AgentInitialConditions object. This object contains the initial position, orientation, radius, and speed of the agent, and an ordered list of goals that the agent should try to accomplish. When you get a reference to this object for a particular agent by calling getAgentInitialConditions() , you can translate this information as needed and incorporate it into your own agents. In most cases, this "translation" is simply copying the data into your own data structures. Similarly, the ObstacleInitialConditions contain the bounding box information of an obstacle. The data provided for obstacles will likely be expanded in future versions of SteerSuite.
**Note**
The TestCaseReader can potentially take a large amount of memory, and it is recommended that you de-allocate it after you are done copying the initial conditions into your own data structures.
## Reading a Recording (Rec File)
## Writing a Recording (Rec File)
## The Spatial Database
## Metrics Collectors and Benchmark Techniques
## The Util Namespace