In addition, the library also has attempted to use the Joint Architecture for Unmanned Systems (JAUS). A robotic architecture can be quite complex and this move was to facilitate a common understanding of the basic components and to have a common terminology. Becoming completely JAUS compliant was quickly abandoned as the messaging topology was deemed too complex for the limited environment of the MRM. Basically, the move was to create classes that reflected the components of JAUS and class methods that reflected the messages of JAUS. Thus where indicated, refer to the JAUS reference architecture for clarification
After more careful analysis, I found the messaging protocol can be adapted, but at a price, but also more importantly, many of my previous classes were misnomers or were slightly off-base than the real JAUS equivalences. The JAUS library has one odd feature in my opinion. All the drivers take wrench efforts rather than a speed. This seemed a bit backwards as even my oEncodedMotor class sends a speed in millimeters/second to the motor, and thus the real equivalence seems the oDCmotor which isn't right either. This seems an oversight in the architecture. Each driver must provide its own control feedback loop with the Velocity State Sensor; it would seem much simpler to put that functionality into the Reflexive Driver or some other component, but as the architecture does not envision that the Drivers can actually be layered. A Waypoint can use a vector driver as a control mechanism, and the vector driver can use a Primitive Driver as a control mechanism; instead each driver must provide redundant control. Arguably, even though the oDCmotor takes a wrench effort, it isn't a primitive driver as the Primitive Driver is definitely intended to be a vehicle level command even if the vehicle has several motors (oDCmotors).
The JAUS classes are in general built (subclassed) from lower level hardware or model components. These subclasses are found in the include/jaus subdirectory. Thus in general, a program can use the hardware components without any knowledge or use of the JAUS layer. Thus be sure to distinguish between the hardware classes available for use and the JAUS components available. Not all hardware components might be mapped to a JAUS component. Only the following are valid JAUS components:
Components like IR sensors can have several completely different sensors (classes). To differentiate these, an extra parameter is added--subtype when adding to the Object_List. Currently, ir_base and sonar_base support JAUS subtyping.
The ir_base and sonar_base are JAUS components whereas just oIR and oSonar are not. Some sensors (classes) have several variations, for instance oIR itsself has a type (GP2Y0A02YK, GP2D12, GP2D120), but this is different than the JAUS subtype. The oIR IR_TYPE simply callibrates the oIR object when created. It is the JAUS subtypes (IR_SUBTYPE, SONAR_SUBTYPE) that are JAUS (object_list) sub-components.
I believe earlier releases of the JAUS RA specified not only the message and components, but also which components are the sender and receiver of the messages. This was removed causing the following:
It is the flexibility which provides a problem. We have a basic problem of who will decode the message? If I send the set wrench effort to the node manager, then is that defined? What effect should it have? Should it be the same as sending it to the subsystem commander or Primitive Driver? Tbus, semantics now become real fuzzy. Who really should receive the message and what happens if it is sent to someone else. Should we still decode it if possible or simply signal an error. Why not just send every message to the subsystem commander and define that component as a black box of functionality eliminating the needs for all other components. This would architecturally be simpler also; don't need to decide what component it goes to--simply decode the basic semantics of the message independent of the destination component. Really, how should semantically the Set_Wrench_Effort differ if sent to a different component than the primitive driver?
With that said, I believe JAUS should reinstate defining minimally the semantics of each message delivered to a specific component, perhaps leaving the semantics undefined when delivered to anyone else. Thus, leaving flexibility in that other semantics can be specified outside the JAUS RA but we must at least define the minimum set.
/// Class JAUS Enabled - core attributes and functions for any JAUS enabled component.
// Also, provides entry point for the capability store (JAUS_Capability_Store).
class JAUS_enabled
{
public:
/// route JAUS message through to the capbility store.
JAUS_message(jaus_message msg);
/// Returns current status of JAUS enabled component.
bool status(void);
protected:
char _status;
};
In retrospect, I think I begin to prefer the above stated method. So, rather than node_manager looking at component and sending to object in table...have one big message resolver and only lookup object when needed to execute message function. This makes more sense as some things like camera count would look up information directly in object table and not need to dereference the class pointer; i.e. why send camera count to a specific camera?
In general, if we think of a JAUS enabled hardware, we really do not know the implementation. Thus, the most flexible solution is to depend upon the function alone and not the destination component. This is especially true if the JAUS specification does not specify source/destination components as it did previously.
Another irritation is the set travel speed message initiates the waypoint driver. Well, how do we set the mission travel speed in general? We can't, unless we agree that travel speed message sent to sub-system commander or any other component simply sets speed without beginning waypoint driver. I think they would have been better to simply have a begin waypoint message. Much less confusion.
Finally though, the best use of components in the message is with regard to the operational status of components. To shutdown the waypoint driver, would require a component part to the shutdown to completely decode its semantics.
void JAUS_enabled::perform(jaus_message msg)
{
...
switch (Jmessage)
{
case Query_Camera_Count_Message: // Not implemented yet
break;
case Query_Camera_Capabilities_Message:
break;
case Report_Camera_Settings_Message: // what am I supposed to do with the report besides use it to set current platform.
case Set_Camera_Settings_Message:
// decode information--may not need to the class pointer.
vertical_resolution(vr);
horizontal_resolution(hr);
}
}
class oCamerac328 : public JAUS_enabled
{
// normal definition.
};
main
JAUS_Message msg;
oCamerac328 camera;
...
if (camera.status() == ACTIVE) // or whatever
{
msg = SNAPSHOT; // again or however msg is populated.
camera.JAUS_message(msg);
}
Currently, subsystem is not implemented.
Be certain to give each node a unique identification. Currently, for message receiving, it doesn't matter; every node will pick up the messages sent to it. On sending though, if the source and destination nodes are identical, then this becomes an intra-node tranfer which does not transfer the message serially across the "network" but instead simply delivers the message to the internal destination component.
Not Implemented.
Because of loose semantics, it is difficult to implement service connections as stated; i.e., what component will establish a Set_Wrench_Effort command code? Primitive driver maybe and what difference is there between a Global Pose Sensor and a Primitive Driver establishing the service connection? To solve these questions, all service connection messages originate from the Node Manager (does not imply that the component involved in the service connection is the Node Manager). Thus requests to create a service connection are forwarded to the node manager and consequently the confirmation is thus sent back to the node manager.
Only the node which is responsible for sending the message manages the service connection. Also note, the ID as specified in JAUS is not used.
Command class service connection are managed on the node which will be responsible for sending the message.
The semantics of a command class create service connection are a bit confusing. As implemented, sending a create service connection to set wrench effort simply informs the other target to expect these messages, but really the other end does not really have to do anything (does it?). In fact, it doesn't seem much different than if I simply sent a bunch of set wrench effort commands without a service connection.