-
Notifications
You must be signed in to change notification settings - Fork 0
DARVIS Dev Guide : How To!
Darvis is based on "Actor Model" design and must have component be implemented as an Actor to be used. Each Feature is an independent part of the Darvis framework that implements an Actor.
Following are the naming conventions used to avoid ambiguity between Darvis core features and other dependencies.
- Feature Struct - should have prefix "Darvis" . e.g DarvisVis, DavisAlign, DarvisOrb etc.
- Actor Message Struct - Should have suffix "Msg". e.e VisMsg, AlignMsg, OrbMsg etc.
To start with the implementation, one should understand the base framework that is needed to be used, in order to link the new feature with the Darvis framework to be usable/ callable.
Core framework source file, containing Prototype trait "Function" to be implemented by each Actor feature.
"Function" Trait - This trait have a function "handle" to be implemented for each new actor introduced.
Following is the prototype of the "handle" function:
fn handle(&mut self, _context: axiom::prelude::Context, message: Message) -> ActorResult<()>;
For implementation example refer "vis.rs" for clarity.
Contains FeatureManager that can instantiate any feature by string name, this is useful for our implementation is can be controlled using config file "config.yaml" FeatureManager contains to public functions. i.e. "new" and "handle", both used by the framework while instantiating a Feature as an Actor.
"getmethod" function - contains pattern match entries for all the existing Features. Give control over instancing object at run time.
For explanation per say, will be using "vis.rs" as an example.
1. Create a new rust source file within src directory, i.e. "vis.rs".
2. use following imports for bare minimum implementation .
use axiom::prelude::*;
use serde::{Deserialize, Serialize};
use crate::pluginfunction::Function;
3. Declare a public Structure (Prefix Darvis) with all the relevant states and derive "Debug" and "Clone" trait. This struct will contain core implementation for the new feature.
#[derive(Debug, Clone)]
// Vis state data
pub struct DarvisVis {
traj_img: Mat, // Trajectory image for visualization
cam_img: Mat, // Camera image for visualization
traj_pos: Vector3, // Built up trajectory translation
traj_rot: Matrix3, // Built up trajectory rotation
id: String
// actor_ids: std::collections::HashMap<String, axiom::actors::Aid>, // Collection of all spawned actor ids
}
4. For the declared structure for the feature, in previous step, define a public constructor i.e. "new" without any parameters or just a string parameter which sets id for the object
pub fn new(id: String) -> DarvisVis {
DarvisVis {
traj_img: Mat::new_rows_cols_with_default(750, 1000, core::CV_8UC3, core::Scalar::all(0.0)).unwrap(),
cam_img: Mat::default(),
traj_pos: Vector3::zeros(),
traj_rot: Matrix3::zeros(),
id: id
// actor_ids: ids,
}
}
*** **5. Define a public function, callable by the actor framework, containing the core function implementation for the target feature** Following is the example prototype that should be used. > pub fn visualize(&mut self, context: Context, message: Message) -> ActorResult<()> {
For Visualization "visualize" public function is implemented and then called in the trait "Function" that implements "handle" function.
6. Implement "Function" trait for the Feature and call the struct's core function implemented in previous step.
impl Function for DarvisVis {
fn handle(&mut self, _context: axiom::prelude::Context, message: Message) -> ActorResult<()>
{
self.visualize(_context, message).unwrap();
Ok(Status::done(()))
}
}
7. Declare a structure for handling Messages for the actor i.e. "VisMsg", which should be serializable i.e. derive Serialize, Deserialize trait.
// Public message struct for the actor
#[derive(Debug, Serialize, Deserialize)]
pub struct VisMsg {
// Pose of image paths to read in/extract, Poses take 2 matrixes, pos and rot <int type, # rows, # col, data storage?>
new_pose: Pose,
// all actor ids
actor_ids: std::collections::HashMap<String, axiom::actors::Aid>
}
8. Implement public constructor for instantiating the Actor message
impl VisMsg {
pub fn new(pose: Pose, ids: std::collections::HashMap<String, axiom::actors::Aid>) -> Self {
Self {
new_pose: pose,
actor_ids: ids,
}
}
}
9. In "registerplugin.rs", add an entry for the desired feature name as string within "getmethod" function for the new feature call its "FunctionProxy" trait object created with new Boxed Feature constructor.
"vis" => FunctionProxy {function: Box::new(crate::vis::DarvisVis::new(id))}
Note: This last step is crucial and should always add new entry below last feature implemented and above the "_" pattern entry.
This is done by the framework in "main.rs" source file. Example for spawning a visualization actor.
let vis_aid = system.spawn().name("visulization").with(registerplugin::FeatureManager::new("vis".to_string(),"vis".to_string()), registerplugin::FeatureManager::handle).unwrap();