Feat/pymmcore integration#264
Open
beniroquai wants to merge 2 commits into
Open
Conversation
Introduce optional pymmcore-plus integration: add a process-wide MMCoreManager singleton and three MMCore* device managers (detector, positioner, laser) that wrap Micro-Manager adapters. Include unit tests that exercise the DemoCamera adapter, example setup JSON files for demo and Andor configurations, and user documentation for pymmcore-plus integration. Add a GitHub Actions workflow to run MMCore tests and to build/publish arm64 mmCoreAndDevices artifacts, plus a Raspberry Pi install script for building Micro-Manager on arm64. Minor controller comment and pyproject update included.
Improve Micro-Manager (pymmcore) integration and fix several device manager behaviors. Docs: require MM 2.0, add detailed install/discovery guidance and adapter-path resolution. Add new example_mmcore_andor_cfg.json and update example_mmcore_andor.json. Tests: use MMCoreManager.discover_adapter_paths() for adapter availability and clearer skip reason. MMCoreManager: implement discover_adapter_paths(), platform globs, Windows DLL dir handling, adapter-path resolution, MM2 verification, and better logging. LaserController: return [0,1] for binary lasers. DetectorManager: fix parameter name mapping (gain) and avoid raising on unknown parameters. MMCoreDetectorManager: track running/frame number, make getLatestFrame optionally return frame number and handle errors, and update running flag on start/stop. MMCorePositionerManager.move: extend signature to support absolute moves, optional blocking, and emit position update signal after moves.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a new integration layer that lets ImSwitch control Micro-Manager device adapters (camera/stage/laser) via pymmcore-plus, along with example setups, docs, tests, and a CI workflow for arm64 adapter builds.
Changes:
- Introduces
MMCoreManager(shared singleton) plusMMCore*Managerdevice managers for detectors, positioners, and lasers. - Adds documentation, example setup JSONs, and Raspberry Pi install guidance for Micro-Manager adapters.
- Adds unit tests for the new managers and a GitHub Actions workflow to test on x86_64 and build adapters for arm64.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
pyproject.toml |
Adds pymmcore-plus as an optional dependency extra (pymmcore). |
imswitch/imcontrol/model/managers/MMCoreManager.py |
Implements lazy, shared CMMCorePlus singleton + adapter path discovery helpers. |
imswitch/imcontrol/model/managers/__init__.py |
Exposes MMCoreManager from the managers package for imports/tests. |
imswitch/imcontrol/model/managers/detectors/MMCoreDetectorManager.py |
New detector manager wrapping MMCore camera devices, including dynamic property discovery. |
imswitch/imcontrol/model/managers/positioners/MMCorePositionerManager.py |
New positioner manager wrapping MMCore XY/Z stages with cfg/manual loading modes. |
imswitch/imcontrol/model/managers/lasers/MMCoreLaserManager.py |
New laser manager supporting shutter mode and property mode. |
imswitch/imcontrol/model/managers/detectors/DetectorManager.py |
Alters parameter-setting behavior (exposure/gain name mapping). |
imswitch/imcontrol/controller/controllers/LaserController.py |
Changes binary laser range reporting to return [0, 1]. |
imswitch/imcontrol/controller/controllers/experiment_controller/experiment_normal_mode.py |
Adds a TODO comment. |
imswitch/imcontrol/_test/unit/test_mmcore_managers.py |
Adds pytest coverage for MMCore managers using DemoCamera (skipped if unavailable). |
imswitch/_data/user_defaults/imcontrol_setups/example_mmcore_demo.json |
Adds DemoCamera-based example setup (manual mode). |
imswitch/_data/user_defaults/imcontrol_setups/example_mmcore_andor_cfg.json |
Adds an Andor inline-declaration example setup. |
imswitch/_data/user_defaults/imcontrol_setups/example_mmcore_andor.json |
Adds cfg-based “real hardware” example setup. |
docs/pymmcore-integration.md |
Adds end-user documentation for installing and using the integration. |
.github/workflows/build-mm-arm64.yml |
Adds CI workflow to test integration on x86 and build arm64 adapters. |
install_micromanager_raspi.sh |
Adds Raspberry Pi build/install script for Micro-Manager + pymmcore stack. |
micromanager-userguide.md |
Adds a standalone usage guide for Micro-Manager + pymmcore-plus. |
pymmcore-feature-integraion.md |
Adds a long implementation-plan style document (currently reads like an internal prompt). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+210
to
+221
| def getLatestFrame(self, returnFrameNumber=False) -> np.ndarray: | ||
| try: | ||
| if self._core.getRemainingImageCount() > 0: | ||
| return self._core.getLastImage() | ||
| except Exception: | ||
| pass | ||
| try: | ||
| self._core.snap() | ||
| self._frameNunber += 1 | ||
| if returnFrameNumber: | ||
| return self._core.getImage(), self._frameNunber | ||
| return self._core.getImage() |
Comment on lines
+133
to
+136
| new_pos = self.getPosition(axis) | ||
| self._position[axis] = new_pos | ||
| self._commChannel.sigUpdateMotorPosition.emit() # TODO: This is a hacky workaround to force Imswitch to update the motor positions in the gui.. | ||
|
|
Comment on lines
+3
to
+7
| # install_micromanager_rpi.sh | ||
| # | ||
| # Build and install Micro-Manager (MMCore + device adapters) and pymmcore-plus | ||
| # on a Raspberry Pi running Pi OS Bookworm (64-bit / arm64). | ||
| # |
Comment on lines
+1
to
+49
| # CLAUDE.md — pymmcore-plus Integration into ImSwitch | ||
|
|
||
| You are implementing Micro-Manager hardware support in the openUC2/ImSwitch | ||
| microscopy platform via `pymmcore-plus`. This adds support for any camera, | ||
| stage, or laser that has a Micro-Manager device adapter (Andor, Hamamatsu, | ||
| Basler, ASI, Prior, Thorlabs, Coherent, etc.) alongside the existing | ||
| ESP32/UC2-REST managers. | ||
|
|
||
|
|
||
| ## STEP 0 — Reconnaissance (do this FIRST, before writing any code) | ||
|
|
||
| Run these commands and summarize what you find. Paste the summary as a | ||
| comment in the first commit. | ||
|
|
||
| ```bash | ||
| # Check for any existing pymmcore/MMCore work | ||
| rg -n -S "pymmcore|MMCore|micromanager|micro.manager" --type py | ||
|
|
||
| # Map the manager directory structure | ||
| find imswitch/imcontrol/model/managers -name "*.py" | head -60 | ||
|
|
||
| # Read the base classes — you MUST match these signatures exactly | ||
| cat imswitch/imcontrol/model/managers/detectors/DetectorManager.py | ||
| cat imswitch/imcontrol/model/managers/positioners/PositionerManager.py | ||
| cat imswitch/imcontrol/model/managers/lasers/LaserManager.py | ||
|
|
||
| # Read one concrete example of each to understand the pattern | ||
| cat imswitch/imcontrol/model/managers/detectors/HIKCamManager.py 2>/dev/null || \ | ||
| ls imswitch/imcontrol/model/managers/detectors/ | ||
| cat imswitch/imcontrol/model/managers/positioners/ESP32StageManager.py 2>/dev/null || \ | ||
| ls imswitch/imcontrol/model/managers/positioners/ | ||
| cat imswitch/imcontrol/model/managers/lasers/ESP32LEDLaserManager.py 2>/dev/null || \ | ||
| ls imswitch/imcontrol/model/managers/lasers/ | ||
|
|
||
| # Check how managers are registered / discovered | ||
| cat imswitch/imcontrol/model/managers/detectors/__init__.py | ||
| cat imswitch/imcontrol/model/managers/positioners/__init__.py | ||
| cat imswitch/imcontrol/model/managers/lasers/__init__.py | ||
|
|
||
| # Check the setup JSON schema / info classes | ||
| rg -n "class DetectorInfo" --type py | ||
| rg -n "class LaserInfo" --type py | ||
| rg -n "class PositionerInfo" --type py | ||
|
|
||
| # Check how lowLevelManagers work | ||
| rg -n "lowLevelManagers" imswitch/imcontrol/model/managers/ --type py | head -20 | ||
|
|
||
| # Look at an existing setup JSON for the structure | ||
| find . -name "*.json" -path "*/imcontrol_setups/*" | head -10 |
Comment on lines
+119
to
+124
| parameters["Exposure"] = DetectorNumberParameter( | ||
| group="Acquisition", | ||
| value=current_exposure, | ||
| editable=True, | ||
| valueUnits="ms", | ||
| ) |
Comment on lines
+129
to
+132
| else: | ||
| self._logger.warning(f"Ignoring move on unsupported axis '{axis}'") | ||
| return self._position[axis] | ||
|
|
Comment on lines
229
to
232
| if lManager.isBinary: | ||
| return None | ||
| return [0, 1] | ||
| else: | ||
| return (lManager.valueRangeMin, lManager.valueRangeMax) |
Comment on lines
+7
to
+11
| "managerProperties": { | ||
| "cfgPath_": "/home/pi/micro-manager-configs/Andor_ASI.cfg", | ||
| "cfgPath": "C:\\Users\\benir\\Desktop\\andor.cfg", | ||
| "deviceLabel": "Andor sCMOS Camera" | ||
| }, |
Comment on lines
159
to
162
| if name.find("posure")>0:name = "exposure" # TODO: Hacky fix for inconsistent naming | ||
| if name.find("ain")>0:name = "gain" # TODO: Hacky fix for inconsistent naming | ||
| self.__parameters[name].value = value | ||
| return self.parameters |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces comprehensive support for integrating Micro-Manager device adapters into ImSwitch via the
pymmcore-plusPython bindings. It adds detailed documentation, provides example configuration files for various hardware setups, and establishes a new GitHub Actions workflow to build and test Micro-Manager adapters (including on arm64). These changes make it significantly easier to use a wide range of hardware with ImSwitch, both in development and deployment environments.Micro-Manager integration and documentation:
docs/pymmcore-integration.md, that explains how to use ImSwitch with Micro-Manager adapters viapymmcore-plus, including installation steps, configuration modes, adapter discovery, and platform-specific notes.Example configuration files:
example_mmcore_demo.jsonshowing a minimal DemoCamera setup, andexample_mmcore_andor_cfg.jsonfor inline device declaration, both demonstrating how to configure detectors, lasers, and positioners using the new MMCore manager classes. [1] [2]example_mmcore_andor.jsonshowing a setup using a Micro-Manager.cfgfile for real hardware (Andor camera and ASI stage), illustrating configuration for both Windows and Linux paths.CI and build improvements:
.github/workflows/build-mm-arm64.yml) to build Micro-Manager adapters for arm64, testpymmcore-plusintegration, and publish prebuilt binaries as workflow artifacts or GitHub Releases. This facilitates using Micro-Manager on platforms like Raspberry Pi.Known LImitations:
exposure, MM providesExposure