forked from ROMEO/nexosim
Introduce ProtoModel trait, remove Model::setup
The external_input example has been as well adapted and (at least temporarily) simplifiedi/modified to remove the dependencies on `atomic_wait` and `mio`.
This commit is contained in:
@ -3,27 +3,29 @@
|
||||
//!
|
||||
//! This example demonstrates in particular:
|
||||
//!
|
||||
//! * model prototypes,
|
||||
//! * submodels,
|
||||
//! * outputs cloning,
|
||||
//! * self-scheduling methods,
|
||||
//! * model setup,
|
||||
//! * model initialization,
|
||||
//! * simulation monitoring with event streams.
|
||||
//! * simulation monitoring with buffered event sinks.
|
||||
//!
|
||||
//! ```text
|
||||
//! ┌──────────────────────────────────────────────┐
|
||||
//! │ Assembly │
|
||||
//! │ ┌──────────┐ ┌──────────┐ │
|
||||
//! PPS │ │ │ coil currents │ │ │position
|
||||
//! Pulse rate ●───────►│──►│ Driver ├───────────────►│ Motor ├──►│─────────►
|
||||
//! (±freq)│ │ │ (IA, IB) │ │ │(0:199)
|
||||
//! │ └──────────┘ └──────────┘ │
|
||||
//! └──────────────────────────────────────────────┘
|
||||
//! ┌────────────────────────────────────────────┐
|
||||
//! │ Assembly │
|
||||
//! │ ┌──────────┐ │
|
||||
//! PPS │ │ │ coil currents ┌─────────┐ │
|
||||
//! Pulse rate ●──────────┼──►│ Driver ├───────────────►│ │ │
|
||||
//! (±freq) │ │ │ (IA, IB) │ │ │ position
|
||||
//! │ └──────────┘ │ Motor ├──┼──────────►
|
||||
//! torque │ │ │ │ (0:199)
|
||||
//! Load ●──────────┼──────────────────────────────►│ │ │
|
||||
//! │ └─────────┘ │
|
||||
//! └────────────────────────────────────────────┘
|
||||
//! ```
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use asynchronix::model::{Model, SetupContext};
|
||||
use asynchronix::model::{BuildContext, Model, ProtoModel};
|
||||
use asynchronix::ports::{EventBuffer, Output};
|
||||
use asynchronix::simulation::{Mailbox, SimInit, SimulationError};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
@ -32,36 +34,59 @@ mod stepper_motor;
|
||||
|
||||
pub use stepper_motor::{Driver, Motor};
|
||||
|
||||
pub struct MotorAssembly {
|
||||
/// A prototype for `MotorAssembly`.
|
||||
pub struct ProtoMotorAssembly {
|
||||
pub position: Output<u16>,
|
||||
init_pos: u16,
|
||||
load: Output<f64>,
|
||||
pps: Output<f64>,
|
||||
}
|
||||
|
||||
impl MotorAssembly {
|
||||
impl ProtoMotorAssembly {
|
||||
/// The prototype has a public constructor.
|
||||
pub fn new(init_pos: u16) -> Self {
|
||||
Self {
|
||||
position: Default::default(),
|
||||
init_pos,
|
||||
load: Default::default(),
|
||||
pps: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the pulse rate (sign = direction) [Hz] -- input port.
|
||||
// Input methods are in the model itself.
|
||||
}
|
||||
|
||||
/// The parent model which submodels are the driver and the motor.
|
||||
pub struct MotorAssembly {
|
||||
/// Private output for submodel connection.
|
||||
pps: Output<f64>,
|
||||
/// Private output for submodel connection.
|
||||
load: Output<f64>,
|
||||
}
|
||||
|
||||
impl MotorAssembly {
|
||||
/// The model now has a module-private constructor.
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
pps: Default::default(),
|
||||
load: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pulse rate (sign = direction) [Hz] -- input port.
|
||||
pub async fn pulse_rate(&mut self, pps: f64) {
|
||||
self.pps.send(pps).await;
|
||||
self.pps.send(pps).await
|
||||
}
|
||||
|
||||
/// Torque applied by the load [N·m] -- input port.
|
||||
pub async fn load(&mut self, torque: f64) {
|
||||
self.load.send(torque).await;
|
||||
self.load.send(torque).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Model for MotorAssembly {
|
||||
fn setup(&mut self, setup_context: &SetupContext<Self>) {
|
||||
impl Model for MotorAssembly {}
|
||||
|
||||
impl ProtoModel for ProtoMotorAssembly {
|
||||
type Model = MotorAssembly;
|
||||
|
||||
fn build(self, ctx: &BuildContext<Self>) -> MotorAssembly {
|
||||
let mut assembly = MotorAssembly::new();
|
||||
let mut motor = Motor::new(self.init_pos);
|
||||
let mut driver = Driver::new(1.0);
|
||||
|
||||
@ -70,17 +95,20 @@ impl Model for MotorAssembly {
|
||||
let driver_mbox = Mailbox::new();
|
||||
|
||||
// Connections.
|
||||
self.pps.connect(Driver::pulse_rate, &driver_mbox);
|
||||
self.load.connect(Motor::load, &motor_mbox);
|
||||
assembly.pps.connect(Driver::pulse_rate, &driver_mbox);
|
||||
assembly.load.connect(Motor::load, &motor_mbox);
|
||||
driver.current_out.connect(Motor::current_in, &motor_mbox);
|
||||
// Note: it is important to clone `position` from the parent to the
|
||||
// submodel so that all connections made by the user to the parent model
|
||||
// are preserved. Connections added after cloning are reflected in all
|
||||
// clones.
|
||||
motor.position = self.position.clone();
|
||||
|
||||
setup_context.add_model(driver, driver_mbox, "driver");
|
||||
setup_context.add_model(motor, motor_mbox, "motor");
|
||||
// Move the prototype's output to the submodel. The `self.position`
|
||||
// output can be cloned if necessary if several submodels need access to
|
||||
// it.
|
||||
motor.position = self.position;
|
||||
|
||||
// Add the submodels to the simulation.
|
||||
ctx.add_submodel(driver, driver_mbox, "driver");
|
||||
ctx.add_submodel(motor, motor_mbox, "motor");
|
||||
|
||||
assembly
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +119,7 @@ fn main() -> Result<(), SimulationError> {
|
||||
|
||||
// Models.
|
||||
let init_pos = 123;
|
||||
let mut assembly = MotorAssembly::new(init_pos);
|
||||
let mut assembly = ProtoMotorAssembly::new(init_pos);
|
||||
|
||||
// Mailboxes.
|
||||
let assembly_mbox = Mailbox::new();
|
||||
|
Reference in New Issue
Block a user