Software: Scripting Engine

The control system includes a scripting engine, written from scratch, for a language similar to C++ or Java. The language is loosely typed and supports primitive types (real numbers, strings, 3d vectors, and lists of arbitrary objects) as well as user-defined compound object types with methods. Scripts are parsed and virtual machine code is generated from them at runtime, so changes to scripts require no recompiles of the C++ code. The scripting engine supports both interpreted and native types and functions, so any expensive processing can be implemented in C++ and called from scripts.

The real usefulness of scripts lies in the ability of the user to declare and implement behaviors in the scripts themselves. This means that arbitrary behaviors can be expressed and tested without a single recompile of any code. For example, consider the hypothetical Waypoint behavior discussed here. Here is a possible implementation of this behavior in script:

# This is a comment line.
# Declare the behavior type.

behavior Waypoint {
    # Members
	real startTime;
	real targetDirection = 0;
	vector targetPosition;
	real timeLimit;
	vector target;

    # Constructors
	method Test() {}
	method Test(vector t, real time) { targetPosition = t; timeLimit = time; }
	method Test(vector t, real time, real d) { target = t; timeLimit = time; targetDirection =d; }

    # Handle the enter event by setting our waypoint.  Once the waypoint is set,
    # the propulsion component will continuously move us closer to it.
    # Also turn on the forward-facing camera and capture color frames.

	method onEnter(robot, t) {
		startTime = t;
		setWaypoint(targetPosition, targetDirection);
		startFrontCamera(1);
	}

    # Handle the think event
	method onThink(robot, t) {
                # How far away are we?
		diff = targetPosition - robot.position;
		dirDiff = targetDirection - robot.heading;
		# Output some debug info.
		print("Current pos: ",robot.position, "\tDistance to target: ", diff.abs(),"\n");

		# Are we close enough to be done? 
		if (diff.abs() < 0.2 && abs(dirDiff) < PI/36 ) {
		   print("Attained waypoint: ", targetPosition, "\n");
		   leave();
		} else if (now()-startTime > timeLimit) {  # Timed out
		   print("Timed out.\n");
		   leave();
	        }
	}

    # Save each frame to a file

	method onFrame(robot, t, camera, image) {
		print("onFrame: t = ", t, "\n");
		saveImage(image, "frame_at_time_"+t+".jpg");
	}
	
    # This is how we identify this behavior object.

	method toString() { return "Waypoint["+targetPosition+","+targetDirection+"]"; }
}

# This is executed after initialization
main()
{
	# Add a new waypoint to the queue of behaviors.
	queueBehavior(new Waypoint([0,2,-1], 30, PI));
}

The scripting engine is also used to parse and evaluate configuration settings, allowing for arbitrary expressions in the configuration file. Here's an example configuration file:


devices {
	dmm32 = "on";
	depth = "on";
	dvl = "on";
	altimeter = "on";
	propulsion = "on";
	frontcam = "on";
	downcam = "off";
}

frontcam {
	device = "/dev/video0";
	brightness = 0.5;
	contrast = 0.5;
	hue = 0;
}

downcam {
	device = "/dev/video1";
	brightness = frontcam.brightness;
	contrast = 0.5;
	hue = 0;
}

depth {
	a = 0.4;
	b = 0.5/(0.5-a);
	channel = 13;
	use_altimeter = "no";
	bottom = 4.58;
}

propulsion {
	check_supply_period = 1000000;
	supply_voltage = 33;
	channels = { 2, 3, 0, 1 };
	inversions = { 0, 0, 0, 1 };
	no_dac = 0;
	max_forward_thrust = 10*NEWTONS_PER_POUND;
	max_reverse_thrust = -4*NEWTONS_PER_POUND;
	long_distance = 1.5;
	short_distance = 0.5;
	big_turn = 3.149;
	kp_heading = 1;
	kp_depth = 4;
}

dvl {
	zero_heading = -3*PI/4;
	angle_to_forward = 3*PI/4;
	offset_from_center = [0,0.25,0];
	start_pos = [0,0,0];
	device = "/dev/ttyS0";
}

altimeter {
	device = "/dev/ttyS1";
	window = 1;
}

robot {
	no_log = 0;
}


Software System:
Design | Platform | Sensors | Propulsion/Navigation | Behavior | Scripting Engine | Vision Processing