Thomas Ales 44febe34b8 Phase 5: shared worker base, self-rescheduling polls, driver robustness
gui/qt_workers.py — one QueueWorker base replaces the per-device command
queue + dispatch + signal boilerplate. The loop blocks on the queue
instead of waking 10-20x/second forever (test_idle_worker_does_not_spin
asserts an idle worker burns ~no CPU). PollingQueueWorker adds
self-rescheduling polling: the next poll is queued only after the
previous finishes, so a device slower than the interval can't accumulate
a backlog (test_polling_never_overlaps_or_backs_up).

Helios responsiveness — the concrete bug that motivated the above: a free
running 1 s QTimer queued a status poll that took ~2 s, so the queue grew
for as long as the panel stayed connected.
- helios_laser._query reads until the CR terminator instead of sleeping a
  fixed 0.05 + 0.2 s per query
- one _query_int() helper replaces five copies of parse-with-logging
- polling is now driven by the worker; HeliosWindow's QTimer is gone
- dropped __del__, which disabled the laser and wrote to the serial port
  from the garbage collector at an unpredictable time

helios_test_app.py — the worker was moveToThread'd but every call site
invoked its methods directly, so all serial I/O (including the sleeps)
ran on the GUI thread; Query All froze the UI for ~2 s. Calls now go
through a queued signal to a pyqtSlot. Also: connect/disconnect cycles
leaked a QThread + worker + 9 connections each time; 16 copies of the
not-connected guard collapse to _require_connection(); the Query Power
button called a method that has never existed (AttributeError popup) and
is now disabled and documented in KNOWN_ISSUES.

DCBiasImageWidget preallocates its image and uses set_data/set_clim, so
the live preview stops rebuilding the array and the whole artist tree per
row (O(rows^2) over a scan).

bbd20x: connect() now raises when no bays respond instead of reporting
success on the wrong port; disconnect() joins with a timeout so a wedged
reader can't hang shutdown; one _channel_for() helper replaces four
copy-pasted axis mappings; hardcoded travel limits become TRAVEL_MM; the
joke error strings are gone.

gui/widgets.py adds the shared ConnectionBar / PortSelector / bounded
LogConsole / StatusGrid for the test benches to adopt. 65 tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 11:21:29 -05:00
2026-02-09 16:33:01 -06:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-05-22 09:38:39 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00
2026-07-28 09:20:58 -05:00

scanengine-3

SRAS Scanning and Instrumentation Control Platform

Overview

scanengine-3 is a unified platform for scanning acoustic microscopy and precision instrumentation control. It integrates multiple hardware control modules into a single cohesive PyQt6-based application.

Key Features

  • Stage Control: ThorLabs BBD202/BBD203 motor controller with 3-axis positioning
  • Laser Systems: Helios and Coherent HOPS laser control
  • Data Acquisition: Tektronix oscilloscope integration with fast-frame support
  • Scan Planning: Automated raster scan generation and execution
  • Real-time Monitoring: Live status updates and progress tracking

Hardware Components

Motion Control

  • ThorLabs BBD202/BBD203 Motor Controller
    • 3-channel APT protocol driver
    • Precision positioning with encoder feedback
    • Programmable velocity and acceleration
    • Trigger output support for synchronized data acquisition

Laser Systems

  • Helios Laser System

    • Frequency control (16.7-125 kHz)
    • Current control (0-7000 mA)
    • Multiple pulse modes
    • Temperature and power monitoring
  • Coherent HOPS Laser

    • I2C/FTDI interface
    • Power and modulation control
    • Temperature monitoring

Data Acquisition

  • Tektronix MSO/DPO Series Oscilloscopes
    • Direct socket communication (no VISA overhead)
    • Fast-frame acquisition for high-speed scanning
    • Multi-channel waveform capture
    • Configurable triggering

Microscope Systems

  • Genesis Microscope (stub implementation)
  • T3R Timing Device (stub implementation)

Project Structure

scanengine-3/
├── scanengine/                    # Main application package
│   ├── __init__.py
│   ├── app.py                     # Main application entry point
│   ├── main_launcher.ui           # Main launcher UI
│   ├── new_scan_wizard.ui         # Scan wizard UI
│   └── options.ui                 # Options dialog UI
│
├── hardware/                      # Hardware driver package
│   ├── __init__.py
│   ├── bbd202.py                  # ThorLabs stage controller
│   ├── uc480_camera.py            # IDS/ThorLabs camera
│   ├── tektronix_base.py          # Tektronix oscilloscope
│   ├── coherent_hops_laser.py     # Coherent HOPS laser
│   └── genesis_core.py            # Genesis laser core logic
│
├── scanning/                      # Scan planning package
│   ├── __init__.py
│   ├── sc3_scan_model.py          # Scan model
│   └── stage_scan_plan_generator.py  # Scan path planning
│
├── tools/                         # Standalone executable tools
│   ├── genesis_laser_control.py   # Standalone Genesis app
│   └── genesis_laser_gui.py       # Alternative Genesis GUI
│
├── tests/                         # Test files
│   ├── __init__.py
│   ├── test_camera_integration.py
│   ├── test_genesis_connection.py
│   ├── test_genesis_protocol.py
│   ├── test_rotated_aoi.py
│   └── test_temperature_scaling.py
│
├── docs/                          # Documentation
│   ├── hardware/                  # Hardware documentation
│   │   ├── BBD203_CONNECTION_GUIDE.md
│   │   ├── BBD203_Communications_Protocol.md
│   │   ├── BBD203_DRIVER_README.md
│   │   ├── HELIOS_DRIVER_README.md
│   │   ├── GENESIS_LASER_README.md
│   │   └── laser_control_implementation_guide.md
│   └── protocols/                 # Protocol specifications
│       ├── apt_communications_protocol.pdf
│       ├── helios_comms_protocol.pdf
│       └── thorlabs_mls_protocol.pdf
│
├── lib/                           # Binary libraries (not in git)
│   ├── libueye_api64.so.3.82
│   ├── ueye_loader.c
│   └── ueye_loader.so
│
├── config.json                    # System configuration
├── requirements.txt               # Python dependencies
├── README.md                      # This file
├── SETUP.md                       # Setup instructions
└── LICENSE                        # License file

Quick Start

Installation

# Clone or navigate to project directory
cd scanengine-3

# Create virtual environment (recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

Running the Application

# Main GUI application
python -m scanengine.app

# Genesis laser control tool
python tools/genesis_laser_control.py

# Alternative Genesis laser GUI
python tools/genesis_laser_gui.py

Dependencies

  • PyQt6 (>=6.4.0) - GUI framework
  • pyserial (>=3.5) - Serial communication
  • pyvisa (>=1.13.0) - VISA instrument control
  • pyvisa-py (>=0.7.0) - Pure Python VISA backend
  • pyftdi (>=0.54.0) - FTDI USB device support

Usage Examples

Stage Control

from hardware.bbd202 import BBD202Controller

# BBD202/BBD203 controller example
controller = BBD202Controller()
controller.connect("/dev/ttyUSB0")  # Serial port
# Use controller for stage operations

Oscilloscope Acquisition

from hardware.tektronix_base import TektronixOscilloscopeBase

scope = TektronixOscilloscopeBase()
scope.connect("192.168.1.100", 4000)
scope.set_acquire_mode("SAMPLE")
waveform = scope.get_curve_binary(1)  # Channel 1

Laser Control

from hardware.coherent_hops_laser import CoherentHOPSLaser

laser = CoherentHOPSLaser()
laser.connect()
laser.set_power_level(50.0)  # 50% power
laser.enable_output(True)

Camera Control

from hardware.uc480_camera import UC480Camera

camera = UC480Camera(camera_id=0)
camera.initialize()
camera.start_capture()
# Camera operations

Configuration

Stage Settings

Stage configuration is stored in ~/.nuescan/stage_settings.json:

  • Velocity and acceleration profiles
  • Trigger configuration
  • Axis limits and safety parameters

Serial Port Configuration

Hardware devices are accessed via:

  • BBD202/203: USB with automatic serial number detection
  • Helios: RS-232 serial port (9600 baud, 8N1)
  • HOPS Laser: FTDI USB (I2C interface)
  • Oscilloscope: Ethernet/LXI (TCP socket on port 4000)

Development

Adding New Hardware

  1. Create driver module in hardware/ directory
  2. Implement connection, control, and status methods
  3. Add UI elements to main window or create new dialog
  4. Connect signals in main_window.py

Testing Without Hardware

All hardware modules include stub implementations or simulation modes. The GUI can be developed and tested without physical devices connected.

Documentation

Detailed documentation available in project subdirectories:

License

Copyright (C) 2025 Thomas Ales Licensed under GNU General Public License v2.0

See LICENSE file for full license text.

Support

For issues, questions, or contributions, please refer to the project documentation or contact the development team.

Version

scanengine-3 v0.1.0 - Initial unified release

S
Description
No description provided
Readme GPL-2.0 7.1 MiB
Languages
Python 100%