Add a New Hardware Device
navigate supports several standard device categories:
Cameras
Data acquisition cards
Deformable mirrors
Filter wheels
Galvo scanners
Lasers
Remote-focusing systems
Shutters
Stages
Zoom devices
This guide explains how to add a new device (for example, CustomStage) to one of these categories.
Note
Integrating new hardware requires solid Python and object-oriented programming experience.
What Is the Device Abstraction Layer?
The device abstraction layer provides a shared control interface across vendors. For example, stage classes expose a common stop() method. When a user clicks Stop Stage, that command flows from controller to model to the concrete stage class (for example, CustomStage), where it is translated into device-specific communication.
Device Integration Approaches
There are two primary integration paths:
Plugin: Recommended if you want to track upstream updates while maintaining custom hardware support. Plugins can also introduce non-standard device types. See Plugin Architecture and Write a Custom Device Plugin.
Fork: Useful for internal development where deep core changes are required. In some cases, these changes can later be proposed upstream.
Device Class Creation
Create a device class in the appropriate directory under
src/navigate/model/devices/.Inherit from the correct abstract base class (for example,
StageBasefor a stage).Use CamelCase class names that describe the device (for example,
NewportStage).Place manufacturer-specific API wrappers in the relevant manufacturer/API directory.
Establish Device Communication
Implement a dedicated connection function (for example,
build_custom_stage_connection()).Keep connection setup separate from the device class when possible.
This separation allows direct hardware tests outside the full navigate runtime (for example, in a notebook or standalone script).
Device Class Constructor
Define
__init__with the required startup parameters (typicallymicroscope_name,device_connection,configuration, and optional device identifiers).Load and validate settings from the configuration.
Reuse the established connection object instead of creating a second connection inside the class.
For stages, this often includes mapping navigate axes to device axes (for example, {"x": "X", "y": "Y", "z": "Z"}).
Device Class Methods
Implement required methods from the base class.
Override defaults where needed for vendor behavior.
Add device-specific methods only when they do not break shared interface expectations.
Startup and Configuration
Register startup logic in
src/navigate/model/device_startup_functions.Parse configuration values and construct the connection/device objects there.
Use retry logic (for example,
auto_redial) to handle transient communication failures.
Integration with Microscope Configurations
Add the new device under the correct microscope entries in
configuration.yaml.Ensure startup wiring injects the new device connection into each configured microscope object that needs it.
Testing and Validation
Test the integration across the supported acquisition modes and expected error paths.
Name test files as
test_<module_name>.py.Place device tests under
test/model/devices/.Use
pytestfor hardware and synthetic-path validation.
Following this workflow keeps new integrations consistent with the existing architecture and reduces long-term maintenance risk.