Skip to content

Adding A Machine

Oshgnacknak edited this page Mar 1, 2026 · 1 revision

How can I add a new Machine?

Adding a new machine follows a common structure in machines/.

TLDR

Summary

When adding a new machine:

  • Create Folder machines/src/YOUR_MACHINE_NAME/.
  • Add the 4 files (mod.rs, new.rs, act.rs, api.rs).
  • Register it in machines/src/lib.rs with a unique constant.
  • mod.rs: define the struct + emit functions.
  • new.rs: assemble devices/controllers into the machine.
  • act.rs: implement the machine loop (MachineAct).
  • api.rs: define request (mutations) and response (events) types.

Tip: Start simple (copy MockMachine) and grow complexity as needed (add EtherCAT devices, controllers, etc.).


1. Create the folder

Create a new directory: machines/src/YOUR_MACHINE_NAME

At a minimum, this folder needs the following files:

  • mod.rs
  • new.rs
  • act.rs
  • api.rs

2. Register the module

Add your machine to machines/src/lib.rs:

// machines/src/lib.rs
pub mod buffer1;
pub mod extruder1;
pub mod laser;
pub mod mock;
pub mod registry;
pub mod winder2;
pub mod YOUR_MACHINE;

pub const VENDOR_QITECH: u16 = 0x0001;
pub const MACHINE_WINDER_V1: u16 = 0x0002;
pub const MACHINE_EXTRUDER_V1: u16 = 0x0004;
pub const MACHINE_LASER_V1: u16 = 0x0006;
pub const MACHINE_MOCK: u16 = 0x0007;
pub const MACHINE_BUFFER_V1: u16 = 0x0008;
pub const YOUR_MACHINE_V1: u16 = 0xffff; // pick a unique ID to avoid collisions also DO NOT touch any already defined ids!!

3. mod.rs

This file defines your machine struct and the required event emitters.

Look at MockMachine’s mod.rs for the simplest possible version.

At a minimum, you need:

  • emit_state
  • emit_live_values
  • A machine struct for state(e.g. MockMachine, Extruder, Laser, Winder, …)

More complex machines (e.g. Extruder, Winder) encapsulate controllers that in turn manage devices like EtherCAT terminals.

4 new.rs

This file implements MachineNewTrait for your machine. Here you assemble your machine from its parts — devices, controllers, and any state.

Minimal example: see MockMachine → basically no devices, just returns a struct.

Medium complexity: see Laser → wraps a single serial USB device.

High complexity: see Extruder → configures multiple EtherCAT devices inside controllers.

Think of new.rs as the factory: This is the place to declare which devices make up your machine and how they’re configured.

5. act.rs

This file implements the machine control loop using MachineAct. The act() method is called repeatedly by the control runtime.

impl MachineAct for YourMachine {
    fn act(&mut self, _now_ts: Instant) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
        Box::pin(async move {
            let now = Instant::now();

            // Update state, e.g. step a controller
            self.some_controller.update();

            // Emit live values ~30 Hz if machine is in Running mode
            if now.duration_since(self.last_measurement_emit) > Duration::from_secs_f64(1.0 / 30.0) {
                self.maybe_emit_state_event();
                self.emit_live_values();
                self.last_measurement_emit = now;
            }
        })
    }
}

6. api.rs

Defines the frontend-facing API for your machine:

Mutations → requests that the machine accepts (e.g. start/stop commands, setpoints, configuration updates).

Events → responses emitted to the frontend (e.g. live sensor data, alarms, machine state changes).

Look at MockMachine’s api.rs for a minimal version.

/// Mutations are API requests to control the machine
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum YourMachineMutation {
    Start,
    Stop,
    SetSpeed { rpm: f64 },
}

/// Events are responses sent to the frontend
#[derive(Debug, Clone, serde::Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum YourMachineEvent {
    StateChanged { state: String },
    LiveValues { rpm: f64, torque: f64 },
}

Clone this wiki locally