Home Curriculum Vitae Research Service Teaching Faculty Pages
Research - Simulation
If you did not arrive at this page from the simulation software page or the simulation research page, you may want to return to it briefly to understand the context for this page. The current page provides more information about scripting languages and the language for studying robotic or animal locomotor control that we developed.

An Explanation of Scripting & Macro Languages
Scripting and macro languages are computer programming languages designed facilitate the rapid construction and configuration of applications. The term 'macro language' is usually reserved for custom-written, highly application-specific languages, like those found in word processors or spreadsheets. For example, one might use the macro language in a spreadsheet program to write an algorithm for computing credit risk based on past history. Macro languages provide a way for end-users to write short algorithms or scripts that manipulate internal application-specific data, and can be found in most large applications.

Whereas macro languages are designed to be run by end-users from within an application, 'scripting' languages are typically targeted at programmers, and are implemented as stand-alone interpreters. A common definition of a scripting language is a language intended for rapidly building programs and utilities which make heavy use of external components. For example, if you had a collection of graphics files that needed to be converted to some other format, you could use a scripting language to write a short program that searched for all graphic files, and for each one, ran a stand-alone conversion utility on that file.

The distinction between traditional programming languages and some of the more general scripting languages can be hard to discern. Some of the more general scripting languages, like Perl, provide a fairly complete and flexible programming environment, and some of the more recent general-purpose programming languages, like Java, provide substantial facilities for easily integrating external components.

In addition to scripting and macro languages, a growing body of tools is being developed to bring some of the functionality of scripting languages to standard programming languages. RAD programs provide a higher level of abstraction to languages like C or Pascal, allowing programmers to assemble third-party pre-built components into complete applications. JavaBeans, an extension of the Java language, is aimed at providing a similar functionality through a different mechanism; while RAD tools are specific applications designed to build programs out of component parts, JavaBeans is a formalism that makes use of built-in language constructs and informal programming paradigms to establish a framework for classes to publish their interfaces and interact with one another in a safe, reusable manner. JavaBeans provides a mechanism for compliant Java classes to declare what properties they want to make visible to other classes, and a mechanism for establishing connections between objects. The intention is to provide a framework whereby conforming objects (JavaBeans) are usable as plug-and-play components that can be created, configured, and connected together by someone with minimal knowledge of the underlying class code (the user-programmer should only need to understand the published interfaces).

An Overview of Config++
Config++ acts as a glue between component C++ class libraries. In the lingo of scripting languages, making an existing class library accessible to the Config++ interpreter is called "wrapping" the class library. Wrapping a class involves writing an extra piece of code that tells the Config++ interpreter how to create and access instances of the class. This represents the back-end of Config++ which is invisible to the user of the class library.

Config++ differs from most scripting languages in that it imposes a more substantial framework for wrapping objects and variables, including the specification of value restrictions and unit conversions, stressing the use of hierarchical objects consisting of component parts and providing a wide variety of mechanisms for accessing class variables and functions. Like JavaBeans, Config++ requires some extra work when building component libraries, in order that the user of the library need do less.

Once a class or class library has been "wrapped" and registered with the Config++ interpreter, it can easily be configured and connected to other registered classes using the Config++ language. In this way, Config++ provides a common bridge for connecting heterogeneous components. Because Config++ libraries are required to specify extended information concerning the valid parameterization of classes (such as argument ranges, etc.), they are amenable to configuration via graphical drag-and-drop construction tools.

The design of Config++ has been motivated by three main goals. The first goal is to provide a generic configuration language that would be intuitive and easy to use by application end-users who are not programmers, and still be powerful enough to support the manipulation of complex, hierarchical data structures by application programmers.

The second goal is to provide a framework for decoupling the interface mechanism from the underlying code of C++ class libraries so that class libraries can be replaced in a transparent fashion. Every Config++ library consists of two parts, the back-end, which represents the underlying library code, and the front-end, which describes the interface for constructing and instantiating library objects. For example, the front-end of the Config++ graphical user interface library consists of a description of the kinds of GUI components that can be built, their names and parameters, and the manner in which they may be constructed and wired together. This description does not depend on the underlying code that actually implements the GUI functionality. Hence, it represents an "interface" as opposed to an "implementation." The actual code that implements the GUI functions is maintained separately; a "wrapper" provides the bridge from the implementation to the interface. In this fashion, the wrapper acts like a translator between the Config++ language and the underlying implementation. By writing a new wrapper, or translator, entire libraries may be replaced transparently.

The final goal of Config++ is to provide a collection of common, reusable, platform-independent tools for C++ programmers working with highly configurable projects, such as simulations. To this end we have been working on a set of libraries, and wrappers for existing C++ libraries, which provide support for platform independent GUI, data visualization, and file manipulation. From a programmer's point of view, an advantage of the approach is that all interaction between different class libraries and between class libraries and the Config++ interpreter is done through intermediate wrapper classes. This promotes encapsulation and portability, ensuring that underlying class library code is usable independently of the Config++ system and of other Config++ components.

While Config++ is an attempt to provide for C++ a framework similar to JavaBeans, it has a slightly different focus. Where JavaBeans is a formalism for constructing classes that will be easy for another programmer to reuse and wire together, typically using a graphical draw-and-drop tool, Config++ is meant to be embedded inside an application, providing an interpreted language for rapidly reconfiguring application projects. In addition, while JavaBeans is a tool for programmers, Config++ is designed to be used by application end-users as well as hard-core application programmers.

Example Application: A Robotic Simulator
In order to explain the design principles underlying Config++, we describe a robotic simulation tool we have implemented using Config++.

Config++ plays two main roles in the simulation. First, Config++ is used as an embedded front-end to the simulation. It parses user configuration files and builds/configures robots by making appropriate calls to the underlying robotic library classes. A substantial amount of work is done while parsing the configuration files because the description of a robot is non-trivial. These descriptions consist of hierarchical components like arms and legs, each of which may be made up of other components, like joints, muscles, and sensors. Config++ allows us to use a simple, straightforward syntax for describing these hierarchical structures, while behind the scenes it instantiates objects, connects them together, infers default settings, registers callbacks, and so forth. Simple control-flow facilities allow users to write simple scripts to conduct multiple experiments, for example running a series of trials while varying certain parameters.

Second, the robotic simulation classes were written completely independently of any user-interface code. Config++ was used to describe generic, platform-independent GUI components and interface them with the robotics classes. Because the user-interface and simulation code is completely decoupled, either could be replaced without modifying the other. In a similar way, Config++ was used to connect the robotic simulation to libraries for visualizing data and reading/writing data files. Config++ also allows end-users to incorporate additional 3rd party libraries seamlessly with no modification of the underlying simulation code. While still in the early stages of development, Config++ also provides facilities for building and connecting components of a simulation project interactively in a drag-and-drop fashion, and for saving and loading projects.

While most of Config++'s syntax is borrowed from C/C++, it differs most obviously in its syntax for instantiating objects, which resembles the hierarchical, object-oriented data description languages and file-formats used in 3d graphics programs such as OpenInventor, VRML, and Povray. Almost everything in a Config++ "program" consists of object instantiations (creating new objects from existing object classes):

					Robot r2d2
						height=1 meter;
						Leg left
							length=.1 meter;
							mass=1 kilogram;
						Leg right
							length=.1 meter;
							mass=2 kilograms;

The example above may seem unnecessarily verbose. However, Config++ code is intentionally verbose; it is meant to be intuitive and easily readable. When parsing this example, Config++ might make C++ calls similar to those shown below:

					Robot *r2d2=new Robot(1,BLUE);
					Leg *left=new Leg(.1,1);
					Leg *right=new Leg(.1,2);

Of course, while one might claim that the Config++ code version looks nicer, it's hardly a compelling example. The main advantage of using the Config++ language, however, is not in describing single objects, but rather in wiring objects together. For example, we might add the following Config++ code to our robot configuration file in order to give the user interactive control over the height of the robot using a standard draggable slider control.

							Wire to r2d2.height;

We can also add the following Config++ code in order to give the user a way to display a plot of how the robot's battery power is holding up over time:

						Axis x
							Wire from simulation.time;
						Axis y
							Wire from r2d2.batterypower;

In the example above, the underlying C++ code for instantiating the slider and graphical plot, and connecting them to the simulation data would depend critically on the underlying library being used to provide the graphical user-interface. It would also depend on the data structures being used to store and retrieve values from the simulation classes and could be quite involved.

Furthermore, without some form of intermediate macro/scripting language, if you wanted to set up multiple simulations with slightly different configurations, each version of the simulation would have to be maintained separately and compiled independently before execution. Because the need for multiple configurations in such programs is so common, nearly all large applications end up providing support for a custom configuration file of some sort. One of the motivations for Config++ was to provide a robust configuration file which could be used across a range of applications.

Applications rarely support the modification of things like the user-interface of the application, but because implementation specific code is encapsulated within Config++ libraries, decoupling application specific code from things like the user-interface library produces a highly-customizable application whose GUI components could be replaced without modifying the underlying application or Config++ code.

Existing Config++ Libraries

We have implemented some basic libraries for use with the Config++ interpreter, described here:

GUI Library

A GUI toolkit is a perfect example of a collection of hierarchical objects that can be assembled and wired together in a variety of ways. We have taken an existing GUI toolkit, FLTK, and provided Config++ wrappers that allow Config++ projects to provide a full-featured user-interface, and methods for easily wiring user interface components to other components. One strategy of our approach to writing the Config++ wrapper interface was to provide routines for guessing parameters and providing default actions. This demonstrates one of the roles that the Config++ interpreter can play, providing a simpler, more intuitive interface to a set of existing classes. FLTK provides the underlying user interface routines and runs on Windows and Unix platforms. One of the advantages of using Config++ is that it would be straightforward to replace the underlying GUI toolkit (FLTK) with another. Because the Config++ interface specification for the GUI components would be unchanged, no applications written for Config++ would have to be changed.

Datafile Library

A set of classes and associated wrappers have been provide that support input and output to data files of various formats. For example, a simulation application can easily be configured to save arbitrary information, at arbitrary intervals, to a datafile in a variety of formats (such as Matlab). Data files are augmented with information about the quantities being saved in order to make them easier to understand. Data files can also be automatically read by the Config++ interpreter, and routed to arbitrary components.

OpenGL Graphic Object (GROB) Library

We have designed a set of classes and Config++ wrappers for providing access to a set of 3d primitives, as well as a basic camera class for displaying and manipulating these primitives. Some basic rendering options are provided to support the rapid design of simple applications, such as the switching between multiple detail levels. The 3d shape classes are implemented using OpenGL, a graphics standard freely available on most platforms. The 3d classes are used by our robotics library, and could easily be added to other applications.

OpenGL Plotting Library

This is a simple OpenGL-based plotting library for generating online xyplots, barplots, 3d scatterplots, etc. Like all Config++ libraries, the intention is to provide a set of components that can receive data easily from any other Config++ components. Further, these components are highly-configurable while still supporting the extensive use of default and best-guess values for rapid design. OpenGL has been used to insure platform independence.

Simulation/Robotic Library

We have written, and described in the document doc04_biobot.txt, a set of classes for conducting discrete-time simulations, and for simulating the dynamics of multibody robotic mechanisms. These classes can be used independently from Config++, but Config++ has been used extensively to provide a way of building and configuring robots. Robot structures are naturally hierarchical, consisting of arms and legs that are themselves built from segments, and can be connected in various ways. Config++ makes it easy to reconfigure and reuse components in the construction of robots and experiments.

Copyright © 1999-2013 F. Delcomyn
vDiv', 0);