Repository navigation
Add a beam-steering interface with Galvo and EOD devices - #81
Open
parzival1401 wants to merge 6 commits into
Open
parzival1401 wants to merge 6 commits into
parzival1401 wants to merge 6 commits into
Conversation
Experiment scripts drive the galvo with raw setdac calls against a specific Triggerscope, and the EOD with raw DAQmx writes against a specific NI channel, so the hardware choice is baked into every script and angles are converted by hand each time. This adds a BeamSteerer interface that separates three things: the device being steered (Galvo, EOD), the backend emitting the two voltages (TriggerscopeBackend, DAQmxBackend), and the AngleCalibration mapping between them. Moving a galvo from the Triggerscope to the NI card is a one-line change with nothing downstream touched. Devices take volts or milliradians. The calibration is a 2x2 mrad/V matrix plus a zero-angle offset, so X/Y cross-coupling and a non-zero rest point are both captured. The EOD additionally models the high-voltage amplifier, so it can be commanded in DAQ volts (setvoltage) or in crystal volts (setcrystalvoltage). Which of the two a calibration was measured against is an explicit field, because getting it wrong is a silent factor-of-gain error on every angle. Out-of-range commands throw before anything reaches hardware, and gridscan range-checks the whole grid before its first move, so a scan that would run off the end fails immediately rather than halfway through. Per CLAUDE.md the three SteeringBackend stubs throw "not implemented" rather than returning nothing. Also adds four step-through dev scripts -- test_galvo.jl, test_EOD.jl, test_triggerscope.jl and a new section in test_nidaq.jl -- each doing setup, write a voltage, read it back. Version 0.2.6 -> 0.2.7-DEV: a new interface and devices are a feature, so Z. Tested without hardware against a recording backend (test/beam_steering.jl): calibration round-trips, limit enforcement, the amplifier conversions, the scan paths, and that the backend stubs throw. Local suite 2242 passed, including 856 Interface Contract. The one failure and one error are test/skills.jl's symlink containment check, which needs Administrator privileges on Windows; that file is unchanged from main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t exists The "Backends" testset constructed a Triggerscope4 unconditionally. Its constructor builds a LibSerialPort.SerialPort eagerly, and sp_get_port_by_name throws SP_ERR_ARG where the named port does not exist, so the testset errored on CI. It passed locally only because Windows accepts a name for a port that is not there, which is what made this look safe when it was checked there. The range table and every NI-backend assertion are unconditional: neither touches a device. The Triggerscope assertions now run only when a Triggerscope4 can be constructed, and log why they were skipped otherwise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
|
Review of The abstraction is good:
It is non-breaking. Full suite on the head (kitt, Julia 1.13): 2249 tests, 2246 pass, 3 known-broken, 0 fail. Changes before merge:
Smaller, fix if convenient:
Main has moved on since this branch was cut (it is now 0.2.7-DEV, with the camera, stage, light-source and Meadowlark work). Merging main into this branch conflicts only in Hardware checks on the MINFLUX microscope before relying on it:
|
# Conflicts: # test/runtests.jl
- An explicit limit outside the backend's range now throws instead of warning (a ±2.5 V Triggerscope with ±10 V limits sent DAC1,98302), and limits are snapped inward onto the backend's grid (snap_limits), so rounding to a DAC code can no longer exceed a limit by one LSB. - EOD requires max_crystal_volts and holds its DAQ limits to max_crystal_volts / gain: omitted limits are narrowed to it, explicit limits beyond it throw. - TriggerscopeBackend no longer sends CLEAR_ALL on open, which erased sequences other devices on a shared board had programmed. A failed open closes a port it opened. - DAQmxBackend releases the X task when the Y task fails, refuses a second open, stops and clears each task in its own try, and a failed park throws after the tasks are released. The Triggerscope backend does the same. - A device refuses a second initialize; shutdown of a closed device does nothing; a failed write or park leaves the recorded voltages NaN instead of a stale or (0, 0) pair. gridscan returns to its start when the scan throws and rethrows the scan's error. - Exports trimmed to the device API; the helpers are public, reached as MicroscopeControl.<name>. - BeamSteerer is registered in test/contract.jl (interfaces, shadowed generics, a BeamSteerer contract testset) and in the API map, with a gui panel. The shared device methods move from interface_functions.jl, which the API map reads as throwing stubs, into shared_methods.jl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ystal_volts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ll and panel fields Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Experiment scripts drive the galvo with raw
setdaccalls against a specificTriggerscope, and the EOD with raw DAQmx writes against a specific NI channel, so the
hardware choice is baked into every script and angles are converted by hand each time.
This adds a
BeamSteererinterface that separates three things:Galvo,EODTriggerscopeBackend,DAQmxBackendAngleCalibration, the 2×2 mrad/V map between themMoving a galvo from the Triggerscope to the NI card is a one-line change, with nothing
downstream touched.
Control
Devices take volts or milliradians. The calibration is a 2×2 mrad/V matrix plus a
zero-angle offset, so X/Y cross-coupling and a non-zero rest point are both captured.
The
EODadditionally models the high-voltage amplifier, so it can be commanded in DAQvolts (
setvoltage) or in crystal volts (setcrystalvoltage). Which of the two acalibration was measured against is an explicit field (
calibration_basis), becausegetting it wrong is a silent factor-of-gain error on every angle — the monitor-based
analysis the lab already uses produces the
:crystalform.Safety
Out-of-range commands throw before anything reaches hardware, so a bad command never
half-applies.
gridscanrange-checks the whole grid before its first move, so a scanthat would run off the end fails immediately rather than halfway through. Per CLAUDE.md
the three
SteeringBackendstubs throw"not implemented"rather than returning nothing.Also
Four step-through dev scripts —
test_galvo.jl,test_EOD.jl,test_triggerscope.jl,and a new section appended to
test_nidaq.jl— each doing setup, write a voltage, readit back.
Version
0.2.6→0.2.7-DEV: a new interface and devices are a feature, so Z.Testing
No hardware required.
test/beam_steering.jlruns against a recording backend and coverscalibration round-trips, limit enforcement, the amplifier conversions, the scan paths,
and that the backend stubs throw.
Local suite: 2242 passed, including 856 Interface Contract. The one failure and one
error are
test/skills.jl's symlink containment check, which needs Administratorprivileges on Windows; that file is unchanged from main.
Known gap
BeamSteereris not intest/contract.jl'sinterfacestuple, soGalvoandEODarenot covered by the core-method contract. Adding them requires a
gui(::BeamSteerer),which is deliberately not in this PR. Happy to add it here or as a follow-up.
Noticed, not touched
ThorCamCSC'sgetdataloops oversequence_frames, which is not in scope in thatfunction — it is a parameter of
sequence(). It would throwUndefVarErrorif asequence were read back. Unrelated to this change, so it is left alone and reported here
rather than folded in.
🤖 Generated with Claude Code