Overview
Cross Platform Hardware Communication Code.
Core Components
ControlSystem
The primary class that manages an entire hardware control system.
- Managing device controllers and devices
- Initializing and uninitializing the system
- Handles command execution and synchronization
- Provids logging and debugging capabilities
DeviceController
Base class for hardware controllers:
- Manages one or more devices
- Implements device communication
- Provides device connection/disconnection management
DeviceInfo
Base class for device descriptions that:
- Stores device-specific information (devices connected to a controller)
- Handles device state tracking
CommandPackage and CommandStatus
The command execution system consists of:
DeviceCommandPackage: Defines command parameters and behaviorCommandStatus: Tracks command execution state and progress
Development Concepts
Control Systems, Controllers, and Devices
The API has a primary class called ControlSystem. Typically 1 of these needs to be instantiated.
Controllers can be added to the ControlSystem. These objects control 1 or more devices and sometimes represent a hub or stand alone physical controller.
Devices can be added to the Controllers. Controllers Expect 1 or more (depending on the nature of the controller) devices that the controller is responsible for managing.
After adding Controllers and Devices, calling ControlSystem::initializeDevices() will connect (USB connection or similar) to all connected controllers and devices.
After this initialization is finished, Commands can be added to devices for runtime one-way or bi-directional control.
CommandPackage, and CommandStatus
A Command is created by creating a CommandPackage and adding it to a device, this will create a CommandStatus object that can be used to control the commands execution progress and monitor it's status:
//create a CommandPackage
auto cp1 = std::make_shared<DeviceCommandPackage>();
//create a CommandStatus object after adding the CommandPackage to the device.
auto cs = myDevice->addCommand(cp1.get());
A command will be created with the parameters given in the passed DeviceCommandPackage (cp1). The CommandStatus object (cs) can then be used to start/stop/update the command on the device:
//run the command until it is finished (blocking execution) cs->runFull(); //start a command to run asynchronously () cs->runAsync(); //wait until the above command is finished. cs->waitFinished();
A command can also be manual stepped during program execution by calling cs->update() methods.
while commands are running - parameters from the CommandPackage are directly used and accessed. (such as target positions for actuators etc.)
These parameters can be changed while a command is running - however it is not strictly thread safe - meaning a command could be making calculations on changing parameters before a final communication result is passed to the hardware. Thread-safe alterations to parameters can be made by utilizing the UpdatePackage facility:
//start an async command cs->runASync(); //prepare an UpdatePackage which will be a deep copy of the original cp1 CommandPackage. auto updatePackage = dynamic_cast<MovementCommandPackage*>(cp1->prepareUpdatePackage()); //update parameters updatePackage->disp_target -= 1; //mark the UpdatePackage as ready. This will signal that the cp1 parameters be updated when the Command is ready to safely read the parameters before its next internal update. cp1->markUpdatePackageReady(); //wait until command is finished at program end. cs->waitFinished();
Feedback state information can be read from a command by using the CommandStatus::stateInfo() function, this will return a CommandStateInfo object containing the any relevent state information from the device. For example the current position and velocity of an actuator:
//start an async command
cs->runASync();
while (!cs->isFinished()) {
//print the current position
auto state = dynamic_cast<MovementStateInfo*>(cs->stateInfo());
printf("position: %f, velocity: %f", state.currentPos, state.currentVel);
}
This can be used in tandum with Command UpdatePackages to achieve bi-directional control loops with a device.
Memory Management
ControlSystems, Controllers, Devices, Command Packages are created in user-side code. Management of the memory is left to the user-side code. The Library does not own and will not delete these objects.
ControlStatus Objects are created/owned by the library and released by the library.
ControlSystems must be un-initilized before user-side managed Controllers, Devices, and Command Packages are released by using the ControlSystem::uninitialize() command which will properly free ControlStatus objects and un-bind other objects tracked by the controlsystem and clean up any outstanding connections etc. It is important this is called before objects can be freed on user side code.