Goal is to meet the requirement to Limit the interconnectedness of code to minimize full-system recompiles.
Dynamically loaded modules provide the majority of the "functional" elements of the software. Such drop-in modules include code components such as behaviors, sensor readers, control interfaces, etc. The main vehicle control loop will be capable of scanning a folder of drop-in-modules to add and/or replace modules without stopping execution.
Each Module provides registration information including metadata about itself (name, version), and a list of the component it includes. Then each component registers:
- the values they write to the slate, plus metadata about these values (name, units, initial value). It also indicates whether these variables are "Universal" variables.
- the type of component: controller, computation, sensor reader, etc.
- whether it should be run even if its data isn't being consumed.
- whether it should run asynchronously to the control cycle, and if so, whether there is a minimum/optimal/maximum run frequency (for example, run every 5 seconds, regardless of other triggers)
The supervisor assimilates this information and uses it to build a component list for the control thread and a similar component list for components that will run in their own threads. The default behavior is that components are not run unless one of the following conditions is met:
- it provides a data value that's required for another Component to be run, or to determine whether to run another Component
- it provides an "universal" data value that's required by another Component and was previously the most accurate
- it needs to run to meet its specified minimum run frequency
- it needs to run every cycle of the control thread.
Approach is to allow either compiled c++ modules or scripted modules.
Modules are included by the standard Lua "require" command. Hence, compiled c++ modules need a Lua wrapper. This wrapper is automatically generated by the makeLuaModule.lua script (in the Build folder, called by the make command). The generated Lua wrapper defines named lua tables for each component in the module, and popluates these tables with the named entities (and enumerations) from the interface (...IF.h) file associated with each component, simplifying their use in missions.
The makeLuaModule.lua script also creates two special Lua wrappers: for the Units class and for the UniversalURI class. In each of theses cases, the static const objects in those classes are defined as lua objects that can be used in a mission.
For example, the ControlModlue code is:
"Contains the Control components, such as Depth, Heading, and Speed Control" )
{
registerComponent( new HeadingControl() );
}
It contains the classes VerticalControl, HeadingControl, SpeedControl, and LoopControl, which reference the interfaces VerticalControlIF, HorizontalControlIF, SpeedControlIF, andLoopControlIf. If we examine SpeedControlIF, it contains:
{
static const Str NAME(
"SpeedControl" );
static const Str SPEED_CMD(
"Speed" );
static const Str PROP_OMEGA_ACTION(
"PropOmega" );
static const double SPEED_SLOW( 0.5 );
static const double SPEED_FAST( 1.0 );
}
VerticalControlIF, HorizontalControlIF, andLoopControlIf contain similar code.
The resulting Lua module wrapper is:
module("Control",package.seeall)
require("Tethys")
__CPPModule = RequireModule("Control")
LoopControl.PERIOD = MakeURI("LoopControl", "Period");
LoopControl.LOOP_FAST = 0.400;
LoopControl.LOOP_SLOW = 5.000;
LoopControl.LOOP_DRIFT = 300.000;
VerticalControl.DEPTH_MODE = MakeURI("VerticalControl", "
VerticalMode");
VerticalControl.
DEPTH = MakeURI("VerticalControl", "Depth");
VerticalControl.
DEPTH_RATE = MakeURI("VerticalControl", "DepthRate");
VerticalControl.
PITCH = MakeURI("VerticalControl", "
Pitch");
VerticalControl.
PITCH_RATE = MakeURI("VerticalControl", "PitchRate");
VerticalControl.ELEVATOR_ANGLE = MakeURI("VerticalControl", "ElevatorAngle");
VerticalControl.MASS_POSITION = MakeURI("VerticalControl", "MassPosition");
VerticalControl.BUOYANCY_GAIN = MakeURI("VerticalControl", "BuoyancyGain");
SpeedControl.SPEED = MakeURI("SpeedControl", "Speed");
SpeedControl.PROP_OMEGA = MakeURI("SpeedControl", "PropOmega");
SpeedControl.SPEED_SLOW = 0.5;
SpeedControl.SPEED_FAST = 1.0;